summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xcompiler/ecmasgen.nim44
-rwxr-xr-xcompiler/ropes.nim782
-rw-r--r--lib/pure/collections/sequtils.nim164
-rwxr-xr-xlib/pure/collections/tables.nim46
-rwxr-xr-xlib/pure/json.nim9
-rwxr-xr-xlib/system.nim6
-rwxr-xr-xlib/wrappers/lua/lua.nim39
-rwxr-xr-xtests/run/ttables.nim39
8 files changed, 565 insertions, 564 deletions
diff --git a/compiler/ecmasgen.nim b/compiler/ecmasgen.nim
index 25d147ebc..8899c904e 100755
--- a/compiler/ecmasgen.nim
+++ b/compiler/ecmasgen.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nimrod Compiler
-#        (c) Copyright 2012 Andreas Rumpf
+#        (c) Copyright 2013 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -964,24 +964,45 @@ proc genDeref(p: var TProc, n: PNode, r: var TCompRes) =
     if a.kind != etyBaseIndex: InternalError(n.info, "genDeref")
     r.res = ropef("$1[$2]", [a.com, a.res])
 
+proc genArg(p: var TProc, n: PNode, r: var TCompRes) =
+  var a: TCompRes
+  gen(p, n, a)
+  if a.kind == etyBaseIndex: 
+    app(r.res, a.com)
+    app(r.res, ", ")
+    app(r.res, a.res)
+  else:
+    app(r.res, mergeExpr(a))
+
 proc genArgs(p: var TProc, n: PNode, r: var TCompRes) =
   app(r.res, "(")
   for i in countup(1, sonsLen(n) - 1): 
     if i > 1: app(r.res, ", ")
-    var a: TCompRes
-    gen(p, n.sons[i], a)
-    if a.kind == etyBaseIndex: 
-      app(r.res, a.com)
-      app(r.res, ", ")
-      app(r.res, a.res)
-    else: 
-      app(r.res, mergeExpr(a))
+    genArg(p, n.sons[i], r)
   app(r.res, ")")
 
 proc genCall(p: var TProc, n: PNode, r: var TCompRes) = 
   gen(p, n.sons[0], r)
   genArgs(p, n, r)
 
+proc genInfixCall(p: var TProc, n: PNode, r: var TCompRes) =
+  gen(p, n.sons[1], r)
+  if r.kind == etyBaseIndex:
+    if r.com == nil:
+      GlobalError(n.info, "cannot invoke with infix syntax")
+    r.res = ropef("$1[0]", [r.res, r.com])
+    r.com = nil
+  app(r.res, ".")
+  var op: TCompRes
+  gen(p, n.sons[0], op)
+  app(r.res, mergeExpr(op))
+  
+  app(r.res, "(")
+  for i in countup(2, sonsLen(n) - 1):
+    if i > 2: app(r.res, ", ")
+    genArg(p, n.sons[i], r)
+  app(r.res, ")")
+
 proc genEcho(p: var TProc, n: PNode, r: var TCompRes) =
   useMagic(p, "rawEcho")
   app(r.res, "rawEcho")
@@ -1513,9 +1534,12 @@ proc gen(p: var TProc, n: PNode, r: var TCompRes) =
     else: r.res = toRope(f.ToStrMaxPrecision)
   of nkBlockExpr: genBlock(p, n, r)
   of nkIfExpr: genIfExpr(p, n, r)
-  of nkCallKinds: 
+  of nkCallKinds:
     if (n.sons[0].kind == nkSym) and (n.sons[0].sym.magic != mNone): 
       genMagic(p, n, r)
+    elif n.sons[0].kind == nkSym and sfInfixCall in n.sons[0].sym.flags and
+      n.len >= 2:
+      genInfixCall(p, n, r)
     else: 
       genCall(p, n, r)
   of nkCurly: genSetConstr(p, n, r)
diff --git a/compiler/ropes.nim b/compiler/ropes.nim
index 95dce8278..50c89e4d9 100755
--- a/compiler/ropes.nim
+++ b/compiler/ropes.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nimrod Compiler
-#        (c) Copyright 2013 Andreas Rumpf
+#        (c) Copyright 2012 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -58,538 +58,266 @@
 import 
   msgs, strutils, platform, hashes, crc, options
 
-const
-  PayloadSize = 64_000 # dummy size for range checking
-
 type
   TFormatStr* = string # later we may change it to CString for better
                        # performance of the code generator (assignments 
                        # copy the format strings
                        # though it is not necessary)
