diff options
Diffstat (limited to 'lib/system')
-rw-r--r-- | lib/system/assign.nim | 5 | ||||
-rw-r--r-- | lib/system/cgprocs.nim | 1 | ||||
-rw-r--r-- | lib/system/excpt.nim | 23 | ||||
-rw-r--r-- | lib/system/gc_ms.nim | 96 | ||||
-rw-r--r-- | lib/system/helpers.nim | 11 | ||||
-rw-r--r-- | lib/system/hti.nim | 12 | ||||
-rw-r--r-- | lib/system/jssys.nim | 23 | ||||
-rw-r--r-- | lib/system/mmdisp.nim | 125 | ||||
-rw-r--r-- | lib/system/nimscript.nim | 40 | ||||
-rw-r--r-- | lib/system/repr.nim | 29 | ||||
-rw-r--r-- | lib/system/reprjs.nim | 5 | ||||
-rw-r--r-- | lib/system/strmantle.nim | 298 | ||||
-rw-r--r-- | lib/system/sysio.nim | 16 | ||||
-rw-r--r-- | lib/system/sysstr.nim | 296 | ||||
-rw-r--r-- | lib/system/threads.nim | 5 | ||||
-rw-r--r-- | lib/system/widestrs.nim | 3 |
16 files changed, 486 insertions, 502 deletions
diff --git a/lib/system/assign.nim b/lib/system/assign.nim index 16b56aba7..2b74e6682 100644 --- a/lib/system/assign.nim +++ b/lib/system/assign.nim @@ -202,11 +202,6 @@ proc objectInit(dest: pointer, typ: PNimType) = # ---------------------- assign zero ----------------------------------------- -proc nimDestroyRange[T](r: T) {.compilerProc.} = - # internal proc used for destroying sequences and arrays - mixin `=destroy` - for i in countup(0, r.len - 1): `=destroy`(r[i]) - proc genericReset(dest: pointer, mt: PNimType) {.compilerProc, benign.} proc genericResetAux(dest: pointer, n: ptr TNimNode) = var d = cast[ByteAddress](dest) diff --git a/lib/system/cgprocs.nim b/lib/system/cgprocs.nim index 660c68116..72219c2b7 100644 --- a/lib/system/cgprocs.nim +++ b/lib/system/cgprocs.nim @@ -12,7 +12,6 @@ type LibHandle = pointer # private type ProcAddr = pointer # library loading and loading of procs: -{.deprecated: [TLibHandle: LibHandle, TProcAddr: ProcAddr].} proc nimLoadLibrary(path: string): LibHandle {.compilerproc.} proc nimUnloadLibrary(lib: LibHandle) {.compilerproc.} diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index f25da0ad8..7d5f5af7f 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -213,7 +213,7 @@ proc auxWriteStackTrace(f: PFrame; s: var seq[StackTraceEntry]) = inc(i) it = it.prev var last = i-1 - if s.isNil: + if s.len == 0: s = newSeq[StackTraceEntry](i) else: last = s.len + i - 1 @@ -307,7 +307,7 @@ when hasSomeStackTrace: when NimStackTrace: auxWriteStackTrace(framePtr, s) else: - s = nil + s = @[] proc stackTraceAvailable(): bool = when NimStackTrace: @@ -361,10 +361,10 @@ proc raiseExceptionAux(e: ref Exception) = else: when hasSomeStackTrace: var buf = newStringOfCap(2000) - if isNil(e.trace): rawWriteStackTrace(buf) + if e.trace.len == 0: rawWriteStackTrace(buf) else: add(buf, $e.trace) add(buf, "Error: unhandled exception: ") - if not isNil(e.msg): add(buf, e.msg) + add(buf, e.msg) add(buf, " [") add(buf, $e.name) add(buf, "]\n") @@ -382,7 +382,7 @@ proc raiseExceptionAux(e: ref Exception) = var buf: array[0..2000, char] var L = 0 add(buf, "Error: unhandled exception: ") - if not isNil(e.msg): add(buf, e.msg) + add(buf, e.msg) add(buf, " [") xadd(buf, e.name, e.name.len) add(buf, "]\n") @@ -397,7 +397,7 @@ proc raiseExceptionAux(e: ref Exception) = proc raiseException(e: ref Exception, ename: cstring) {.compilerRtl.} = if e.name.isNil: e.name = ename when hasSomeStackTrace: - if e.trace.isNil: + if e.trace.len == 0: rawWriteStackTrace(e.trace) elif framePtr != nil: e.trace.add reraisedFrom(reraisedFromBegin) @@ -427,15 +427,16 @@ proc getStackTrace(): string = result = "No stack traceback available\n" proc getStackTrace(e: ref Exception): string = - if not isNil(e) and not isNil(e.trace): + if not isNil(e): result = $e.trace else: result = "" -proc getStackTraceEntries*(e: ref Exception): seq[StackTraceEntry] = - ## Returns the attached stack trace to the exception ``e`` as - ## a ``seq``. This is not yet available for the JS backend. - shallowCopy(result, e.trace) +when not defined(gcDestructors): + proc getStackTraceEntries*(e: ref Exception): seq[StackTraceEntry] = + ## Returns the attached stack trace to the exception ``e`` as + ## a ``seq``. This is not yet available for the JS backend. + shallowCopy(result, e.trace) when defined(nimRequiresNimFrame): proc stackOverflow() {.noinline.} = diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim index 75f9c6749..96221b175 100644 --- a/lib/system/gc_ms.nim +++ b/lib/system/gc_ms.nim @@ -264,12 +264,13 @@ proc forAllChildren(cell: PCell, op: WalkOp) = of tyRef, tyOptAsRef: # common case forAllChildrenAux(cellToUsr(cell), cell.typ.base, op) of tySequence: - var d = cast[ByteAddress](cellToUsr(cell)) - var s = cast[PGenericSeq](d) - if s != nil: - for i in 0..s.len-1: - forAllChildrenAux(cast[pointer](d +% i *% cell.typ.base.size +% - GenericSeqSize), cell.typ.base, op) + when not defined(gcDestructors): + var d = cast[ByteAddress](cellToUsr(cell)) + var s = cast[PGenericSeq](d) + if s != nil: + for i in 0..s.len-1: + forAllChildrenAux(cast[pointer](d +% i *% cell.typ.base.size +% + GenericSeqSize), cell.typ.base, op) else: discard proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer = @@ -310,53 +311,54 @@ proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} = result = rawNewObj(typ, size, gch) when defined(memProfiler): nimProfile(size) -proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} = - # `newObj` already uses locks, so no need for them here. - let size = addInt(mulInt(len, typ.base.size), GenericSeqSize) - result = newObj(typ, size) - cast[PGenericSeq](result).len = len - cast[PGenericSeq](result).reserved = len - when defined(memProfiler): nimProfile(size) - proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} = result = rawNewObj(typ, size, gch) zeroMem(result, size) when defined(memProfiler): nimProfile(size) -proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} = - let size = addInt(mulInt(len, typ.base.size), GenericSeqSize) - result = newObj(typ, size) - cast[PGenericSeq](result).len = len - cast[PGenericSeq](result).reserved = len - when defined(memProfiler): nimProfile(size) - -proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer = - acquire(gch) - collectCT(gch, newsize + sizeof(Cell)) - var ol = usrToCell(old) - sysAssert(ol.typ != nil, "growObj: 1") - gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2") - - var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell))) - var elemSize = 1 - if ol.typ.kind != tyString: elemSize = ol.typ.base.size - incTypeSize ol.typ, newsize - - var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize - copyMem(res, ol, oldsize + sizeof(Cell)) - zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(Cell)), - newsize-oldsize) - sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3") - when withBitvectors: incl(gch.allocated, res) - when useCellIds: - inc gch.idGenerator - res.id = gch.idGenerator - release(gch) - result = cellToUsr(res) - when defined(memProfiler): nimProfile(newsize-oldsize) +when not defined(gcDestructors): + proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} = + # `newObj` already uses locks, so no need for them here. + let size = addInt(mulInt(len, typ.base.size), GenericSeqSize) + result = newObj(typ, size) + cast[PGenericSeq](result).len = len + cast[PGenericSeq](result).reserved = len + when defined(memProfiler): nimProfile(size) + + proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} = + let size = addInt(mulInt(len, typ.base.size), GenericSeqSize) + result = newObj(typ, size) + cast[PGenericSeq](result).len = len + cast[PGenericSeq](result).reserved = len + when defined(memProfiler): nimProfile(size) + + proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer = + acquire(gch) + collectCT(gch, newsize + sizeof(Cell)) + var ol = usrToCell(old) + sysAssert(ol.typ != nil, "growObj: 1") + gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2") + + var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell))) + var elemSize = 1 + if ol.typ.kind != tyString: elemSize = ol.typ.base.size + incTypeSize ol.typ, newsize + + var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize + copyMem(res, ol, oldsize + sizeof(Cell)) + zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(Cell)), + newsize-oldsize) + sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3") + when withBitvectors: incl(gch.allocated, res) + when useCellIds: + inc gch.idGenerator + res.id = gch.idGenerator + release(gch) + result = cellToUsr(res) + when defined(memProfiler): nimProfile(newsize-oldsize) -proc growObj(old: pointer, newsize: int): pointer {.rtl.} = - result = growObj(old, newsize, gch) + proc growObj(old: pointer, newsize: int): pointer {.rtl.} = + result = growObj(old, newsize, gch) {.push profiler:off.} diff --git a/lib/system/helpers.nim b/lib/system/helpers.nim new file mode 100644 index 000000000..fb1218684 --- /dev/null +++ b/lib/system/helpers.nim @@ -0,0 +1,11 @@ +## helpers used system.nim and other modules, avoids code duplication while +## also minimizing symbols exposed in system.nim +# +# TODO: move other things here that should not be exposed in system.nim + +proc lineInfoToString(file: string, line, column: int): string = + file & "(" & $line & ", " & $column & ")" + +proc `$`(info: type(instantiationInfo(0))): string = + # The +1 is needed here + lineInfoToString(info.fileName, info.line, info.column+1) diff --git a/lib/system/hti.nim b/lib/system/hti.nim index 45b1d1cd3..c7b52bbdf 100644 --- a/lib/system/hti.nim +++ b/lib/system/hti.nim @@ -7,12 +7,6 @@ # distribution, for details about the copyright. # -when declared(NimString): - # we are in system module: - {.pragma: codegenType, compilerproc.} -else: - {.pragma: codegenType, importc.} - type # This should be the same as ast.TTypeKind # many enum fields are not used at runtime @@ -79,7 +73,7 @@ type tyVoidHidden TNimNodeKind = enum nkNone, nkSlot, nkList, nkCase - TNimNode {.codegenType.} = object + TNimNode {.compilerProc.} = object kind: TNimNodeKind offset: int typ: ptr TNimType @@ -92,7 +86,7 @@ type ntfAcyclic = 1, # type cannot form a cycle ntfEnumHole = 2 # enum has holes and thus `$` for them needs the slow # version - TNimType {.codegenType.} = object + TNimType {.compilerProc.} = object size: int kind: TNimKind flags: set[TNimTypeFlag] @@ -109,6 +103,6 @@ type PNimType = ptr TNimType when defined(nimTypeNames): - var nimTypeRoot {.codegenType.}: PNimType + var nimTypeRoot {.compilerProc.}: PNimType # node.len may be the ``first`` element of a set diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index 8d4a2e482..836ac198d 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -31,8 +31,6 @@ type JSRef = ref RootObj # Fake type. -{.deprecated: [TSafePoint: SafePoint, TCallFrame: CallFrame].} - var framePtr {.importc, nodecl, volatile.}: PCallFrame excHandler {.importc, nodecl, volatile.}: int = 0 @@ -184,12 +182,10 @@ proc setConstr() {.varargs, asmNoStackFrame, compilerproc.} = proc makeNimstrLit(c: cstring): string {.asmNoStackFrame, compilerproc.} = {.emit: """ var ln = `c`.length; - var result = new Array(ln + 1); - var i = 0; - for (; i < ln; ++i) { + var result = new Array(ln); + for (var i = 0; i < ln; ++i) { result[i] = `c`.charCodeAt(i); } - result[i] = 0; // terminating zero return result; """.} @@ -227,13 +223,12 @@ proc cstrToNimstr(c: cstring): string {.asmNoStackFrame, compilerproc.} = } ++r; } - result[r] = 0; // terminating zero return result; """.} proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} = asm """ - var len = `s`.length-1; + var len = `s`.length; var asciiPart = new Array(len); var fcc = String.fromCharCode; var nonAsciiPart = null; @@ -264,10 +259,7 @@ proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} = proc mnewString(len: int): string {.asmNoStackFrame, compilerproc.} = asm """ - var result = new Array(`len`+1); - result[0] = 0; - result[`len`] = 0; - return result; + return new Array(`len`); """ proc SetCard(a: int): int {.compilerproc, asmNoStackFrame.} = @@ -325,7 +317,7 @@ proc cmpStrings(a, b: string): int {.asmNoStackFrame, compilerProc.} = if (`a` == `b`) return 0; if (!`a`) return -1; if (!`b`) return 1; - for (var i = 0; i < `a`.length - 1 && i < `b`.length - 1; i++) { + for (var i = 0; i < `a`.length && i < `b`.length; i++) { var result = `a`[i] - `b`[i]; if (result != 0) return result; } @@ -506,7 +498,6 @@ proc chckNilDisp(p: pointer) {.compilerproc.} = if p == nil: sysFatal(NilAccessError, "cannot dispatch; dispatcher is nil") -type NimString = string # hack for hti.nim include "system/hti" proc isFatPointer(ti: PNimType): bool = @@ -654,9 +645,7 @@ proc isObj(obj, subclass: PNimType): bool {.compilerproc.} = return true proc addChar(x: string, c: char) {.compilerproc, asmNoStackFrame.} = - asm """ - `x`[`x`.length-1] = `c`; `x`.push(0); - """ + asm "`x`.push(`c`);" {.pop.} diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim index b33ca93f2..e7e14b948 100644 --- a/lib/system/mmdisp.nim +++ b/lib/system/mmdisp.nim @@ -175,8 +175,7 @@ when defined(boehmgc): dest[] = src type - MemRegion = object {.final, pure.} - {.deprecated: [TMemRegion: MemRegion].} + MemRegion = object proc alloc(r: var MemRegion, size: int): pointer = result = boehmAlloc(size) @@ -215,60 +214,58 @@ elif defined(gogc): goNumSizeClasses = 67 type - cbool {.importc: "_Bool", nodecl.} = bool - goMStats_inner_struct = object - size: uint32 - nmalloc: uint64 - nfree: uint64 + size: uint32 + nmalloc: uint64 + nfree: uint64 goMStats = object - # General statistics. - alloc: uint64 # bytes allocated and still in use - total_alloc: uint64 # bytes allocated (even if freed) - sys: uint64 # bytes obtained from system (should be sum of xxx_sys below, no locking, approximate) - nlookup: uint64 # number of pointer lookups - nmalloc: uint64 # number of mallocs - nfree: uint64 # number of frees - # Statistics about malloc heap. - # protected by mheap.Lock - heap_alloc: uint64 # bytes allocated and still in use - heap_sys: uint64 # bytes obtained from system - heap_idle: uint64 # bytes in idle spans - heap_inuse: uint64 # bytes in non-idle spans - heap_released: uint64 # bytes released to the OS - heap_objects: uint64 # total number of allocated objects - # Statistics about allocation of low-level fixed-size structures. - # Protected by FixAlloc locks. - stacks_inuse: uint64 # bootstrap stacks - stacks_sys: uint64 - mspan_inuse: uint64 # MSpan structures - mspan_sys: uint64 - mcache_inuse: uint64 # MCache structures - mcache_sys: uint64 - buckhash_sys: uint64 # profiling bucket hash table - gc_sys: uint64 - other_sys: uint64 - # Statistics about garbage collector. - # Protected by mheap or stopping the world during GC. - next_gc: uint64 # next GC (in heap_alloc time) - last_gc: uint64 # last GC (in absolute time) - pause_total_ns: uint64 - pause_ns: array[256, uint64] # circular buffer of recent gc pause lengths - pause_end: array[256, uint64] # circular buffer of recent gc end times (nanoseconds since 1970) - numgc: uint32 - numforcedgc: uint32 # number of user-forced GCs - gc_cpu_fraction: float64 # fraction of CPU time used by GC - enablegc: cbool - debuggc: cbool - # Statistics about allocation size classes. - by_size: array[goNumSizeClasses, goMStats_inner_struct] - # Statistics below here are not exported to MemStats directly. - tinyallocs: uint64 # number of tiny allocations that didn't cause actual allocation; not exported to go directly - gc_trigger: uint64 - heap_live: uint64 - heap_scan: uint64 - heap_marked: uint64 + # General statistics. + alloc: uint64 # bytes allocated and still in use + total_alloc: uint64 # bytes allocated (even if freed) + sys: uint64 # bytes obtained from system (should be sum of xxx_sys below, no locking, approximate) + nlookup: uint64 # number of pointer lookups + nmalloc: uint64 # number of mallocs + nfree: uint64 # number of frees + # Statistics about malloc heap. + # protected by mheap.Lock + heap_alloc: uint64 # bytes allocated and still in use + heap_sys: uint64 # bytes obtained from system + heap_idle: uint64 # bytes in idle spans + heap_inuse: uint64 # bytes in non-idle spans + heap_released: uint64 # bytes released to the OS + heap_objects: uint64 # total number of allocated objects + # Statistics about allocation of low-level fixed-size structures. + # Protected by FixAlloc locks. + stacks_inuse: uint64 # bootstrap stacks + stacks_sys: uint64 + mspan_inuse: uint64 # MSpan structures + mspan_sys: uint64 + mcache_inuse: uint64 # MCache structures + mcache_sys: uint64 + buckhash_sys: uint64 # profiling bucket hash table + gc_sys: uint64 + other_sys: uint64 + # Statistics about garbage collector. + # Protected by mheap or stopping the world during GC. + next_gc: uint64 # next GC (in heap_alloc time) + last_gc: uint64 # last GC (in absolute time) + pause_total_ns: uint64 + pause_ns: array[256, uint64] # circular buffer of recent gc pause lengths + pause_end: array[256, uint64] # circular buffer of recent gc end times (nanoseconds since 1970) + numgc: uint32 + numforcedgc: uint32 # number of user-forced GCs + gc_cpu_fraction: float64 # fraction of CPU time used by GC + enablegc: bool + debuggc: bool + # Statistics about allocation size classes. + by_size: array[goNumSizeClasses, goMStats_inner_struct] + # Statistics below here are not exported to MemStats directly. + tinyallocs: uint64 # number of tiny allocations that didn't cause actual allocation; not exported to go directly + gc_trigger: uint64 + heap_live: uint64 + heap_scan: uint64 + heap_marked: uint64 proc goRuntime_ReadMemStats(a2: ptr goMStats) {.cdecl, importc: "runtime_ReadMemStats", @@ -341,9 +338,12 @@ elif defined(gogc): proc getOccupiedSharedMem(): int = discard const goFlagNoZero: uint32 = 1 shl 3 - proc goRuntimeMallocGC(size: uint, typ: uint, flag: uint32): pointer {.importc: "runtime_mallocgc", dynlib: goLib.} + proc goRuntimeMallocGC(size: uint, typ: uint, flag: uint32): pointer {. + importc: "runtime_mallocgc", dynlib: goLib.} - proc goSetFinalizer(obj: pointer, f: pointer) {.importc: "set_finalizer", codegenDecl:"$1 $2$3 __asm__ (\"main.Set_finalizer\");\n$1 $2$3", dynlib: goLib.} + proc goSetFinalizer(obj: pointer, f: pointer) {. + importc: "set_finalizer", codegenDecl: "$1 $2$3 __asm__ (\"main.Set_finalizer\");\n$1 $2$3", + dynlib: goLib.} proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} = result = goRuntimeMallocGC(roundup(size, sizeof(pointer)).uint, 0.uint, 0.uint32) @@ -369,8 +369,7 @@ elif defined(gogc): proc growObj(old: pointer, newsize: int): pointer = # the Go GC doesn't have a realloc - var - oldsize = cast[PGenericSeq](old).len * cast[PGenericSeq](old).elemSize + GenericSeqSize + let oldsize = cast[PGenericSeq](old).len * cast[PGenericSeq](old).elemSize + GenericSeqSize result = goRuntimeMallocGC(roundup(newsize, sizeof(pointer)).uint, 0.uint, goFlagNoZero) copyMem(result, old, oldsize) zeroMem(cast[pointer](cast[ByteAddress](result) +% oldsize), newsize - oldsize) @@ -386,8 +385,7 @@ elif defined(gogc): dest[] = src type - MemRegion = object {.final, pure.} - {.deprecated: [TMemRegion: MemRegion].} + MemRegion = object proc alloc(r: var MemRegion, size: int): pointer = result = alloc(size) @@ -477,8 +475,7 @@ elif defined(nogc) and defined(useMalloc): dest[] = src type - MemRegion = object {.final, pure.} - {.deprecated: [TMemRegion: MemRegion].} + MemRegion = object proc alloc(r: var MemRegion, size: int): pointer = result = alloc(size) @@ -551,15 +548,13 @@ else: elif defined(gcRegions): # XXX due to bootstrapping reasons, we cannot use compileOption("gc", "stack") here include "system/gc_regions" - elif defined(gcMarkAndSweep): + elif defined(gcMarkAndSweep) or defined(gcDestructors): # XXX use 'compileOption' here include "system/gc_ms" - elif defined(gcGenerational): - include "system/gc" else: include "system/gc" -when not declared(nimNewSeqOfCap): +when not declared(nimNewSeqOfCap) and not defined(gcDestructors): proc nimNewSeqOfCap(typ: PNimType, cap: int): pointer {.compilerproc.} = when defined(gcRegions): let s = mulInt(cap, typ.base.size) # newStr already adds GenericSeqSize diff --git a/lib/system/nimscript.nim b/lib/system/nimscript.nim index 5bf69dd94..64d6255da 100644 --- a/lib/system/nimscript.nim +++ b/lib/system/nimscript.nim @@ -73,12 +73,12 @@ proc switch*(key: string, val="") = proc warning*(name: string; val: bool) = ## Disables or enables a specific warning. let v = if val: "on" else: "off" - warningImpl(name & "]:" & v, "warning[" & name & "]:" & v) + warningImpl(name & ":" & v, "warning:" & name & ":" & v) proc hint*(name: string; val: bool) = ## Disables or enables a specific hint. let v = if val: "on" else: "off" - hintImpl(name & "]:" & v, "hint[" & name & "]:" & v) + hintImpl(name & ":" & v, "hint:" & name & ":" & v) proc patchFile*(package, filename, replacement: string) = ## Overrides the location of a given file belonging to the @@ -305,7 +305,6 @@ template withDir*(dir: string; body: untyped): untyped = finally: cd(curDir) -template `==?`(a, b: string): bool = cmpIgnoreStyle(a, b) == 0 proc writeTask(name, desc: string) = if desc.len > 0: @@ -313,29 +312,30 @@ proc writeTask(name, desc: string) = for i in 0 ..< 20 - name.len: spaces.add ' ' echo name, spaces, desc -template task*(name: untyped; description: string; body: untyped): untyped = - ## Defines a task. Hidden tasks are supported via an empty description. - ## Example: - ## - ## .. code-block:: nim - ## task build, "default build is via the C backend": - ## setCommand "c" - proc `name Task`*() = body - - let cmd = getCommand() - if cmd.len == 0 or cmd ==? "help": - setCommand "help" - writeTask(astToStr(name), description) - elif cmd ==? astToStr(name): - setCommand "nop" - `name Task`() - proc cppDefine*(define: string) = ## tell Nim that ``define`` is a C preprocessor ``#define`` and so always ## needs to be mangled. builtin when not defined(nimble): + template `==?`(a, b: string): bool = cmpIgnoreStyle(a, b) == 0 + template task*(name: untyped; description: string; body: untyped): untyped = + ## Defines a task. Hidden tasks are supported via an empty description. + ## Example: + ## + ## .. code-block:: nim + ## task build, "default build is via the C backend": + ## setCommand "c" + proc `name Task`*() = body + + let cmd = getCommand() + if cmd.len == 0 or cmd ==? "help": + setCommand "help" + writeTask(astToStr(name), description) + elif cmd ==? astToStr(name): + setCommand "nop" + `name Task`() + # nimble has its own implementation for these things. var packageName* = "" ## Nimble support: Set this to the package name. It diff --git a/lib/system/repr.nim b/lib/system/repr.nim index 982b07467..85701c28f 100644 --- a/lib/system/repr.nim +++ b/lib/system/repr.nim @@ -25,29 +25,13 @@ proc reprPointer(x: pointer): string {.compilerproc.} = discard c_sprintf(buf, "%p", x) return $buf -proc `$`(x: uint64): string = - if x == 0: - result = "0" - else: - result = newString(60) - var i = 0 - var n = x - while n != 0: - let nn = n div 10'u64 - result[i] = char(n - 10'u64 * nn + ord('0')) - inc i - n = nn - result.setLen i - - let half = i div 2 - # Reverse - for t in 0 .. half-1: swap(result[t], result[i-t-1]) - proc reprStrAux(result: var string, s: cstring; len: int) = if cast[pointer](s) == nil: add result, "nil" return - add result, reprPointer(cast[pointer](s)) & "\"" + if len > 0: + add result, reprPointer(cast[pointer](s)) + add result, "\"" for i in 0 .. pred(len): let c = s[i] case c @@ -180,9 +164,10 @@ when not defined(useNimRtl): proc reprSequence(result: var string, p: pointer, typ: PNimType, cl: var ReprClosure) = if p == nil: - add result, "nil" + add result, "[]" return - result.add(reprPointer(p) & "[") + result.add(reprPointer(p)) + result.add '[' var bs = typ.base.size for i in 0..cast[PGenericSeq](p).len-1: if i > 0: add result, ", " @@ -284,7 +269,7 @@ when not defined(useNimRtl): of tyChar: add result, reprChar(cast[ptr char](p)[]) of tyString: let sp = cast[ptr string](p) - reprStrAux(result, if sp[].isNil: nil else: sp[].cstring, sp[].len) + reprStrAux(result, sp[].cstring, sp[].len) of tyCString: let cs = cast[ptr cstring](p)[] if cs.isNil: add result, "nil" diff --git a/lib/system/reprjs.nim b/lib/system/reprjs.nim index d04d6e12b..7cb25a252 100644 --- a/lib/system/reprjs.nim +++ b/lib/system/reprjs.nim @@ -232,10 +232,7 @@ proc reprAux(result: var string, p: pointer, typ: PNimType, of tyString: var fp: int {. emit: "`fp` = `p`;\n" .} - if cast[string](fp).isNil: - add(result, "nil") - else: - add( result, reprStr(cast[string](p)) ) + add( result, reprStr(cast[string](p)) ) of tyCString: var fp: cstring {. emit: "`fp` = `p`;\n" .} diff --git a/lib/system/strmantle.nim b/lib/system/strmantle.nim new file mode 100644 index 000000000..ceaecb4f9 --- /dev/null +++ b/lib/system/strmantle.nim @@ -0,0 +1,298 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2018 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Compilerprocs for strings that do not depend on the string implementation. + +proc cmpStrings(a, b: string): int {.inline, compilerProc.} = + let alen = a.len + let blen = b.len + let minlen = min(alen, blen) + if minlen > 0: + result = c_memcmp(unsafeAddr a[0], unsafeAddr b[0], minlen.csize) + if result == 0: + result = alen - blen + else: + result = alen - blen + +proc eqStrings(a, b: string): bool {.inline, compilerProc.} = + let alen = a.len + let blen = b.len + if alen == blen: + if alen == 0: return true + return equalMem(unsafeAddr(a[0]), unsafeAddr(b[0]), alen) + +proc hashString(s: string): int {.compilerproc.} = + # the compiler needs exactly the same hash function! + # this used to be used for efficient generation of string case statements + var h = 0 + for i in 0..len(s)-1: + h = h +% ord(s[i]) + h = h +% h shl 10 + h = h xor (h shr 6) + h = h +% h shl 3 + h = h xor (h shr 11) + h = h +% h shl 15 + result = h + +proc add*(result: var string; x: int64) = + let base = result.len + setLen(result, base + sizeof(x)*4) + var i = 0 + var y = x + while true: + var d = y div 10 + result[base+i] = chr(abs(int(y - d*10)) + ord('0')) + inc(i) + y = d + if y == 0: break + if x < 0: + result[base+i] = '-' + inc(i) + setLen(result, base+i) + # mirror the string: + for j in 0..i div 2 - 1: + swap(result[base+j], result[base+i-j-1]) + +proc nimIntToStr(x: int): string {.compilerRtl.} = + result = newStringOfCap(sizeof(x)*4) + result.add x + +proc add*(result: var string; x: float) = + when nimvm: + result.add $x + else: + var buf: array[0..64, char] + when defined(nimNoArrayToCstringConversion): + var n: int = c_sprintf(addr buf, "%.16g", x) + else: + var n: int = c_sprintf(buf, "%.16g", x) + var hasDot = false + for i in 0..n-1: + if buf[i] == ',': + buf[i] = '.' + hasDot = true + elif buf[i] in {'a'..'z', 'A'..'Z', '.'}: + hasDot = true + if not hasDot: + buf[n] = '.' + buf[n+1] = '0' + buf[n+2] = '\0' + # On Windows nice numbers like '1.#INF', '-1.#INF' or '1.#NAN' + # of '-1.#IND' are produced. + # We want to get rid of these here: + if buf[n-1] in {'n', 'N', 'D', 'd'}: + result.add "nan" + elif buf[n-1] == 'F': + if buf[0] == '-': + result.add "-inf" + else: + result.add "inf" + else: + var i = 0 + while buf[i] != '\0': + result.add buf[i] + inc i + +proc nimFloatToStr(f: float): string {.compilerproc.} = + result = newStringOfCap(8) + result.add f + +proc c_strtod(buf: cstring, endptr: ptr cstring): float64 {. + importc: "strtod", header: "<stdlib.h>", noSideEffect.} + +const + IdentChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'} + powtens = [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, + 1e20, 1e21, 1e22] + +proc nimParseBiggestFloat(s: string, number: var BiggestFloat, + start = 0): int {.compilerProc.} = + # This routine attempt to parse float that can parsed quickly. + # ie whose integer part can fit inside a 53bits integer. + # their real exponent must also be <= 22. If the float doesn't follow + # these restrictions, transform the float into this form: + # INTEGER * 10 ^ exponent and leave the work to standard `strtod()`. + # This avoid the problems of decimal character portability. + # see: http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ + var + i = start + sign = 1.0 + kdigits, fdigits = 0 + exponent: int + integer: uint64 + frac_exponent = 0 + exp_sign = 1 + first_digit = -1 + has_sign = false + + # Sign? + if s[i] == '+' or s[i] == '-': + has_sign = true + if s[i] == '-': + sign = -1.0 + inc(i) + + # NaN? + if s[i] == 'N' or s[i] == 'n': + if s[i+1] == 'A' or s[i+1] == 'a': + if s[i+2] == 'N' or s[i+2] == 'n': + if s[i+3] notin IdentChars: + number = NaN + return i+3 - start + return 0 + + # Inf? + if s[i] == 'I' or s[i] == 'i': + if s[i+1] == 'N' or s[i+1] == 'n': + if s[i+2] == 'F' or s[i+2] == 'f': + if s[i+3] notin IdentChars: + number = Inf*sign + return i+3 - start + return 0 + + if s[i] in {'0'..'9'}: + first_digit = (s[i].ord - '0'.ord) + # Integer part? + while s[i] in {'0'..'9'}: + inc(kdigits) + integer = integer * 10'u64 + (s[i].ord - '0'.ord).uint64 + inc(i) + while s[i] == '_': inc(i) + + # Fractional part? + if s[i] == '.': + inc(i) + # if no integer part, Skip leading zeros + if kdigits <= 0: + while s[i] == '0': + inc(frac_exponent) + inc(i) + while s[i] == '_': inc(i) + + if first_digit == -1 and s[i] in {'0'..'9'}: + first_digit = (s[i].ord - '0'.ord) + # get fractional part + while s[i] in {'0'..'9'}: + inc(fdigits) + inc(frac_exponent) + integer = integer * 10'u64 + (s[i].ord - '0'.ord).uint64 + inc(i) + while s[i] == '_': inc(i) + + # if has no digits: return error + if kdigits + fdigits <= 0 and + (i == start or # no char consumed (empty string). + (i == start + 1 and has_sign)): # or only '+' or '- + return 0 + + if s[i] in {'e', 'E'}: + inc(i) + if s[i] == '+' or s[i] == '-': + if s[i] == '-': + exp_sign = -1 + + inc(i) + if s[i] notin {'0'..'9'}: + return 0 + while s[i] in {'0'..'9'}: + exponent = exponent * 10 + (ord(s[i]) - ord('0')) + inc(i) + while s[i] == '_': inc(i) # underscores are allowed and ignored + + var real_exponent = exp_sign*exponent - frac_exponent + let exp_negative = real_exponent < 0 + var abs_exponent = abs(real_exponent) + + # if exponent greater than can be represented: +/- zero or infinity + if abs_exponent > 999: + if exp_negative: + number = 0.0*sign + else: + number = Inf*sign + return i - start + + # if integer is representable in 53 bits: fast path + # max fast path integer is 1<<53 - 1 or 8999999999999999 (16 digits) + let digits = kdigits + fdigits + if digits <= 15 or (digits <= 16 and first_digit <= 8): + # max float power of ten with set bits above the 53th bit is 10^22 + if abs_exponent <= 22: + if exp_negative: + number = sign * integer.float / powtens[abs_exponent] + else: + number = sign * integer.float * powtens[abs_exponent] + return i - start + + # if exponent is greater try to fit extra exponent above 22 by multiplying + # integer part is there is space left. + let slop = 15 - kdigits - fdigits + if abs_exponent <= 22 + slop and not exp_negative: + number = sign * integer.float * powtens[slop] * powtens[abs_exponent-slop] + return i - start + + # if failed: slow path with strtod. + var t: array[500, char] # flaviu says: 325 is the longest reasonable literal + var ti = 0 + let maxlen = t.high - "e+000".len # reserve enough space for exponent + + result = i - start + i = start + # re-parse without error checking, any error should be handled by the code above. + if s[i] == '.': i.inc + while s[i] in {'0'..'9','+','-'}: + if ti < maxlen: + t[ti] = s[i]; inc(ti) + inc(i) + while s[i] in {'.', '_'}: # skip underscore and decimal point + inc(i) + + # insert exponent + t[ti] = 'E'; inc(ti) + t[ti] = (if exp_negative: '-' else: '+'); inc(ti) + inc(ti, 3) + + # insert adjusted exponent + t[ti-1] = ('0'.ord + abs_exponent mod 10).char; abs_exponent = abs_exponent div 10 + t[ti-2] = ('0'.ord + abs_exponent mod 10).char; abs_exponent = abs_exponent div 10 + t[ti-3] = ('0'.ord + abs_exponent mod 10).char + + when defined(nimNoArrayToCstringConversion): + number = c_strtod(addr t, nil) + else: + number = c_strtod(t, nil) + +proc nimInt64ToStr(x: int64): string {.compilerRtl.} = + result = newStringOfCap(sizeof(x)*4) + result.add x + +proc nimBoolToStr(x: bool): string {.compilerRtl.} = + return if x: "true" else: "false" + +proc nimCharToStr(x: char): string {.compilerRtl.} = + result = newString(1) + result[0] = x + +proc `$`(x: uint64): string = + if x == 0: + result = "0" + else: + result = newString(60) + var i = 0 + var n = x + while n != 0: + let nn = n div 10'u64 + result[i] = char(n - 10'u64 * nn + ord('0')) + inc i + n = nn + result.setLen i + + let half = i div 2 + # Reverse + for t in 0 .. half-1: swap(result[t], result[i-t-1]) diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim index 7a10849dd..df13ab628 100644 --- a/lib/system/sysio.nim +++ b/lib/system/sysio.nim @@ -143,19 +143,17 @@ proc getFileHandle*(f: File): FileHandle = c_fileno(f) proc readLine(f: File, line: var TaintedString): bool = var pos = 0 - var sp: cint = 80 + # Use the currently reserved space for a first try - if line.string.isNil: - line = TaintedString(newStringOfCap(80)) - else: - when not defined(nimscript): - sp = cint(cast[PGenericSeq](line.string).space) + var sp = line.string.len + if sp == 0: + sp = 80 line.string.setLen(sp) while true: # memset to \L so that we can tell how far fgets wrote, even on EOF, where # fgets doesn't append an \L nimSetMem(addr line.string[pos], '\L'.ord, sp) - var fgetsSuccess = c_fgets(addr line.string[pos], sp, f) != nil + var fgetsSuccess = c_fgets(addr line.string[pos], sp.cint, f) != nil if not fgetsSuccess: checkErr(f) let m = c_memchr(addr line.string[pos], '\L'.ord, sp) if m != nil: @@ -163,7 +161,7 @@ proc readLine(f: File, line: var TaintedString): bool = var last = cast[ByteAddress](m) - cast[ByteAddress](addr line.string[0]) if last > 0 and line.string[last-1] == '\c': line.string.setLen(last-1) - return fgetsSuccess + return last > 1 or fgetsSuccess # We have to distinguish between two possible cases: # \0\l\0 => line ending in a null character. # \0\l\l => last line without newline, null was put there by fgets. @@ -171,7 +169,7 @@ proc readLine(f: File, line: var TaintedString): bool = if last < pos + sp - 1 and line.string[last+1] != '\0': dec last line.string.setLen(last) - return fgetsSuccess + return last > 0 or fgetsSuccess else: # fgets will have inserted a null byte at the end of the string. dec sp diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index 0e690d832..6438a0541 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -20,37 +20,6 @@ proc resize(old: int): int {.inline.} = elif old < 65536: result = old * 2 else: result = old * 3 div 2 # for large arrays * 3/2 is better -proc cmpStrings(a, b: NimString): int {.inline, compilerProc.} = - if a == b: return 0 - when defined(nimNoNil): - let alen = if a == nil: 0 else: a.len - let blen = if b == nil: 0 else: b.len - else: - if a == nil: return -1 - if b == nil: return 1 - let alen = a.len - let blen = b.len - let minlen = min(alen, blen) - if minlen > 0: - result = nimCmpMem(addr a.data, addr b.data, minlen.csize) - if result == 0: - result = alen - blen - else: - result = alen - blen - -proc eqStrings(a, b: NimString): bool {.inline, compilerProc.} = - if a == b: return true - when defined(nimNoNil): - let alen = if a == nil: 0 else: a.len - let blen = if b == nil: 0 else: b.len - else: - if a == nil or b == nil: return false - let alen = a.len - let blen = b.len - if alen == blen: - if alen == 0: return true - return equalMem(addr(a.data), addr(b.data), alen) - when declared(allocAtomic): template allocStr(size: untyped): untyped = cast[NimString](allocAtomic(size)) @@ -94,6 +63,8 @@ proc mnewString(len: int): NimString {.compilerProc.} = result.len = len proc copyStrLast(s: NimString, start, last: int): NimString {.compilerProc.} = + # This is not used by most recent versions of the compiler anymore, but + # required for bootstrapping purposes. let start = max(start, 0) if s == nil: return nil let len = min(last, s.len-1) - start + 1 @@ -105,14 +76,16 @@ proc copyStrLast(s: NimString, start, last: int): NimString {.compilerProc.} = else: result = rawNewString(len) -proc nimToCStringConv(s: NimString): cstring {.compilerProc, inline.} = - if s == nil or s.len == 0: result = cstring"" - else: result = cstring(addr s.data) - proc copyStr(s: NimString, start: int): NimString {.compilerProc.} = + # This is not used by most recent versions of the compiler anymore, but + # required for bootstrapping purposes. if s == nil: return nil result = copyStrLast(s, start, s.len-1) +proc nimToCStringConv(s: NimString): cstring {.compilerProc, inline.} = + if s == nil or s.len == 0: result = cstring"" + else: result = cstring(addr s.data) + proc toNimStr(str: cstring, len: int): NimString {.compilerProc.} = result = rawNewStringNoInit(len) result.len = len @@ -164,19 +137,6 @@ proc copyDeepString(src: NimString): NimString {.inline.} = result.len = src.len copyMem(addr(result.data), addr(src.data), src.len + 1) -proc hashString(s: string): int {.compilerproc.} = - # the compiler needs exactly the same hash function! - # this used to be used for efficient generation of string case statements - var h = 0 - for i in 0..len(s)-1: - h = h +% ord(s[i]) - h = h +% h shl 10 - h = h xor (h shr 6) - h = h +% h shl 3 - h = h xor (h shr 11) - h = h +% h shl 15 - result = h - proc addChar(s: NimString, c: char): NimString = # is compilerproc! if s == nil: @@ -403,243 +363,3 @@ proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {. result.len = newLen else: result = setLengthSeq(s, typ.base.size, newLen) - -# --------------- other string routines ---------------------------------- -proc add*(result: var string; x: int64) = - let base = result.len - setLen(result, base + sizeof(x)*4) - var i = 0 - var y = x - while true: - var d = y div 10 - result[base+i] = chr(abs(int(y - d*10)) + ord('0')) - inc(i) - y = d - if y == 0: break - if x < 0: - result[base+i] = '-' - inc(i) - setLen(result, base+i) - # mirror the string: - for j in 0..i div 2 - 1: - swap(result[base+j], result[base+i-j-1]) - -proc nimIntToStr(x: int): string {.compilerRtl.} = - result = newStringOfCap(sizeof(x)*4) - result.add x - -proc add*(result: var string; x: float) = - when nimvm: - result.add $x - else: - var buf: array[0..64, char] - when defined(nimNoArrayToCstringConversion): - var n: int = c_sprintf(addr buf, "%.16g", x) - else: - var n: int = c_sprintf(buf, "%.16g", x) - var hasDot = false - for i in 0..n-1: - if buf[i] == ',': - buf[i] = '.' - hasDot = true - elif buf[i] in {'a'..'z', 'A'..'Z', '.'}: - hasDot = true - if not hasDot: - buf[n] = '.' - buf[n+1] = '0' - buf[n+2] = '\0' - # On Windows nice numbers like '1.#INF', '-1.#INF' or '1.#NAN' - # of '-1.#IND' are produced. - # We want to get rid of these here: - if buf[n-1] in {'n', 'N', 'D', 'd'}: - result.add "nan" - elif buf[n-1] == 'F': - if buf[0] == '-': - result.add "-inf" - else: - result.add "inf" - else: - var i = 0 - while buf[i] != '\0': - result.add buf[i] - inc i - -proc nimFloatToStr(f: float): string {.compilerproc.} = - result = newStringOfCap(8) - result.add f - -proc c_strtod(buf: cstring, endptr: ptr cstring): float64 {. - importc: "strtod", header: "<stdlib.h>", noSideEffect.} - -const - IdentChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'} - powtens = [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, - 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, - 1e20, 1e21, 1e22] - -proc nimParseBiggestFloat(s: string, number: var BiggestFloat, - start = 0): int {.compilerProc.} = - # This routine attempt to parse float that can parsed quickly. - # ie whose integer part can fit inside a 53bits integer. - # their real exponent must also be <= 22. If the float doesn't follow - # these restrictions, transform the float into this form: - # INTEGER * 10 ^ exponent and leave the work to standard `strtod()`. - # This avoid the problems of decimal character portability. - # see: http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ - var - i = start - sign = 1.0 - kdigits, fdigits = 0 - exponent: int - integer: uint64 - frac_exponent = 0 - exp_sign = 1 - first_digit = -1 - has_sign = false - - # Sign? - if s[i] == '+' or s[i] == '-': - has_sign = true - if s[i] == '-': - sign = -1.0 - inc(i) - - # NaN? - if s[i] == 'N' or s[i] == 'n': - if s[i+1] == 'A' or s[i+1] == 'a': - if s[i+2] == 'N' or s[i+2] == 'n': - if s[i+3] notin IdentChars: - number = NaN - return i+3 - start - return 0 - - # Inf? - if s[i] == 'I' or s[i] == 'i': - if s[i+1] == 'N' or s[i+1] == 'n': - if s[i+2] == 'F' or s[i+2] == 'f': - if s[i+3] notin IdentChars: - number = Inf*sign - return i+3 - start - return 0 - - if s[i] in {'0'..'9'}: - first_digit = (s[i].ord - '0'.ord) - # Integer part? - while s[i] in {'0'..'9'}: - inc(kdigits) - integer = integer * 10'u64 + (s[i].ord - '0'.ord).uint64 - inc(i) - while s[i] == '_': inc(i) - - # Fractional part? - if s[i] == '.': - inc(i) - # if no integer part, Skip leading zeros - if kdigits <= 0: - while s[i] == '0': - inc(frac_exponent) - inc(i) - while s[i] == '_': inc(i) - - if first_digit == -1 and s[i] in {'0'..'9'}: - first_digit = (s[i].ord - '0'.ord) - # get fractional part - while s[i] in {'0'..'9'}: - inc(fdigits) - inc(frac_exponent) - integer = integer * 10'u64 + (s[i].ord - '0'.ord).uint64 - inc(i) - while s[i] == '_': inc(i) - - # if has no digits: return error - if kdigits + fdigits <= 0 and - (i == start or # no char consumed (empty string). - (i == start + 1 and has_sign)): # or only '+' or '- - return 0 - - if s[i] in {'e', 'E'}: - inc(i) - if s[i] == '+' or s[i] == '-': - if s[i] == '-': - exp_sign = -1 - - inc(i) - if s[i] notin {'0'..'9'}: - return 0 - while s[i] in {'0'..'9'}: - exponent = exponent * 10 + (ord(s[i]) - ord('0')) - inc(i) - while s[i] == '_': inc(i) # underscores are allowed and ignored - - var real_exponent = exp_sign*exponent - frac_exponent - let exp_negative = real_exponent < 0 - var abs_exponent = abs(real_exponent) - - # if exponent greater than can be represented: +/- zero or infinity - if abs_exponent > 999: - if exp_negative: - number = 0.0*sign - else: - number = Inf*sign - return i - start - - # if integer is representable in 53 bits: fast path - # max fast path integer is 1<<53 - 1 or 8999999999999999 (16 digits) - let digits = kdigits + fdigits - if digits <= 15 or (digits <= 16 and first_digit <= 8): - # max float power of ten with set bits above the 53th bit is 10^22 - if abs_exponent <= 22: - if exp_negative: - number = sign * integer.float / powtens[abs_exponent] - else: - number = sign * integer.float * powtens[abs_exponent] - return i - start - - # if exponent is greater try to fit extra exponent above 22 by multiplying - # integer part is there is space left. - let slop = 15 - kdigits - fdigits - if abs_exponent <= 22 + slop and not exp_negative: - number = sign * integer.float * powtens[slop] * powtens[abs_exponent-slop] - return i - start - - # if failed: slow path with strtod. - var t: array[500, char] # flaviu says: 325 is the longest reasonable literal - var ti = 0 - let maxlen = t.high - "e+000".len # reserve enough space for exponent - - result = i - start - i = start - # re-parse without error checking, any error should be handled by the code above. - if s[i] == '.': i.inc - while s[i] in {'0'..'9','+','-'}: - if ti < maxlen: - t[ti] = s[i]; inc(ti) - inc(i) - while s[i] in {'.', '_'}: # skip underscore and decimal point - inc(i) - - # insert exponent - t[ti] = 'E'; inc(ti) - t[ti] = (if exp_negative: '-' else: '+'); inc(ti) - inc(ti, 3) - - # insert adjusted exponent - t[ti-1] = ('0'.ord + abs_exponent mod 10).char; abs_exponent = abs_exponent div 10 - t[ti-2] = ('0'.ord + abs_exponent mod 10).char; abs_exponent = abs_exponent div 10 - t[ti-3] = ('0'.ord + abs_exponent mod 10).char - - when defined(nimNoArrayToCstringConversion): - number = c_strtod(addr t, nil) - else: - number = c_strtod(t, nil) - -proc nimInt64ToStr(x: int64): string {.compilerRtl.} = - result = newStringOfCap(sizeof(x)*4) - result.add x - -proc nimBoolToStr(x: bool): string {.compilerRtl.} = - return if x: "true" else: "false" - -proc nimCharToStr(x: char): string {.compilerRtl.} = - result = newString(1) - result[0] = x diff --git a/lib/system/threads.nim b/lib/system/threads.nim index 2434ea21e..aaf0164fd 100644 --- a/lib/system/threads.nim +++ b/lib/system/threads.nim @@ -393,8 +393,9 @@ proc onThreadDestruction*(handler: proc () {.closure, gcsafe.}) = ## A thread is destructed when the ``.thread`` proc returns ## normally or when it raises an exception. Note that unhandled exceptions ## in a thread nevertheless cause the whole process to die. - if threadDestructionHandlers.isNil: - threadDestructionHandlers = @[] + when not defined(nimNoNilSeqs): + if threadDestructionHandlers.isNil: + threadDestructionHandlers = @[] threadDestructionHandlers.add handler template afterThreadRuns() = diff --git a/lib/system/widestrs.nim b/lib/system/widestrs.nim index a8b28c279..85e5e1462 100644 --- a/lib/system/widestrs.nim +++ b/lib/system/widestrs.nim @@ -10,13 +10,12 @@ # Nim support for C/C++'s `wide strings`:idx:. This is part of the system # module! Do not import it directly! -when not declared(NimString): +when not declared(ThisIsSystem): {.error: "You must not import this module explicitly".} type Utf16Char* = distinct int16 WideCString* = ref UncheckedArray[Utf16Char] -{.deprecated: [TUtf16Char: Utf16Char].} proc len*(w: WideCString): int = ## returns the length of a widestring. This traverses the whole string to |