summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--doc/tut1.txt8
-rw-r--r--doc/tut2.txt4
-rw-r--r--examples/statcsv.nim2
-rw-r--r--lib/alloc.nim6
-rw-r--r--lib/ansi_c.nim1
-rw-r--r--lib/cellsets.nim196
-rw-r--r--lib/mm.nim1
-rw-r--r--nim/highlite.pas3
-rw-r--r--nim/strutils.pas8
-rw-r--r--pycompab.py103
-rw-r--r--rod/nimrod.cfg7
11 files changed, 324 insertions, 15 deletions
diff --git a/doc/tut1.txt b/doc/tut1.txt
index 58a56e8f1..237663cdc 100644
--- a/doc/tut1.txt
+++ b/doc/tut1.txt
@@ -522,7 +522,7 @@ Result variable
 ---------------
 A procedure that returns a value has an implicit ``result`` variable that
 represents the return value. A ``return`` statement with no expression is a
-shorthand for ``return result``. So all tree code snippets are equivalent:
+shorthand for ``return result``. So all three code snippets are equivalent:
 
 .. code-block:: nimrod
   return 42
@@ -556,7 +556,7 @@ caller, a ``var`` parameter can be used:
 
 In the example, ``res`` and ``remainder`` are `var parameters`.
 Var parameters can be modified by the procedure and the changes are
-visible to the caller. 
+visible to the caller.
 
 
 Discard statement
@@ -952,8 +952,8 @@ Operation             Comment
 ``dec(x, n)``         decrements `x` by `n`; `n` is an integer
 ``succ(x)``           returns the successor of `x`
 ``succ(x, n)``        returns the `n`'th successor of `x`
-``succ(x)``           returns the predecessor of `x`
-``succ(x, n)``        returns the `n`'th predecessor of `x`
+``prec(x)``           returns the predecessor of `x`
+``pred(x, n)``        returns the `n`'th predecessor of `x`
 -----------------     --------------------------------------------------------
 
 The ``inc dec succ pred`` operations can fail by raising an `EOutOfRange` or
diff --git a/doc/tut2.txt b/doc/tut2.txt
index 6d2fd3094..114039887 100644
--- a/doc/tut2.txt
+++ b/doc/tut2.txt
@@ -34,7 +34,7 @@ While Nimrod's support for object oriented programming (OOP) is minimalistic,
 powerful OOP technics can be used. OOP is seen as *one* way to design a 
 program, not *the only* way. Often a procedural approach leads to simpler
 and more efficient code. In particular, prefering aggregation over inheritance
-often yields to a better design.
+often results in a better design.
 
 
 Objects
@@ -422,7 +422,7 @@ containers:
     else:
       var it = root
       while it != nil:
-        # compare the data items; uses the generic ``cmd`` proc
+        # compare the data items; uses the generic ``cmp`` proc
         # that works for any type that has a ``==`` and ``<`` operator
         var c = cmp(it.data, n.data) 
         if c < 0:
diff --git a/examples/statcsv.nim b/examples/statcsv.nim
index 9c1ebd113..e2f272a21 100644
--- a/examples/statcsv.nim
+++ b/examples/statcsv.nim
@@ -6,7 +6,7 @@
 import os, streams, parsecsv, strutils, math
 
 if paramCount() < 1:
-  quit("Usage: sumcsv filename[.csv]")
+  quit("Usage: statcsv filename[.csv]")
 
 var filename = appendFileExt(ParamStr(1), "csv")
 var s = newFileStream(filename, fmRead)
diff --git a/lib/alloc.nim b/lib/alloc.nim
index e4d828449..95feff854 100644
--- a/lib/alloc.nim
+++ b/lib/alloc.nim
@@ -493,6 +493,10 @@ proc rawDealloc(a: var TAllocator, p: pointer) =
     f.zeroField = 0
     f.next = c.freeList
     c.freeList = f
+    when overwriteFree: 
+      # set to 0xff to check for usage after free bugs:
+      c_memset(cast[pointer](cast[int](p) +% sizeof(TFreeCell)), -1'i32, 
+               s -% sizeof(TFreeCell))
     # check if it is not in the freeSmallChunks[s] list:
     if c.free < s:
       assert c notin a.freeSmallChunks[s div memAlign]
@@ -506,6 +510,8 @@ proc rawDealloc(a: var TAllocator, p: pointer) =
         c.size = SmallChunkSize
         freeBigChunk(a, cast[PBigChunk](c))
   else:
