summary refs log tree commit diff stats
path: root/lib/pure
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2017-12-13 09:46:42 +0100
committerAndreas Rumpf <rumpf_a@web.de>2017-12-28 09:21:22 +0100
commit6cf2fcaaf17c3b60101302061dd0cc04699cf78b (patch)
tree7cadeb21753808e3e9c17c8bc868a3d336dc47a3 /lib/pure
parent383c80971cee93496c5317b7464021ac99711176 (diff)
downloadNim-6cf2fcaaf17c3b60101302061dd0cc04699cf78b.tar.gz
optimized friendly stack traces
Diffstat (limited to 'lib/pure')
-rw-r--r--lib/pure/asyncfutures.nim48
-rw-r--r--lib/pure/asyncmacro.nim2
2 files changed, 21 insertions, 29 deletions
diff --git a/lib/pure/asyncfutures.nim b/lib/pure/asyncfutures.nim
index a122e0c41..5675f5399 100644
--- a/lib/pure/asyncfutures.nim
+++ b/lib/pure/asyncfutures.nim
@@ -1,4 +1,4 @@
-import os, tables, strutils, times, heapqueue, options, deques
+import os, tables, strutils, times, heapqueue, options, deques, cstrutils
 
 # TODO: This shouldn't need to be included, but should ideally be exported.
 type
@@ -217,19 +217,15 @@ proc `callback=`*[T](future: Future[T],
   ## If future has already completed then ``cb`` will be called immediately.
   future.callback = proc () = cb(future)
 
-proc diff[T](a, b: seq[T]): (int, seq[T]) =
+proc diff[T](a, b: seq[T]; firstB, lastB: int): int =
   ## Iterates through both sequences until the items do not match,
-  ## returns the remainder of `b` after the last item that does not match
+  ## returns the remainder of `b[firstB..lastB]` after the last item that does not match
   ## together with the index of the last match.
-  ##
-  ## .. code-block::nim
-  ##   doAssert(diff(@[1,2,42,123], @[1,2,123,678,21]) == (1, @[123,678,21]))
-  var lastIndex = 0
-  for i in 0..<min(a.len, b.len):
-    lastIndex = i
-    if a[i] != b[i]:
+  result = firstB
+  for i in 0..<min(a.len, lastB - firstB + 1):
+    result = i+firstB
+    if a[i] != b[i+firstB]:
       break
-  return (lastIndex, b[lastIndex .. ^1])
 
 proc mergeEntries(entries: seq[StackTraceEntry]): seq[StackTraceEntry] =
   ## Merges stack trace entries containing re-raise entries into one
@@ -248,12 +244,11 @@ proc mergeEntries(entries: seq[StackTraceEntry]): seq[StackTraceEntry] =
         reRaiseEnd.inc()
       assert entries[reRaiseEnd].procName.isNil
       assert entries[reRaiseEnd].line == -100 # Signifies end of re-raise block.
-      let reRaisedEntries = entries[i+1 .. reRaiseEnd-1]
 
-      let (lastIndex, remainder) = diff(result, reRaisedEntries)
+      let lastIndex = diff(result, entries, i+1, reRaiseEnd-1)
       # Insert all the entries after lastIndex.
-      for i in 0..<remainder.len:
-        result.insert(remainder[i], lastIndex+i)
+      for j in lastIndex..<reRaiseEnd - i - 1:
+        result.insert(entries[j+i+1], j)
       i = reRaiseEnd+1
       continue
 
@@ -264,17 +259,15 @@ proc getHint(entry: StackTraceEntry): string =
   ## We try to provide some hints about stack trace entries that the user
   ## may not be familiar with, in particular calls inside the stdlib.
   result = ""
-  let name = ($entry.procName).normalize()
-  case name
-  of "processpendingcallbacks":
-    if cmpIgnoreStyle($entry.filename, "asyncdispatch.nim") == 0:
+  if entry.procname == "processPendingCallbacks":
+    if cmpIgnoreStyle(entry.filename, "asyncdispatch.nim") == 0:
       return "Executes pending callbacks"
-  of "poll":
-    if cmpIgnoreStyle($entry.filename, "asyncdispatch.nim") == 0:
+  elif entry.procname == "poll":
+    if cmpIgnoreStyle(entry.filename, "asyncdispatch.nim") == 0:
       return "Processes asynchronous completion events"
 
-  if name.endsWith("continue"):
-    if cmpIgnoreStyle($entry.filename, "asyncmacro.nim") == 0:
+  if entry.procname.endsWith("_continue"):
+    if cmpIgnoreStyle(entry.filename, "asyncmacro.nim") == 0:
       return "Resumes an async procedure"
 
 proc `$`*(entries: seq[StackTraceEntry]): string =
@@ -286,21 +279,18 @@ proc `$`*(entries: seq[StackTraceEntry]): string =
     if left.len > longestLeft:
       longestLeft = left.len
 
-  const indent = 2
+  const indent = spaces(2)
   # Format the entries.
   for entry in entries:
-    let indentStr = spaces(indent)
-
     let left = "$#($#)" % [$entry.filename, $entry.line]
-    result.add("$#$#$# $#\n" % [
-      indentStr,
+    result.add((indent & "$#$# $#\n") % [
       left,
       spaces(longestLeft - left.len + 2),
       $entry.procName
     ])
     let hint = getHint(entry)
     if hint.len > 0:
-      result.add(indentStr & "└─" & hint & "\n")
+      result.add(indent & "└─" & hint & "\n")
 
 proc injectStacktrace[T](future: Future[T]) =
   when not defined(release):
diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim
index 85d44b9f4..8c679929d 100644
--- a/lib/pure/asyncmacro.nim
+++ b/lib/pure/asyncmacro.nim
@@ -389,6 +389,8 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
     outerProcBody.add(closureIterator)
 
     # -> createCb(retFuture)
+    # NOTE: The "_continue" suffix is checked for in asyncfutures.nim to produce
+    # friendlier stack traces:
     var cbName = genSym(nskProc, prcName & "_continue")
     var procCb = getAst createCb(retFutureSym, iteratorNameSym,
                          newStrLitNode(prcName),