-
-when true:
-  # old version:
-  type
-    PRope* = ref TRope
-    TRope*{.acyclic.} = object of TObject # the empty rope is represented 
-                                          # by nil to safe space
-      left*, right*: PRope
-      length*: int
-      data*: string             # != nil if a leaf
-    
-    TRopeSeq* = seq[PRope]
-
-  proc con*(a, b: PRope): PRope
-  proc con*(a: PRope, b: string): PRope
-  proc con*(a: string, b: PRope): PRope
-  proc con*(a: varargs[PRope]): PRope
-  proc app*(a: var PRope, b: PRope)
-  proc app*(a: var PRope, b: string)
-  proc prepend*(a: var PRope, b: PRope)
-  proc toRope*(s: string): PRope
-  proc toRope*(i: BiggestInt): PRope
-  proc ropeLen*(a: PRope): int
-  proc writeRopeIfNotEqual*(r: PRope, filename: string): bool
-  proc ropeToStr*(p: PRope): string
-  proc ropef*(frmt: TFormatStr, args: varargs[PRope]): PRope
-  proc appf*(c: var PRope, frmt: TFormatStr, args: varargs[PRope])
-  proc RopeEqualsFile*(r: PRope, f: string): bool
-    # returns true if the rope r is the same as the contents of file f
-  proc RopeInvariant*(r: PRope): bool
-    # exported for debugging
-  # implementation
-
-  proc ropeLen(a: PRope): int = 
-    if a == nil: result = 0
-    else: result = a.length
-    
-  proc newRope(data: string = nil): PRope = 
-    new(result)
-    if data != nil: 
-      result.length = len(data)
-      result.data = data
-
-  proc newMutableRope*(capacity = 30): PRope =
-    ## creates a new rope that supports direct modifications of the rope's
-    ## 'data' and 'length' fields.
-    new(result)
-    result.data = newStringOfCap(capacity)
-
-  proc freezeMutableRope*(r: PRope) {.inline.} =
-    r.length = r.data.len
-
-  var 
-    cache: array[0..2048*2 -1, PRope]
-
-  proc RopeInvariant(r: PRope): bool = 
-    if r == nil: 
-      result = true
-    else: 
-      result = true #
-                    #    if r.data <> snil then
-                    #      result := true
-                    #    else begin
-                    #      result := (r.left <> nil) and (r.right <> nil);
-                    #      if result then result := ropeInvariant(r.left);
-                    #      if result then result := ropeInvariant(r.right);
-                    #    end 
-
-  proc insertInCache(s: string): PRope = 
-    var h = hash(s) and high(cache)
-    result = cache[h]
-    if isNil(result) or result.data != s:
-      result = newRope(s)
-      cache[h] = result
-    
-  proc toRope(s: string): PRope =
-    if s.len == 0:
-      result = nil
-    else:
-      result = insertInCache(s)
-    assert(RopeInvariant(result))
-
-  proc RopeSeqInsert(rs: var TRopeSeq, r: PRope, at: Natural) = 
-    var length = len(rs)
-    if at > length: 
-      setlen(rs, at + 1)
-    else: 
-      setlen(rs, length + 1)    # move old rope elements:
-    for i in countdown(length, at + 1): 
-      rs[i] = rs[i - 1] # this is correct, I used pen and paper to validate it
-    rs[at] = r
-
-  proc newRecRopeToStr(result: var string, resultLen: var int, r: PRope) = 
-    var stack = @[r]
-    while len(stack) > 0: 
-      var it = pop(stack)
-      while it.data == nil: 
-        add(stack, it.right)
-        it = it.left
-      assert(it.data != nil)
-      CopyMem(addr(result[resultLen]), addr(it.data[0]), it.length)
-      Inc(resultLen, it.length)
-      assert(resultLen <= len(result))
-
-  proc ropeToStr(p: PRope): string = 
-    if p == nil: 
-      result = ""
-    else: 
-      result = newString(p.length)
-      var resultLen = 0
-      newRecRopeToStr(result, resultLen, p)
-
-  proc con(a, b: PRope): PRope = 
-    if a == nil: result = b
-    elif b == nil: result = a
-    else:
-      result = newRope()
-      result.length = a.length + b.length
-      result.left = a
-      result.right = b
-
-  proc con(a: PRope, b: string): PRope = result = con(a, toRope(b))
-  proc con(a: string, b: PRope): PRope = result = con(toRope(a), b)
-
-  proc con(a: varargs[PRope]): PRope = 
-    for i in countup(0, high(a)): result = con(result, a[i])
-
-  proc toRope(i: BiggestInt): PRope = result = toRope($i)
-
-  proc app(a: var PRope, b: PRope) = a = con(a, b)
-  proc app(a: var PRope, b: string) = a = con(a, b)
-  proc prepend(a: var PRope, b: PRope) = a = con(b, a)
-
-  proc writeRope*(f: TFile, c: PRope) = 
-    var stack = @[c]
-    while len(stack) > 0: 
-      var it = pop(stack)
-      while it.data == nil: 
-        add(stack, it.right)
-        it = it.left
-        assert(it != nil)
-      assert(it.data != nil)
-      write(f, it.data)
-
-  proc WriteRope*(head: PRope, filename: string, useWarning = false) =
-    var f: tfile
-    if open(f, filename, fmWrite):
-      if head != nil: WriteRope(f, head)
-      close(f)
-    else:
-      rawMessage(if useWarning: warnCannotOpenFile else: errCannotOpenFile,
-                 filename)
-
-  proc ropef(frmt: TFormatStr, args: varargs[PRope]): PRope = 
-    var i = 0
-    var length = len(frmt)
+  PRope* = ref TRope
+  TRope*{.acyclic.} = object of TObject # the empty rope is represented 
+                                        # by nil to safe space
+    left*, right*: PRope
+    length*: int
+    data*: string             # != nil if a leaf
+  
+  TRopeSeq* = seq[PRope]
+
+proc con*(a, b: PRope): PRope
+proc con*(a: PRope, b: string): PRope
+proc con*(a: string, b: PRope): PRope
+proc con*(a: varargs[PRope]): PRope
+proc app*(a: var PRope, b: PRope)
+proc app*(a: var PRope, b: string)
+proc prepend*(a: var PRope, b: PRope)
+proc toRope*(s: string): PRope
+proc toRope*(i: BiggestInt): PRope
+proc ropeLen*(a: PRope): int
+proc writeRopeIfNotEqual*(r: PRope, filename: string): bool
+proc ropeToStr*(p: PRope): string
+proc ropef*(frmt: TFormatStr, args: varargs[PRope]): PRope
+proc appf*(c: var PRope, frmt: TFormatStr, args: varargs[PRope])
+proc RopeEqualsFile*(r: PRope, f: string): bool
+  # returns true if the rope r is the same as the contents of file f
+proc RopeInvariant*(r: PRope): bool
+  # exported for debugging
+# implementation
+
+proc ropeLen(a: PRope): int = 
+  if a == nil: result = 0
+  else: result = a.length
+  
+proc newRope(data: string = nil): PRope = 
+  new(result)
+  if data != nil: 
+    result.length = len(data)
+    result.data = data
+
+proc newMutableRope*(capacity = 30): PRope =
+  ## creates a new rope that supports direct modifications of the rope's
+  ## 'data' and 'length' fields.
+  new(result)
+  result.data = newStringOfCap(capacity)
+
+proc freezeMutableRope*(r: PRope) {.inline.} =
+  r.length = r.data.len
+
+var 
+  cache: array[0..2048*2 -1, PRope]
+
+proc RopeInvariant(r: PRope): bool = 
+  if r == nil: 
+    result = true
+  else: 
+    result = true #
+                  #    if r.data <> snil then
+                  #      result := true
+                  #    else begin
+                  #      result := (r.left <> nil) and (r.right <> nil);
+                  #      if result then result := ropeInvariant(r.left);
+                  #      if result then result := ropeInvariant(r.right);
+                  #    end 
+
+proc insertInCache(s: string): PRope = 
+  var h = hash(s) and high(cache)
+  result = cache[h]
+  if isNil(result) or result.data != s:
+    result = newRope(s)
+    cache[h] = result
+  
+proc toRope(s: string): PRope =
+  if s.len == 0:
     result = nil
