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

This commit is contained in:
Andreas Rumpf 2018-01-04 15:59:10 +01:00
commit 464d037c17
31 changed files with 301 additions and 98 deletions

View file

@ -187,3 +187,6 @@ let
mySeq = @[1, 2, 1, 3, 1, 4] mySeq = @[1, 2, 1, 3, 1, 4]
myCounter = mySeq.toCountTable() myCounter = mySeq.toCountTable()
``` ```
- Added support for casting between integers of same bitsize in VM (compile time and nimscript).
This allow to among other things to reinterpret signed integers as unsigned.

View file

@ -1258,7 +1258,7 @@ proc resetModule*(m: BModule) =
# indicate that this is now cached module # indicate that this is now cached module
# the cache will be invalidated by nullifying gModules # the cache will be invalidated by nullifying gModules
m.fromCache = true #m.fromCache = true
m.g = nil m.g = nil
# we keep only the "merge info" information for the module # we keep only the "merge info" information for the module
@ -1390,7 +1390,7 @@ proc writeModule(m: BModule, pending: bool) =
# generate code for the init statements of the module: # generate code for the init statements of the module:
let cfile = getCFile(m) let cfile = getCFile(m)
if not m.fromCache or optForceFullMake in gGlobalOptions: if m.rd == nil or optForceFullMake in gGlobalOptions:
genInitCode(m) genInitCode(m)
finishTypeDescriptions(m) finishTypeDescriptions(m)
if sfMainModule in m.module.flags: if sfMainModule in m.module.flags:
@ -1465,10 +1465,10 @@ proc cgenWriteModules*(backend: RootRef, config: ConfigRef) =
if g.generatedHeader != nil: finishModule(g.generatedHeader) if g.generatedHeader != nil: finishModule(g.generatedHeader)
while g.forwardedProcsCounter > 0: while g.forwardedProcsCounter > 0:
for m in cgenModules(g): for m in cgenModules(g):
if not m.fromCache: if m.rd == nil:
finishModule(m) finishModule(m)
for m in cgenModules(g): for m in cgenModules(g):
if m.fromCache: if m.rd != nil:
m.updateCachedModule m.updateCachedModule
else: else:
m.writeModule(pending=true) m.writeModule(pending=true)

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

@ -2051,10 +2051,10 @@ proc genConv(p: PProc, n: PNode, r: var TCompRes) =
return return
case dest.kind: case dest.kind:
of tyBool: of tyBool:
r.res = "(($1)? 1:0)" % [r.res] r.res = "(!!($1))" % [r.res]
r.kind = resExpr r.kind = resExpr
of tyInt: of tyInt:
r.res = "($1|0)" % [r.res] r.res = "(($1)|0)" % [r.res]
else: else:
# TODO: What types must we handle here? # TODO: What types must we handle here?
discard discard

View file

