mirror of
https://github.com/nim-lang/Nim.git
synced 2026-09-16 10:12:07 +00:00
Merge branch 'devel' of github.com:nim-lang/Nim into devel
This commit is contained in:
@@ -1856,10 +1856,16 @@ proc genClosure(p: BProc, n: PNode, d: var TLoc) =
|
||||
initLocExpr(p, n.sons[1], b)
|
||||
if n.sons[0].skipConv.kind == nkClosure:
|
||||
internalError(n.info, "closure to closure created")
|
||||
getTemp(p, n.typ, tmp)
|
||||
linefmt(p, cpsStmts, "$1.ClPrc = $2; $1.ClEnv = $3;$n",
|
||||
tmp.rdLoc, a.rdLoc, b.rdLoc)
|
||||
putLocIntoDest(p, d, tmp)
|
||||
# tasyncawait.nim breaks with this optimization:
|
||||
when false:
|
||||
if d.k != locNone:
|
||||
linefmt(p, cpsStmts, "$1.ClPrc = $2; $1.ClEnv = $3;$n",
|
||||
d.rdLoc, a.rdLoc, b.rdLoc)
|
||||
else:
|
||||
getTemp(p, n.typ, tmp)
|
||||
linefmt(p, cpsStmts, "$1.ClPrc = $2; $1.ClEnv = $3;$n",
|
||||
tmp.rdLoc, a.rdLoc, b.rdLoc)
|
||||
putLocIntoDest(p, d, tmp)
|
||||
|
||||
proc genArrayConstr(p: BProc, n: PNode, d: var TLoc) =
|
||||
var arr: TLoc
|
||||
|
||||
@@ -1059,9 +1059,8 @@ proc genModule(m: BModule, cfile: string): Rope =
|
||||
result = getFileHeader(cfile)
|
||||
result.add(genMergeInfo(m))
|
||||
|
||||
generateHeaders(m)
|
||||
|
||||
generateThreadLocalStorage(m)
|
||||
generateHeaders(m)
|
||||
for i in countup(cfsHeaders, cfsProcs):
|
||||
add(result, genSectionStart(i))
|
||||
add(result, m.s[i])
|
||||
|
||||
@@ -721,6 +721,10 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
|
||||
let m = newSymNode(n[namePos].sym)
|
||||
m.typ = n.typ
|
||||
result = liftCapturedVars(m, owner, d, c)
|
||||
of nkHiddenStdConv:
|
||||
if n.len == 2:
|
||||
n.sons[1] = liftCapturedVars(n[1], owner, d, c)
|
||||
if n[1].kind == nkClosure: result = n[1]
|
||||
else:
|
||||
if owner.isIterator:
|
||||
if n.kind == nkYieldStmt:
|
||||
|
||||
@@ -326,6 +326,7 @@ proc parseSymbol(p: var TParser, allowNil = false): PNode =
|
||||
getTok(p)
|
||||
else:
|
||||
parMessage(p, errIdentifierExpected, p.tok)
|
||||
break
|
||||
eat(p, tkAccent)
|
||||
else:
|
||||
if allowNil and p.tok.tokType == tkNil:
|
||||
|
||||
@@ -256,8 +256,9 @@ proc expectDynlibNode(c: PContext, n: PNode): PNode =
|
||||
|
||||
proc processDynLib(c: PContext, n: PNode, sym: PSym) =
|
||||
if (sym == nil) or (sym.kind == skModule):
|
||||
POptionEntry(c.optionStack.tail).dynlib = getLib(c, libDynamic,
|
||||
expectDynlibNode(c, n))
|
||||
let lib = getLib(c, libDynamic, expectDynlibNode(c, n))
|
||||
if not lib.isOverriden:
|
||||
POptionEntry(c.optionStack.tail).dynlib = lib
|
||||
else:
|
||||
if n.kind == nkExprColonExpr:
|
||||
var lib = getLib(c, libDynamic, expectDynlibNode(c, n))
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
## This file implements the new evaluation engine for Nim code.
|
||||
## An instruction is 1-3 int32s in memory, it is a register based VM.
|
||||
|
||||
const debugEchoCode = false
|
||||
const
|
||||
debugEchoCode = false
|
||||
traceCode = debugEchoCode
|
||||
|
||||
import ast except getstr
|
||||
|
||||
@@ -121,7 +123,7 @@ template move(a, b: expr) {.immediate, dirty.} = system.shallowCopy(a, b)
|
||||
# XXX fix minor 'shallowCopy' overloading bug in compiler
|
||||
|
||||
proc createStrKeepNode(x: var TFullReg; keepNode=true) =
|
||||
if x.node.isNil:
|
||||
if x.node.isNil or not keepNode:
|
||||
x.node = newNode(nkStrLit)
|
||||
elif x.node.kind == nkNilLit and keepNode:
|
||||
when defined(useNodeIds):
|
||||
@@ -404,7 +406,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
let instr = c.code[pc]
|
||||
let ra = instr.regA
|
||||
#if c.traceActive:
|
||||
#echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra, " rb ", instr.regB, " rc ", instr.regC
|
||||
when traceCode:
|
||||
echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra, " rb ", instr.regB, " rc ", instr.regC
|
||||
# message(c.debug[pc], warnUser, "Trace")
|
||||
|
||||
case instr.opcode
|
||||
@@ -542,7 +545,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
if regs[rb].node.kind == nkRefTy:
|
||||
regs[ra].node = regs[rb].node.sons[0]
|
||||
else:
|
||||
stackTrace(c, tos, pc, errGenerated, "limited VM support for 'ref'")
|
||||
stackTrace(c, tos, pc, errGenerated, "limited VM support for pointers")
|
||||
else:
|
||||
stackTrace(c, tos, pc, errNilAccess)
|
||||
of opcWrDeref:
|
||||
|
||||
@@ -102,6 +102,10 @@ proc gABC(ctx: PCtx; n: PNode; opc: TOpcode; a, b, c: TRegister = 0) =
|
||||
let ins = (opc.uint32 or (a.uint32 shl 8'u32) or
|
||||
(b.uint32 shl 16'u32) or
|
||||
(c.uint32 shl 24'u32)).TInstr
|
||||
when false:
|
||||
if ctx.code.len == 43:
|
||||
writeStackTrace()
|
||||
echo "generating ", opc
|
||||
ctx.code.add(ins)
|
||||
ctx.debug.add(n.info)
|
||||
|
||||
@@ -122,6 +126,11 @@ proc gABI(c: PCtx; n: PNode; opc: TOpcode; a, b: TRegister; imm: BiggestInt) =
|
||||
proc gABx(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0; bx: int) =
|
||||
# Applies `opc` to `bx` and stores it into register `a`
|
||||
# `bx` must be signed and in the range [-32768, 32767]
|
||||
when false:
|
||||
if c.code.len == 43:
|
||||
writeStackTrace()
|
||||
echo "generating ", opc
|
||||
|
||||
if bx >= -32768 and bx <= 32767:
|
||||
let ins = (opc.uint32 or a.uint32 shl 8'u32 or
|
||||
(bx+wordExcess).uint32 shl 16'u32).TInstr
|
||||
@@ -704,6 +713,10 @@ 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:
|
||||
gen(c, arg, dest)
|
||||
return
|
||||
let tmp = c.genx(arg)
|
||||
if dest < 0: dest = c.getTemp(n.typ)
|
||||
c.gABC(n, opc, dest, tmp)
|
||||
@@ -1117,7 +1130,10 @@ proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
|
||||
if isAddr and (let m = canElimAddr(n); m != nil):
|
||||
gen(c, m, dest, flags)
|
||||
return
|
||||
let newflags = if isAddr: flags+{gfAddrOf} else: flags
|
||||
|
||||
let af = if n[0].kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr}: {gfAddrOf, gfFieldAccess}
|
||||
else: {gfAddrOf}
|
||||
let newflags = if isAddr: flags+af else: flags
|
||||
# consider:
|
||||
# proc foo(f: var ref int) =
|
||||
# f = new(int)
|
||||
@@ -1132,7 +1148,7 @@ proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
|
||||
if gfAddrOf notin flags and fitsRegister(n.typ):
|
||||
c.gABC(n, opcNodeToReg, dest, dest)
|
||||
elif isAddr and isGlobal(n.sons[0]):
|
||||
gen(c, n.sons[0], dest, flags+{gfAddrOf})
|
||||
gen(c, n.sons[0], dest, flags+af)
|
||||
else:
|
||||
let tmp = c.genx(n.sons[0], newflags)
|
||||
if dest < 0: dest = c.getTemp(n.typ)
|
||||
@@ -1447,12 +1463,12 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
|
||||
of tyObject:
|
||||
result = newNodeIT(nkObjConstr, info, t)
|
||||
result.add(newNodeIT(nkEmpty, info, t))
|
||||
getNullValueAux(t.n, result)
|
||||
# initialize inherited fields:
|
||||
var base = t.sons[0]
|
||||
while base != nil:
|
||||
getNullValueAux(skipTypes(base, skipPtrs).n, result)
|
||||
base = base.sons[0]
|
||||
getNullValueAux(t.n, result)
|
||||
of tyArray, tyArrayConstr:
|
||||
result = newNodeIT(nkBracket, info, t)
|
||||
for i in countup(0, int(lengthOrd(t)) - 1):
|
||||
@@ -1736,9 +1752,9 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
|
||||
of declarativeDefs:
|
||||
unused(n, dest)
|
||||
of nkLambdaKinds:
|
||||
let s = n.sons[namePos].sym
|
||||
discard genProc(c, s)
|
||||
genLit(c, n.sons[namePos], dest)
|
||||
#let s = n.sons[namePos].sym
|
||||
#discard genProc(c, s)
|
||||
genLit(c, newSymNode(n.sons[namePos].sym), dest)
|
||||
of nkChckRangeF, nkChckRange64, nkChckRange:
|
||||
let
|
||||
tmp0 = c.genx(n.sons[0])
|
||||
|
||||
@@ -420,7 +420,7 @@ 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 `triggering yourself the collection <gc.html>`_.
|
||||
are `yourself triggering the collection <gc.html>`_.
|
||||
|
||||
|
||||
Custom data types
|
||||
|
||||
@@ -77,38 +77,6 @@ Once bound, typedesc params can appear in the rest of the proc signature:
|
||||
|
||||
declareVariableWithType int, 42
|
||||
|
||||
When used with macros and .compileTime. procs on the other hand, the compiler
|
||||
does not need to instantiate the code multiple times, because types then can be
|
||||
manipulated using the unified internal symbol representation. In such context
|
||||
typedesc acts as any other type. One can create variables, store typedesc
|
||||
values inside containers and so on. For example, here is how one can create
|
||||
a type-safe wrapper for the unsafe `printf` function from C:
|
||||
|
||||
.. code-block:: nim
|
||||
macro safePrintF(formatString: string{lit}, args: varargs[expr]): expr =
|
||||
var i = 0
|
||||
for c in formatChars(formatString):
|
||||
var expectedType = case c
|
||||
of 'c': char
|
||||
of 'd', 'i', 'x', 'X': int
|
||||
of 'f', 'e', 'E', 'g', 'G': float
|
||||
of 's': string
|
||||
of 'p': pointer
|
||||
else: EOutOfRange
|
||||
|
||||
var actualType = args[i].getType
|
||||
inc i
|
||||
|
||||
if expectedType == EOutOfRange:
|
||||
error c & " is not a valid format character"
|
||||
elif expectedType != actualType:
|
||||
error "type mismatch for argument ", i, ". expected type: ",
|
||||
expectedType.name, ", actual type: ", actualType.name
|
||||
|
||||
# keep the original callsite, but use cprintf instead
|
||||
result = callsite()
|
||||
result[0] = newIdentNode(!"cprintf")
|
||||
|
||||
|
||||
Overload resolution can be further influenced by constraining the set of
|
||||
types that will match the typedesc param:
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
## This module contains Nim's support for locks and condition vars.
|
||||
|
||||
const insideRLocksModule = false
|
||||
include "system/syslocks"
|
||||
|
||||
type
|
||||
@@ -63,4 +64,4 @@ template withLock*(a: Lock, body: untyped) =
|
||||
try:
|
||||
body
|
||||
finally:
|
||||
a.release()
|
||||
a.release()
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
## This module contains Nim's support for reentrant locks.
|
||||
|
||||
const insideRLocksModule = true
|
||||
include "system/syslocks"
|
||||
|
||||
type
|
||||
|
||||
@@ -35,6 +35,15 @@ const
|
||||
hasSpawnH = not defined(haiku) # should exist for every Posix system nowadays
|
||||
hasAioH = defined(linux)
|
||||
|
||||
when defined(linux):
|
||||
# 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".}
|
||||
|
||||
when false:
|
||||
const
|
||||
C_IRUSR = 0c000400 ## Read by owner.
|
||||
@@ -2309,9 +2318,9 @@ proc strftime*(a1: cstring, a2: int, a3: cstring,
|
||||
a4: var Tm): int {.importc, header: "<time.h>".}
|
||||
proc strptime*(a1, a2: cstring, a3: var Tm): cstring {.importc, header: "<time.h>".}
|
||||
proc time*(a1: var Time): Time {.importc, header: "<time.h>".}
|
||||
proc timer_create*(a1: var ClockId, a2: var SigEvent,
|
||||
proc timer_create*(a1: ClockId, a2: var SigEvent,
|
||||
a3: var Timer): cint {.importc, header: "<time.h>".}
|
||||
proc timer_delete*(a1: var Timer): cint {.importc, header: "<time.h>".}
|
||||
proc timer_delete*(a1: Timer): cint {.importc, header: "<time.h>".}
|
||||
proc timer_gettime*(a1: Timer, a2: var Itimerspec): cint {.
|
||||
importc, header: "<time.h>".}
|
||||
proc timer_getoverrun*(a1: Timer): cint {.importc, header: "<time.h>".}
|
||||
|
||||
44
lib/pure/collections/chains.nim
Normal file
44
lib/pure/collections/chains.nim
Normal file
@@ -0,0 +1,44 @@
|
||||
#
|
||||
#
|
||||
# Nim's Runtime Library
|
||||
# (c) Copyright 2016 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Template based implementation of singly and doubly linked lists.
|
||||
## The involved types should have 'prev' or 'next' fields and the
|
||||
## list header should have 'head' or 'tail' fields.
|
||||
|
||||
template prepend*(header, node) =
|
||||
when compiles(header.head):
|
||||
when compiles(node.prev):
|
||||
if header.head != nil:
|
||||
header.head.prev = node
|
||||
node.next = header.head
|
||||
header.head = node
|
||||
when compiles(header.tail):
|
||||
if header.tail == nil:
|
||||
header.tail = node
|
||||
|
||||
template append*(header, node) =
|
||||
when compiles(header.head):
|
||||
if header.head == nil:
|
||||
header.head = node
|
||||
when compiles(header.tail):
|
||||
when compiles(node.prev):
|
||||
node.prev = header.tail
|
||||
if header.tail != nil:
|
||||
header.tail.next = node
|
||||
header.tail = node
|
||||
|
||||
template unlink*(header, node) =
|
||||
if node.next != nil:
|
||||
node.next.prev = node.prev
|
||||
if node.prev != nil:
|
||||
node.prev.next = node.next
|
||||
if header.head == node:
|
||||
header.head = node.prev
|
||||
if header.tail == node:
|
||||
header.tail = node.next
|
||||
@@ -5,29 +5,31 @@ type
|
||||
|
||||
{.deprecated: [TMersenneTwister: MersenneTwister].}
|
||||
|
||||
proc newMersenneTwister*(seed: int): MersenneTwister =
|
||||
proc newMersenneTwister*(seed: uint32): MersenneTwister =
|
||||
result.index = 0
|
||||
result.mt[0]= uint32(seed)
|
||||
result.mt[0] = seed
|
||||
for i in 1..623'u32:
|
||||
result.mt[i]= (0x6c078965'u32 * (result.mt[i-1] xor (result.mt[i-1] shr 30'u32)) + i)
|
||||
result.mt[i] = (0x6c078965'u32 * (result.mt[i-1] xor (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)
|
||||
var y = (m.mt[i] and 0x80000000'u32) +
|
||||
(m.mt[(i+1) mod 624] and 0x7fffffff'u32)
|
||||
m.mt[i] = m.mt[(i+397) mod 624] xor uint32(y shr 1'u32)
|
||||
if (y mod 2'u32) != 0:
|
||||
m.mt[i] = m.mt[i] xor 0x9908b0df'u32
|
||||
m.mt[i] = m.mt[i] xor 0x9908b0df'u32
|
||||
|
||||
proc getNum*(m: var MersenneTwister): int =
|
||||
proc getNum*(m: var MersenneTwister): uint32 =
|
||||
## Returns the next pseudo random number ranging from 0 to high(uint32)
|
||||
if m.index == 0:
|
||||
generateNumbers(m)
|
||||
var y = m.mt[m.index]
|
||||
y = y xor (y shr 11'u32)
|
||||
y = y xor ((7'u32 shl y) and 0x9d2c5680'u32)
|
||||
y = y xor ((15'u32 shl y) and 0xefc60000'u32)
|
||||
y = y xor (y shr 18'u32)
|
||||
m.index = (m.index+1) mod 624
|
||||
return int(y)
|
||||
result = m.mt[m.index]
|
||||
m.index = (m.index + 1) mod m.mt.len
|
||||
|
||||
result = result xor (result shr 11'u32)
|
||||
result = result xor ((7'u32 shl result) and 0x9d2c5680'u32)
|
||||
result = result xor ((15'u32 shl result) and 0xefc60000'u32)
|
||||
result = result xor (result shr 18'u32)
|
||||
|
||||
# Test
|
||||
when not defined(testing) and isMainModule:
|
||||
|
||||
@@ -222,9 +222,9 @@ when defined(ssl):
|
||||
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 protSSLv3")
|
||||
raiseSslError("SSLv2 is no longer secure and has been deprecated, use protSSLv23")
|
||||
of protSSLv3:
|
||||
newCTX = SSL_CTX_new(SSLv3_method())
|
||||
raiseSslError("SSLv3 is no longer secure and has been deprecated, use protSSLv23")
|
||||
of protTLSv1:
|
||||
newCTX = SSL_CTX_new(TLSv1_method())
|
||||
|
||||
|
||||
@@ -234,6 +234,47 @@ proc parseInt*(s: string, number: var int, start = 0): int {.
|
||||
elif result != 0:
|
||||
number = int(res)
|
||||
|
||||
# overflowChecks doesn't work with uint64
|
||||
proc rawParseUInt(s: string, b: var uint64, start = 0): int =
|
||||
var
|
||||
res = 0'u64
|
||||
prev = 0'u64
|
||||
i = start
|
||||
if s[i] == '+': inc(i) # Allow
|
||||
if s[i] in {'0'..'9'}:
|
||||
b = 0
|
||||
while s[i] in {'0'..'9'}:
|
||||
prev = res
|
||||
res = res * 10 + (ord(s[i]) - ord('0')).uint64
|
||||
if prev > res:
|
||||
return 0 # overflowChecks emulation
|
||||
inc(i)
|
||||
while s[i] == '_': inc(i) # underscores are allowed and ignored
|
||||
b = res
|
||||
result = i - start
|
||||
|
||||
proc parseBiggestUInt*(s: string, number: var uint64, start = 0): int {.
|
||||
rtl, extern: "npuParseBiggestUInt", noSideEffect.} =
|
||||
## parses an unsigned integer starting at `start` and stores the value into `number`.
|
||||
## Result is the number of processed chars or 0 if there is no integer or overflow detected.
|
||||
var res: uint64
|
||||
# use 'res' for exception safety (don't write to 'number' in case of an
|
||||
# overflow exception):
|
||||
result = rawParseUInt(s, res, start)
|
||||
number = res
|
||||
|
||||
proc parseUInt*(s: string, number: var uint, start = 0): int {.
|
||||
rtl, extern: "npuParseUInt", noSideEffect.} =
|
||||
## parses an unsigned integer starting at `start` and stores the value into `number`.
|
||||
## Result is the number of processed chars or 0 if there is no integer or overflow detected.
|
||||
var res: uint64
|
||||
result = parseBiggestUInt(s, res, start)
|
||||
if (sizeof(uint) <= 4) and
|
||||
(res > 0xFFFF_FFFF'u64):
|
||||
raise newException(OverflowError, "overflow")
|
||||
elif result != 0:
|
||||
number = uint(res)
|
||||
|
||||
proc parseBiggestFloat*(s: string, number: var BiggestFloat, start = 0): int {.
|
||||
magic: "ParseBiggestFloat", importc: "nimParseBiggestFloat", noSideEffect.}
|
||||
## parses a float starting at `start` and stores the value into `number`.
|
||||
|
||||
@@ -560,6 +560,24 @@ 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,
|
||||
rtl, extern: "nsuParseUInt".} =
|
||||
## Parses a decimal unsigned integer value contained in `s`.
|
||||
##
|
||||
## If `s` is not a valid integer, `ValueError` is raised.
|
||||
var L = parseutils.parseUInt(s, result, 0)
|
||||
if L != s.len or L == 0:
|
||||
raise newException(ValueError, "invalid unsigned integer: " & s)
|
||||
|
||||
proc parseBiggestUInt*(s: string): uint64 {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuParseBiggestUInt".} =
|
||||
## Parses a decimal unsigned integer value contained in `s`.
|
||||
##
|
||||
## If `s` is not a valid integer, `ValueError` is raised.
|
||||
var L = parseutils.parseBiggestUInt(s, result, 0)
|
||||
if L != s.len or L == 0:
|
||||
raise newException(ValueError, "invalid unsigned integer: " & s)
|
||||
|
||||
proc parseFloat*(s: string): float {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuParseFloat".} =
|
||||
## Parses a decimal floating point value contained in `s`. If `s` is not
|
||||
|
||||
@@ -2877,6 +2877,7 @@ when not defined(JS): #and not defined(nimscript):
|
||||
when declared(initAllocator):
|
||||
initAllocator()
|
||||
when hasThreadSupport:
|
||||
const insideRLocksModule = false
|
||||
include "system/syslocks"
|
||||
when hostOS != "standalone": include "system/threads"
|
||||
elif not defined(nogc) and not defined(nimscript):
|
||||
|
||||
@@ -109,9 +109,30 @@ elif defined(windows) or defined(dos):
|
||||
proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr =
|
||||
result = getProcAddress(cast[THINSTANCE](lib), name)
|
||||
if result != nil: return
|
||||
var decorated: array[250, char]
|
||||
const decorated_length = 250
|
||||
var decorated: array[decorated_length, char]
|
||||
decorated[0] = '_'
|
||||
var m = 1
|
||||
while m < (decorated_length - 5):
|
||||
if name[m - 1] == '\x00': break
|
||||
decorated[m] = name[m - 1]
|
||||
inc(m)
|
||||
decorated[m] = '@'
|
||||
for i in countup(0, 50):
|
||||
discard csprintf(decorated, "_%s@%ld", name, i*4)
|
||||
var k = i * 4
|
||||
if k div 100 == 0:
|
||||
if k div 10 == 0:
|
||||
m = m + 1
|
||||
else:
|
||||
m = m + 2
|
||||
else:
|
||||
m = m + 3
|
||||
decorated[m + 1] = '\x00'
|
||||
while true:
|
||||
decorated[m] = chr(ord('0') + (k %% 10))
|
||||
dec(m)
|
||||
k = k div 10
|
||||
if k == 0: break
|
||||
result = getProcAddress(cast[THINSTANCE](lib), decorated)
|
||||
if result != nil: return
|
||||
procAddrError(name)
|
||||
|
||||
@@ -14,39 +14,41 @@
|
||||
when defined(Windows):
|
||||
type
|
||||
Handle = int
|
||||
SysLock {.final, pure.} = object # CRITICAL_SECTION in WinApi
|
||||
|
||||
SysLock {.importc: "CRITICAL_SECTION",
|
||||
header: "<windows.h>", final, pure.} = object # CRITICAL_SECTION in WinApi
|
||||
DebugInfo: pointer
|
||||
LockCount: int32
|
||||
RecursionCount: int32
|
||||
OwningThread: int
|
||||
LockSemaphore: int
|
||||
Reserved: int32
|
||||
SpinCount: int
|
||||
|
||||
SysCond = Handle
|
||||
|
||||
{.deprecated: [THandle: Handle, TSysLock: SysLock, TSysCond: SysCond].}
|
||||
|
||||
proc initSysLock(L: var SysLock) {.stdcall, noSideEffect,
|
||||
dynlib: "kernel32", importc: "InitializeCriticalSection".}
|
||||
proc initSysLock(L: var SysLock) {.importc: "InitializeCriticalSection",
|
||||
header: "<windows.h>".}
|
||||
## Initializes the lock `L`.
|
||||
|
||||
proc tryAcquireSysAux(L: var SysLock): int32 {.stdcall, noSideEffect,
|
||||
dynlib: "kernel32", importc: "TryEnterCriticalSection".}
|
||||
proc tryAcquireSysAux(L: var SysLock): int32 {.importc: "TryEnterCriticalSection",
|
||||
header: "<windows.h>".}
|
||||
## Tries to acquire the lock `L`.
|
||||
|
||||
proc tryAcquireSys(L: var SysLock): bool {.inline.} =
|
||||
result = tryAcquireSysAux(L) != 0'i32
|
||||
|
||||
proc acquireSys(L: var SysLock) {.stdcall, noSideEffect,
|
||||
dynlib: "kernel32", importc: "EnterCriticalSection".}
|
||||
proc acquireSys(L: var SysLock) {.importc: "EnterCriticalSection",
|
||||
header: "<windows.h>".}
|
||||
## Acquires the lock `L`.
|
||||
|
||||
proc releaseSys(L: var SysLock) {.stdcall, noSideEffect,
|
||||
dynlib: "kernel32", importc: "LeaveCriticalSection".}
|
||||
proc releaseSys(L: var SysLock) {.importc: "LeaveCriticalSection",
|
||||
header: "<windows.h>".}
|
||||
## Releases the lock `L`.
|
||||
|
||||
proc deinitSys(L: var SysLock) {.stdcall, noSideEffect,
|
||||
dynlib: "kernel32", importc: "DeleteCriticalSection".}
|
||||
proc deinitSys(L: var SysLock) {.importc: "DeleteCriticalSection",
|
||||
header: "<windows.h>".}
|
||||
|
||||
proc createEvent(lpEventAttributes: pointer,
|
||||
bManualReset, bInitialState: int32,
|
||||
@@ -86,17 +88,16 @@ else:
|
||||
#include <pthread.h>""".} = object
|
||||
SysLockType = distinct cint
|
||||
|
||||
proc SysLockType_Reentrant: SysLockType =
|
||||
{.emit: "`result` = PTHREAD_MUTEX_RECURSIVE;".}
|
||||
|
||||
proc initSysLock(L: var SysLock, attr: ptr SysLockAttr = nil) {.
|
||||
importc: "pthread_mutex_init", header: "<pthread.h>", noSideEffect.}
|
||||
|
||||
proc initSysLockAttr(a: var SysLockAttr) {.
|
||||
importc: "pthread_mutexattr_init", header: "<pthread.h>", noSideEffect.}
|
||||
|
||||
proc setSysLockType(a: var SysLockAttr, t: SysLockType) {.
|
||||
importc: "pthread_mutexattr_settype", header: "<pthread.h>", noSideEffect.}
|
||||
when insideRLocksModule:
|
||||
proc SysLockType_Reentrant: SysLockType =
|
||||
{.emit: "`result` = PTHREAD_MUTEX_RECURSIVE;".}
|
||||
proc initSysLockAttr(a: var SysLockAttr) {.
|
||||
importc: "pthread_mutexattr_init", header: "<pthread.h>", noSideEffect.}
|
||||
proc setSysLockType(a: var SysLockAttr, t: SysLockType) {.
|
||||
importc: "pthread_mutexattr_settype", header: "<pthread.h>", noSideEffect.}
|
||||
|
||||
proc acquireSys(L: var SysLock) {.noSideEffect,
|
||||
importc: "pthread_mutex_lock", header: "<pthread.h>".}
|
||||
@@ -111,14 +112,12 @@ else:
|
||||
proc deinitSys(L: var SysLock) {.noSideEffect,
|
||||
importc: "pthread_mutex_destroy", header: "<pthread.h>".}
|
||||
|
||||
proc initSysCond(cond: var SysCond, cond_attr: pointer = nil) {.
|
||||
importc: "pthread_cond_init", header: "<pthread.h>", noSideEffect.}
|
||||
proc waitSysCond(cond: var SysCond, lock: var SysLock) {.
|
||||
importc: "pthread_cond_wait", header: "<pthread.h>", noSideEffect.}
|
||||
proc signalSysCond(cond: var SysCond) {.
|
||||
importc: "pthread_cond_signal", header: "<pthread.h>", noSideEffect.}
|
||||
|
||||
proc deinitSysCond(cond: var SysCond) {.noSideEffect,
|
||||
importc: "pthread_cond_destroy", header: "<pthread.h>".}
|
||||
|
||||
{.pop.}
|
||||
when not insideRLocksModule:
|
||||
proc initSysCond(cond: var SysCond, cond_attr: pointer = nil) {.
|
||||
importc: "pthread_cond_init", header: "<pthread.h>", noSideEffect.}
|
||||
proc waitSysCond(cond: var SysCond, lock: var SysLock) {.
|
||||
importc: "pthread_cond_wait", header: "<pthread.h>", noSideEffect.}
|
||||
proc signalSysCond(cond: var SysCond) {.
|
||||
importc: "pthread_cond_signal", header: "<pthread.h>", noSideEffect.}
|
||||
proc deinitSysCond(cond: var SysCond) {.noSideEffect,
|
||||
importc: "pthread_cond_destroy", header: "<pthread.h>".}
|
||||
|
||||
24
tests/closure/tflatmap.nim
Normal file
24
tests/closure/tflatmap.nim
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
# bug #3995
|
||||
|
||||
import future
|
||||
|
||||
type
|
||||
RNG* = tuple[]
|
||||
Rand*[A] = (RNG) -> (A, RNG)
|
||||
|
||||
proc nextInt*(r: RNG): (int, RNG) =
|
||||
(1, ())
|
||||
|
||||
proc flatMap[A,B](f: Rand[A], g: A -> Rand[B]): Rand[B] =
|
||||
(rng: RNG) => (
|
||||
let (a, rng2) = f(rng);
|
||||
let g1 = g(a);
|
||||
g1(rng2)
|
||||
)
|
||||
|
||||
proc map[A,B](s: Rand[A], f: A -> B): Rand[B] =
|
||||
let g: A -> Rand[B] = (a: A) => ((rng: RNG) => (f(a), rng))
|
||||
flatMap(s, g)
|
||||
|
||||
let f = nextInt.map(i => i - i mod 2)
|
||||
48
tests/macros/typesafeprintf.nim
Normal file
48
tests/macros/typesafeprintf.nim
Normal file
@@ -0,0 +1,48 @@
|
||||
discard """
|
||||
output: '''test 10'''
|
||||
"""
|
||||
|
||||
# bug #1152
|
||||
|
||||
import macros, typetraits
|
||||
proc printfImpl(formatstr: cstring) {.importc: "printf", varargs.}
|
||||
|
||||
iterator tokenize(format: string): char =
|
||||
var i = 0
|
||||
while true:
|
||||
case format[i]
|
||||
of '%':
|
||||
case format[i+1]
|
||||
of '\0': break
|
||||
else: yield format[i+1]
|
||||
i.inc
|
||||
of '\0': break
|
||||
else: discard
|
||||
i.inc
|
||||
|
||||
macro printf(formatString: string{lit}, args: varargs[typed]): untyped =
|
||||
var i = 0
|
||||
let err = getType(bindSym"ValueError")
|
||||
for c in tokenize(formatString.strVal):
|
||||
var expectedType = case c
|
||||
of 'c': getType(bindSym"char")
|
||||
of 'd', 'i', 'x', 'X': getType(bindSym"int")
|
||||
of 'f', 'e', 'E', 'g', 'G': getType(bindSym"float")
|
||||
of 's': getType(bindSym"string")
|
||||
of 'p': getType(bindSym"pointer")
|
||||
else: err
|
||||
|
||||
var actualType = getType(args[i])
|
||||
inc i
|
||||
|
||||
if sameType(expectedType, err):
|
||||
error c & " is not a valid format character"
|
||||
elif not sameType(expectedType, actualType):
|
||||
error "type mismatch for argument " & $i & ". expected type: " &
|
||||
$expectedType & ", actual type: " & $actualType
|
||||
|
||||
# keep the original callsite, but use cprintf instead
|
||||
result = callsite()
|
||||
result[0] = bindSym"printfImpl"
|
||||
|
||||
printf("test %d\n", 10)
|
||||
11
tests/stdlib/tparseuints.nim
Normal file
11
tests/stdlib/tparseuints.nim
Normal file
@@ -0,0 +1,11 @@
|
||||
discard """
|
||||
action: run
|
||||
"""
|
||||
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")
|
||||
52
tests/vm/tanonproc.nim
Normal file
52
tests/vm/tanonproc.nim
Normal file
@@ -0,0 +1,52 @@
|
||||
discard """
|
||||
output: '''`Test`'''
|
||||
"""
|
||||
|
||||
# bug #3561
|
||||
|
||||
import macros, future, strutils
|
||||
|
||||
type
|
||||
Option[T] = ref object
|
||||
case valid: bool
|
||||
of true:
|
||||
data: T
|
||||
else:
|
||||
discard
|
||||
|
||||
proc some[T](v: T): Option[T] = Option[T](valid: true, data: v)
|
||||
proc none[T](v: T): Option[T] = Option[T](valid: false)
|
||||
proc none(T: typedesc): Option[T] = Option[T](valid: false)
|
||||
|
||||
proc map[T,U](o: Option[T], f: T -> U): Option[U] =
|
||||
case o.valid
|
||||
of true:
|
||||
f(o.data).some
|
||||
else:
|
||||
U.none
|
||||
|
||||
proc notEmpty(o: Option[string]): Option[string] =
|
||||
case o.valid
|
||||
of true:
|
||||
if o.data.strip == "": string.none else: o.data.strip.some
|
||||
else:
|
||||
o
|
||||
|
||||
proc getOrElse[T](o: Option[T], def: T): T =
|
||||
case o.valid
|
||||
of true:
|
||||
o.data
|
||||
else:
|
||||
def
|
||||
|
||||
proc quoteStr(s: string): Option[string] =
|
||||
s.some.notEmpty.map(v => "`" & v & "`")
|
||||
|
||||
macro str(s: string): stmt =
|
||||
let x = s.strVal
|
||||
let y = quoteStr(x)
|
||||
let sn = newStrLitNode(y.getOrElse("NONE"))
|
||||
result = quote do:
|
||||
echo `sn`
|
||||
|
||||
str"Test"
|
||||
29
tests/vm/tinheritance.nim
Normal file
29
tests/vm/tinheritance.nim
Normal file
@@ -0,0 +1,29 @@
|
||||
discard """
|
||||
msg: '''Hello fred , managed by sally
|
||||
Hello sally , managed by bob'''
|
||||
"""
|
||||
# bug #3973
|
||||
|
||||
type
|
||||
EmployeeCode = enum
|
||||
ecCode1,
|
||||
ecCode2
|
||||
|
||||
Person* = object of RootObj
|
||||
name* : string
|
||||
last_name*: string
|
||||
|
||||
Employee* = object of Person
|
||||
empl_code* : EmployeeCode
|
||||
mgr_name* : string
|
||||
|
||||
proc test() =
|
||||
var
|
||||
empl1 = Employee(name: "fred", last_name: "smith", mgr_name: "sally", empl_code: ecCode1)
|
||||
empl2 = Employee(name: "sally", last_name: "jones", mgr_name: "bob", empl_code: ecCode2)
|
||||
|
||||
echo "Hello ", empl1.name, " , managed by ", empl1.mgr_name
|
||||
echo "Hello ", empl2.name, " , managed by ", empl2.mgr_name
|
||||
|
||||
static:
|
||||
test()
|
||||
31
tests/vm/tmitems.nim
Normal file
31
tests/vm/tmitems.nim
Normal file
@@ -0,0 +1,31 @@
|
||||
discard """
|
||||
msg: '''13'''
|
||||
output: '''3
|
||||
3
|
||||
3'''
|
||||
"""
|
||||
# bug #3731
|
||||
var list {.compileTime.} = newSeq[int]()
|
||||
|
||||
macro calc*(): stmt {.immediate.} =
|
||||
list.add(1)
|
||||
for c in list.mitems:
|
||||
c = 13
|
||||
|
||||
for c in list:
|
||||
echo c
|
||||
|
||||
calc()
|
||||
|
||||
# bug #3859
|
||||
import macros
|
||||
macro m: stmt =
|
||||
var s = newseq[NimNode](3)
|
||||
# var s: array[3,NimNode] # not working either
|
||||
for i in 0..<s.len: s[i] = newLit(3) # works
|
||||
#for x in s.mitems: x = newLit(3)
|
||||
result = newStmtList()
|
||||
for i in s:
|
||||
result.add newCall(bindsym"echo", i)
|
||||
|
||||
m()
|
||||
28
tests/vm/twrong_concat.nim
Normal file
28
tests/vm/twrong_concat.nim
Normal file
@@ -0,0 +1,28 @@
|
||||
discard """
|
||||
output: '''success'''
|
||||
"""
|
||||
|
||||
# bug #3804
|
||||
|
||||
#import sequtils
|
||||
|
||||
type AnObj = ref object
|
||||
field: string
|
||||
|
||||
#proc aBug(objs: seq[AnObj]) {.compileTime.} =
|
||||
# discard objs.mapIt(it.field & " bug")
|
||||
|
||||
proc sameBug(objs: seq[AnObj]) {.compileTime.} =
|
||||
var strSeq = newSeq[string](objs.len)
|
||||
strSeq[0] = objs[0].field & " bug"
|
||||
|
||||
static:
|
||||
var objs: seq[AnObj] = @[]
|
||||
objs.add(AnObj(field: "hello"))
|
||||
|
||||
sameBug(objs)
|
||||
# sameBug(objs)
|
||||
echo objs[0].field
|
||||
assert(objs[0].field == "hello") # fails, because (objs[0].field == "hello bug") - mutated!
|
||||
|
||||
echo "success"
|
||||
@@ -20,6 +20,9 @@ Changes affecting backwards compatibility
|
||||
new experimental ``this`` pragma to achieve a similar effect to what the old ``using`` statement tried to achieve.
|
||||
- Typeless parameters have been removed from the language since it would
|
||||
clash with ``using``.
|
||||
- Procedures in ``mersenne.nim`` (Mersenne Twister implementation) no longer
|
||||
accept and produce ``int`` values which have platform-dependent size -
|
||||
they use ``uint32`` instead.
|
||||
|
||||
|
||||
Library Additions
|
||||
|
||||
Reference in New Issue
Block a user