-    var num = 0
-    while i <= length - 1: 
-      if frmt[i] == '$': 
-        inc(i)                  # skip '$'
-        case frmt[i]
-        of '$': 
-          app(result, "$")
-          inc(i)
-        of '#': 
-          inc(i)
-          app(result, args[num])
-          inc(num)
-        of '0'..'9': 
-          var j = 0
-          while true: 
-            j = (j * 10) + Ord(frmt[i]) - ord('0')
-            inc(i)
-            if (i > length + 0 - 1) or not (frmt[i] in {'0'..'9'}): break 
-          num = j
-          if j > high(args) + 1: 
-            internalError("ropes: invalid format string $" & $(j))
-          else:
-            app(result, args[j - 1])
-        of 'n':
-          if optLineDir notin gOptions: app(result, tnl)
-          inc i
-        of 'N':
-          app(result, tnl)
-          inc(i)
-        else: InternalError("ropes: invalid format string $" & frmt[i])
-      var start = i
-      while i < length:
-        if frmt[i] != '$': inc(i)
-        else: break
-      if i - 1 >= start: 
-        app(result, substr(frmt, start, i - 1))
-    assert(RopeInvariant(result))
-
-  proc appf(c: var PRope, frmt: TFormatStr, args: varargs[PRope]) = 
-    app(c, ropef(frmt, args))
-
-  const 
-    bufSize = 1024              # 1 KB is reasonable
-
-  proc auxRopeEqualsFile(r: PRope, bin: var tfile, buf: Pointer): bool = 
-    if r.data != nil:
-      if r.length > bufSize: 
-        internalError("ropes: token too long")
-        return
-      var readBytes = readBuffer(bin, buf, r.length)
-      result = readBytes == r.length and
-          equalMem(buf, addr(r.data[0]), r.length) # BUGFIX
-    else: 
-      result = auxRopeEqualsFile(r.left, bin, buf)
-      if result: result = auxRopeEqualsFile(r.right, bin, buf)
-    
-  proc RopeEqualsFile(r: PRope, f: string): bool = 
-    var bin: tfile
-    result = open(bin, f)
-    if not result: 
-      return                    # not equal if file does not exist
-    var buf = alloc(BufSize)
-    result = auxRopeEqualsFile(r, bin, buf)
-    if result: 
-      result = readBuffer(bin, buf, bufSize) == 0 # really at the end of file?
-    dealloc(buf)
-    close(bin)
-
-  proc crcFromRopeAux(r: PRope, startVal: TCrc32): TCrc32 = 
-    if r.data != nil: 
-      result = startVal
-      for i in countup(0, len(r.data) - 1): 
-        result = updateCrc32(r.data[i], result)
-    else: 
-      result = crcFromRopeAux(r.left, startVal)
-      result = crcFromRopeAux(r.right, result)
-
-  proc newCrcFromRopeAux(r: PRope, startVal: TCrc32): TCrc32 = 
-    # XXX profiling shows this is actually expensive
-    var stack: TRopeSeq = @[r]
-    result = startVal
-    while len(stack) > 0: 
-      var it = pop(stack)
-      while it.data == nil: 
-        add(stack, it.right)
-        it = it.left
-      assert(it.data != nil)
-      var i = 0
-      var L = len(it.data)
-      while i < L: 
-        result = updateCrc32(it.data[i], result)
+  else:
+    result = insertInCache(s)
+  assert(RopeInvariant(result))
+
+proc RopeSeqInsert(rs: var TRopeSeq, r: PRope, at: Natural) = 
+  var length = len(rs)
+  if at > length: 
+    setlen(rs, at + 1)
+  else: 
+    setlen(rs, length + 1)    # move old rope elements:
+  for i in countdown(length, at + 1): 
+    rs[i] = rs[i - 1] # this is correct, I used pen and paper to validate it
+  rs[at] = r
+
+proc newRecRopeToStr(result: var string, resultLen: var int, r: PRope) = 
+  var stack = @[r]
+  while len(stack) > 0: 
+    var it = pop(stack)
+    while it.data == nil: 
+      add(stack, it.right)
+      it = it.left
+    assert(it.data != nil)
+    CopyMem(addr(result[resultLen]), addr(it.data[0]), it.length)
+    Inc(resultLen, it.length)
+    assert(resultLen <= len(result))
+
+proc ropeToStr(p: PRope): string = 
+  if p == nil: 
+    result = ""
+  else: 
+    result = newString(p.length)
+    var resultLen = 0
+    newRecRopeToStr(result, resultLen, p)
+
+proc con(a, b: PRope): PRope = 
+  if a == nil: result = b
+  elif b == nil: result = a
+  else:
+    result = newRope()
+    result.length = a.length + b.length
+    result.left = a
+    result.right = b
+
+proc con(a: PRope, b: string): PRope = result = con(a, toRope(b))
+proc con(a: string, b: PRope): PRope = result = con(toRope(a), b)
+
+proc con(a: varargs[PRope]): PRope = 
+  for i in countup(0, high(a)): result = con(result, a[i])
+
+proc toRope(i: BiggestInt): PRope = result = toRope($i)
+
+proc app(a: var PRope, b: PRope) = a = con(a, b)
+proc app(a: var PRope, b: string) = a = con(a, b)
+proc prepend(a: var PRope, b: PRope) = a = con(b, a)
+
+proc writeRope*(f: TFile, c: PRope) = 
+  var stack = @[c]
+  while len(stack) > 0: 
+    var it = pop(stack)
+    while it.data == nil: 
+      add(stack, it.right)
+      it = it.left
+      assert(it != nil)
+    assert(it.data != nil)
+    write(f, it.data)
+
+proc WriteRope*(head: PRope, filename: string, useWarning = false) =
+  var f: tfile
+  if open(f, filename, fmWrite):
+    if head != nil: WriteRope(f, head)
+    close(f)
+  else:
+    rawMessage(if useWarning: warnCannotOpenFile else: errCannotOpenFile,
+               filename)
+
+proc ropef(frmt: TFormatStr, args: varargs[PRope]): PRope = 
+  var i = 0
+  var length = len(frmt)
+  result = nil
+  var num = 0
+  while i <= length - 1: 
+    if frmt[i] == '$': 
+      inc(i)                  # skip '$'
+      case frmt[i]
+      of '$': 
+        app(result, "$")
         inc(i)