@ -18,7 +18,7 @@ import
type type
TPassContext* = object of RootObj # the pass's context TPassContext* = object of RootObj # the pass's context
fromCache*: bool # true if created by "openCached" rd*: PRodReader # != nil if created by "openCached"
PPassContext* = ref TPassContext PPassContext* = ref TPassContext
@ -118,7 +118,7 @@ proc openPassesCached(g: ModuleGraph; a: var TPassContextArray, module: PSym,
if not isNil(gPasses[i].openCached): if not isNil(gPasses[i].openCached):
a[i] = gPasses[i].openCached(g, module, rd) a[i] = gPasses[i].openCached(g, module, rd)
if a[i] != nil: if a[i] != nil:
a[i].fromCache = true a[i].rd = rd
else: else:
a[i] = nil a[i] = nil

View file

@ -719,6 +719,7 @@ proc gcase(g: var TSrcGen, n: PNode) =
var c: TContext var c: TContext
initContext(c) initContext(c)
var length = sonsLen(n) var length = sonsLen(n)
if length == 0: return
var last = if n.sons[length-1].kind == nkElse: -2 else: -1 var last = if n.sons[length-1].kind == nkElse: -2 else: -1
if longMode(g, n, 0, last): incl(c.flags, rfLongMode) if longMode(g, n, 0, last): incl(c.flags, rfLongMode)
putWithSpace(g, tkCase, "case") putWithSpace(g, tkCase, "case")

View file

@ -74,7 +74,7 @@ proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode =
localError(arg.info, errExprXHasNoType, localError(arg.info, errExprXHasNoType,
renderTree(arg, {renderNoComments})) renderTree(arg, {renderNoComments}))
# error correction: # error correction:
result = copyNode(arg) result = copyTree(arg)
result.typ = formal result.typ = formal
else: else:
result = indexTypesMatch(c, formal, arg.typ, arg) result = indexTypesMatch(c, formal, arg.typ, arg)
@ -168,9 +168,9 @@ proc commonType*(x, y: PType): PType =
proc endsInNoReturn(n: PNode): bool = proc endsInNoReturn(n: PNode): bool =
# check if expr ends in raise exception or call of noreturn proc # check if expr ends in raise exception or call of noreturn proc
var it = n var it = n
while it.kind in {nkStmtList, nkStmtListExpr} and it.len > 0: while it.kind in {nkStmtList, nkStmtListExpr} and it.len > 0:
it = it.lastSon it = it.lastSon
result = it.kind == nkRaiseStmt or result = it.kind == nkRaiseStmt or
it.kind in nkCallKinds and it[0].kind == nkSym and sfNoReturn in it[0].sym.flags it.kind in nkCallKinds and it[0].kind == nkSym and sfNoReturn in it[0].sym.flags
proc commonType*(x: PType, y: PNode): PType = proc commonType*(x: PType, y: PNode): PType =
@ -501,6 +501,8 @@ proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
proc myOpenCached(graph: ModuleGraph; module: PSym; rd: PRodReader): PPassContext = proc myOpenCached(graph: ModuleGraph; module: PSym; rd: PRodReader): PPassContext =
result = myOpen(graph, module, rd.cache) result = myOpen(graph, module, rd.cache)
proc replayMethodDefs(graph: ModuleGraph; rd: PRodReader) =
for m in items(rd.methods): methodDef(graph, m, true) for m in items(rd.methods): methodDef(graph, m, true)
proc isImportSystemStmt(n: PNode): bool = proc isImportSystemStmt(n: PNode): bool =
@ -607,6 +609,8 @@ proc myClose(graph: ModuleGraph; context: PPassContext, n: PNode): PNode =
addCodeForGenerics(c, result) addCodeForGenerics(c, result)
if c.module.ast != nil: if c.module.ast != nil:
result.add(c.module.ast) result.add(c.module.ast)
if c.rd != nil:
replayMethodDefs(graph, c.rd)
popOwner(c) popOwner(c)
popProcCon(c) popProcCon(c)
if c.runnableExamples != nil: testExamples(c) if c.runnableExamples != nil: testExamples(c)

View file

@ -1425,11 +1425,7 @@ proc semProcBody(c: PContext, n: PNode): PNode =
openScope(c) openScope(c)
result = semExpr(c, n) result = semExpr(c, n)
if c.p.resultSym != nil and not isEmptyType(result.typ): if c.p.resultSym != nil and not isEmptyType(result.typ):
# transform ``expr`` to ``result = expr``, but not if the expr is already if result.kind == nkNilLit:
# ``result``:
if result.kind == nkSym and result.sym == c.p.resultSym:
discard
elif result.kind == nkNilLit:
# or ImplicitlyDiscardable(result): # or ImplicitlyDiscardable(result):
# new semantic: 'result = x' triggers the void context # new semantic: 'result = x' triggers the void context
result.typ = nil result.typ = nil

View file

@ -914,7 +914,7 @@ proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
# Note: For interactive mode we cannot call 'passes.skipCodegen' and skip # Note: For interactive mode we cannot call 'passes.skipCodegen' and skip
# this step! We have to rely that the semantic pass transforms too errornous # this step! We have to rely that the semantic pass transforms too errornous
# nodes into an empty node. # nodes into an empty node.
if c.fromCache or nfTransf in n.flags: return n if c.rd != nil or nfTransf in n.flags: return n
pushTransCon(c, newTransCon(owner)) pushTransCon(c, newTransCon(owner))
result = PNode(transform(c, n)) result = PNode(transform(c, n))
popTransCon(c) popTransCon(c)

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

@ -260,7 +260,7 @@ proc buildTools(latest: bool) =
" nimsuggest/nimsuggest.nim" " nimsuggest/nimsuggest.nim"
let nimgrepExe = "bin/nimgrep".exe let nimgrepExe = "bin/nimgrep".exe
nimexec "c -o:" & nimgrepExe & " tools/nimgrep.nim" nimexec "c -d:release -o:" & nimgrepExe & " tools/nimgrep.nim"
when defined(windows): buildVccTool() when defined(windows): buildVccTool()
#nimexec "c -o:" & ("bin/nimresolve".exe) & " tools/nimresolve.nim" #nimexec "c -o:" & ("bin/nimresolve".exe) & " tools/nimresolve.nim"

View file

@ -400,11 +400,11 @@ typedef struct TStringDesc* string;
// NAN definition copied from math.h included in the Windows SDK version 10.0.14393.0 // NAN definition copied from math.h included in the Windows SDK version 10.0.14393.0
#ifndef NAN #ifndef NAN
#ifndef _HUGE_ENUF # ifndef _HUGE_ENUF
#define _HUGE_ENUF 1e+300 // _HUGE_ENUF*_HUGE_ENUF must overflow # define _HUGE_ENUF 1e+300 // _HUGE_ENUF*_HUGE_ENUF must overflow
#endif # endif
#define NAN_INFINITY ((float)(_HUGE_ENUF * _HUGE_ENUF)) # define NAN_INFINITY ((float)(_HUGE_ENUF * _HUGE_ENUF))
#define NAN ((float)(NAN_INFINITY * 0.0F)) # define NAN ((float)(NAN_INFINITY * 0.0F))
#endif #endif
#ifndef INF #ifndef INF
@ -482,7 +482,6 @@ static inline void GCGuard (void *ptr) { asm volatile ("" :: "X" (ptr)); }
On disagreement, your C compiler will say something like: 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" */ "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]; typedef int Nim_and_C_compiler_disagree_on_target_architecture[sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(NI)*8 ? 1 : -1];
#endif
#ifdef __cplusplus #ifdef __cplusplus
# define NIM_EXTERNC extern "C" # define NIM_EXTERNC extern "C"
@ -509,3 +508,5 @@ extern Libc::Env *genodeEnv;
/* Compile with -d:checkAbi and a sufficiently C11:ish compiler to enable */ /* Compile with -d:checkAbi and a sufficiently C11:ish compiler to enable */
#define NIM_CHECK_SIZE(typ, sz) \ #define NIM_CHECK_SIZE(typ, sz) \
_Static_assert(sizeof(typ) == sz, "Nim & C disagree on type size") _Static_assert(sizeof(typ) == sz, "Nim & C disagree on type size")
#endif /* NIMBASE_H */

