mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-31 10:22:15 +00:00
Merge branch 'devel' of github.com:nim-lang/Nim into devel
This commit is contained in:
@@ -253,7 +253,7 @@ compiler tcc:
|
||||
compilerExe: "tcc",
|
||||
cppCompiler: "",
|
||||
compileTmpl: "-c $options $include -o $objfile $file",
|
||||
buildGui: "UNAVAILABLE!",
|
||||
buildGui: "-Wl,-subsystem=gui",
|
||||
buildDll: " -shared",
|
||||
buildLib: "", # XXX: not supported yet
|
||||
linkerExe: "tcc",
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
import
|
||||
strutils, ast, astalgo, types, msgs, renderer, vmdef,
|
||||
trees, intsets, rodread, magicsys, options, lowerings
|
||||
|
||||
import platform
|
||||
from os import splitFile
|
||||
|
||||
when hasFFI:
|
||||
@@ -761,6 +761,49 @@ proc genCard(c: PCtx; n: PNode; dest: var TDest) =
|
||||
c.gABC(n, opcCard, dest, tmp)
|
||||
c.freeTemp(tmp)
|
||||
|
||||
proc genIntCast(c: PCtx; n: PNode; dest: var TDest) =
|
||||
const allowedIntegers = {tyInt..tyInt64, tyUInt..tyUInt64, tyChar}
|
||||
var signedIntegers = {tyInt8..tyInt32}
|
||||
var unsignedIntegers = {tyUInt8..tyUInt32, tyChar}
|
||||
let src = n.sons[1].typ.skipTypes(abstractRange)#.kind
|
||||
let dst = n.sons[0].typ.skipTypes(abstractRange)#.kind
|
||||
let src_size = src.getSize
|
||||
|
||||
if platform.intSize < 8:
|
||||
signedIntegers.incl(tyInt)
|
||||
unsignedIntegers.incl(tyUInt)
|
||||
if src_size == dst.getSize and src.kind in allowedIntegers and
|
||||
dst.kind in allowedIntegers:
|
||||
let tmp = c.genx(n.sons[1])
|
||||
var tmp2 = c.getTemp(n.sons[1].typ)
|
||||
let tmp3 = c.getTemp(n.sons[1].typ)
|
||||
if dest < 0: dest = c.getTemp(n[0].typ)
|
||||
proc mkIntLit(ival: int): int =
|
||||
result = genLiteral(c, newIntTypeNode(nkIntLit, ival, getSysType(tyInt)))
|
||||
if src.kind in unsignedIntegers and dst.kind in signedIntegers:
|
||||
# cast unsigned to signed integer of same size
|
||||
# signedVal = (unsignedVal xor offset) -% offset
|
||||
let offset = 1 shl (src_size * 8 - 1)
|
||||
c.gABx(n, opcLdConst, tmp2, mkIntLit(offset))
|
||||
c.gABC(n, opcBitxorInt, tmp3, tmp, tmp2)
|
||||
c.gABC(n, opcSubInt, dest, tmp3, tmp2)
|
||||
elif src.kind in signedIntegers and dst.kind in unsignedIntegers:
|
||||
# cast signed to unsigned integer of same size
|
||||
# unsignedVal = (offset +% signedVal +% 1) and offset
|
||||
let offset = (1 shl (src_size * 8)) - 1
|
||||
c.gABx(n, opcLdConst, tmp2, mkIntLit(offset))
|
||||
c.gABx(n, opcLdConst, dest, mkIntLit(offset+1))
|
||||
c.gABC(n, opcAddu, tmp3, tmp, dest)
|
||||
c.gABC(n, opcNarrowU, tmp3, TRegister(src_size*8))
|
||||
c.gABC(n, opcBitandInt, dest, tmp3, tmp2)
|
||||
else:
|
||||
c.gABC(n, opcAsgnInt, dest, tmp)
|
||||
c.freeTemp(tmp)
|
||||
c.freeTemp(tmp2)
|
||||
c.freeTemp(tmp3)
|
||||
else:
|
||||
globalError(n.info, errGenerated, "VM is only allowed to 'cast' between integers of same size")
|
||||
|
||||
proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||
case m
|
||||
of mAnd: c.genAndOr(n, opcFJmp, dest)
|
||||
@@ -1844,7 +1887,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
|
||||
if allowCast in c.features:
|
||||
genConv(c, n, n.sons[1], dest, opcCast)
|
||||
else:
|
||||
globalError(n.info, errGenerated, "VM is not allowed to 'cast'")
|
||||
genIntCast(c, n, dest)
|
||||
of nkTypeOfExpr:
|
||||
genTypeLit(c, n.typ, dest)
|
||||
of nkComesFrom:
|
||||
|
||||
@@ -92,6 +92,10 @@ Collections and algorithms
|
||||
* `sequtils <sequtils.html>`_
|
||||
This module implements operations for the built-in seq type
|
||||
which were inspired by functional programming languages.
|
||||
* `sharedtables <sharedtables.html>`_
|
||||
Nim shared hash table support. Contains shared tables.
|
||||
* `sharedlist <sharedlist.html>`_
|
||||
Nim shared linked list support. Contains shared singly linked list.
|
||||
|
||||
|
||||
String handling
|
||||
|
||||
@@ -296,6 +296,10 @@ empty ``discard`` statement should be used.
|
||||
For non ordinal types it is not possible to list every possible value and so
|
||||
these always require an ``else`` part.
|
||||
|
||||
As case statements perform compile-time exhaustiveness checks, the value in
|
||||
every ``of`` branch must be known at compile time. This fact is also exploited
|
||||
to generate more performant code.
|
||||
|
||||
As a special semantic extension, an expression in an ``of`` branch of a case
|
||||
statement may evaluate to a set or array constructor; the set or array is then
|
||||
expanded into a list of its elements:
|
||||
|
||||
@@ -1487,7 +1487,7 @@ proc drain*(timeout = 500) =
|
||||
## if there are no pending operations. In contrast to ``poll`` this
|
||||
## processes as many events as are available.
|
||||
if runOnce(timeout):
|
||||
while runOnce(0): discard
|
||||
while hasPendingOperations() and runOnce(0): discard
|
||||
|
||||
proc poll*(timeout = 500) =
|
||||
## Waits for completion events and processes them. Raises ``ValueError``
|
||||
|
||||
@@ -73,10 +73,10 @@ proc add*[A](x: var SharedList[A]; y: A) =
|
||||
node.d[node.dataLen] = y
|
||||
inc(node.dataLen)
|
||||
|
||||
proc initSharedList*[A](): SharedList[A] =
|
||||
initLock result.lock
|
||||
result.head = nil
|
||||
result.tail = nil
|
||||
proc init*[A](t: var SharedList[A]) =
|
||||
initLock t.lock
|
||||
t.head = nil
|
||||
t.tail = nil
|
||||
|
||||
proc clear*[A](t: var SharedList[A]) =
|
||||
withLock(t):
|
||||
@@ -92,4 +92,11 @@ proc deinitSharedList*[A](t: var SharedList[A]) =
|
||||
clear(t)
|
||||
deinitLock t.lock
|
||||
|
||||
proc initSharedList*[A](): SharedList[A] {.deprecated.} =
|
||||
## Deprecated. Use `init` instead.
|
||||
## This is not posix compliant, may introduce undefined behavior.
|
||||
initLock result.lock
|
||||
result.head = nil
|
||||
result.tail = nil
|
||||
|
||||
{.pop.}
|
||||
|
||||
@@ -192,19 +192,29 @@ proc del*[A, B](t: var SharedTable[A, B], key: A) =
|
||||
withLock t:
|
||||
delImpl()
|
||||
|
||||
proc initSharedTable*[A, B](initialSize=64): SharedTable[A, B] =
|
||||
proc init*[A, B](t: var SharedTable[A, B], initialSize=64) =
|
||||
## creates a new hash table that is empty.
|
||||
##
|
||||
## `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 <math.html>`_ module or the ``rightSize`` proc from this module.
|
||||
assert isPowerOfTwo(initialSize)
|
||||
result.counter = 0
|
||||
result.dataLen = initialSize
|
||||
result.data = cast[KeyValuePairSeq[A, B]](allocShared0(
|
||||
t.counter = 0
|
||||
t.dataLen = initialSize
|
||||
t.data = cast[KeyValuePairSeq[A, B]](allocShared0(
|
||||
sizeof(KeyValuePair[A, B]) * initialSize))
|
||||
initLock result.lock
|
||||
initLock t.lock
|
||||
|
||||
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.} =
|
||||
## 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
|
||||
|
||||
@@ -1352,29 +1352,42 @@ else:
|
||||
proc fromSeconds*(since1970: float): Time {.tags: [], raises: [], benign, deprecated.} =
|
||||
## Takes a float which contains the number of seconds since the unix epoch and
|
||||
## returns a time object.
|
||||
##
|
||||
## **Deprecated since v0.18.0:** use ``fromUnix`` instead
|
||||
Time(since1970)
|
||||
|
||||
proc fromSeconds*(since1970: int64): Time {.tags: [], raises: [], benign, deprecated.} =
|
||||
## Takes an int which contains the number of seconds since the unix epoch and
|
||||
## returns a time object.
|
||||
##
|
||||
## **Deprecated since v0.18.0:** use ``fromUnix`` instead
|
||||
Time(since1970)
|
||||
|
||||
proc toSeconds*(time: Time): float {.tags: [], raises: [], benign, deprecated.} =
|
||||
## Returns the time in seconds since the unix epoch.
|
||||
##
|
||||
## **Deprecated since v0.18.0:** use ``toUnix`` instead
|
||||
float(time)
|
||||
|
||||
proc getLocalTime*(time: Time): DateTime {.tags: [], raises: [], benign, deprecated.} =
|
||||
## Converts the calendar time `time` to broken-time representation,
|
||||
## expressed relative to the user's specified time zone.
|
||||
##
|
||||
## **Deprecated since v0.18.0:** use ``local`` instead
|
||||
time.local
|
||||
|
||||
proc getGMTime*(time: Time): DateTime {.tags: [], raises: [], benign, deprecated.} =
|
||||
## Converts the calendar time `time` to broken-down time representation,
|
||||
## expressed in Coordinated Universal Time (UTC).
|
||||
## expressed in Coordinated Universal Time (UTC).
|
||||
##
|
||||
## **Deprecated since v0.18.0:** use ``utc`` instead
|
||||
time.utc
|
||||
|
||||
proc getTimezone*(): int {.tags: [TimeEffect], raises: [], benign, deprecated.} =
|
||||
## Returns the offset of the local (non-DST) timezone in seconds west of UTC.
|
||||
##
|
||||
## **Deprecated since v0.18.0:** use ``now().utcOffset`` to get the current
|
||||
## utc offset (including DST).
|
||||
when defined(JS):
|
||||
return newDate().getTimezoneOffset() * 60
|
||||
elif defined(freebsd) or defined(netbsd) or defined(openbsd):
|
||||
@@ -1468,4 +1481,4 @@ proc getDayOfWeekJulian*(day, month, year: int): WeekDay {.deprecated.} =
|
||||
y = year - a
|
||||
m = month + (12*a) - 2
|
||||
d = (5 + day + y + (y div 4) + (31*m) div 12) mod 7
|
||||
result = d.WeekDay
|
||||
result = d.WeekDay
|
||||
|
||||
@@ -318,7 +318,7 @@ proc initGC() =
|
||||
init(gch.marked)
|
||||
init(gch.additionalRoots)
|
||||
when hasThreadSupport:
|
||||
gch.toDispose = initSharedList[pointer]()
|
||||
init(gch.toDispose)
|
||||
|
||||
when useMarkForDebug or useBackupGc:
|
||||
type
|
||||
|
||||
@@ -133,7 +133,7 @@ proc initGC() =
|
||||
init(gch.additionalRoots)
|
||||
init(gch.greyStack)
|
||||
when hasThreadSupport:
|
||||
gch.toDispose = initSharedList[pointer]()
|
||||
init(gch.toDispose)
|
||||
|
||||
# Which color to use for new objects is tricky: When we're marking,
|
||||
# they have to be *white* so that everything is marked that is only
|
||||
|
||||
@@ -233,7 +233,7 @@ proc initGC() =
|
||||
init(gch.allocated)
|
||||
init(gch.marked)
|
||||
when hasThreadSupport:
|
||||
gch.toDispose = initSharedList[pointer]()
|
||||
init(gch.toDispose)
|
||||
|
||||
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) {.benign.} =
|
||||
var d = cast[ByteAddress](dest)
|
||||
|
||||
@@ -213,7 +213,8 @@ block clearCountTableTest:
|
||||
assert t.len() == 0
|
||||
|
||||
block withKeyTest:
|
||||
var t = initSharedTable[int, int]()
|
||||
var t: SharedTable[int, int]
|
||||
t.init()
|
||||
t.withKey(1) do (k: int, v: var int, pairExists: var bool):
|
||||
assert(v == 0)
|
||||
pairExists = true
|
||||
|
||||
@@ -290,20 +290,6 @@ proc compilerOutputTests(test: TTest, target: TTarget, given: var TSpec,
|
||||
if given.err == reSuccess: inc(r.passed)
|
||||
r.addResult(test, target, expectedmsg, givenmsg, given.err)
|
||||
|
||||
proc analyzeAndConsolidateOutput(s: string): string =
|
||||
result = ""
|
||||
let rows = s.splitLines
|
||||
for i in 0 ..< rows.len:
|
||||
if (let pos = find(rows[i], "Traceback (most recent call last)"); pos != -1):
|
||||
result = substr(rows[i], pos) & "\n"
|
||||
for i in i+1 ..< rows.len:
|
||||
result.add rows[i] & "\n"
|
||||
if not (rows[i] =~ peg"['(']+ '(' \d+ ')' \s+"):
|
||||
return
|
||||
elif (let pos = find(rows[i], "SIGSEGV: Illegal storage access."); pos != -1):
|
||||
result = substr(rows[i], pos)
|
||||
return
|
||||
|
||||
proc testSpec(r: var TResults, test: TTest, target = targetC) =
|
||||
let tname = test.name.addFileExt(".nim")
|
||||
#echo "TESTING ", tname
|
||||
@@ -376,8 +362,7 @@ proc testSpec(r: var TResults, test: TTest, target = targetC) =
|
||||
if exitCode != expected.exitCode:
|
||||
r.addResult(test, target, "exitcode: " & $expected.exitCode,
|
||||
"exitcode: " & $exitCode & "\n\nOutput:\n" &
|
||||
analyzeAndConsolidateOutput(bufB),
|
||||
reExitCodesDiffer)
|
||||
bufB, reExitCodesDiffer)
|
||||
continue
|
||||
|
||||
if bufB != expectedOut and expected.action != actionRunNoSpec:
|
||||
|
||||
120
tests/vm/tcastint.nim
Normal file
120
tests/vm/tcastint.nim
Normal file
@@ -0,0 +1,120 @@
|
||||
discard """
|
||||
file: "tcastint.nim"
|
||||
output: "OK"
|
||||
"""
|
||||
|
||||
type
|
||||
Dollar = distinct int
|
||||
XCoord = distinct int32
|
||||
Digit = range[-9..0]
|
||||
|
||||
# those are necessary for comparisons below.
|
||||
proc `==`(x, y: Dollar): bool {.borrow.}
|
||||
proc `==`(x, y: XCoord): bool {.borrow.}
|
||||
|
||||
proc dummy[T](x: T): T = x
|
||||
|
||||
proc test() =
|
||||
let U8 = 0b1011_0010'u8
|
||||
let I8 = 0b1011_0010'i8
|
||||
let C8 = 0b1011_0010'u8.char
|
||||
let C8_1 = 0b1011_0011'u8.char
|
||||
let U16 = 0b10100111_00101000'u16
|
||||
let I16 = 0b10100111_00101000'i16
|
||||
let U32 = 0b11010101_10011100_11011010_01010000'u32
|
||||
let I32 = 0b11010101_10011100_11011010_01010000'i32
|
||||
let U64A = 0b11000100_00111111_01111100_10001010_10011001_01001000_01111010_00010001'u64
|
||||
let I64A = 0b11000100_00111111_01111100_10001010_10011001_01001000_01111010_00010001'i64
|
||||
let U64B = 0b00110010_11011101_10001111_00101000_00000000_00000000_00000000_00000000'u64
|
||||
let I64B = 0b00110010_11011101_10001111_00101000_00000000_00000000_00000000_00000000'i64
|
||||
when sizeof(int) == 8:
|
||||
let UX = U64A.uint
|
||||
let IX = I64A.int
|
||||
elif sizeof(int) == 4:
|
||||
let UX = U32.uint
|
||||
let IX = I32.int
|
||||
elif sizeof(int) == 2:
|
||||
let UX = U16.uint
|
||||
let IX = I16.int
|
||||
else:
|
||||
let UX = U8.uint
|
||||
let IX = I8.int
|
||||
|
||||
doAssert(cast[char](I8) == C8)
|
||||
doAssert(cast[uint8](I8) == U8)
|
||||
doAssert(cast[uint16](I16) == U16)
|
||||
doAssert(cast[uint32](I32) == U32)
|
||||
doAssert(cast[uint64](I64A) == U64A)
|
||||
doAssert(cast[uint64](I64B) == U64B)
|
||||
doAssert(cast[int8](U8) == I8)
|
||||
doAssert(cast[int16](U16) == I16)
|
||||
doAssert(cast[int32](U32) == I32)
|
||||
doAssert(cast[int64](U64A) == I64A)
|
||||
doAssert(cast[int64](U64B) == I64B)
|
||||
doAssert(cast[uint](IX) == UX)
|
||||
doAssert(cast[int](UX) == IX)
|
||||
|
||||
doAssert(cast[char](I8 + 1) == C8_1)
|
||||
doAssert(cast[uint8](I8 + 1) == U8 + 1)
|
||||
doAssert(cast[uint16](I16 + 1) == U16 + 1)
|
||||
doAssert(cast[uint32](I32 + 1) == U32 + 1)
|
||||
doAssert(cast[uint64](I64A + 1) == U64A + 1)
|
||||
doAssert(cast[uint64](I64B + 1) == U64B + 1)
|
||||
doAssert(cast[int8](U8 + 1) == I8 + 1)
|
||||
doAssert(cast[int16](U16 + 1) == I16 + 1)
|
||||
doAssert(cast[int32](U32 + 1) == I32 + 1)
|
||||
doAssert(cast[int64](U64A + 1) == I64A + 1)
|
||||
doAssert(cast[int64](U64B + 1) == I64B + 1)
|
||||
doAssert(cast[uint](IX + 1) == UX + 1)
|
||||
doAssert(cast[int](UX + 1) == IX + 1)
|
||||
|
||||
doAssert(cast[char](I8.dummy) == C8.dummy)
|
||||
doAssert(cast[uint8](I8.dummy) == U8.dummy)
|
||||
doAssert(cast[uint16](I16.dummy) == U16.dummy)
|
||||
doAssert(cast[uint32](I32.dummy) == U32.dummy)
|
||||
doAssert(cast[uint64](I64A.dummy) == U64A.dummy)
|
||||
doAssert(cast[uint64](I64B.dummy) == U64B.dummy)
|
||||
doAssert(cast[int8](U8.dummy) == I8.dummy)
|
||||
doAssert(cast[int16](U16.dummy) == I16.dummy)
|
||||
doAssert(cast[int32](U32.dummy) == I32.dummy)
|
||||
doAssert(cast[int64](U64A.dummy) == I64A.dummy)
|
||||
doAssert(cast[int64](U64B.dummy) == I64B.dummy)
|
||||
doAssert(cast[uint](IX.dummy) == UX.dummy)
|
||||
doAssert(cast[int](UX.dummy) == IX.dummy)
|
||||
|
||||
|
||||
doAssert(cast[int64](if false: U64B else: 0'u64) == (if false: I64B else: 0'i64))
|
||||
|
||||
block:
|
||||
let raw = 3
|
||||
let money = Dollar(raw) # this must be a variable, is otherwise constant folded.
|
||||
doAssert(cast[int](money) == raw)
|
||||
doAssert(cast[Dollar](raw) == money)
|
||||
block:
|
||||
let raw = 150'i32
|
||||
let position = XCoord(raw) # this must be a variable, is otherwise constant folded.
|
||||
doAssert(cast[int32](position) == raw)
|
||||
doAssert(cast[XCoord](raw) == position)
|
||||
block:
|
||||
let raw = -2
|
||||
let digit = Digit(raw)
|
||||
doAssert(cast[int](digit) == raw)
|
||||
doAssert(cast[Digit](raw) == digit)
|
||||
|
||||
when defined nimvm:
|
||||
doAssert(not compiles(cast[float](I64A)))
|
||||
doAssert(not compiles(cast[float32](I64A)))
|
||||
|
||||
doAssert(not compiles(cast[char](I64A)))
|
||||
doAssert(not compiles(cast[uint16](I64A)))
|
||||
doAssert(not compiles(cast[uint32](I64A)))
|
||||
|
||||
doAssert(not compiles(cast[uint16](I8)))
|
||||
doAssert(not compiles(cast[uint32](I8)))
|
||||
doAssert(not compiles(cast[uint64](I8)))
|
||||
|
||||
test()
|
||||
static:
|
||||
test()
|
||||
|
||||
echo "OK"
|
||||
@@ -51,6 +51,7 @@ srcdoc2: "pure/ropes;pure/unidecode/unidecode;pure/xmldom;pure/xmldomparser"
|
||||
srcdoc2: "pure/xmlparser;pure/htmlparser;pure/xmltree;pure/colors;pure/mimetypes"
|
||||
srcdoc2: "pure/json;pure/base64;pure/scgi"
|
||||
srcdoc2: "pure/collections/tables;pure/collections/sets;pure/collections/lists"
|
||||
srcdoc2: "pure/collections/sharedlist;pure/collections/sharedtables"
|
||||
srcdoc2: "pure/collections/intsets;pure/collections/queues;pure/collections/deques;pure/encodings"
|
||||
srcdoc2: "pure/events;pure/collections/sequtils;pure/cookies"
|
||||
srcdoc2: "pure/memfiles;pure/subexes;pure/collections/critbits"
|
||||
|
||||
Reference in New Issue
Block a user