-
-  proc crcFromRope(r: PRope): TCrc32 = 
-    result = newCrcFromRopeAux(r, initCrc32)
-
-  proc writeRopeIfNotEqual(r: PRope, filename: string): bool = 
-    # returns true if overwritten
-    var c: TCrc32
-    c = crcFromFile(filename)
-    if c != crcFromRope(r): 
-      writeRope(r, filename)
-      result = true
-    else: 
-      result = false
-
-else:
-  # optimized version with 'unsafeNew':
-
-  type
-    PRope* = ref TRope
-    TRope*{.acyclic.} = object of TObject # the empty rope is represented 
-                                          # by nil to safe space
-      left, right: PRope
-      L: int                            # < 0 if a leaf
-      d: array [0..PayloadSize, char]             # != nil if a leaf
-    
-    TRopeSeq* = seq[PRope]
-
-  proc con*(a, b: PRope): PRope
-  proc con*(a: PRope, b: string): PRope
-  proc con*(a: string, b: PRope): PRope
-  proc con*(a: varargs[PRope]): PRope
-  proc app*(a: var PRope, b: PRope)
-  proc app*(a: var PRope, b: string)
-  proc prepend*(a: var PRope, b: PRope)
-  proc toRope*(s: string): PRope
-  proc toRope*(i: BiggestInt): PRope
-  proc ropeLen*(a: PRope): int
-  proc writeRopeIfNotEqual*(r: PRope, filename: string): bool
-  proc ropeToStr*(p: PRope): string
-  proc ropef*(frmt: TFormatStr, args: varargs[PRope]): PRope
-  proc appf*(c: var PRope, frmt: TFormatStr, args: varargs[PRope])
-  proc RopeEqualsFile*(r: PRope, f: string): bool
-    # returns true if the rope r is the same as the contents of file f
-  proc RopeInvariant*(r: PRope): bool
-    # exported for debugging
-  # implementation
-
-  proc ropeLen(a: PRope): int = 
-    if a == nil: result = 0
-    else: result = a.L.abs
-    
-  proc newRope(data: string = nil): PRope =
-    if data != nil:
-      unsafeNew(result, sizeof(TRope)-PayloadSize+len(data)+1)
-      result.L = -len(data)
-      # copy including '\0':
-      copyMem(addr result.d, cstring(data), len(data))
-    else:
-      unsafeNew(result, sizeof(TRope)-PayloadSize+1)
-
-  proc eqContent(r: PRope, s: string): bool =
-    assert r.L < 0
-    if -r.L == s.len:
-      result = equalMem(addr(r.d), cstring(s), s.len)
-
-  when false:
-    proc newMutableRope*(capacity = 30): PRope =
-      ## creates a new rope that supports direct modifications of the rope's
-      ## 'data' and 'length' fields.
-      new(result)
-      result.data = newStringOfCap(capacity)
-
-    proc freezeMutableRope*(r: PRope) {.inline.} =
-      r.length = r.data.len
-
-  var 
-    cache: array[0..2048*2 -1, PRope]
-
-  proc RopeInvariant(r: PRope): bool = 
-    if r == nil: 
-      result = true
-    else: 
-      result = true #
-                    #    if r.data <> snil then
-                    #      result := true
-                    #    else begin
-                    #      result := (r.left <> nil) and (r.right <> nil);
-                    #      if result then result := ropeInvariant(r.left);
-                    #      if result then result := ropeInvariant(r.right);
-                    #    end 
-
-  proc insertInCache(s: string): PRope = 
-    var h = hash(s) and high(cache)
-    result = cache[h]
-    if isNil(result) or not eqContent(result, s):
-      result = newRope(s)
-      cache[h] = result
-    
-  proc toRope(s: string): PRope =
-    if s.len == 0:
-      result = nil
-    else:
-      result = insertInCache(s)
-    assert(RopeInvariant(result))
-
-  proc RopeSeqInsert(rs: var TRopeSeq, r: PRope, at: Natural) = 
-    var length = len(rs)
-    if at > length: 
-      setlen(rs, at + 1)
-    else: 
-      setlen(rs, length + 1)    # move old rope elements:
-    for i in countdown(length, at + 1): 
-      rs[i] = rs[i - 1] # this is correct, I used pen and paper to validate it
-    rs[at] = r
-
-  proc newRecRopeToStr(result: var string, resultLen: var int, r: PRope) = 
-    var stack = @[r]
-    while len(stack) > 0: 
-      var it = pop(stack)
-      while it.L >= 0:
-        add(stack, it.right)
-        it = it.left
-      assert(it.L < 0)
-      CopyMem(addr(result[resultLen]), addr(it.d[0]), -it.L)
-      Inc(resultLen, -it.L)
-      assert(resultLen <= len(result))
-
-  proc ropeToStr(p: PRope): string = 
-    if p == nil: 
-      result = ""
-    else:
-      result = newString(p.L.abs)
-      var resultLen = 0
-      newRecRopeToStr(result, resultLen, p)
-
-  proc con(a, b: PRope): PRope = 
-    if a == nil: result = b
-    elif b == nil: result = a
-    else:
-      result = newRope()
-      result.L = a.L.abs + b.L.abs
-      result.left = a
-      result.right = b
-
-  proc con(a: PRope, b: string): PRope = result = con(a, toRope(b))
-  proc con(a: string, b: PRope): PRope = result = con(toRope(a), b)
-
-  proc con(a: varargs[PRope]): PRope = 
-    for i in countup(0, high(a)): result = con(result, a[i])
-
-  proc toRope(i: BiggestInt): PRope = result = toRope($i)
-
-  proc app(a: var PRope, b: PRope) = a = con(a, b)
-  proc app(a: var PRope, b: string) = a = con(a, b)
-  proc prepend(a: var PRope, b: PRope) = a = con(b, a)
-
-  proc writeRope*(f: TFile, c: PRope) =
-    var stack = @[c]
-    while len(stack) > 0:
-      var it = pop(stack)
-      while it.L >= 0:
-        add(stack, it.right)
-        it = it.left
-        assert(it != nil)
-      assert(it.L < 0)
-      let L = -it.L
-      if writeBuffer(f, cstring(it.d), L) != L:
-        InternalError("cannot store file")
-
-  proc WriteRope*(head: PRope, filename: string, useWarning = false) =
-    var f: tfile
-    if open(f, filename, fmWrite):
-      if head != nil: WriteRope(f, head)
-      close(f)
-    else:
-      rawMessage(if useWarning: warnCannotOpenFile else: errCannotOpenFile,
-                 filename)
-
-  proc ropef(frmt: TFormatStr, args: varargs[PRope]): PRope = 
-    var i = 0
-    var length = len(frmt)
-    result = nil
-    var num = 0
-    while i <= length - 1: 
-      if frmt[i] == '$': 
-        inc(i)                  # skip '$'
-        case frmt[i]
-        of '$': 
-          app(result, "$")
-          inc(i)
-        of '#': 
-          inc(i)
-          app(result, args[num])
-          inc(num)
-        of '0'..'9': 
-          var j = 0
-          while true: 
-            j = (j * 10) + Ord(frmt[i]) - ord('0')
-            inc(i)
-            if (i > length + 0 - 1) or not (frmt[i] in {'0'..'9'}): break 
-          num = j
-          if j > high(args) + 1: 
-            internalError("ropes: invalid format string $" & $(j))
-          else:
-            app(result, args[j - 1])
-        of 'n':
-          if optLineDir notin gOptions: app(result, tnl)
-          inc i
-        of 'N':
-          app(result, tnl)
+      of '#': 
+        inc(i)
+        app(result, args[num])
+        inc(num)
+      of '0'..'9': 
+        var j = 0
+        while true: 
+          j = (j * 10) + Ord(frmt[i]) - ord('0')
           inc(i)