View file

@ -34,7 +34,7 @@ type
{.deprecated: [TSocketHandle: SocketHandle].} {.deprecated: [TSocketHandle: SocketHandle].}
type type
Time* {.importc: "time_t", header: "<time.h>".} = distinct int Time* {.importc: "time_t", header: "<time.h>".} = distinct clong
Timespec* {.importc: "struct timespec", Timespec* {.importc: "struct timespec",
header: "<time.h>", final, pure.} = object ## struct timespec header: "<time.h>", final, pure.} = object ## struct timespec

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)
result.counter = 0 t.counter = 0
result.dataLen = initialSize t.dataLen = initialSize
result.data = cast[KeyValuePairSeq[A, B]](allocShared0( t.data = cast[KeyValuePairSeq[A, B]](allocShared0(
sizeof(KeyValuePair[A, B]) * initialSize)) sizeof(KeyValuePair[A, B]) * initialSize))
initLock result.lock initLock t.lock
proc deinitSharedTable*[A, B](t: var SharedTable[A, B]) = proc deinitSharedTable*[A, B](t: var SharedTable[A, B]) =
deallocShared(t.data) deallocShared(t.data)
deinitLock t.lock 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

View file

@ -257,10 +257,13 @@ proc close*(f: var MemFile) =
when defined(windows): when defined(windows):
if f.wasOpened: if f.wasOpened:
error = unmapViewOfFile(f.mem) == 0 error = unmapViewOfFile(f.mem) == 0
lastErr = osLastError() if not error:
error = (closeHandle(f.mapHandle) == 0) or error error = closeHandle(f.mapHandle) == 0
if f.fHandle != INVALID_HANDLE_VALUE: if not error and f.fHandle != INVALID_HANDLE_VALUE:
error = (closeHandle(f.fHandle) == 0) or error discard closeHandle(f.fHandle)
f.fHandle = INVALID_HANDLE_VALUE
if error:
lastErr = osLastError()
else: else:
error = munmap(f.mem, f.size) != 0 error = munmap(f.mem, f.size) != 0
lastErr = osLastError() lastErr = osLastError()

View file

