Merge branch 'devel' of github.com:nim-lang/Nim into devel

This commit is contained in:
Araq 2018-01-03 02:36:49 +01:00
commit 49a00fe6ff
15 changed files with 223 additions and 35 deletions

View file

@ -253,7 +253,7 @@ compiler tcc:
compilerExe: "tcc", compilerExe: "tcc",
cppCompiler: "", cppCompiler: "",
compileTmpl: "-c $options $include -o $objfile $file", compileTmpl: "-c $options $include -o $objfile $file",
buildGui: "UNAVAILABLE!", buildGui: "-Wl,-subsystem=gui",
buildDll: " -shared", buildDll: " -shared",
buildLib: "", # XXX: not supported yet buildLib: "", # XXX: not supported yet
linkerExe: "tcc", linkerExe: "tcc",

View file

@ -30,7 +30,7 @@
import import
strutils, ast, astalgo, types, msgs, renderer, vmdef, strutils, ast, astalgo, types, msgs, renderer, vmdef,
trees, intsets, rodread, magicsys, options, lowerings trees, intsets, rodread, magicsys, options, lowerings
import platform
from os import splitFile from os import splitFile
when hasFFI: when hasFFI:
@ -761,6 +761,49 @@ proc genCard(c: PCtx; n: PNode; dest: var TDest) =
c.gABC(n, opcCard, dest, tmp) c.gABC(n, opcCard, dest, tmp)
c.freeTemp(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) = proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
case m case m
of mAnd: c.genAndOr(n, opcFJmp, dest) 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: if allowCast in c.features:
genConv(c, n, n.sons[1], dest, opcCast) genConv(c, n, n.sons[1], dest, opcCast)
else: else:
globalError(n.info, errGenerated, "VM is not allowed to 'cast'") genIntCast(c, n, dest)
of nkTypeOfExpr: of nkTypeOfExpr:
genTypeLit(c, n.typ, dest) genTypeLit(c, n.typ, dest)
of nkComesFrom: of nkComesFrom:

View file

@ -92,6 +92,10 @@ Collections and algorithms
* `sequtils <sequtils.html>`_ * `sequtils <sequtils.html>`_
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. 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 String handling

View file

@ -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 For non ordinal types it is not possible to list every possible value and so
these always require an ``else`` part. 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 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 statement may evaluate to a set or array constructor; the set or array is then
expanded into a list of its elements: expanded into a list of its elements:

View file

@ -1487,7 +1487,7 @@ proc drain*(timeout = 500) =
## if there are no pending operations. In contrast to ``poll`` this ## if there are no pending operations. In contrast to ``poll`` this
## processes as many events as are available. ## processes as many events as are available.
if runOnce(timeout): if runOnce(timeout):
while runOnce(0): discard while hasPendingOperations() and runOnce(0): discard
proc poll*(timeout = 500) = proc poll*(timeout = 500) =
## Waits for completion events and processes them. Raises ``ValueError`` ## Waits for completion events and processes them. Raises ``ValueError``

View file

@ -73,10 +73,10 @@ proc add*[A](x: var SharedList[A]; y: A) =
node.d[node.dataLen] = y node.d[node.dataLen] = y
inc(node.dataLen) inc(node.dataLen)
proc initSharedList*[A](): SharedList[A] = proc init*[A](t: var SharedList[A]) =
initLock result.lock initLock t.lock
result.head = nil t.head = nil
result.tail = nil t.tail = nil
proc clear*[A](t: var SharedList[A]) = proc clear*[A](t: var SharedList[A]) =
withLock(t): withLock(t):
@ -92,4 +92,11 @@ proc deinitSharedList*[A](t: var SharedList[A]) =
clear(t) clear(t)
deinitLock t.lock 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.} {.pop.}

View file

@ -192,19 +192,29 @@ proc del*[A, B](t: var SharedTable[A, B], key: A) =
withLock t: withLock t:
delImpl() 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. ## creates a new hash table that is empty.
## ##
## `initialSize` needs to be a power of two. If you need to accept runtime ## `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 ## values for this you could use the ``nextPowerOfTwo`` proc from the
## `math <math.html>`_ module or the ``rightSize`` proc from this module. ## `math <math.html>`_ module or the ``rightSize`` proc from this module.
assert isPowerOfTwo(initialSize) assert isPowerOfTwo(initialSize)
t.counter = 0
t.dataLen = initialSize
t.data = cast[KeyValuePairSeq[A, B]](allocShared0(
sizeof(KeyValuePair[A, B]) * initialSize))
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.counter = 0
result.dataLen = initialSize result.dataLen = initialSize
result.data = cast[KeyValuePairSeq[A, B]](allocShared0( result.data = cast[KeyValuePairSeq[A, B]](allocShared0(
sizeof(KeyValuePair[A, B]) * initialSize)) sizeof(KeyValuePair[A, B]) * initialSize))
initLock result.lock initLock result.lock
proc deinitSharedTable*[A, B](t: var SharedTable[A, B]) =
deallocShared(t.data)
deinitLock t.lock

View file