-        else: InternalError("ropes: invalid format string $" & frmt[i])
-      var start = i
-      while i < length:
-        if frmt[i] != '$': inc(i)
-        else: break
-      if i - 1 >= start: 
-        app(result, substr(frmt, start, i - 1))
-    assert(RopeInvariant(result))
-
-  proc appf(c: var PRope, frmt: TFormatStr, args: varargs[PRope]) = 
-    app(c, ropef(frmt, args))
-
-  const 
-    bufSize = 1024              # 1 KB is reasonable
-
-  proc auxRopeEqualsFile(r: PRope, bin: var tfile, buf: Pointer): bool = 
-    if r.L < 0:
-      if -r.L > bufSize: 
-        internalError("ropes: token too long")
-        return
-      var readBytes = readBuffer(bin, buf, -r.L)
-      result = readBytes == -r.L and
-          equalMem(buf, addr(r.d[0]), readBytes)
-    else:
-      result = auxRopeEqualsFile(r.left, bin, buf)
-      if result: result = auxRopeEqualsFile(r.right, bin, buf)
-    
-  proc RopeEqualsFile(r: PRope, f: string): bool = 
-    var bin: tfile
-    result = open(bin, f)
-    if not result: 
-      return                    # not equal if file does not exist
-    var buf = alloc(BufSize)
-    result = auxRopeEqualsFile(r, bin, buf)
-    if result: 
-      result = readBuffer(bin, buf, bufSize) == 0 # really at the end of file?
-    dealloc(buf)
-    close(bin)
-
-  proc newCrcFromRopeAux(r: PRope, startVal: TCrc32): TCrc32 = 
-    # XXX profiling shows this is actually expensive
-    var stack: TRopeSeq = @[r]
-    result = startVal
-    while len(stack) > 0: 
-      var it = pop(stack)
-      while it.L >= 0:
-        add(stack, it.right)
-        it = it.left
-      assert(it.L < 0)
-      var i = 0
-      var L = -it.L
-      while i < L:
-        result = updateCrc32(it.d[i], result)
+          if (i > length + 0 - 1) or not (frmt[i] in {'0'..'9'}): break 
+        num = j
+        if j > high(args) + 1: 
+          internalError("ropes: invalid format string $" & $(j))
+        else:
+          app(result, args[j - 1])
+      of 'n':
+        if optLineDir notin gOptions: app(result, tnl)
+        inc i
+      of 'N':
+        app(result, tnl)
         inc(i)
-
-  proc crcFromRope(r: PRope): TCrc32 = 
-    result = newCrcFromRopeAux(r, initCrc32)
-
-  proc writeRopeIfNotEqual(r: PRope, filename: string): bool = 
-    # returns true if overwritten
-    var c: TCrc32
-    c = crcFromFile(filename)
-    if c != crcFromRope(r): 
-      writeRope(r, filename)
-      result = true
-    else: 
-      result = false
+      else: InternalError("ropes: invalid format string $" & frmt[i])
+    var start = i
+    while i < length:
+      if frmt[i] != '$': inc(i)
+      else: break
+    if i - 1 >= start: 
+      app(result, substr(frmt, start, i - 1))
+  assert(RopeInvariant(result))
+
+proc appf(c: var PRope, frmt: TFormatStr, args: varargs[PRope]) = 
+  app(c, ropef(frmt, args))
+
+const 
+  bufSize = 1024              # 1 KB is reasonable
+
+proc auxRopeEqualsFile(r: PRope, bin: var tfile, buf: Pointer): bool = 
+  if r.data != nil:
+    if r.length > bufSize: 
+      internalError("ropes: token too long")
+      return
+    var readBytes = readBuffer(bin, buf, r.length)
+    result = readBytes == r.length and
+        equalMem(buf, addr(r.data[0]), r.length) # BUGFIX
+  else: 
+    result = auxRopeEqualsFile(r.left, bin, buf)
+    if result: result = auxRopeEqualsFile(r.right, bin, buf)
+  
+proc RopeEqualsFile(r: PRope, f: string): bool = 
+  var bin: tfile
+  result = open(bin, f)
+  if not result: 
+    return                    # not equal if file does not exist
+  var buf = alloc(BufSize)
+  result = auxRopeEqualsFile(r, bin, buf)
+  if result: 
+    result = readBuffer(bin, buf, bufSize) == 0 # really at the end of file?
+  dealloc(buf)
+  close(bin)
+
+proc crcFromRopeAux(r: PRope, startVal: TCrc32): TCrc32 = 
+  if r.data != nil: 
+    result = startVal
+    for i in countup(0, len(r.data) - 1): 
+      result = updateCrc32(r.data[i], result)
+  else: 
+    result = crcFromRopeAux(r.left, startVal)
+    result = crcFromRopeAux(r.right, result)
+
+proc newCrcFromRopeAux(r: PRope, startVal: TCrc32): TCrc32 = 
+  # XXX profiling shows this is actually expensive
+  var stack: TRopeSeq = @[r]
+  result = startVal
+  while len(stack) > 0: 
+    var it = pop(stack)
+    while it.data == nil: 
+      add(stack, it.right)
+      it = it.left
+    assert(it.data != nil)
+    var i = 0
+    var L = len(it.data)
+    while i < L: 
+      result = updateCrc32(it.data[i], result)
+      inc(i)
+
+proc crcFromRope(r: PRope): TCrc32 = 
+  result = newCrcFromRopeAux(r, initCrc32)
+
+proc writeRopeIfNotEqual(r: PRope, filename: string): bool = 
+  # returns true if overwritten
+  var c: TCrc32
+  c = crcFromFile(filename)
+  if c != crcFromRope(r): 
+    writeRope(r, filename)
+    result = true
+  else: 
+    result = false
diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim
index 0fda5700e..e4ea22830 100644
--- a/lib/pure/collections/sequtils.nim
+++ b/lib/pure/collections/sequtils.nim
@@ -9,8 +9,16 @@
 
 ## :Author: Alex Mitchell
 ##