@ -39,7 +39,7 @@ proc toRational*[T:SomeInteger](x: T): Rational[T] =
result.num = x result.num = x
result.den = 1 result.den = 1
proc toRational*(x: float, n: int = high(int32)): Rational[int] = proc toRational*(x: float, n: int = high(int) shr (sizeof(int) div 2 * 8)): Rational[int] =
## Calculates the best rational numerator and denominator ## Calculates the best rational numerator and denominator
## that approximates to `x`, where the denominator is ## that approximates to `x`, where the denominator is
## smaller than `n` (default is the largest possible ## smaller than `n` (default is the largest possible
@ -323,8 +323,13 @@ when isMainModule:
assert abs(toFloat(y) - 0.4814814814814815) < 1.0e-7 assert abs(toFloat(y) - 0.4814814814814815) < 1.0e-7
assert toInt(z) == 0 assert toInt(z) == 0
assert toRational(0.98765432) == 2111111029 // 2137499919 when sizeof(int) == 8:
assert toRational(PI) == 817696623 // 260280919 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.1) == 1 // 10
assert toRational(0.9) == 9 // 10 assert toRational(0.9) == 9 // 10

View file

@ -176,7 +176,7 @@ proc assertValidDate(monthday: MonthdayRange, month: Month, year: int) {.inline.
assert monthday <= getDaysInMonth(month, year), assert monthday <= getDaysInMonth(month, year),
$year & "-" & $ord(month) & "-" & $monthday & " is not a valid date" $year & "-" & $ord(month) & "-" & $monthday & " is not a valid date"
proc toEpochDay*(monthday: MonthdayRange, month: Month, year: int): int64 = proc toEpochDay(monthday: MonthdayRange, month: Month, year: int): int64 =
## Get the epoch day from a year/month/day date. ## 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). ## The epoch day is the number of days since 1970/01/01 (it might be negative).
assertValidDate monthday, month, year assertValidDate monthday, month, year
@ -191,7 +191,7 @@ proc toEpochDay*(monthday: MonthdayRange, month: Month, year: int): int64 =
let doe = yoe * 365 + yoe div 4 - yoe div 100 + doy let doe = yoe * 365 + yoe div 4 - yoe div 100 + doy
return era * 146097 + doe - 719468 return era * 146097 + doe - 719468
proc fromEpochDay*(epochday: int64): tuple[monthday: MonthdayRange, month: Month, year: int] = proc fromEpochDay(epochday: int64): tuple[monthday: MonthdayRange, month: Month, year: int] =
## Get the year/month/day date from a epoch day. ## 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). ## 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 # Based on http://howardhinnant.github.io/date_algorithms.html
@ -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):
@ -1468,4 +1481,4 @@ proc getDayOfWeekJulian*(day, month, year: int): WeekDay {.deprecated.} =
y = year - a y = year - a
m = month + (12*a) - 2 m = month + (12*a) - 2
d = (5 + day + y + (y div 4) + (31*m) div 12) mod 7 d = (5 + day + y + (y div 4) + (31*m) div 12) mod 7
result = d.WeekDay result = d.WeekDay

View file