@ -1352,29 +1352,42 @@ else:
proc fromSeconds*(since1970: float): Time {.tags: [], raises: [], benign, deprecated.} = proc fromSeconds*(since1970: float): Time {.tags: [], raises: [], benign, deprecated.} =
## Takes a float which contains the number of seconds since the unix epoch and ## Takes a float which contains the number of seconds since the unix epoch and
## returns a time object. ## returns a time object.
##
## **Deprecated since v0.18.0:** use ``fromUnix`` instead
Time(since1970) Time(since1970)
proc fromSeconds*(since1970: int64): Time {.tags: [], raises: [], benign, deprecated.} = proc fromSeconds*(since1970: int64): Time {.tags: [], raises: [], benign, deprecated.} =
## Takes an int which contains the number of seconds since the unix epoch and ## Takes an int which contains the number of seconds since the unix epoch and
## returns a time object. ## returns a time object.
##
## **Deprecated since v0.18.0:** use ``fromUnix`` instead
Time(since1970) Time(since1970)
proc toSeconds*(time: Time): float {.tags: [], raises: [], benign, deprecated.} = proc toSeconds*(time: Time): float {.tags: [], raises: [], benign, deprecated.} =
## Returns the time in seconds since the unix epoch. ## Returns the time in seconds since the unix epoch.
##
## **Deprecated since v0.18.0:** use ``toUnix`` instead
float(time) float(time)
proc getLocalTime*(time: Time): DateTime {.tags: [], raises: [], benign, deprecated.} = proc getLocalTime*(time: Time): DateTime {.tags: [], raises: [], benign, deprecated.} =
## Converts the calendar time `time` to broken-time representation, ## Converts the calendar time `time` to broken-time representation,
## expressed relative to the user's specified time zone. ## expressed relative to the user's specified time zone.
##
## **Deprecated since v0.18.0:** use ``local`` instead
time.local time.local
proc getGMTime*(time: Time): DateTime {.tags: [], raises: [], benign, deprecated.} = proc getGMTime*(time: Time): DateTime {.tags: [], raises: [], benign, deprecated.} =
## Converts the calendar time `time` to broken-down time representation, ## 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 time.utc
proc getTimezone*(): int {.tags: [TimeEffect], raises: [], benign, deprecated.} = proc getTimezone*(): int {.tags: [TimeEffect], raises: [], benign, deprecated.} =
## Returns the offset of the local (non-DST) timezone in seconds west of UTC. ## 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): when defined(JS):
return newDate().getTimezoneOffset() * 60 return newDate().getTimezoneOffset() * 60
elif defined(freebsd) or defined(netbsd) or defined(openbsd): elif defined(freebsd) or defined(netbsd) or defined(openbsd):

View file

@ -318,7 +318,7 @@ proc initGC() =
init(gch.marked) init(gch.marked)
init(gch.additionalRoots) init(gch.additionalRoots)
when hasThreadSupport: when hasThreadSupport:
gch.toDispose = initSharedList[pointer]() init(gch.toDispose)
when useMarkForDebug or useBackupGc: when useMarkForDebug or useBackupGc:
type type

View file

@ -133,7 +133,7 @@ proc initGC() =
init(gch.additionalRoots) init(gch.additionalRoots)
init(gch.greyStack) init(gch.greyStack)
when hasThreadSupport: when hasThreadSupport:
gch.toDispose = initSharedList[pointer]() init(gch.toDispose)
# Which color to use for new objects is tricky: When we're marking, # 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 # they have to be *white* so that everything is marked that is only

View file

@ -233,7 +233,7 @@ proc initGC() =
init(gch.allocated) init(gch.allocated)
init(gch.marked) init(gch.marked)
when hasThreadSupport: when hasThreadSupport:
gch.toDispose = initSharedList[pointer]() init(gch.toDispose)
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) {.benign.} = proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) {.benign.} =
var d = cast[ByteAddress](dest) var d = cast[ByteAddress](dest)

View file

@ -213,7 +213,8 @@ block clearCountTableTest:
assert t.len() == 0 assert t.len() == 0
block withKeyTest: 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): t.withKey(1) do (k: int, v: var int, pairExists: var bool):
assert(v == 0) assert(v == 0)
pairExists = true pairExists = true

View file

@ -290,20 +290,6 @@ proc compilerOutputTests(test: TTest, target: TTarget, given: var TSpec,
if given.err == reSuccess: inc(r.passed) if given.err == reSuccess: inc(r.passed)
r.addResult(test, target, expectedmsg, givenmsg, given.err) 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) = proc testSpec(r: var TResults, test: TTest, target = targetC) =
let tname = test.name.addFileExt(".nim") let tname = test.name.addFileExt(".nim")
#echo "TESTING ", tname #echo "TESTING ", tname
@ -376,8 +362,7 @@ proc testSpec(r: var TResults, test: TTest, target = targetC) =
if exitCode != expected.exitCode: if exitCode != expected.exitCode:
r.addResult(test, target, "exitcode: " & $expected.exitCode, r.addResult(test, target, "exitcode: " & $expected.exitCode,
"exitcode: " & $exitCode & "\n\nOutput:\n" & "exitcode: " & $exitCode & "\n\nOutput:\n" &
analyzeAndConsolidateOutput(bufB), bufB, reExitCodesDiffer)
reExitCodesDiffer)
continue continue
if bufB != expectedOut and expected.action != actionRunNoSpec: if bufB != expectedOut and expected.action != actionRunNoSpec:

120
tests/vm/tcastint.nim Normal file
View 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"

View file

@ -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/xmlparser;pure/htmlparser;pure/xmltree;pure/colors;pure/mimetypes"
srcdoc2: "pure/json;pure/base64;pure/scgi" srcdoc2: "pure/json;pure/base64;pure/scgi"
srcdoc2: "pure/collections/tables;pure/collections/sets;pure/collections/lists" 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/collections/intsets;pure/collections/queues;pure/collections/deques;pure/encodings"
srcdoc2: "pure/events;pure/collections/sequtils;pure/cookies" srcdoc2: "pure/events;pure/collections/sequtils;pure/cookies"
srcdoc2: "pure/memfiles;pure/subexes;pure/collections/critbits" srcdoc2: "pure/memfiles;pure/subexes;pure/collections/critbits"