-## This module implements operations for the built-in `seq`:idx: type
-## which were inspired by functional programming languages.
+## This module implements operations for the built-in `seq`:idx: type which
+## were inspired by functional programming languages. If you are looking for
+## the typical `map` function which applies a function to every element in a
+## sequence, it already exists as the `each` proc in the `system
+## <system.html>`_ module in both mutable and immutable styles.
+##
+## Also, for functional style programming you may want to pass `anonymous procs
+## <manual.html#anonymous-procs>`_ to procs like ``filter`` to reduce typing.
+## Anonymous procs can use `the special do notation <manual.html#do-notation>`_
+## which is more convenient in certain situations.
 ##
 ## **Note**: This interface will change as soon as the compiler supports
 ## closures and proper coroutines.
@@ -19,7 +27,17 @@ when not defined(nimhygiene):
   {.pragma: dirty.}
 
 proc concat*[T](seqs: varargs[seq[T]]): seq[T] =
-  ## Takes several sequences' items and returns them inside of one sequence.
+  ## Takes several sequences' items and returns them inside a new sequence.
+  ##
+  ## Example:
+  ##
+  ## .. code-block:: nimrod
+  ##   let
+  ##     s1 = @[1, 2, 3]
+  ##     s2 = @[4, 5]
+  ##     s3 = @[6, 7]
+  ##     total = concat(s1, s2, s3)
+  ##   assert total == @[1, 2, 3, 4, 5, 6, 7]
   var L = 0
   for seqitm in items(seqs): inc(L, len(seqitm))
   newSeq(result, L)
@@ -30,14 +48,42 @@ proc concat*[T](seqs: varargs[seq[T]]): seq[T] =
       inc(i)
 
 proc distnct*[T](seq1: seq[T]): seq[T] =
-  ## Removes duplicates from a sequence and returns it.
+  ## Returns a new sequence without duplicates.
+  ##
+  ## This proc is `misspelled` on purpose to avoid a clash with the keyword
+  ## ``distinct`` used to `define a derived type incompatible with its base
+  ## type <manual.html#distinct-type>`_. Example:
+  ##
+  ## .. code-block:: nimrod
+  ##   let
+  ##     dup1 = @[1, 1, 3, 4, 2, 2, 8, 1, 4]
+  ##     dup2 = @["a", "a", "c", "d", "d"]
+  ##     unique1 = distnct(dup1)
+  ##     unique2 = distnct(dup2)
+  ##   assert unique1 == @[1, 3, 4, 2, 8]
+  ##   assert unique2 == @["a", "c", "d"]
   result = @[]
   for itm in items(seq1):
     if not result.contains(itm): result.add(itm)
     
 proc zip*[S, T](seq1: seq[S], seq2: seq[T]): seq[tuple[a: S, b: T]] =
-  ## Combines two sequences. If one sequence is too short,
-  ## the remaining items in the longer sequence are discarded.
+  ## Returns a new sequence with a combination of the two input sequences.
+  ##
+  ## For convenience you can access the returned tuples through the named
+  ## fields `a` and `b`. If one sequence is shorter, the remaining items in the
+  ## longer sequence are discarded. Example:
+  ##
+  ## .. code-block:: nimrod
+  ##   let
+  ##     short = @[1, 2, 3]
+  ##     long = @[6, 5, 4, 3, 2, 1]
+  ##     words = @["one", "two", "three"]
+  ##     zip1 = zip(short, long)
+  ##     zip2 = zip(short, words)
+  ##   assert zip1 == @[(1, 6), (2, 5), (3, 4)]
+  ##   assert zip2 == @[(1, "one"), (2, "two"), (3, "three")]
+  ##   assert zip1[2].b == 4
+  ##   assert zip2[2].b == "three"
   var m = min(seq1.len, seq2.len)
   newSeq(result, m)
   for i in 0 .. m-1: result[i] = (seq1[i], seq2[i])
@@ -45,18 +91,44 @@ proc zip*[S, T](seq1: seq[S], seq2: seq[T]): seq[tuple[a: S, b: T]] =
 iterator filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): T =
   ## Iterates through a sequence and yields every item that fulfills the
   ## predicate.
+  ##
+  ## Example:
+  ##
+  ## .. code-block:: nimrod
+  ##   let numbers = @[1, 4, 5, 8, 9, 7, 4]
+  ##   for n in filter(numbers, proc (x: int): bool = x mod 2 == 0):
+  ##     echo($n)
+  ##   # echoes 4, 8, 4 in separate lines
   for i in countup(0, len(seq1) -1):
     var item = seq1[i]
     if pred(item): yield seq1[i]
 
 proc filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): seq[T] =
