diff options
-rw-r--r-- | changelog.md | 13 | ||||
-rw-r--r-- | compiler/ccgexprs.nim | 6 | ||||
-rw-r--r-- | compiler/idents.nim | 37 | ||||
-rw-r--r-- | compiler/modulegraphs.nim | 54 | ||||
-rw-r--r-- | compiler/options.nim | 28 | ||||
-rw-r--r-- | compiler/pragmas.nim | 2 | ||||
-rw-r--r-- | compiler/semtypes.nim | 2 | ||||
-rw-r--r-- | compiler/vmdef.nim | 2 | ||||
-rw-r--r-- | doc/exception_hierarchy_fragment.txt | 28 | ||||
-rw-r--r-- | doc/manual.rst | 77 | ||||
-rw-r--r-- | lib/packages/docutils/rstgen.nim | 7 | ||||
-rw-r--r-- | lib/pure/asyncnet.nim | 2 | ||||
-rw-r--r-- | lib/pure/concurrency/threadpool.nim | 6 | ||||
-rw-r--r-- | lib/pure/smtp.nim | 6 | ||||
-rw-r--r-- | lib/pure/strutils.nim | 15 | ||||
-rw-r--r-- | lib/system.nim | 112 | ||||
-rw-r--r-- | lib/system/sysstr.nim | 2 | ||||
-rw-r--r-- | nimsuggest/tester.nim | 12 | ||||
-rw-r--r-- | nimsuggest/tests/tdot4.nim | 2 | ||||
-rw-r--r-- | nimsuggest/tests/tinclude.nim | 8 | ||||
-rw-r--r-- | tests/generics/tobjecttyperel.nim | 12 | ||||
-rw-r--r-- | tests/parallel/tptr_to_ref.nim | 4 | ||||
-rw-r--r-- | tests/system/tnilconcats.nim | 2 |
23 files changed, 159 insertions, 280 deletions
diff --git a/changelog.md b/changelog.md index 9ab7a0b72..5a28fc7ff 100644 --- a/changelog.md +++ b/changelog.md @@ -170,6 +170,17 @@ - Nim now supports ``except`` clause in the export statement. - Range float types, example ``range[0.0 .. Inf]``. More details in language manual. +- The ``{.this.}`` pragma has been deprecated. It never worked within generics and + we found the resulting code harder to read than the more explicit ``obj.field`` + syntax. +- "Memory regions" for pointer types have been deprecated, they were hardly used + anywhere. Note that this has **nothing** to do with the ``--gc:regions`` switch + of managing memory. + +- The exception hierarchy was slightly reworked, ``SystemError`` was renamed to + ``Error`` and is the new base class for any exception that is guaranteed to + be catchable. This change should have minimal impact on most existing Nim code. + ### Tool changes @@ -178,7 +189,7 @@ ### Compiler changes -- The VM's instruction count limit was raised to 1 billion instructions in +- The VM's instruction count limit was raised to 3 million instructions in order to support more complex computations at compile-time. - Support for hot code reloading has been implemented for the JavaScript diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 6803a9478..e8bb70f13 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -65,9 +65,9 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope = of tyString: # with the new semantics for 'nil' strings, we can map "" to nil and # save tons of allocations: - #if n.strVal.len == 0: result = genNilStringLiteral(p.module, n.info) - #else: - result = genStringLiteral(p.module, n) + if n.strVal.len == 0: result = genNilStringLiteral(p.module, n.info) + else: + result = genStringLiteral(p.module, n) else: if n.strVal.isNil: result = rope("NIM_NIL") else: result = makeCString(n.strVal) diff --git a/compiler/idents.nim b/compiler/idents.nim index 0a2f2d5cf..58800b73d 100644 --- a/compiler/idents.nim +++ b/compiler/idents.nim @@ -30,14 +30,7 @@ type wordCounter: int idAnon*, idDelegator*, emptyIdent*: PIdent -when false: - var - legacy: IdentCache - -proc resetIdentCache*() = - when false: - for i in low(legacy.buckets)..high(legacy.buckets): - legacy.buckets[i] = nil +proc resetIdentCache*() = discard proc cmpIgnoreStyle*(a, b: cstring, blen: int): int = if a[0] != b[0]: return 1 @@ -73,11 +66,9 @@ proc cmpExact(a, b: cstring, blen: int): int = if result == 0: if a[i] != '\0': result = 1 -{.this: self.} - -proc getIdent*(self: IdentCache; identifier: cstring, length: int, h: Hash): PIdent = - var idx = h and high(buckets) - result = buckets[idx] +proc getIdent*(ic: IdentCache; identifier: cstring, length: int, h: Hash): PIdent = + var idx = h and high(ic.buckets) + result = ic.buckets[idx] var last: PIdent = nil var id = 0 while result != nil: @@ -85,8 +76,8 @@ proc getIdent*(self: IdentCache; identifier: cstring, length: int, h: Hash): PId if last != nil: # make access to last looked up identifier faster: last.next = result.next - result.next = buckets[idx] - buckets[idx] = result + result.next = ic.buckets[idx] + ic.buckets[idx] = result return elif cmpIgnoreStyle(cstring(result.s), identifier, length) == 0: assert((id == 0) or (id == result.id)) @@ -97,20 +88,20 @@ proc getIdent*(self: IdentCache; identifier: cstring, length: int, h: Hash): PId result.h = h result.s = newString(length) for i in countup(0, length - 1): result.s[i] = identifier[i] - result.next = buckets[idx] - buckets[idx] = result + result.next = ic.buckets[idx] + ic.buckets[idx] = result if id == 0: - inc(wordCounter) - result.id = -wordCounter + inc(ic.wordCounter) + result.id = -ic.wordCounter else: result.id = id -proc getIdent*(self: IdentCache; identifier: string): PIdent = - result = getIdent(cstring(identifier), len(identifier), +proc getIdent*(ic: IdentCache; identifier: string): PIdent = + result = getIdent(ic, cstring(identifier), len(identifier), hashIgnoreStyle(identifier)) -proc getIdent*(self: IdentCache; identifier: string, h: Hash): PIdent = - result = getIdent(cstring(identifier), len(identifier), h) +proc getIdent*(ic: IdentCache; identifier: string, h: Hash): PIdent = + result = getIdent(ic, cstring(identifier), len(identifier), h) proc newIdentCache*(): IdentCache = result = IdentCache() diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 334cd1ae6..1eecc4176 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -65,10 +65,8 @@ type proc hash*(x: FileIndex): Hash {.borrow.} -{.this: g.} - proc stopCompile*(g: ModuleGraph): bool {.inline.} = - result = doStopCompile != nil and doStopCompile() + result = g.doStopCompile != nil and g.doStopCompile() proc createMagic*(g: ModuleGraph; name: string, m: TMagic): PSym = result = newSym(skProc, getIdent(g.cache, name), nil, unknownLineInfo(), {}) @@ -98,44 +96,44 @@ proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph = result.cacheTables = initTable[string, BTree[string, PNode]]() proc resetAllModules*(g: ModuleGraph) = - initStrTable(packageSyms) - deps = initIntSet() - modules = @[] - importStack = @[] - inclToMod = initTable[FileIndex, FileIndex]() - usageSym = nil - owners = @[] - methods = @[] - initStrTable(compilerprocs) - initStrTable(exposed) + initStrTable(g.packageSyms) + g.deps = initIntSet() + g.modules = @[] + g.importStack = @[] + g.inclToMod = initTable[FileIndex, FileIndex]() + g.usageSym = nil + g.owners = @[] + g.methods = @[] + initStrTable(g.compilerprocs) + initStrTable(g.exposed) proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym = - if fileIdx.int32 >= 0 and fileIdx.int32 < modules.len: - result = modules[fileIdx.int32] + if fileIdx.int32 >= 0 and fileIdx.int32 < g.modules.len: + result = g.modules[fileIdx.int32] proc dependsOn(a, b: int): int {.inline.} = (a shl 15) + b proc addDep*(g: ModuleGraph; m: PSym, dep: FileIndex) = assert m.position == m.info.fileIndex.int32 addModuleDep(g.incr, g.config, m.info.fileIndex, dep, isIncludeFile = false) - if suggestMode: - deps.incl m.position.dependsOn(dep.int) + if g.suggestMode: + g.deps.incl m.position.dependsOn(dep.int) # we compute the transitive closure later when quering the graph lazily. # this improves efficiency quite a lot: #invalidTransitiveClosure = true proc addIncludeDep*(g: ModuleGraph; module, includeFile: FileIndex) = addModuleDep(g.incr, g.config, module, includeFile, isIncludeFile = true) - discard hasKeyOrPut(inclToMod, includeFile, module) + discard hasKeyOrPut(g.inclToMod, includeFile, module) proc parentModule*(g: ModuleGraph; fileIdx: FileIndex): FileIndex = ## returns 'fileIdx' if the file belonging to this index is ## directly used as a module or else the module that first ## references this include file. - if fileIdx.int32 >= 0 and fileIdx.int32 < modules.len and modules[fileIdx.int32] != nil: + if fileIdx.int32 >= 0 and fileIdx.int32 < g.modules.len and g.modules[fileIdx.int32] != nil: result = fileIdx else: - result = inclToMod.getOrDefault(fileIdx) + result = g.inclToMod.getOrDefault(fileIdx) proc transitiveClosure(g: var IntSet; n: int) = # warshall's algorithm @@ -147,22 +145,22 @@ proc transitiveClosure(g: var IntSet; n: int) = g.incl i.dependsOn(j) proc markDirty*(g: ModuleGraph; fileIdx: FileIndex) = - let m = getModule fileIdx + let m = g.getModule fileIdx if m != nil: incl m.flags, sfDirty proc markClientsDirty*(g: ModuleGraph; fileIdx: FileIndex) = # we need to mark its dependent modules D as dirty right away because after # nimsuggest is done with this module, the module's dirty flag will be # cleared but D still needs to be remembered as 'dirty'. - if invalidTransitiveClosure: - invalidTransitiveClosure = false - transitiveClosure(deps, modules.len) + if g.invalidTransitiveClosure: + g.invalidTransitiveClosure = false + transitiveClosure(g.deps, g.modules.len) # every module that *depends* on this file is also dirty: - for i in 0i32..<modules.len.int32: - let m = modules[i] - if m != nil and deps.contains(i.dependsOn(fileIdx.int)): + for i in 0i32..<g.modules.len.int32: + let m = g.modules[i] + if m != nil and g.deps.contains(i.dependsOn(fileIdx.int)): incl m.flags, sfDirty proc isDirty*(g: ModuleGraph; m: PSym): bool = - result = suggestMode and sfDirty in m.flags + result = g.suggestMode and sfDirty in m.flags diff --git a/compiler/options.nim b/compiler/options.nim index 44519ea22..ef2b6023a 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -600,18 +600,22 @@ proc findModule*(conf: ConfigRef; modulename, currentModule: string): string = proc findProjectNimFile*(conf: ConfigRef; pkg: string): string = const extensions = [".nims", ".cfg", ".nimcfg", ".nimble"] var candidates: seq[string] = @[] - for k, f in os.walkDir(pkg, relative=true): - if k == pcFile and f != "config.nims": - let (_, name, ext) = splitFile(f) - if ext in extensions: - let x = changeFileExt(pkg / name, ".nim") - if fileExists(x): - candidates.add x - for c in candidates: - # nim-foo foo or foo nfoo - if (pkg in c) or (c in pkg): return c - if candidates.len >= 1: - return candidates[0] + var dir = pkg + while true: + for k, f in os.walkDir(dir, relative=true): + if k == pcFile and f != "config.nims": + let (_, name, ext) = splitFile(f) + if ext in extensions: + let x = changeFileExt(dir / name, ".nim") + if fileExists(x): + candidates.add x + for c in candidates: + # nim-foo foo or foo nfoo + if (pkg in c) or (c in pkg): return c + if candidates.len >= 1: + return candidates[0] + dir = parentDir(dir) + if dir == "": break return "" proc canonDynlibName(s: string): string = diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index afe60e9dd..a067f2074 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -1066,8 +1066,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, of wThis: if it.kind in nkPragmaCallKinds and it.len == 2: c.selfName = considerQuotedIdent(c, it[1]) + message(c.config, n.info, warnDeprecated, "the '.this' pragma") elif it.kind == nkIdent or it.len == 1: c.selfName = getIdent(c.cache, "self") + message(c.config, n.info, warnDeprecated, "the '.this' pragma") else: localError(c.config, it.info, "'this' pragma is allowed to have zero or one arguments") of wNoRewrite: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 972c8c709..99f2cf20d 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -193,6 +193,8 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType = if region.skipTypes({tyGenericInst, tyAlias, tySink}).kind notin { tyError, tyObject}: message c.config, n[i].info, errGenerated, "region needs to be an object type" + else: + message(c.config, n.info, warnDeprecated, "region for pointer types") addSonSkipIntLit(result, region) addSonSkipIntLit(result, t) if tfPartial in result.flags: diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 50235c95f..1abd9ae4a 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -17,7 +17,7 @@ const byteExcess* = 128 # we use excess-K for immediates wordExcess* = 32768 - MaxLoopIterations* = 1_000_000_000 # max iterations of all loops + MaxLoopIterations* = 3_000_000 # max iterations of all loops type diff --git a/doc/exception_hierarchy_fragment.txt b/doc/exception_hierarchy_fragment.txt deleted file mode 100644 index a02d9ccef..000000000 --- a/doc/exception_hierarchy_fragment.txt +++ /dev/null @@ -1,28 +0,0 @@ -* `Exception <system.html#Exception>`_ - * `AccessViolationError <system.html#AccessViolationError>`_ - * `ArithmeticError <system.html#ArithmeticError>`_ - * `DivByZeroError <system.html#DivByZeroError>`_ - * `OverflowError <system.html#OverflowError>`_ - * `AssertionError <system.html#AssertionError>`_ - * `DeadThreadError <system.html#DeadThreadError>`_ - * `FloatingPointError <system.html#FloatingPointError>`_ - * `FloatDivByZeroError <system.html#FloatDivByZeroError>`_ - * `FloatInexactError <system.html#FloatInexactError>`_ - * `FloatInvalidOpError <system.html#FloatInvalidOpError>`_ - * `FloatOverflowError <system.html#FloatOverflowError>`_ - * `FloatUnderflowError <system.html#FloatUnderflowError>`_ - * `FieldError <system.html#FieldError>`_ - * `IndexError <system.html#IndexError>`_ - * `ObjectAssignmentError <system.html#ObjectAssignmentError>`_ - * `ObjectConversionError <system.html#ObjectConversionError>`_ - * `ValueError <system.html#ValueError>`_ - * `KeyError <system.html#KeyError>`_ - * `ReraiseError <system.html#ReraiseError>`_ - * `RangeError <system.html#RangeError>`_ - * `OutOfMemoryError <system.html#OutOfMemoryError>`_ - * `ResourceExhaustedError <system.html#ResourceExhaustedError>`_ - * `StackOverflowError <system.html#StackOverflowError>`_ - * `SystemError <system.html#SystemError>`_ - * `IOError <system.html#IOError>`_ - * `OSError <system.html#OSError>`_ - * `LibraryError <system.html#LibraryError>`_ diff --git a/doc/manual.rst b/doc/manual.rst index de0a13143..d60d58fe7 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -769,8 +769,8 @@ Pre-defined floating point types The following floating point types are pre-defined: ``float`` - the generic floating point type; its size is platform dependent - (the compiler chooses the processor's fastest floating point type). + the generic floating point type; its size used to be platform dependent, + but now it is always mapped to ``float64``. This type should be used in general. floatXX @@ -1507,68 +1507,6 @@ non nilable pointers. The details of this analysis are still to be specified here. -Memory regions --------------- - -The types ``ref`` and ``ptr`` can get an optional ``region`` annotation. -A region has to be an object type. - -Regions are very useful to separate user space and kernel memory in the -development of OS kernels: - -.. code-block:: nim - type - Kernel = object - Userspace = object - - var a: Kernel ptr Stat - var b: Userspace ptr Stat - - # the following does not compile as the pointer types are incompatible: - a = b - -As the example shows ``ptr`` can also be used as a binary -operator, ``region ptr T`` is a shortcut for ``ptr[region, T]``. - -In order to make generic code easier to write ``ptr T`` is a subtype -of ``ptr[R, T]`` for any ``R``. - -Furthermore the subtype relation of the region object types is lifted to -the pointer types: If ``A <: B`` then ``ptr[A, T] <: ptr[B, T]``. This can be -used to model subregions of memory. As a special typing rule ``ptr[R, T]`` is -not compatible to ``pointer`` to prevent the following from compiling: - -.. code-block:: nim - # from system - proc dealloc(p: pointer) - - # wrap some scripting language - type - PythonsHeap = object - PyObjectHeader = object - rc: int - typ: pointer - PyObject = ptr[PythonsHeap, PyObjectHeader] - - proc createPyObject(): PyObject {.importc: "...".} - proc destroyPyObject(x: PyObject) {.importc: "...".} - - var foo = createPyObject() - # type error here, how convenient: - dealloc(foo) - - -Future directions: - -* Memory regions might become available for ``string`` and ``seq`` too. -* Builtin regions like ``private``, ``global`` and ``local`` might be - useful for an OpenCL target. -* Builtin "regions" can model ``lent`` and ``unique`` pointers. -* An assignment operator can be attached to a region so that proper write - barriers can be generated. This would imply that the GC can be implemented - completely in user-space. - - Procedural type --------------- A procedural type is internally a pointer to a procedure. ``nil`` is @@ -2337,6 +2275,8 @@ pointer type and overloading resolution is tried with ``a[]`` instead. Automatic self insertions ------------------------- +**Note**: The ``.this`` pragma is deprecated and should not be used anymore. + Starting with version 0.14 of the language, Nim supports ``field`` as a shortcut for ``self.field`` comparable to the `this`:idx: keyword in Java or C++. This feature has to be explicitly enabled via a ``{.this: self.}`` @@ -4029,9 +3969,12 @@ exception. Exception hierarchy ------------------- -The exception tree is defined in the `system <system.html>`_ module: - -.. include:: exception_hierarchy_fragment.txt +The exception tree is defined in the `system <system.html>`_ module. +Every exception inherits from ``system.Exception``. Exceptions that indicate +programming bugs inherit from ``system.Defect`` (which is a subtype of ``Exception``) +and are stricly speaking not catchable as they can also be mapped to an operation +that terminates the whole process. Exceptions that indicate any other runtime error +that can be caught inherit from ``system.Error`` (which is a subtype of ``Exception``). Imported exceptions diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 43a429a17..db9a83755 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -312,7 +312,6 @@ proc setIndexTerm*(d: var RstGenerator, id, term: string, ## The index won't be written to disk unless you call `writeIndexFile() ## <#writeIndexFile>`_. The purpose of the index is documented in the `docgen ## tools guide <docgen.html#index-switch>`_. - assert(not d.theIndex.isNil) var entry = term isTitle = false @@ -337,7 +336,7 @@ proc hash(n: PRstNode): int = result = hash(n.text) elif n.len > 0: result = hash(n.sons[0]) - for i in 1 .. <len(n): + for i in 1 ..< len(n): result = result !& hash(n.sons[i]) result = !$result @@ -452,7 +451,7 @@ proc generateSymbolIndex(symbols: seq[IndexEntry]): string = title="$3" data-doc-search-tag="$2" href="$1">$2</a></li> """, [url, text, desc]) else: - result.addf("""<li><a class="reference external" + result.addf("""<li><a class="reference external" data-doc-search-tag="$2" href="$1">$2</a></li> """, [url, text]) inc j @@ -524,7 +523,7 @@ proc generateDocumentationTOC(entries: seq[IndexEntry]): string = titleTag = levels[L].text else: result.add(level.indentToLevel(levels[L].level)) - result.addf("""<li><a class="reference" data-doc-search-tag="$1" href="$2"> + result.addf("""<li><a class="reference" data-doc-search-tag="$1" href="$2"> $3</a></li> """, [titleTag & " : " & levels[L].text, link, levels[L].text]) inc L diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index e7552e3e3..da7c3473c 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -493,8 +493,6 @@ proc recvLineInto*(socket: AsyncSocket, resString: FutureVar[string], ## **Warning**: ``recvLineInto`` on unbuffered sockets assumes that the ## protocol uses ``\r\L`` to delimit a new line. assert SocketFlag.Peek notin flags ## TODO: - assert(not resString.mget.isNil(), - "String inside resString future needs to be initialised") result = newFuture[void]("asyncnet.recvLineInto") # TODO: Make the async transformation check for FutureVar params and complete diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim index 6ec71e912..826e42b6c 100644 --- a/lib/pure/concurrency/threadpool.nim +++ b/lib/pure/concurrency/threadpool.nim @@ -89,8 +89,6 @@ proc closeBarrier(b: ptr Barrier) {.compilerProc.} = # ---------------------------------------------------------------------------- type - foreign* = object ## a region that indicates the pointer comes from a - ## foreign thread heap. AwaitInfo = object cv: Semaphore idx: int @@ -231,10 +229,10 @@ proc awaitAndThen*[T](fv: FlowVar[T]; action: proc (x: T) {.closure.}) = action(fv.blob) finished(fv) -proc unsafeRead*[T](fv: FlowVar[ref T]): foreign ptr T = +proc unsafeRead*[T](fv: FlowVar[ref T]): ptr T = ## blocks until the value is available and then returns this value. await(fv) - result = cast[foreign ptr T](fv.data) + result = cast[ptr T](fv.data) proc `^`*[T](fv: FlowVar[ref T]): ref T = ## blocks until the value is available and then returns this value. diff --git a/lib/pure/smtp.nim b/lib/pure/smtp.nim index c2c674b84..d9b863a52 100644 --- a/lib/pure/smtp.nim +++ b/lib/pure/smtp.nim @@ -119,8 +119,7 @@ proc newSmtp*(useSsl = false, debug=false, when compiledWithSsl: sslContext.wrapSocket(result.sock) else: - raise newException(SystemError, - "SMTP module compiled without SSL support") + {.error: "SMTP module compiled without SSL support".} proc newAsyncSmtp*(useSsl = false, debug=false, sslContext = defaultSslContext): AsyncSmtp = @@ -133,8 +132,7 @@ proc newAsyncSmtp*(useSsl = false, debug=false, when compiledWithSsl: sslContext.wrapSocket(result.sock) else: - raise newException(SystemError, - "SMTP module compiled without SSL support") + {.error: "SMTP module compiled without SSL support".} proc quitExcpt(smtp: AsyncSmtp, msg: string): Future[void] = var retFuture = newFuture[void]() diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index f8c5f9a91..989a832cf 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -358,9 +358,6 @@ proc isNilOrEmpty*(s: string): bool {.noSideEffect, procvar, rtl, proc isNilOrWhitespace*(s: string): bool {.noSideEffect, procvar, rtl, extern: "nsuIsNilOrWhitespace".} = ## Checks if `s` is nil or consists entirely of whitespace characters. - if len(s) == 0: - return true - result = true for c in s: if not c.isSpaceAscii(): @@ -908,7 +905,7 @@ proc parseOctInt*(s: string): int {.noSideEffect, ## `s` are ignored. let L = parseutils.parseOct(s, result, 0) if L != s.len or L == 0: - raise newException(ValueError, "invalid oct integer: " & s) + raise newException(ValueError, "invalid oct integer: " & s) proc parseHexInt*(s: string): int {.noSideEffect, procvar, rtl, extern: "nsuParseHexInt".} = @@ -1369,9 +1366,11 @@ proc find*(s: string, sub: char, start: Natural = 0, last: Natural = 0): int {.n if sub == s[i]: return i else: when hasCStringBuiltin: - let found = c_memchr(s[start].unsafeAddr, sub, last-start+1) - if not found.isNil: - return cast[ByteAddress](found) -% cast[ByteAddress](s.cstring) + let L = last-start+1 + if L > 0: + let found = c_memchr(s[start].unsafeAddr, sub, L) + if not found.isNil: + return cast[ByteAddress](found) -% cast[ByteAddress](s.cstring) else: for i in start..last: if sub == s[i]: return i @@ -1518,7 +1517,7 @@ proc replace*(s, sub: string, by = ""): string {.noSideEffect, elif subLen == 1: # when the pattern is a single char, we use a faster # char-based search that doesn't need a skip table: - var c = sub[0] + let c = sub[0] let last = s.high var i = 0 while true: diff --git a/lib/system.nim b/lib/system.nim index 53605f9fd..531363eb1 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -484,141 +484,103 @@ type raise_id: uint # set when exception is raised up: ref Exception # used for stacking exceptions. Not exported! - SystemError* = object of Exception ## \ - ## Abstract class for exceptions that the runtime system raises. - ## - ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. - IOError* = object of SystemError ## \ + Defect* = object of Exception ## \ + ## Abstract base class for all exceptions that Nim's runtime raises + ## but that are strictly uncatchable as they can also be mapped to + ## a ``quit`` / ``trap`` / ``exit`` operation. + + Error* = object of Exception ## \ + ## Abstract class for all exceptions that are catchable. + IOError* = object of Error ## \ ## Raised if an IO error occurred. - ## - ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. EOFError* = object of IOError ## \ ## Raised if an IO "end of file" error occurred. - ## - ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. - OSError* = object of SystemError ## \ + OSError* = object of Error ## \ ## Raised if an operating system service failed. - ## - ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. errorCode*: int32 ## OS-defined error code describing this error. LibraryError* = object of OSError ## \ ## Raised if a dynamic library could not be loaded. - ## - ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. - ResourceExhaustedError* = object of SystemError ## \ + ResourceExhaustedError* = object of Error ## \ ## Raised if a resource request could not be fulfilled. - ## - ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. - ArithmeticError* = object of Exception ## \ + ArithmeticError* = object of Defect ## \ ## Raised if any kind of arithmetic error occurred. - ## - ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. DivByZeroError* = object of ArithmeticError ## \ ## Raised for runtime integer divide-by-zero errors. - ## - ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. OverflowError* = object of ArithmeticError ## \ ## Raised for runtime integer overflows. ## ## This happens for calculations whose results are too large to fit in the - ## provided bits. See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. - AccessViolationError* = object of Exception ## \ + ## provided bits. + AccessViolationError* = object of Defect ## \ ## Raised for invalid memory access errors - ## - ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. - AssertionError* = object of Exception ## \ + AssertionError* = object of Defect ## \ ## Raised when assertion is proved wrong. ## - ## Usually the result of using the `assert() template <#assert>`_. See the - ## full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. - ValueError* = object of Exception ## \ + ## Usually the result of using the `assert() template <#assert>`_. + ValueError* = object of Defect ## \ ## Raised for string and object conversion errors. KeyError* = object of ValueError ## \ ## Raised if a key cannot be found in a table. ## ## Mostly used by the `tables <tables.html>`_ module, it can also be raised ## by other collection modules like `sets <sets.html>`_ or `strtabs - ## <strtabs.html>`_. See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. - OutOfMemError* = object of SystemError ## \ + ## <strtabs.html>`_. + OutOfMemError* = object of Defect ## \ ## Raised for unsuccessful attempts to allocate memory. - ## - ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. - IndexError* = object of Exception ## \ + IndexError* = object of Defect ## \ ## Raised if an array index is out of bounds. - ## - ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. - FieldError* = object of Exception ## \ + FieldError* = object of Defect ## \ ## Raised if a record field is not accessible because its dicriminant's ## value does not fit. - ## - ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. - RangeError* = object of Exception ## \ + RangeError* = object of Defect ## \ ## Raised if a range check error occurred. - ## - ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. - StackOverflowError* = object of SystemError ## \ + StackOverflowError* = object of Defect ## \ ## Raised if the hardware stack used for subroutine calls overflowed. - ## - ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. - ReraiseError* = object of Exception ## \ + ReraiseError* = object of Defect ## \ ## Raised if there is no exception to reraise. - ## - ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. - ObjectAssignmentError* = object of Exception ## \ + ObjectAssignmentError* = object of Defect ## \ ## Raised if an object gets assigned to its parent's object. - ## - ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. - ObjectConversionError* = object of Exception ## \ + ObjectConversionError* = object of Defect ## \ ## Raised if an object is converted to an incompatible object type. ## You can use ``of`` operator to check if conversion will succeed. - ## - ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. - FloatingPointError* = object of Exception ## \ + FloatingPointError* = object of Defect ## \ ## Base class for floating point exceptions. - ## - ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. FloatInvalidOpError* = object of FloatingPointError ## \ ## Raised by invalid operations according to IEEE. ## - ## Raised by ``0.0/0.0``, for example. See the full `exception - ## hierarchy <manual.html#exception-handling-exception-hierarchy>`_. + ## Raised by ``0.0/0.0``, for example. FloatDivByZeroError* = object of FloatingPointError ## \ ## Raised by division by zero. ## - ## Divisor is zero and dividend is a finite nonzero number. See the full - ## `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. + ## Divisor is zero and dividend is a finite nonzero number. FloatOverflowError* = object of FloatingPointError ## \ ## Raised for overflows. ## ## The operation produced a result that exceeds the range of the exponent. - ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. FloatUnderflowError* = object of FloatingPointError ## \ ## Raised for underflows. ## ## The operation produced a result that is too small to be represented as a - ## normal number. See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. + ## normal number. FloatInexactError* = object of FloatingPointError ## \ ## Raised for inexact results. ## ## The operation produced a result that cannot be represented with infinite ## precision -- for example: ``2.0 / 3.0, log(1.1)`` ## - ## **NOTE**: Nim currently does not detect these! See the full - ## `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. - DeadThreadError* = object of Exception ## \ + ## **NOTE**: Nim currently does not detect these! + DeadThreadError* = object of Defect ## \ ## Raised if it is attempted to send a message to a dead thread. - ## - ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. - NilAccessError* = object of SystemError ## \ + NilAccessError* = object of Defect ## \ ## Raised on dereferences of ``nil`` pointers. ## ## This is only raised if the ``segfaults.nim`` module was imported! when defined(nimNewRuntime): type - MoveError* = object of SystemError ## \ + MoveError* = object of Defect ## \ ## Raised on attempts to re-sink an already consumed ``sink`` parameter. when defined(js) or defined(nimdoc): @@ -2321,9 +2283,9 @@ iterator mpairs*(a: var cstring): tuple[key: int, val: var char] {.inline.} = inc(i) -proc isNil*[T](x: seq[T]): bool {.noSideEffect, magic: "IsNil".} +proc isNil*[T](x: seq[T]): bool {.noSideEffect, magic: "IsNil", deprecated.} proc isNil*[T](x: ref T): bool {.noSideEffect, magic: "IsNil".} -proc isNil*(x: string): bool {.noSideEffect, magic: "IsNil".} +proc isNil*(x: string): bool {.noSideEffect, magic: "IsNil", deprecated.} proc isNil*[T](x: ptr T): bool {.noSideEffect, magic: "IsNil".} proc isNil*(x: pointer): bool {.noSideEffect, magic: "IsNil".} proc isNil*(x: cstring): bool {.noSideEffect, magic: "IsNil".} @@ -2520,7 +2482,7 @@ proc `$`*[T: tuple|object](x: T): string = result.add(name) result.add(": ") when compiles($value): - when compiles(value.isNil): + when value isnot string and value isnot seq and compiles(value.isNil): if value.isNil: result.add "nil" else: result.addQuoted(value) else: @@ -2539,7 +2501,7 @@ proc collectionToString[T](x: T, prefix, separator, suffix: string): string = else: result.add(separator) - when compiles(value.isNil): + when value isnot string and value isnot seq and compiles(value.isNil): # this branch should not be necessary if value.isNil: result.add "nil" diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index 19c2c62ad..0e690d832 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -95,6 +95,7 @@ proc mnewString(len: int): NimString {.compilerProc.} = proc copyStrLast(s: NimString, start, last: int): NimString {.compilerProc.} = let start = max(start, 0) + if s == nil: return nil let len = min(last, s.len-1) - start + 1 if len > 0: result = rawNewStringNoInit(len) @@ -109,6 +110,7 @@ proc nimToCStringConv(s: NimString): cstring {.compilerProc, inline.} = else: result = cstring(addr s.data) proc copyStr(s: NimString, start: int): NimString {.compilerProc.} = + if s == nil: return nil result = copyStrLast(s, start, s.len-1) proc toNimStr(str: cstring, len: int): NimString {.compilerProc.} = diff --git a/nimsuggest/tester.nim b/nimsuggest/tester.nim index 4cda272af..b962a9f83 100644 --- a/nimsuggest/tester.nim +++ b/nimsuggest/tester.nim @@ -70,22 +70,22 @@ proc parseCmd(c: string): seq[string] = result = @[] var i = 0 var a = "" - while true: + while i < c.len: setLen(a, 0) # eat all delimiting whitespace - while c[i] in {' ', '\t', '\l', '\r'}: inc(i) + while i < c.len and c[i] in {' ', '\t', '\l', '\r'}: inc(i) + if i >= c.len: break case c[i] of '"': raise newException(ValueError, "double quotes not yet supported: " & c) of '\'': var delim = c[i] inc(i) # skip ' or " - while c[i] != '\0' and c[i] != delim: + while i < c.len and c[i] != delim: add a, c[i] inc(i) - if c[i] != '\0': inc(i) - of '\0': break + if i < c.len: inc(i) else: - while c[i] > ' ': + while i < c.len and c[i] > ' ': add(a, c[i]) inc(i) add(result, a) diff --git a/nimsuggest/tests/tdot4.nim b/nimsuggest/tests/tdot4.nim index 25e77ed04..8510162ac 100644 --- a/nimsuggest/tests/tdot4.nim +++ b/nimsuggest/tests/tdot4.nim @@ -2,7 +2,7 @@ discard """ $nimsuggest --tester --maxresults:2 $file >sug $1 sug;;skProc;;tdot4.main;;proc (inp: string): string;;$file;;10;;5;;"";;100;;None -sug;;skProc;;strutils.replace;;proc (s: string, sub: string, by: string): string{.noSideEffect, gcsafe, locks: 0.};;$lib/pure/strutils.nim;;1575;;5;;"Replaces `sub` in `s` by the string `by`.";;100;;None +sug;;skProc;;strutils.replace;;proc (s: string, sub: string, by: string): string{.noSideEffect, gcsafe, locks: 0.};;$lib/pure/strutils.nim;;1506;;5;;"Replaces `sub` in `s` by the string `by`.";;100;;None """ import strutils diff --git a/nimsuggest/tests/tinclude.nim b/nimsuggest/tests/tinclude.nim index 12d40d1e7..0616b7164 100644 --- a/nimsuggest/tests/tinclude.nim +++ b/nimsuggest/tests/tinclude.nim @@ -1,7 +1,7 @@ discard """ $nimsuggest --tester compiler/nim.nim ->def compiler/semexprs.nim:13:50 -def;;skType;;ast.PSym;;PSym;;*ast.nim;;691;;2;;"";;100 ->def compiler/semexprs.nim:13:50 -def;;skType;;ast.PSym;;PSym;;*ast.nim;;691;;2;;"";;100 +>def compiler/semexprs.nim:25:50 +def;;skType;;ast.PSym;;PSym;;*ast.nim;;707;;2;;"";;100 +>def compiler/semexprs.nim:25:50 +def;;skType;;ast.PSym;;PSym;;*ast.nim;;707;;2;;"";;100 """ diff --git a/tests/generics/tobjecttyperel.nim b/tests/generics/tobjecttyperel.nim index 8c8f90098..6c2184cc2 100644 --- a/tests/generics/tobjecttyperel.nim +++ b/tests/generics/tobjecttyperel.nim @@ -2,8 +2,8 @@ discard """ output: '''(peel: 0, color: 15) (color: 15) 17 -(width: 0.0, taste: nil, color: 13) -(width: 0.0, taste: nil, color: 15) +(width: 0.0, taste: "", color: 13) +(width: 0.0, taste: "", color: 15) cool''' """ @@ -11,16 +11,16 @@ cool''' type BaseFruit[T] = object of RootObj color: T - + MidLevel[T] = object of BaseFruit[T] - + Mango = object of MidLevel[int] peel: int - + Peach[X, T, Y] = object of T width: X taste: Y - + proc setColor[T](self: var BaseFruit[T]) = self.color = 15 diff --git a/tests/parallel/tptr_to_ref.nim b/tests/parallel/tptr_to_ref.nim index fee210dcd..ae02c16e5 100644 --- a/tests/parallel/tptr_to_ref.nim +++ b/tests/parallel/tptr_to_ref.nim @@ -11,7 +11,7 @@ type Killer* = object lock: Lock bailed {.guard: lock.}: bool - processes {.guard: lock.}: array[0..MAX_WORKERS-1, foreign ptr Process] + processes {.guard: lock.}: array[0..MAX_WORKERS-1, ptr Process] # Hold a lock for a statement. template hold(lock: Lock, body: untyped) = @@ -32,7 +32,7 @@ proc initKiller*(): Killer = var killer = initKiller() # remember that a process has been launched, killing it if we have bailed. -proc launched*(process: foreign ptr Process): int {.gcsafe.} = +proc launched*(process: ptr Process): int {.gcsafe.} = result = killer.processes.high + 1 killer.lock.hold: if killer.bailed: diff --git a/tests/system/tnilconcats.nim b/tests/system/tnilconcats.nim index ce059b7b0..5e4a1b317 100644 --- a/tests/system/tnilconcats.nim +++ b/tests/system/tnilconcats.nim @@ -1,5 +1,5 @@ discard """ - output: '''@[nil, nil, nil, nil, nil, nil, nil, "meh"]''' + output: '''@["", "", "", "", "", "", "", "meh"]''' exitcode: "0" """ |