@ -743,6 +743,18 @@ proc newSeqOfCap*[T](cap: Natural): seq[T] {.
## ``cap``. ## ``cap``.
discard discard
when not defined(JS):
proc newSeqUninitialized*[T: SomeNumber](len: Natural): seq[T] =
## creates a new sequence of type ``seq[T]`` with length ``len``.
##
## Only available for numbers types. Note that the sequence will be
## uninitialized. After the creation of the sequence you should assign
## entries to the sequence instead of adding them.
result = newSeqOfCap[T](len)
var s = cast[PGenericSeq](result)
s.len = len
proc len*[TOpenArray: openArray|varargs](x: TOpenArray): int {. proc len*[TOpenArray: openArray|varargs](x: TOpenArray): int {.
magic: "LengthOpenArray", noSideEffect.} magic: "LengthOpenArray", noSideEffect.}
proc len*(x: string): int {.magic: "LengthStr", noSideEffect.} proc len*(x: string): int {.magic: "LengthStr", noSideEffect.}

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

@ -1,10 +1,8 @@
discard """ discard """
file: "tmemfiles2.nim" file: "tmemfiles2.nim"
disabled: true
output: '''Full read size: 20 output: '''Full read size: 20
Half read size: 10 Data: Hello''' Half read size: 10 Data: Hello'''
""" """
# doesn't work on windows. fmReadWrite doesn't create a file.
import memfiles, os import memfiles, os
var var
mm, mm_full, mm_half: MemFile mm, mm_full, mm_half: MemFile

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

@ -45,6 +45,9 @@ type
TOptions = set[TOption] TOptions = set[TOption]
TConfirmEnum = enum TConfirmEnum = enum
ceAbort, ceYes, ceAll, ceNo, ceNone ceAbort, ceYes, ceAll, ceNo, ceNone
Pattern = Regex | Peg
using pattern: Pattern
var var
filenames: seq[string] = @[] filenames: seq[string] = @[]
@ -118,7 +121,7 @@ proc highlight(s, match, repl: string, t: tuple[first, last: int],
stdout.write("\n") stdout.write("\n")
stdout.flushFile() stdout.flushFile()
proc processFile(filename: string) = proc processFile(pattern; filename: string) =
var filenameShown = false var filenameShown = false
template beforeHighlight = template beforeHighlight =
if not filenameShown and optVerbose notin options: if not filenameShown and optVerbose notin options:
@ -135,18 +138,8 @@ proc processFile(filename: string) =
if optVerbose in options: if optVerbose in options:
stdout.writeLine(filename) stdout.writeLine(filename)
stdout.flushFile() stdout.flushFile()
var pegp: Peg
var rep: Regex
var result: string var result: string
if optRegex in options:
if {optIgnoreCase, optIgnoreStyle} * options != {}:
rep = re(pattern, {reExtended, reIgnoreCase})
else:
rep = re(pattern)
else:
pegp = peg(pattern)
if optReplace in options: if optReplace in options:
result = newStringOfCap(buffer.len) result = newStringOfCap(buffer.len)
@ -156,11 +149,7 @@ proc processFile(filename: string) =
for j in 0..high(matches): matches[j] = "" for j in 0..high(matches): matches[j] = ""
var reallyReplace = true var reallyReplace = true
while i < buffer.len: while i < buffer.len:
var t: tuple[first, last: int] let t = findBounds(buffer, pattern, matches, i)
if optRegex notin options:
t = findBounds(buffer, pegp, matches, i)
else:
t = findBounds(buffer, rep, matches, i)
if t.first < 0: break if t.first < 0: break
inc(line, countLines(buffer, i, t.first-1)) inc(line, countLines(buffer, i, t.first-1))
@ -170,11 +159,7 @@ proc processFile(filename: string) =
if optReplace notin options: if optReplace notin options:
highlight(buffer, wholeMatch, "", t, line, showRepl=false) highlight(buffer, wholeMatch, "", t, line, showRepl=false)
else: else:
var r: string let r = replace(wholeMatch, pattern, replacement % matches)
if optRegex notin options:
r = replace(wholeMatch, pegp, replacement % matches)
else:
r = replace(wholeMatch, rep, replacement % matches)
if optConfirm in options: if optConfirm in options:
highlight(buffer, wholeMatch, r, t, line, showRepl=true) highlight(buffer, wholeMatch, r, t, line, showRepl=true)
case confirm() case confirm()
@ -246,17 +231,17 @@ proc styleInsensitive(s: string): string =
addx() addx()
else: addx() else: addx()
proc walker(dir: string) = proc walker(pattern; dir: string) =
for kind, path in walkDir(dir): for kind, path in walkDir(dir):
case kind case kind
of pcFile: of pcFile:
if extensions.len == 0 or path.hasRightExt(extensions): if extensions.len == 0 or path.hasRightExt(extensions):
processFile(path) processFile(pattern, path)
of pcDir: of pcDir:
if optRecursive in options: if optRecursive in options:
walker(path) walker(pattern, path)
else: discard else: discard
if existsFile(dir): processFile(dir) if existsFile(dir): processFile(pattern, dir)
proc writeHelp() = proc writeHelp() =
stdout.write(Usage) stdout.write(Usage)
@ -332,11 +317,18 @@ else:
pattern = "\\y " & pattern pattern = "\\y " & pattern
elif optIgnoreCase in options: elif optIgnoreCase in options:
pattern = "\\i " & pattern pattern = "\\i " & pattern
let pegp = peg(pattern)
for f in items(filenames):
walker(pegp, f)
else: else:
var reflags = {reStudy, reExtended}
if optIgnoreStyle in options: if optIgnoreStyle in options:
pattern = styleInsensitive(pattern) pattern = styleInsensitive(pattern)
if optWord in options: if optWord in options:
pattern = r"\b (:?" & pattern & r") \b" pattern = r"\b (:?" & pattern & r") \b"
for f in items(filenames): if {optIgnoreCase, optIgnoreStyle} * options != {}:
walker(f) reflags.incl reIgnoreCase
let rep = re(pattern, reflags)
for f in items(filenames):
walker(rep, f)

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"