-  ## Returns all items in a sequence that fulfilled the predicate.
+  ## Returns a new sequence with all the items that fulfilled the predicate.
+  ##
+  ## Example:
+  ##
+  ## .. code-block:: nimrod
+  ##   let
+  ##     colors = @["red", "yellow", "black"]
+  ##     f1 = filter(colors, proc(x: string): bool = x.len < 6)
+  ##     f2 = filter(colors) do (x: string) -> bool : x.len > 5
+  ##   assert f1 == @["red", "black"]
+  ##   assert f2 == @["yellow"]
   accumulateResult(filter(seq1, pred))
 
 template filterIt*(seq1, pred: expr): expr {.immediate, dirty.} =
-  ## Finds a specific item in a sequence as long as the 
-  ## predicate returns true. The predicate needs to be an expression
-  ## containing ``it``: ``filterIt("abcxyz", it == 'x')``.
+  ## Returns a new sequence with all the items that fulfilled the predicate.
+  ##
+  ## Unlike the `proc` version, the predicate needs to be an expression using
+  ## the ``it`` variable for testing, like: ``filterIt("abcxyz", it == 'x')``.
+  ## Example:
+  ##
+  ## .. code-block:: nimrod
+  ##    let
+  ##      temperatures = @[-272.15, -2.0, 24.5, 44.31, 99.9, -113.44]
+  ##      acceptable = filterIt(temperatures, it < 50 and it > -10)
+  ##    assert acceptable == @[-2.0, 24.5, 44.31]
   block:
     var result: type(seq1) = @[]
     for it in items(seq1):
@@ -65,7 +137,79 @@ template filterIt*(seq1, pred: expr): expr {.immediate, dirty.} =
 
 template toSeq*(iter: expr): expr {.immediate.} =
   ## Transforms any iterator into a sequence.
+  ##
+  ## Example:
+  ##
+  ## .. code-block:: nimrod
+  ##   let
+  ##     numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
+  ##     odd_numbers = toSeq(filter(numeric) do (x: int) -> bool:
+  ##       if x mod 2 == 1:
+  ##         result = true)
+  ##   assert odd_numbers == @[1, 3, 5, 7, 9]
+  ##
   var result {.gensym.}: seq[type(iter)] = @[]
   for x in iter: add(result, x)
   result
 
+when isMainModule:
+  import strutils
+  proc toStr(x: int): string {.procvar.} = $x
+  # concat test
+  let
+    s1 = @[1, 2, 3]
+    s2 = @[4, 5]
+    s3 = @[6, 7]
+    total = concat(s1, s2, s3)
+  assert total == @[1, 2, 3, 4, 5, 6, 7]
+
+  # duplicates test
+  let
+    dup1 = @[1, 1, 3, 4, 2, 2, 8, 1, 4]
+    dup2 = @["a", "a", "c", "d", "d"]
+    unique1 = distnct(dup1)
+    unique2 = distnct(dup2)
+  assert unique1 == @[1, 3, 4, 2, 8]
+  assert unique2 == @["a", "c", "d"]
+
+  # zip test
+  let
+    short = @[1, 2, 3]
+    long = @[6, 5, 4, 3, 2, 1]
+    words = @["one", "two", "three"]
+    zip1 = zip(short, long)
+    zip2 = zip(short, words)
+  assert zip1 == @[(1, 6), (2, 5), (3, 4)]
+  assert zip2 == @[(1, "one"), (2, "two"), (3, "three")]
+  assert zip1[2].b == 4
+  assert zip2[2].b == "three"
+
+  # filter proc test
+  let
+    colors = @["red", "yellow", "black"]
+    f1 = filter(colors, proc(x: string): bool = x.len < 6)
+    f2 = filter(colors) do (x: string) -> bool : x.len > 5
+  assert f1 == @["red", "black"]
+  assert f2 == @["yellow"]
+
+  # filter iterator test
+  let numbers = @[1, 4, 5, 8, 9, 7, 4]
+  for n in filter(numbers, proc (x: int): bool = x mod 2 == 0):
+    echo($n)
+  # echoes 4, 8, 4 in separate lines
+
+  # filterIt test
+  let
+    temperatures = @[-272.15, -2.0, 24.5, 44.31, 99.9, -113.44]
+    acceptable = filterIt(temperatures, it < 50 and it > -10)
+  assert acceptable == @[-2.0, 24.5, 44.31]
+
+  # toSeq test
+  let
+    numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
+    odd_numbers = toSeq(filter(numeric) do (x: int) -> bool:
+      if x mod 2 == 1:
+        result = true)
+  assert odd_numbers == @[1, 3, 5, 7, 9]
+
+  echo "Finished doc tests"
diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim
index fc394d1f8..4290af08a 100755
--- a/lib/pure/collections/tables.nim
+++ b/lib/pure/collections/tables.nim
@@ -308,6 +308,52 @@ proc `$`*[A, B](t: TOrderedTable[A, B]): string =
   ## The `$` operator for ordered hash tables.
   dollarImpl()
 
+proc sort*[A, B](t: var TOrderedTable[A, B], 
+                 cmp: proc (x,y: tuple[key: A, val: B]): int) =
+  ## sorts `t` according to `cmp`. This modifies the internal list
+  ## that kept the insertion order, so insertion order is lost after this
+  ## call but key lookup and insertions remain possible after `sort` (in
+  ## contrast to the `sort` for count tables).
+  var list = t.first
+  var
+    p, q, e, tail, oldhead: int
+    nmerges, psize, qsize, i: int
+  if t.counter == 0: return
+  var insize = 1
+  while true:
+    p = list; oldhead = list
+    list = -1; tail = -1; nmerges = 0
+    while p >= 0:
+      inc(nmerges)
+      q = p
+      psize = 0
+      i = 0
+      while i < insize:
+        inc(psize)
+        q = t.data[q].next
+        if q < 0: break 
+        inc(i)
+      qsize = insize
+      while psize > 0 or (qsize > 0 and q >= 0):
+        if psize == 0:
+          e = q; q = t.data[q].next; dec(qsize)
+        elif qsize == 0 or q < 0:
+          e = p; p = t.data[p].next; dec(psize)
+        elif cmp((t.data[p].key, t.data[p].val), 
+                 (t.data[q].key, t.data[q].val)) <= 0:
+          e = p; p = t.data[p].next; dec(psize)
+        else:
+          e = q; q = t.data[q].next; dec(qsize)
+        if tail >= 0: t.data[tail].next = e
+        else: list = e
+        tail = e
+      p = q
+    t.data[tail].next = -1
+    if nmerges <= 1: break
+    insize = insize * 2
+  t.first = list
+  t.last = tail
+
 # ------------------------------ count tables -------------------------------
 
 type
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index cee135f08..cca1e4a70 100755
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -541,6 +541,11 @@ proc newJString*(s: String): PJsonNode =
   result.kind = JString
   result.str = s
 