+    # set to 0xff to check for usage after free bugs:
+    when overwriteFree: c_memset(p, -1'i32, c.size -% bigChunkOverhead())
     # free big chunk
     freeBigChunk(a, cast[PBigChunk](c))
 
diff --git a/lib/ansi_c.nim b/lib/ansi_c.nim
index 81abd2a3e..f307fb9ab 100644
--- a/lib/ansi_c.nim
+++ b/lib/ansi_c.nim
@@ -15,6 +15,7 @@ proc c_strcmp(a, b: CString): cint {.nodecl, importc: "strcmp".}
 proc c_memcmp(a, b: CString, size: cint): cint {.nodecl, importc: "memcmp".}
 proc c_memcpy(a, b: CString, size: cint) {.nodecl, importc: "memcpy".}
 proc c_strlen(a: CString): cint {.nodecl, importc: "strlen".}
+proc c_memset(p: pointer, value: cint, size: int) {.nodecl, importc: "memset".}
 
 type
   C_TextFile {.importc: "FILE", nodecl, final.} = object   # empty record for
diff --git a/lib/cellsets.nim b/lib/cellsets.nim
new file mode 100644
index 000000000..0ce83864c
--- /dev/null
+++ b/lib/cellsets.nim
@@ -0,0 +1,196 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2009 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# Efficient set of pointers for the GC (and repr)
+
+type
+  TCell {.pure.} = object
+    refcount: int  # the refcount and some flags
+    typ: PNimType
+    when debugGC:
+      filename: cstring
+      line: int
+
+  PCell = ptr TCell
+
+  PPageDesc = ptr TPageDesc
+  TBitIndex = range[0..UnitsPerPage-1]
+  TPageDesc {.final, pure.} = object
+    next: PPageDesc # all nodes are connected with this pointer
+    key: TAddress   # start address at bit 0
+    bits: array[TBitIndex, int] # a bit vector
+
+  PPageDescArray = ptr array[0..1000_000, PPageDesc]
+  TCellSet {.final, pure.} = object
+    counter, max: int
+    head: PPageDesc
+    data: PPageDescArray
+
+  PCellArray = ptr array[0..100_000_000, PCell]
+  TCellSeq {.final, pure.} = object
+    len, cap: int
+    d: PCellArray
+
+# ------------------- cell set handling ---------------------------------------
+
+proc contains(s: TCellSeq, c: PCell): bool {.inline.} =
+  for i in 0 .. s.len-1:
+    if s.d[i] == c: return True
+  return False
+
+proc add(s: var TCellSeq, c: PCell) {.inline.} =
+  if s.len >= s.cap:
+    s.cap = s.cap * 3 div 2
+    var d = cast[PCellArray](alloc(s.cap * sizeof(PCell)))
+    copyMem(d, s.d, s.len * sizeof(PCell))
+    dealloc(s.d)
+    s.d = d
+    # XXX: realloc?
+  s.d[s.len] = c
+  inc(s.len)
+
+proc init(s: var TCellSeq, cap: int = 1024) =
+  s.len = 0
+  s.cap = cap
+  s.d = cast[PCellArray](alloc0(cap * sizeof(PCell)))
+
+proc deinit(s: var TCellSeq) = 
+  dealloc(s.d)
+  s.d = nil
+  s.len = 0
+  s.cap = 0
+
+const
+  InitCellSetSize = 1024 # must be a power of two!
+
+proc Init(s: var TCellSet) =
+  s.data = cast[PPageDescArray](alloc0(InitCellSetSize * sizeof(PPageDesc)))
+  s.max = InitCellSetSize-1
+  s.counter = 0
+  s.head = nil
+
+proc Deinit(s: var TCellSet) =
+  var it = s.head
+  while it != nil:
+    var n = it.next
+    dealloc(it)
+    it = n
+  s.head = nil # play it safe here
+  dealloc(s.data)
+  s.data = nil
+  s.counter = 0
+
+proc nextTry(h, maxHash: int): int {.inline.} =
+  result = ((5*h) + 1) and maxHash
+  # For any initial h in range(maxHash), repeating that maxHash times
+  # generates each int in range(maxHash) exactly once (see any text on
+  # random-number generation for proof).
+  
+proc CellSetGet(t: TCellSet, key: TAddress): PPageDesc =
+  var h = cast[int](key) and t.max
+  while t.data[h] != nil:
+    if t.data[h].key == key: return t.data[h]
+    h = nextTry(h, t.max)
+  return nil
+
+proc CellSetRawInsert(t: TCellSet, data: PPageDescArray, desc: PPageDesc) =
+  var h = cast[int](desc.key) and t.max
+  while data[h] != nil:
+    assert(data[h] != desc)
+    h = nextTry(h, t.max)
+  assert(data[h] == nil)
+  data[h] = desc
+
+proc CellSetEnlarge(t: var TCellSet) =
+  var oldMax = t.max
+  t.max = ((t.max+1)*2)-1
+  var n = cast[PPageDescArray](alloc0((t.max + 1) * sizeof(PPageDesc)))
+  for i in 0 .. oldmax:
+    if t.data[i] != nil:
+      CellSetRawInsert(t, n, t.data[i])
+  dealloc(t.data)
+  t.data = n
+
+proc CellSetPut(t: var TCellSet, key: TAddress): PPageDesc =
+  var h = cast[int](key) and t.max
+  while true:
+    var x = t.data[h]
+    if x == nil: break
+    if x.key == key: return x
+    h = nextTry(h, t.max)
+
+  if ((t.max+1)*2 < t.counter*3) or ((t.max+1)-t.counter < 4):
+    CellSetEnlarge(t)
+  inc(t.counter)
+  h = cast[int](key) and t.max
+  while t.data[h] != nil: h = nextTry(h, t.max)
+  assert(t.data[h] == nil)
+  # the new page descriptor goes into result
+  result = cast[PPageDesc](alloc0(sizeof(TPageDesc)))
+  result.next = t.head
+  result.key = key
+  t.head = result
+  t.data[h] = result
+
+# ---------- slightly higher level procs --------------------------------------
+
+proc contains(s: TCellSet, cell: PCell): bool =
+  var u = cast[TAddress](cell)
+  var t = CellSetGet(s, u shr PageShift)
+  if t != nil:
+    u = (u %% PageSize) /% MemAlign
+    result = (t.bits[u shr IntShift] and (1 shl (u and IntMask))) != 0
+  else:
+    result = false
+
+proc incl(s: var TCellSet, cell: PCell) {.noinline.} =
+  var u = cast[TAddress](cell)
+  var t = CellSetPut(s, u shr PageShift)
+  u = (u %% PageSize) /% MemAlign
+  t.bits[u shr IntShift] = t.bits[u shr IntShift] or (1 shl (u and IntMask))
+
+proc excl(s: var TCellSet, cell: PCell) =
+  var u = cast[TAddress](cell)
+  var t = CellSetGet(s, u shr PageShift)
+  if t != nil:
+    u = (u %% PageSize) /% MemAlign
+    t.bits[u shr IntShift] = (t.bits[u shr IntShift] and
+                              not (1 shl (u and IntMask)))
+
+proc containsOrIncl(s: var TCellSet, cell: PCell): bool = 
+  var u = cast[TAddress](cell)
+  var t = CellSetGet(s, u shr PageShift)
+  if t != nil:
+    u = (u %% PageSize) /% MemAlign
+    result = (t.bits[u shr IntShift] and (1 shl (u and IntMask))) != 0
+    if not result: 
+      t.bits[u shr IntShift] = t.bits[u shr IntShift] or
+          (1 shl (u and IntMask))
+  else: 
+    Incl(s, cell)
+    result = false
+
+iterator elements(t: TCellSet): PCell {.inline.} =
+  # while traversing it is forbidden to add pointers to the tree!
+  var r = t.head
+  while r != nil:
+    var i = 0
+    while i <= high(r.bits):
+      var w = r.bits[i] # taking a copy of r.bits[i] here is correct, because
+      # modifying operations are not allowed during traversation
+      var j = 0
+      while w != 0:         # test all remaining bits for zero
+        if (w and 1) != 0:  # the bit is set!
+          yield cast[PCell]((r.key shl PageShift) or
+                              (i shl IntShift +% j) *% MemAlign)
+        inc(j)
+        w = w shr 1
+      inc(i)
+    r = r.next
+
diff --git a/lib/mm.nim b/lib/mm.nim
index 5f16f7304..3bfb8a689 100644
--- a/lib/mm.nim
+++ b/lib/mm.nim
@@ -23,6 +23,7 @@ const
   reallyOsDealloc = true
   coalescRight = true
   coalescLeft = true
+  overwriteFree = false
 
 type
   PPointer = ptr pointer
diff --git a/nim/highlite.pas b/nim/highlite.pas
index ad7a6f724..1867268d3 100644
--- a/nim/highlite.pas
+++ b/nim/highlite.pas
@@ -358,7 +358,8 @@ begin
     end
   end;
   g.len := pos - g.pos;
-  if (g.kind <> gtEof) and (g.len <= 0) then InternalError('nimNextToken');
+  if (g.kind <> gtEof) and (g.len <= 0) then 
+    InternalError('nimNextToken: ' + toString(g.buf));
   g.pos := pos;
 end;
 
diff --git a/nim/strutils.pas b/nim/strutils.pas
index cd07105be..377d3abc6 100644
--- a/nim/strutils.pas
+++ b/nim/strutils.pas
@@ -1,7 +1,7 @@
 //
 //
 //           The Nimrod Compiler
-//        (c) Copyright 2008 Andreas Rumpf
+//        (c) Copyright 2009 Andreas Rumpf
 //
 //    See the file "copying.txt", included in this
 //    distribution, for details about the copyright.
@@ -45,6 +45,7 @@ function toString(i: BiggestInt): string; overload;
 //function toString(i: int): string; overload;
 function ToStringF(const r: Real): string; overload;
 function ToString(b: Boolean): string; overload;
+function ToString(b: PChar): string; overload;
 
 function IntToStr(i: BiggestInt; minChars: int): string;
 
@@ -415,6 +416,11 @@ begin
   result := sysUtils.intToStr(i);
 end;
 
+function ToString(b: PChar): string; overload;
+begin
+  result := string(b);
+end;
+
 function normalize(const s: string): string;
 var
   i: int;
diff --git a/pycompab.py b/pycompab.py
new file mode 100644
index 000000000..3121856ef
--- /dev/null
+++ b/pycompab.py
@@ -0,0 +1,103 @@
+""" Python compability library

+    

+    With careful and painful coding, compability from Python 1.5.2 up to 3.0

+    is achieved. Don't try this at home.

+

+    Copyright 2009, Andreas Rumpf

+"""

+

+import sys

+

+python3 = sys.version[0] >= "3"

+python26 = sys.version[:3] == "2.6"

+

+true, false = 0==0, 0==1

+

+if python3:

+  sys.exit("This script does not yet work with Python 3.0")

+

+try:

+  from cStringIO import StringIO

+except ImportError:

+  from io import StringIO

+

+if python3:

+  def replace(s, a, b): return s.replace(a, b)

+  def lower(s): return s.lower()

+  def join(a, s=""): return s.join(a)

+  def find(s, a): return s.find(a)

+  def split(s, a=None): return s.split(a)

+  def strip(s): return s.strip()

+

+  def has_key(dic, key): return key in dic

+else:

+  from string import replace, lower, join, find, split, strip

+

+  def has_key(dic, key): return dic.has_key(key)

+

+if not python3 and not python26:

+  import md5

+  def newMD5(): return md5.new()

+  def MD5update(obj, x):

+    return obj.update(x)

+else:

+  import hashlib

+  def newMD5(): return hashlib.md5()

+  def MD5update(obj, x):

+    if python26:

+      return obj.update(x)

+    else:

+      return obj.update(bytes(x, "utf-8"))

+

+def mydigest(hasher):

+  result = ""

+  for c in hasher.digest():

+    if python3:

+      x = hex(c)[2:]

+    else:

+      x = hex(ord(c))[2:]

+    if len(x) == 1: x = "0" + x

+    result = result + x

+  return result

+

+def Subs(frmt, *args, **substitution):

+  DIGITS = "0123456789"

+  LETTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

+  chars = DIGITS+LETTERS+"_"

+  d = substitution

+  a = args

+  result = []

+  i = 0

+  L = len(frmt)

+  while i < L:

+    if frmt[i] == '$':

+      i = i+1

+      if frmt[i] == '$':

+        result.append('$')

+        i = i+1

+      elif frmt[i] == '{':

+        i = i+1

+        j = i

+        while frmt[i] != '}': i = i+1

+        i = i+1 # skip }

+        x = frmt[j:i-1]

+        if x[0] in DIGITS:

+          result.append(str(a[int(x)-1]))

+        else:

+          result.append(str(d[x]))

+      elif frmt[i] in chars:

+        j = i

+        i = i+1

+        while i < len(frmt) and frmt[i] in chars: i = i + 1

+        x = frmt[j:i]

+        if x[0] in DIGITS:

+          result.append(str(a[int(x)-1]))

+        else:

+          result.append(str(d[x]))

+      else:

+        assert(false)

+    else:

+      result.append(frmt[i])

+      i = i+1

+  return join(result, "")

+

diff --git a/rod/nimrod.cfg b/rod/nimrod.cfg
index 65bb92bc5..d0293a5dd 100644
--- a/rod/nimrod.cfg
+++ b/rod/nimrod.cfg
@@ -5,12 +5,7 @@
 @if llvm_gcc or gcc:
   # GCC, LLVM and Visual C++ have a problem to optimize some modules.
   # This is really strange.
-  @if windows or macosX:
-    cgen.speed = "-O0"
-  @else:
-    cgen.speed = "-O1 -fno-strict-aliasing"
-  @end
+  cgen.speed = "-O0"
 @elif vcc:
   cgen.speed = ""
 @end
-