+proc newJStringMove(s: String): PJsonNode =
+  new(result)
+  result.kind = JString
+  shallowCopy(result.str, s)
+
 proc newJInt*(n: biggestInt): PJsonNode =
   ## Creates a new `JInt PJsonNode`.
   new(result)
@@ -809,7 +814,9 @@ proc parseJson(p: var TJsonParser): PJsonNode =
   ## Parses JSON from a JSON Parser `p`.
   case p.tok
   of tkString:
-    result = newJString(p.a)
+    # we capture 'p.a' here, so we need to give it a fresh buffer afterwards:
+    result = newJStringMove(p.a)
+    p.a = ""
     discard getTok(p)
   of tkInt:
     result = newJInt(parseBiggestInt(p.a))
diff --git a/lib/system.nim b/lib/system.nim
index 3d17b1d6d..26e5ac228 100755
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -1461,14 +1461,14 @@ proc pop*[T](s: var seq[T]): T {.inline, noSideEffect.} =
   setLen(s, L)
 
 proc each*[T, S](data: openArray[T], op: proc (x: T): S {.closure.}): seq[S] = 
-  ## The well-known ``map`` operation from functional programming. Applies
+  ## The well-known `map`:idx: operation from functional programming. Applies
   ## `op` to every item in `data` and returns the result as a sequence.
   newSeq(result, data.len)
   for i in 0..data.len-1: result[i] = op(data[i])
 
 proc each*[T](data: var openArray[T], op: proc (x: var T) {.closure.}) =
-  ## The well-known ``map`` operation from functional programming. Applies
-  ## `op` to every item in `data`.
+  ## The well-known `map`:idx: operation from functional programming. Applies
+  ## `op` to every item in `data` modifying it directly.
   for i in 0..data.len-1: op(data[i])
 
 iterator fields*[T: tuple](x: T): TObject {.
diff --git a/lib/wrappers/lua/lua.nim b/lib/wrappers/lua/lua.nim
index 000e09993..0346c4285 100755
--- a/lib/wrappers/lua/lua.nim
+++ b/lib/wrappers/lua/lua.nim
@@ -35,19 +35,32 @@
 #**   In french or in english
 #
 
-when defined(MACOSX): 
-  const 
-    NAME* = "liblua(|5.2|5.1|5.0).dylib"
-    LIB_NAME* = "liblua(|5.2|5.1|5.0).dylib"
-elif defined(UNIX): 
-  const 
-    NAME* = "liblua(|5.2|5.1|5.0).so(|.0)"
-    LIB_NAME* = "liblua(|5.2|5.1|5.0).so(|.0)"
-else: 
-  const 
-    NAME* = "lua(|5.2|5.1|5.0).dll"
-    LIB_NAME* = "lua(|5.2|5.1|5.0).dll"
-
+when defined(useLuajit):
+  when defined(MACOSX):
+    const
+      NAME* = "libluajit.dylib"
+      LIB_NAME* = "libluajit.dylib"
+  elif defined(UNIX):
+    const
+      NAME* = "libluajit.so(|.0)"
+      LIB_NAME* = "libluajit.so(|.0)"
+  else:
+    const
+      NAME* = "luajit.dll"
+      LIB_NAME* = "luajit.dll"
+else:
+  when defined(MACOSX):
+    const
+      NAME* = "liblua(|5.2|5.1|5.0).dylib"
+      LIB_NAME* = "liblua(|5.2|5.1|5.0).dylib"
+  elif defined(UNIX):
+    const
+      NAME* = "liblua(|5.2|5.1|5.0).so(|.0)"
+      LIB_NAME* = "liblua(|5.2|5.1|5.0).so(|.0)"
+  else:
+    const 
+      NAME* = "lua(|5.2|5.1|5.0).dll"
+      LIB_NAME* = "lua(|5.2|5.1|5.0).dll"
 
 const 
   VERSION* = "Lua 5.1"
diff --git a/tests/run/ttables.nim b/tests/run/ttables.nim
index 3eb17a803..681ff5424 100755
--- a/tests/run/ttables.nim
+++ b/tests/run/ttables.nim
@@ -19,6 +19,25 @@ const
     "50": 344490, "60": 344491, "70": 344492,
     "80": 344497}
 
+  sorteddata = {
+    "---00": 346677844,
+    "0": 34404,
+    "1": 344004,
+    "10": 34484, 
+    "11": 34474,
+    "12": 789,
+    "19": 34464,
+    "2": 344774, "20": 34454, 
+    "3": 342244, "30": 34141244,
+    "34": 123456,
+    "4": 3412344, "40": 344114,
+    "5": 341232144, "50": 344490, 
+    "6": 34214544, "60": 344491,
+    "7": 3434544, "70": 344492,
+    "8": 344544, "80": 344497,
+    "9": 34435644,
+    "90": 343}
+
 block tableTest1:
   var t = initTable[tuple[x, y: int], string]()
   t[(0,0)] = "00"
@@ -86,5 +105,25 @@ block countTableTest1:
 block SyntaxTest:
   var x = toTable[int, string]({:})
 
+proc orderedTableSortTest() =
+  var t = initOrderedTable[string, int](2)
+  for key, val in items(data): t[key] = val
+  for key, val in items(data): assert t[key] == val
+  t.sort(proc (x, y: tuple[key: string, val: int]): int = cmp(x.key, y.key))
+  var i = 0
+  # `pairs` needs to yield in sorted order:
+  for key, val in pairs(t):
+    doAssert key == sorteddata[i][0]
+    doAssert val == sorteddata[i][1]
+    inc(i)
+
+  # check that lookup still works:
+  for key, val in pairs(t):
+    doAssert val == t[key]
+  # check that insert still works:
+  t["newKeyHere"] = 80
+
+
+orderedTableSortTest()
 echo "true"