summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <andreas@andreas-desktop>2010-08-08 22:45:21 +0200
committerAndreas Rumpf <andreas@andreas-desktop>2010-08-08 22:45:21 +0200
commit8098e2a421bf26ad0f350f297f19f34619207443 (patch)
treeada62dabe6a38c7fbe47d65e2674b9070f2cef3c
parentc9e011e36cf400e1a2e5466a1339f716623508f7 (diff)
downloadNim-8098e2a421bf26ad0f350f297f19f34619207443.tar.gz
inlining of the write barrier for dlls
-rwxr-xr-xdoc/intern.txt10
-rwxr-xr-xdoc/nimrodc.txt25
-rwxr-xr-xdoc/pegdocs.txt2
-rwxr-xr-xlib/nimrtl.nim13
-rwxr-xr-xlib/pure/lexbase.nim3
-rwxr-xr-xlib/pure/os.nim134
-rwxr-xr-xlib/pure/osproc.nim69
-rwxr-xr-xlib/pure/parsecfg.nim51
-rwxr-xr-xlib/pure/parseopt.nim98
-rwxr-xr-xlib/pure/parseutils.nim20
-rwxr-xr-xlib/pure/pegs.nim91
-rwxr-xr-xlib/pure/ropes.nim42
-rwxr-xr-xlib/pure/strtabs.nim78
-rwxr-xr-xlib/pure/strutils.nim622
-rwxr-xr-xlib/pure/times.nim74
-rwxr-xr-xlib/pure/unicode.nim27
-rwxr-xr-xlib/system.nim62
-rwxr-xr-xlib/system/alloc.nim77
-rwxr-xr-xlib/system/dyncalls.nim5
-rwxr-xr-xlib/system/excpt.nim6
-rwxr-xr-xlib/system/gc.nim167
-rwxr-xr-xlib/system/inclrtl.nim1
-rwxr-xr-xlib/system/mmdisp.nim22
-rwxr-xr-xrod/semtempl.nim10
-rwxr-xr-xtodo.txt5
25 files changed, 860 insertions, 854 deletions
diff --git a/doc/intern.txt b/doc/intern.txt
index 50fc9b8b1..c347a498c 100755
--- a/doc/intern.txt
+++ b/doc/intern.txt
@@ -169,16 +169,6 @@ in mind:
   without the ``-w`` option helps!
 
 
-Generation of dynamic link libraries
-====================================
-
-Generation of dynamic link libraries or shared libraries is not difficult; the
-underlying C compiler already does all the hard work for us. The problem is the
-common runtime library, especially the memory manager. Note that Borland's
-Delphi had exactly the same problem. The workaround is to not link the GC with
-the Dll and provide an extra runtime dll that needs to be initialized.
-
-
 The Garbage Collector
 =====================
 
diff --git a/doc/nimrodc.txt b/doc/nimrodc.txt
index 1ada1fffb..997146ede 100755
--- a/doc/nimrodc.txt
+++ b/doc/nimrodc.txt
@@ -70,17 +70,22 @@ However, the generated C code is not platform independent. C code generated for
 Linux does not compile on Windows, for instance. The comment on top of the

 C file lists the OS, CPU and CC the file has been compiled for.

 
-..
-  DLL generation
-  ==============
 
-  Nimrod supports the generation of DLLs. However, there must be only one 
-  instance of the GC per process/address space. This instance is contained in
-  ``nimrtl.dll``. This means that every generated Nimrod DLL depends
-  on ``nimrtl.dll``. To generate the "nimrtl.dll" file, use the command::
-    
-    nimrod c -d:release lib/nimrtl.nim
-

+DLL generation
+==============
+
+Nimrod supports the generation of DLLs. However, there must be only one 
+instance of the GC per process/address space. This instance is contained in
+``nimrtl.dll``. This means that every generated Nimrod DLL depends
+on ``nimrtl.dll``. To generate the "nimrtl.dll" file, use the command::
+  
+  nimrod c -d:release lib/nimrtl.nim
+
+To link to ``nimrtl.dll`` use the command::
+
+  nimrod c -d:useNimRtl myprog.nim
+
+
 

 Additional Features

 ===================

diff --git a/doc/pegdocs.txt b/doc/pegdocs.txt
index 87b4e25bc..a97f7c765 100755
--- a/doc/pegdocs.txt
+++ b/doc/pegdocs.txt
@@ -88,6 +88,8 @@ macro              meaning
                    ``[^ \9-\13]``
 ``\w``             any "word" character: ``[a-zA-Z0-9_]``
 ``\W``             any "non-word" character: ``[^a-zA-Z0-9_]``
+``\a``             same as ``[a-zA-Z]``
+``\A``             same as ``[^a-zA-Z]``
 ``\n``             any newline combination: ``\10 / \13\10 / \13``
 ``\i``             ignore case for matching; use this at the start of the PEG
 ``\y``             ignore style for matching; use this at the start of the PEG
diff --git a/lib/nimrtl.nim b/lib/nimrtl.nim
index c61824f49..68b7d7bd9 100755
--- a/lib/nimrtl.nim
+++ b/lib/nimrtl.nim
@@ -11,23 +11,18 @@
 ## The default Nimrtl does not only contain the ``system`` module, but these 
 ## too:
 ##
-## * strutils
 ## * parseutils
+## * strutils
 ## * parseopt
 ## * parsecfg
 ## * strtabs
 ## * times
 ## * os
 ## * osproc
-## * pegs
 ## * unicode
+## * pegs
 ## * ropes
-## * re
 ## 
-## So the resulting dynamic library is quite big. However, it is very easy to
-## strip modules out. Just modify the ``import`` statement in
-## ``lib/nimrtl.nim`` and recompile. Note that simply *adding* a module
-## here is not sufficient, though.
 
 when system.appType != "lib":
   {.error: "This file has to be compiled as a library!".}
@@ -35,5 +30,7 @@ when system.appType != "lib":
 when not defined(createNimRtl): 
   {.error: "This file has to be compiled with '-d:createNimRtl'".}
 
-
+import
+  parseutils, strutils, parseopt, parsecfg, strtabs, unicode, pegs, ropes,
+  os, osproc, times
 
diff --git a/lib/pure/lexbase.nim b/lib/pure/lexbase.nim
index bb207e92a..c875e10bc 100755
--- a/lib/pure/lexbase.nim
+++ b/lib/pure/lexbase.nim
@@ -78,7 +78,8 @@ proc FillBuffer(L: var TBaseLexer) =
   toCopy = L.BufLen - L.sentinel - 1
   assert(toCopy >= 0)
   if toCopy > 0:
-    MoveMem(L.buf, addr(L.buf[L.sentinel + 1]), toCopy * chrSize) # "moveMem" handles overlapping regions
+    MoveMem(L.buf, addr(L.buf[L.sentinel + 1]), toCopy * chrSize) 
+    # "moveMem" handles overlapping regions
   charsRead = L.input.readData(L.input, addr(L.buf[toCopy]),
                                (L.sentinel + 1) * chrSize) div chrSize
   s = toCopy + charsRead
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index 39ff699bb..6ad39d5ca 100755
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -14,6 +14,8 @@
 
 {.push debugger: off.}
 
+include "system/inclrtl"
+
 import
   strutils, times
 
@@ -145,19 +147,7 @@ const
     ## The character which separates the base filename from the extension;
     ## for example, the '.' in ``os.nim``.
 
-# procs dealing with command line arguments:
-proc paramCount*(): int
-  ## Returns the number of command line arguments given to the
-  ## application.
-
-proc paramStr*(i: int): string
-  ## Returns the `i`-th command line arguments given to the
-  ## application.
-  ##
-  ## `i` should be in the range `1..paramCount()`, else
-  ## the `EOutOfIndex` exception is raised.
-
-proc OSError*(msg: string = "") {.noinline.} =
+proc OSError*(msg: string = "") {.noinline, rtl, extern: "nos$1".} =
   ## raises an EOS exception with the given message ``msg``.
   ## If ``msg == ""``, the operating system's error flag
   ## (``errno``) is converted to a readable error message. On Windows
@@ -182,7 +172,8 @@ proc OSError*(msg: string = "") {.noinline.} =
   else:
     raise newException(EOS, msg)
 
-proc UnixToNativePath*(path: string): string {.noSideEffect.} =
+proc UnixToNativePath*(path: string): string {.
+  noSideEffect, rtl, extern: "nos$1".} =
   ## Converts an UNIX-like path to a native one.
   ##
   ## On an UNIX system this does nothing. Else it converts
@@ -227,7 +218,7 @@ proc UnixToNativePath*(path: string): string {.noSideEffect.} =
         add result, path[i]
         inc(i)
 
-proc existsFile*(filename: string): bool =
+proc existsFile*(filename: string): bool {.rtl, extern: "nos$1".} =
   ## Returns true if the file exists, false otherwise.
   when defined(windows):
     var a = GetFileAttributesA(filename)
@@ -237,7 +228,7 @@ proc existsFile*(filename: string): bool =
     var res: TStat
     return stat(filename, res) >= 0'i32 and S_ISREG(res.st_mode)
 
-proc existsDir*(dir: string): bool =
+proc existsDir*(dir: string): bool {.rtl, extern: "nos$1".} =
   ## Returns true iff the directory `dir` exists. If `dir` is a file, false
   ## is returned.
   when defined(windows):
@@ -248,7 +239,7 @@ proc existsDir*(dir: string): bool =
     var res: TStat
     return stat(dir, res) >= 0'i32 and S_ISDIR(res.st_mode)
 
-proc getLastModificationTime*(file: string): TTime =
+proc getLastModificationTime*(file: string): TTime {.rtl, extern: "nos$1".} =
   ## Returns the `file`'s last modification time.
   when defined(posix):
     var res: TStat
@@ -261,7 +252,7 @@ proc getLastModificationTime*(file: string): TTime =
     result = winTimeToUnixTime(rdFileTime(f.ftLastWriteTime))
     findclose(h)
 
-proc getLastAccessTime*(file: string): TTime =
+proc getLastAccessTime*(file: string): TTime {.rtl, extern: "nos$1".} =
   ## Returns the `file`'s last read or write access time.
   when defined(posix):
     var res: TStat
@@ -274,7 +265,7 @@ proc getLastAccessTime*(file: string): TTime =
     result = winTimeToUnixTime(rdFileTime(f.ftLastAccessTime))
     findclose(h)
 
-proc getCreationTime*(file: string): TTime = 
+proc getCreationTime*(file: string): TTime {.rtl, extern: "nos$1".} = 
   ## Returns the `file`'s creation time.
   when defined(posix):
     var res: TStat
@@ -287,12 +278,12 @@ proc getCreationTime*(file: string): TTime =
     result = winTimeToUnixTime(rdFileTime(f.ftCreationTime))
     findclose(h)
 
-proc fileNewer*(a, b: string): bool =
+proc fileNewer*(a, b: string): bool {.rtl, extern: "nos$1".} =
   ## Returns true if the file `a` is newer than file `b`, i.e. if `a`'s
   ## modification time is later than `b`'s.
   result = getLastModificationTime(a) - getLastModificationTime(b) > 0
 
-proc getCurrentDir*(): string =
+proc getCurrentDir*(): string {.rtl, extern: "nos$1".} =
   ## Returns the current working directory.
   const bufsize = 512 # should be enough
   result = newString(bufsize)
@@ -314,7 +305,8 @@ proc setCurrentDir*(newDir: string) {.inline.} =
   else:
     if chdir(newDir) != 0'i32: OSError()
 
-proc JoinPath*(head, tail: string): string {.noSideEffect.} =
+proc JoinPath*(head, tail: string): string {.
+  noSideEffect, rtl, extern: "nos$1".} =
   ## Joins two directory names to one.
   ##
   ## For example on Unix:
@@ -342,7 +334,8 @@ proc JoinPath*(head, tail: string): string {.noSideEffect.} =
     else:
       result = head & DirSep & tail
 
-proc JoinPath*(parts: openarray[string]): string {.noSideEffect.} =
+proc JoinPath*(parts: openarray[string]): string {.noSideEffect,
+  rtl, extern: "nos$1OpenArray".} =
   ## The same as `JoinPath(head, tail)`, but works with any number
   ## of directory parts.
   result = parts[0]
@@ -370,7 +363,8 @@ proc SplitPath*(path: string, head, tail: var string) {.noSideEffect,
     head = ""
     tail = path # make a string copy here
 
-proc SplitPath*(path: string): tuple[head, tail: string] {.noSideEffect.} =
+proc SplitPath*(path: string): tuple[head, tail: string] {.
+  noSideEffect, rtl, extern: "nos$1".} =
   ## Splits a directory into (head, tail), so that
   ## ``JoinPath(head, tail) == path``.
   ##
@@ -395,7 +389,8 @@ proc SplitPath*(path: string): tuple[head, tail: string] {.noSideEffect.} =
     result.head = ""
     result.tail = path
 
-proc parentDir*(path: string): string {.noSideEffect.} =
+proc parentDir*(path: string): string {.
+  noSideEffect, rtl, extern: "nos$1".} =
   ## Returns the parent directory of `path`.
   ##
   ## This is often the same as the ``head`` result of ``splitPath``.
@@ -434,7 +429,8 @@ proc searchExtPos(s: string): int =
     elif s[i] in {dirsep, altsep}:
       break # do not skip over path
 
-proc splitFile*(path: string): tuple[dir, name, ext: string] {.noSideEffect.} =
+proc splitFile*(path: string): tuple[dir, name, ext: string] {.
+  noSideEffect, rtl, extern: "nos$1".} =
   ## Splits a filename into (dir, filename, extension).
   ## `dir` does not end in `DirSep`.
   ## `extension` includes the leading dot.
@@ -472,7 +468,8 @@ proc extractDir*(path: string): string {.noSideEffect, deprecated.} =
   ## **Deprecated since version 0.8.2**: Use ``splitFile(path).dir`` instead.
   result = splitFile(path).dir
 
-proc extractFilename*(path: string): string {.noSideEffect.} =
+proc extractFilename*(path: string): string {.
+  noSideEffect, rtl, extern: "nos$1".} =
   ## Extracts the filename of a given `path`. This is the same as 
   ## ``name & ext`` from ``splitFile(path)``.
   if path.len == 0 or path[path.len-1] in {dirSep, altSep}:
@@ -480,7 +477,7 @@ proc extractFilename*(path: string): string {.noSideEffect.} =
   else:
     result = splitPath(path).tail
 
-proc expandFilename*(filename: string): string =
+proc expandFilename*(filename: string): string {.rtl, extern: "nos$1".} =
   ## Returns the full path of `filename`, raises EOS in case of an error.
   when defined(windows):
     var unused: cstring
@@ -524,7 +521,8 @@ proc extractFileTrunk*(filename: string): string {.noSideEffect, deprecated.} =
   ## **Deprecated since version 0.8.2**: Use ``splitFile(path).name`` instead.
   result = splitFile(filename).name
   
-proc ChangeFileExt*(filename, ext: string): string {.noSideEffect.} =
+proc ChangeFileExt*(filename, ext: string): string {.
+  noSideEffect, rtl, extern: "nos$1".} =
   ## Changes the file extension to `ext`.
   ##
   ## If the `filename` has no extension, `ext` will be added.
@@ -536,7 +534,8 @@ proc ChangeFileExt*(filename, ext: string): string {.noSideEffect.} =
   if extPos < 0: result = filename & normExt(ext)
   else: result = copy(filename, 0, extPos-1) & normExt(ext)
 
-proc addFileExt*(filename, ext: string): string {.noSideEffect.} =
+proc addFileExt*(filename, ext: string): string {.
+  noSideEffect, rtl, extern: "nos$1".} =
   ## Adds the file extension `ext` to `filename`, unless
   ## `filename` already has an extension.
   ##
@@ -552,7 +551,8 @@ proc AppendFileExt*(filename, ext: string): string {.
   ## **Deprecated since version 0.8.2**: Use `addFileExt` instead.
   result = addFileExt(filename, ext)
 
-proc cmpPaths*(pathA, pathB: string): int {.noSideEffect.} =
+proc cmpPaths*(pathA, pathB: string): int {.
+  noSideEffect, rtl, extern: "nos$1".} =
   ## Compares two paths.
   ##
   ## On a case-sensitive filesystem this is done
@@ -566,7 +566,7 @@ proc cmpPaths*(pathA, pathB: string): int {.noSideEffect.} =
   else:
     result = cmpIgnoreCase(pathA, pathB)
 
-proc sameFile*(path1, path2: string): bool =
+proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1".} =
   ## Returns True if both pathname arguments refer to the same file or
   ## directory (as indicated by device number and i-node number).
   ## Raises an exception if an stat() call on either pathname fails.
@@ -590,7 +590,7 @@ proc sameFile*(path1, path2: string): bool =
     else:
       result = a.st_dev == b.st_dev and a.st_ino == b.st_ino
 
-proc sameFileContent*(path1, path2: string): bool =
+proc sameFileContent*(path1, path2: string): bool {.rtl, extern: "nos$1".} =
   ## Returns True if both pathname arguments refer to files with identical
   ## binary content.
   const
@@ -620,7 +620,7 @@ proc sameFileContent*(path1, path2: string): bool =
   close(a)
   close(b)
 
-proc copyFile*(dest, source: string) {.deprecated.} =
+proc copyFile*(dest, source: string) {.deprecated, rtl, extern: "nos$1".} =
   ## Copies a file from `source` to `dest`. If this fails,
   ## `EOS` is raised.
   ## **Deprecated since version 0.8.8**: Use this proc with named arguments
@@ -650,13 +650,13 @@ proc copyFile*(dest, source: string) {.deprecated.} =
     close(s)
     close(d)
 
-proc moveFile*(dest, source: string) {.deprecated.} =
+proc moveFile*(dest, source: string) {.deprecated, rtl, extern: "nos$1".} =
   ## Moves a file from `source` to `dest`. If this fails, `EOS` is raised.
   ## **Deprecated since version 0.8.8**: Use this proc with named arguments
   ## only, because the order will change!
   if crename(source, dest) != 0'i32: OSError()
 
-proc removeFile*(file: string) =
+proc removeFile*(file: string) {.rtl, extern: "nos$1".} =
   ## Removes the `file`. If this fails, `EOS` is raised.
   if cremove(file) != 0'i32: OSError()
 
@@ -664,7 +664,7 @@ proc executeShellCommand*(command: string): int {.deprecated.} =
   ## **Deprecated since version 0.8.2**: Use `execShellCmd` instead.
   result = csystem(command)
 
-proc execShellCmd*(command: string): int =
+proc execShellCmd*(command: string): int {.rtl, extern: "nos$1".} =
   ## Executes a shell command.
   ##
   ## Command has the form 'program args' where args are the command
@@ -675,6 +675,9 @@ proc execShellCmd*(command: string): int =
   ## module.
   result = csystem(command)
 
+# Environment handling cannot be put into RTL, because the ``envPairs`` 
+# iterator depends on ``environment``.
+
 var
   envComputed: bool = false
   environment: seq[string] = @[]
@@ -700,8 +703,8 @@ when defined(windows):
       discard FreeEnvironmentStringsA(env)
 
 else:
-  var
-    gEnv {.importc: "gEnv".}: ptr array [0..10_000, CString]
+  var gEnv {.importc: "environ".}: cstringArray
+  # var gEnv {.importc: "gEnv".}: cstringArray
 
   proc getEnvVarsC() =
     # retrieves the variables of char** env of C's main proc
@@ -897,7 +900,7 @@ proc rawRemoveDir(dir: string) =
   else:
     if rmdir(dir) != 0'i32: OSError()
 
-proc removeDir*(dir: string) =
+proc removeDir*(dir: string) {.rtl, extern: "nos$1".} =
   ## Removes the directory `dir` including all subdirectories and files
   ## in `dir` (recursively). If this fails, `EOS` is raised.
   for kind, path in walkDir(dir): 
@@ -914,7 +917,7 @@ proc rawCreateDir(dir: string) =
     if CreateDirectoryA(dir, nil) == 0'i32 and GetLastError() != 183'i32:
       OSError()
 
-proc createDir*(dir: string) =
+proc createDir*(dir: string) {.rtl, extern: "nos$1".} =
   ## Creates the directory `dir`.
   ##
   ## The directory may contain several subdirectories that do not exist yet.
@@ -925,7 +928,8 @@ proc createDir*(dir: string) =
     if dir[i] in {dirsep, altsep}: rawCreateDir(copy(dir, 0, i-1))
   rawCreateDir(dir)
 
-proc parseCmdLine*(c: string): seq[string] =
+proc parseCmdLine*(c: string): seq[string] {.
+  noSideEffect, rtl, extern: "nos$1".} =
   ## Splits a command line into several components;  
   ## This proc is only occassionally useful, better use the `parseopt` module.
   ##
@@ -1025,7 +1029,8 @@ type
     fpOthersWrite,         ## write access for others
     fpOthersRead           ## read access for others
 
-proc getFilePermissions*(filename: string): set[TFilePermission] =
+proc getFilePermissions*(filename: string): set[TFilePermission] {.
+  rtl, extern: "nos$1".} =
   ## retrieves file permissions for `filename`. `OSError` is raised in case of
   ## an error. On Windows, only the ``readonly`` flag is checked, every other
   ## permission is available in any case.
@@ -1053,7 +1058,8 @@ proc getFilePermissions*(filename: string): set[TFilePermission] =
     else:
       result = {fpUserExec..fpOthersRead}
   
-proc setFilePermissions*(filename: string, permissions: set[TFilePermission]) =
+proc setFilePermissions*(filename: string, permissions: set[TFilePermission]) {.
+  rtl, extern: "nos$1".} =
   ## sets the file permissions for `filename`. `OSError` is raised in case of
   ## an error. On Windows, only the ``readonly`` flag is changed, depending on
   ## ``fpUserWrite``.
@@ -1083,7 +1089,8 @@ proc setFilePermissions*(filename: string, permissions: set[TFilePermission]) =
       OSError()
   
 proc inclFilePermissions*(filename: string, 
-                          permissions: set[TFilePermission]) =
+                          permissions: set[TFilePermission]) {.
+  rtl, extern: "nos$1".} =
   ## a convenience procedure for: 
   ##
   ## .. code-block:: nimrod
@@ -1091,19 +1098,20 @@ proc inclFilePermissions*(filename: string,
   setFilePermissions(filename, getFilePermissions(filename)+permissions)
 
 proc exclFilePermissions*(filename: string, 
-                          permissions: set[TFilePermission]) =
+                          permissions: set[TFilePermission]) {.
+  rtl, extern: "nos$1".} =
   ## a convenience procedure for: 
   ##
   ## .. code-block:: nimrod
   ##   setFilePermissions(filename, getFilePermissions(filename)-permissions)
   setFilePermissions(filename, getFilePermissions(filename)-permissions)
 
-proc getHomeDir*(): string =
+proc getHomeDir*(): string {.rtl, extern: "nos$1".} =
   ## Returns the home directory of the current user.
   when defined(windows): return getEnv("USERPROFILE") & "\\"
   else: return getEnv("HOME") & "/"
 
-proc getConfigDir*(): string =
+proc getConfigDir*(): string {.rtl, extern: "nos$1".} =
   ## Returns the config directory of the current user for applications.
   when defined(windows): return getEnv("APPDATA") & "\\"
   else: return getEnv("HOME") & "/.config/"
@@ -1117,24 +1125,32 @@ when defined(windows):
   var
     ownArgv: seq[string]
 
-  proc paramStr(i: int): string =
+  proc paramCount*(): int {.rtl, extern: "nos$1".} =
+    ## Returns the number of command line arguments given to the
+    ## application.
     if isNil(ownArgv): ownArgv = parseCmdLine($getCommandLineA())
-    return ownArgv[i]
+    result = ownArgv.len-1
 
-  proc paramCount(): int =
+  proc paramStr*(i: int): string {.rtl, extern: "nos$1".} =
+    ## Returns the `i`-th command line argument given to the
+    ## application.
+    ##
+    ## `i` should be in the range `1..paramCount()`, else
+    ## the `EOutOfIndex` exception is raised.
     if isNil(ownArgv): ownArgv = parseCmdLine($getCommandLineA())
-    result = ownArgv.len-1
+    return ownArgv[i]
 
-else:
+elif not defined(createNimRtl):
+  # On Posix, there is no portable way to get the command line from a DLL.
   var
     cmdCount {.importc: "cmdCount".}: cint
     cmdLine {.importc: "cmdLine".}: cstringArray
 
-  proc paramStr(i: int): string =
+  proc paramStr*(i: int): string =
     if i < cmdCount and i >= 0: return $cmdLine[i]
     raise newException(EInvalidIndex, "invalid index")
 
-  proc paramCount(): int = return cmdCount-1
+  proc paramCount*(): int = return cmdCount-1
 
 when defined(linux) or defined(solaris) or defined(bsd) or defined(aix):
   proc getApplAux(procPath: string): string =
@@ -1153,7 +1169,7 @@ when defined(macosx):
   proc getExecPath2(c: cstring, size: var int32): bool {.
     importc: "_NSGetExecutablePath", header: "<mach-o/dyld.h>".}
 
-proc getApplicationFilename*(): string =
+proc getApplicationFilename*(): string {.rtl, extern: "nos$1".} =
   ## Returns the filename of the application's executable.
 
   # Linux: /proc/<pid>/exe
@@ -1190,11 +1206,11 @@ proc getApplicationFilename*(): string =
           var x = joinPath(p, result)
           if ExistsFile(x): return x
 
-proc getApplicationDir*(): string =
+proc getApplicationDir*(): string {.rtl, extern: "nos$1".} =
   ## Returns the directory of the application's executable.
   result = splitFile(getApplicationFilename()).dir
 
-proc sleep*(milsecs: int) =
+proc sleep*(milsecs: int) {.rtl, extern: "nos$1".} =
   ## sleeps `milsecs` milliseconds.
   when defined(windows):
     winlean.sleep(int32(milsecs))
@@ -1204,7 +1220,7 @@ proc sleep*(milsecs: int) =
     a.tv_nsec = (milsecs mod 1000) * 1000
     discard posix.nanosleep(a, b)
 
-proc getFileSize*(file: string): biggestInt =
+proc getFileSize*(file: string): biggestInt {.rtl, extern: "nos$1".} =
   ## returns the file size of `file`. Can raise ``EOS``. 
   when defined(windows):
     var a: TWin32FindData
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index 764a1f896..082851a81 100755
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -10,6 +10,8 @@
 ## This module implements an advanced facility for executing OS processes
 ## and process communication.
 
+include "system/inclrtl"
+
 import
   strutils, os, strtabs, streams
 
@@ -39,7 +41,8 @@ type
 
 proc execProcess*(command: string,
                   options: set[TProcessOption] = {poStdErrToStdOut,
-                                                  poUseShell}): string
+                                                  poUseShell}): string {.
+                                                  rtl, extern: "nosp$1".}
   ## A convience procedure that executes ``command`` with ``startProcess``
   ## and returns its output as a string.
 
@@ -50,7 +53,7 @@ proc executeProcess*(command: string,
   ## **Deprecated since version 0.8.2**: Use `execProcess` instead.
   result = execProcess(command, options)
 
-proc execCmd*(command: string): int
+proc execCmd*(command: string): int {.rtl, extern: "nosp$1".}
   ## Executes ``command`` and returns its error code. Standard input, output,
   ## error streams are inherited from the calling process.
 
@@ -62,8 +65,9 @@ proc executeCommand*(command: string): int {.deprecated.} =
 proc startProcess*(command: string,
                    workingDir: string = "",
                    args: openarray[string] = [],
-                   env: PStringTable = nil,
-                   options: set[TProcessOption] = {poStdErrToStdOut}): PProcess
+                   env: PStringTable = nil, 
+                   options: set[TProcessOption] = {poStdErrToStdOut}): 
+              PProcess {.rtl, extern: "nosp$1".}
   ## Starts a process. `Command` is the executable file, `workingDir` is the
   ## process's working directory. If ``workingDir == ""`` the current directory
   ## is used. `args` are the command line arguments that are passed to the
@@ -78,32 +82,32 @@ proc startProcess*(command: string,
   ## Return value: The newly created process object. Nil is never returned,
   ## but ``EOS`` is raised in case of an error.
 
-proc suspend*(p: PProcess)
+proc suspend*(p: PProcess) {.rtl, extern: "nosp$1".}
   ## Suspends the process `p`.
 
-proc resume*(p: PProcess)
+proc resume*(p: PProcess) {.rtl, extern: "nosp$1".}
   ## Resumes the process `p`.
 
-proc terminate*(p: PProcess)
+proc terminate*(p: PProcess) {.rtl, extern: "nosp$1".}
   ## Terminates the process `p`.
 
-proc running*(p: PProcess): bool
+proc running*(p: PProcess): bool {.rtl, extern: "nosp$1".}
   ## Returns true iff the process `p` is still running. Returns immediately.
 
-proc processID*(p: PProcess): int =
+proc processID*(p: PProcess): int {.rtl, extern: "nosp$1".} =
   ## returns `p`'s process ID.
   return p.id
 
-proc waitForExit*(p: PProcess): int
+proc waitForExit*(p: PProcess): int {.rtl, extern: "nosp$1".}
   ## waits for the process to finish and returns `p`'s error code.
 
-proc inputStream*(p: PProcess): PStream
+proc inputStream*(p: PProcess): PStream {.rtl, extern: "nosp$1".}
   ## returns ``p``'s input stream for writing to
 
-proc outputStream*(p: PProcess): PStream
+proc outputStream*(p: PProcess): PStream {.rtl, extern: "nosp$1".}
   ## returns ``p``'s output stream for reading from
 
-proc errorStream*(p: PProcess): PStream
+proc errorStream*(p: PProcess): PStream {.rtl, extern: "nosp$1".}
   ## returns ``p``'s output stream for reading from
 
 when defined(macosx) or defined(bsd):
@@ -115,7 +119,7 @@ when defined(macosx) or defined(bsd):
               a: var int, b: pointer, c: int): cint {.
              importc: "sysctl", header: "<sys/sysctl.h>".}
 
-proc countProcessors*(): int =
+proc countProcessors*(): int {.rtl, extern: "nosp$1".} =
   ## returns the numer of the processors/cores the machine has.
   ## Returns 0 if it cannot be detected.
   when defined(windows):
@@ -150,7 +154,7 @@ proc startProcessAux(cmd: string, options: set[TProcessOption]): PProcess =
 
 proc execProcesses*(cmds: openArray[string],
                     options = {poStdErrToStdOut, poParentStreams},
-                    n = countProcessors()): int =
+                    n = countProcessors()): int {.rtl, extern: "nosp$1".} =
   ## executes the commands `cmds` in parallel. Creates `n` processes
   ## that execute in parallel. The highest return value of all processes
   ## is returned.
@@ -192,27 +196,16 @@ proc execProcesses*(cmds: openArray[string],
       var p = startProcessAux(cmds[i], options=options)
       result = max(waitForExit(p), result)
 
-when true:
-  nil
-else:
-  proc startGUIProcess*(command: string,
-                     workingDir: string = "",
-                     args: openarray[string] = [],
-                     env: PStringTable = nil,
-                     x = -1,
-                     y = -1,
-                     width = -1,
-                     height = -1): PProcess
-
-proc execProcess(command: string,
-                 options: set[TProcessOption] = {poStdErrToStdOut,
-                                                 poUseShell}): string =
-  var p = startProcessAux(command, options=options)
-  var outp = outputStream(p)
-  result = ""
-  while running(p) or not outp.atEnd(outp):
-    result.add(outp.readLine())
-    result.add("\n")
+when not defined(useNimRtl):
+  proc execProcess(command: string,
+                   options: set[TProcessOption] = {poStdErrToStdOut,
+                                                   poUseShell}): string =
+    var p = startProcessAux(command, options=options)
+    var outp = outputStream(p)
+    result = ""
+    while running(p) or not outp.atEnd(outp):
+      result.add(outp.readLine())
+      result.add("\n")
 
 when false:
   proc deallocCStringArray(a: cstringArray) =
@@ -222,7 +215,7 @@ when false:
       inc(i)
     dealloc(a)
 
-when defined(Windows):
+when defined(Windows) and not defined(useNimRtl):
   # We need to implement a handle stream for Windows:
   type
     PFileHandleStream = ref TFileHandleStream
@@ -405,7 +398,7 @@ when defined(Windows):
         result = -1
       discard CloseHandle(Process)
 
-else:
+elif not defined(useNimRtl):
   const
     readIdx = 0
     writeIdx = 1
diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim
index 4f8f5347f..ae151ff94 100755
--- a/lib/pure/parsecfg.nim
+++ b/lib/pure/parsecfg.nim
@@ -27,6 +27,8 @@
 import 
   hashes, strutils, lexbase, streams
 
+include "system/inclrtl"
+
 type 
   TCfgEventKind* = enum ## enumation of all events that may occur when parsing
     cfgEof,             ## end of file reached
@@ -65,37 +67,17 @@ type
     state: TParserState
     filename: string
 
-proc open*(c: var TCfgParser, input: PStream, filename: string)
-  ## initializes the parser with an input stream. `Filename` is only used
-  ## for nice error messages.
-
-proc close*(c: var TCfgParser)
-  ## closes the parser `c` and its associated input stream.
-
-proc next*(c: var TCfgParser): TCfgEvent
-  ## retrieves the first/next event. This controls the parser.
-
-proc getColumn*(c: TCfgParser): int
-  ## get the current column the parser has arrived at.
-
-proc getLine*(c: TCfgParser): int
-  ## get the current line the parser has arrived at.
-  
-proc getFilename*(c: TCfgParser): string
-  ## get the filename of the file that the parser processes.
-
-proc errorStr*(c: TCfgParser, msg: string): string
-  ## returns a properly formated error message containing current line and
-  ## column information.
-
-
 # implementation
 
 const 
   SymChars: TCharSet = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\x80'..'\xFF'} 
   
 proc rawGetTok(c: var TCfgParser, tok: var TToken)
-proc open(c: var TCfgParser, input: PStream, filename: string) = 
+
+proc open*(c: var TCfgParser, input: PStream, filename: string) {.
+  rtl, extern: "npc$1".} =
+  ## initializes the parser with an input stream. `Filename` is only used
+  ## for nice error messages.
   lexbase.open(c, input)
   c.filename = filename
   c.state = startState
@@ -103,16 +85,20 @@ proc open(c: var TCfgParser, input: PStream, filename: string) =
   c.tok.literal = ""
   rawGetTok(c, c.tok)
   
-proc close(c: var TCfgParser) = 
+proc close*(c: var TCfgParser) {.rtl, extern: "npc$1".} =
+  ## closes the parser `c` and its associated input stream.
   lexbase.close(c)
 
-proc getColumn(c: TCfgParser): int = 
+proc getColumn*(c: TCfgParser): int {.rtl, extern: "npc$1".} =
+  ## get the current column the parser has arrived at.
   result = getColNumber(c, c.bufPos)
 
-proc getLine(c: TCfgParser): int = 
+proc getLine*(c: TCfgParser): int {.rtl, extern: "npc$1".} =
+  ## get the current line the parser has arrived at.
   result = c.linenumber
 
-proc getFilename(c: TCfgParser): string = 
+proc getFilename*(c: TCfgParser): string {.rtl, extern: "npc$1".} =
+  ## get the filename of the file that the parser processes.
   result = c.filename
 
 proc handleHexChar(c: var TCfgParser, xi: var int) = 
@@ -300,7 +286,9 @@ proc rawGetTok(c: var TCfgParser, tok: var TToken) =
     tok.literal = "[EOF]"
   else: getSymbol(c, tok)
   
-proc errorStr(c: TCfgParser, msg: string): string = 
+proc errorStr*(c: TCfgParser, msg: string): string {.rtl, extern: "npc$1".} =
+  ## returns a properly formated error message containing current line and
+  ## column information.
   result = `%`("$1($2, $3) Error: $4", 
                [c.filename, $getLine(c), $getColumn(c), msg])
 
@@ -323,7 +311,8 @@ proc getKeyValPair(c: var TCfgParser, kind: TCfgEventKind): TCfgEvent =
     result.msg = errorStr(c, "symbol expected, but found: " & c.tok.literal)
     rawGetTok(c, c.tok)
 
-proc next(c: var TCfgParser): TCfgEvent = 
+proc next*(c: var TCfgParser): TCfgEvent {.rtl, extern: "npc$1".} =
+  ## retrieves the first/next event. This controls the parser.
   case c.tok.kind  
   of tkEof: 
     result.kind = cfgEof
diff --git a/lib/pure/parseopt.nim b/lib/pure/parseopt.nim
index 8f4be98f4..1b09934f2 100755
--- a/lib/pure/parseopt.nim
+++ b/lib/pure/parseopt.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nimrod's Runtime Library
-#        (c) Copyright 2009 Andreas Rumpf
+#        (c) Copyright 2010 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -13,6 +13,8 @@
 
 {.push debugger: off.}
 
+include "system/inclrtl"
+
 import 
   os, strutils
 
@@ -32,24 +34,28 @@ type
                               ## or the argument, ``value`` is not "" if
                               ## the option was given a value
 
-proc initOptParser*(cmdline = ""): TOptParser =
-  ## inits the option parser. If ``cmdline == ""``, the real command line
-  ## (as provided by the ``OS`` module) is taken.
-  result.pos = 0
-  result.inShortState = false
-  if cmdline != "": 
-    result.cmd = cmdline
-  else: 
-    result.cmd = ""
-    for i in countup(1, ParamCount()): 
-      result.cmd = result.cmd & quoteIfContainsWhite(paramStr(i)) & ' '
-  result.kind = cmdEnd
-  result.key = ""
-  result.val = ""
+when defined(os.ParamCount):
+  # we cannot provide this for NimRtl creation on Posix, because we can't 
+  # access the command line arguments then!
 
-proc init*(cmdline: string = ""): TOptParser {.deprecated.} = 
-  ## **Deprecated since version 0.8.2**: Use `initOptParser` instead.
-  result = initOptParser(cmdline)
+  proc initOptParser*(cmdline = ""): TOptParser =
+    ## inits the option parser. If ``cmdline == ""``, the real command line
+    ## (as provided by the ``OS`` module) is taken.
+    result.pos = 0
+    result.inShortState = false
+    if cmdline != "": 
+      result.cmd = cmdline
+    else: 
+      result.cmd = ""
+      for i in countup(1, ParamCount()): 
+        result.cmd = result.cmd & quoteIfContainsWhite(paramStr(i)) & ' '
+    result.kind = cmdEnd
+    result.key = ""
+    result.val = ""
+
+  proc init*(cmdline: string = ""): TOptParser {.deprecated.} = 
+    ## **Deprecated since version 0.8.2**: Use `initOptParser` instead.
+    result = initOptParser(cmdline)
 
 proc parseWord(s: string, i: int, w: var string, 
                delim: TCharSet = {'\x09', ' ', '\0'}): int = 
@@ -82,7 +88,8 @@ proc handleShortOption(p: var TOptParser) =
   if p.cmd[i] == '\0': p.inShortState = false
   p.pos = i
 
-proc next*(p: var TOptParser) = 
+proc next*(p: var TOptParser) {.
+  rtl, extern: "npo$1".} = 
   ## parses the first or next option; ``p.kind`` describes what token has been
   ## parsed. ``p.key`` and ``p.val`` are set accordingly.
   var i = p.pos
@@ -116,7 +123,8 @@ proc next*(p: var TOptParser) =
     p.kind = cmdArgument
     p.pos = parseWord(p.cmd, i, p.key)
 
-proc cmdLineRest*(p: TOptParser): string = 
+proc cmdLineRest*(p: TOptParser): string {.
+  rtl, extern: "npo$1".} = 
   ## retrieves the rest of the command line that has not been parsed yet.
   result = strip(copy(p.cmd, p.pos, len(p.cmd) - 1)) 
 
@@ -124,29 +132,31 @@ proc getRestOfCommandLine*(p: TOptParser): string {.deprecated.} =
   ## **Deprecated since version 0.8.2**: Use `cmdLineRest` instead.
   result = cmdLineRest(p) 
 
-iterator getopt*(): tuple[kind: TCmdLineKind, key, val: string] =
-  ## This is an convenience iterator for iterating over the command line.
-  ## This uses the TOptParser object. Example:
-  ##
-  ## .. code-block:: nimrod
-  ##   var
-  ##     filename = ""
-  ##   for kind, key, val in getopt():
-  ##     case kind
-  ##     of cmdArgument: 
-  ##       filename = key
-  ##     of cmdLongOption, cmdShortOption:
-  ##       case key
-  ##       of "help", "h": writeHelp()
-  ##       of "version", "v": writeVersion()
-  ##     of cmdEnd: assert(false) # cannot happen
-  ##   if filename == "":
-  ##     # no filename has been given, so we show the help:
-  ##     writeHelp()
-  var p = initOptParser()
-  while true:
-    next(p)
-    if p.kind == cmdEnd: break
-    yield (p.kind, p.key, p.val)
+when defined(initOptParser):
+
+  iterator getopt*(): tuple[kind: TCmdLineKind, key, val: string] =
+    ## This is an convenience iterator for iterating over the command line.
+    ## This uses the TOptParser object. Example:
+    ##
+    ## .. code-block:: nimrod
+    ##   var
+    ##     filename = ""
+    ##   for kind, key, val in getopt():
+    ##     case kind
+    ##     of cmdArgument: 
+    ##       filename = key
+    ##     of cmdLongOption, cmdShortOption:
+    ##       case key
+    ##       of "help", "h": writeHelp()
+    ##       of "version", "v": writeVersion()
+    ##     of cmdEnd: assert(false) # cannot happen
+    ##   if filename == "":
+    ##     # no filename has been given, so we show the help:
+    ##     writeHelp()
+    var p = initOptParser()
+    while true:
+      next(p)
+      if p.kind == cmdEnd: break
+      yield (p.kind, p.key, p.val)
 
 {.pop.}
diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim
index 0f107793c..ea4b17b65 100755
--- a/lib/pure/parseutils.nim
+++ b/lib/pure/parseutils.nim
@@ -14,6 +14,8 @@
 {.push debugger:off .} # the user does not want to trace a part
                        # of the standard library!
 
+include "system/inclrtl"
+
 const
   Whitespace = {' ', '\t', '\v', '\r', '\l', '\f'}
   IdentChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'}
@@ -23,7 +25,8 @@ const
 proc toLower(c: char): char {.inline.} =
   result = if c in {'A'..'Z'}: chr(ord(c)-ord('A')+ord('a')) else: c
 
-proc parseHex*(s: string, number: var int, start = 0): int = 
+proc parseHex*(s: string, number: var int, start = 0): int {.
+  rtl, extern: "npuParseHex", noSideEffect.}  = 
   ## parses a hexadecimal number and stores its value in ``number``. Returns
   ## the number of the parsed characters or 0 in case of an error.
   var i = start
@@ -46,7 +49,8 @@ proc parseHex*(s: string, number: var int, start = 0): int =
     inc(i)
   if foundDigit: result = i-start
 
-proc parseOct*(s: string, number: var int, start = 0): int = 
+proc parseOct*(s: string, number: var int, start = 0): int  {.
+  rtl, extern: "npuParseOct", noSideEffect.} = 
   ## parses an octal number and stores its value in ``number``. Returns
   ## the number of the parsed characters or 0 in case of an error.
   var i = start
@@ -116,13 +120,15 @@ proc rawParseInt(s: string, b: var biggestInt, start = 0): int =
     result = i - start
 {.pop.} # overflowChecks
 
-proc parseBiggestInt*(s: string, number: var biggestInt, start = 0): int =
+proc parseBiggestInt*(s: string, number: var biggestInt, start = 0): int {.
+  rtl, extern: "npuParseBiggestInt", noSideEffect.} =
   ## parses an integer starting at `start` and stores the value into `number`.
   ## Result is the number of processed chars or 0 if there is no integer.
   ## `EOverflow` is raised if an overflow occurs.
   result = rawParseInt(s, number, start)
 
-proc parseInt*(s: string, number: var int, start = 0): int =
+proc parseInt*(s: string, number: var int, start = 0): int {.
+  rtl, extern: "npuParseInt", noSideEffect.} =
   ## parses an integer starting at `start` and stores the value into `number`.
   ## Result is the number of processed chars or 0 if there is no integer.
   ## `EOverflow` is raised if an overflow occurs.
@@ -134,7 +140,8 @@ proc parseInt*(s: string, number: var int, start = 0): int =
   else:
     number = int(res)
 
-proc parseBiggestFloat*(s: string, number: var biggestFloat, start = 0): int =
+proc parseBiggestFloat*(s: string, number: var biggestFloat, start = 0): int {.
+  rtl, extern: "npuParseBiggestFloat", noSideEffect.} =
   ## parses a float starting at `start` and stores the value into `number`.
   ## Result is the number of processed chars or 0 if there occured a parsing
   ## error.
@@ -206,7 +213,8 @@ proc parseBiggestFloat*(s: string, number: var biggestFloat, start = 0): int =
   number = number * sign
   result = i - start
 
-proc parseFloat*(s: string, number: var float, start = 0): int =
+proc parseFloat*(s: string, number: var float, start = 0): int {.
+  rtl, extern: "npuParseFloat", noSideEffect.} =
   ## parses a float starting at `start` and stores the value into `number`.
   ## Result is the number of processed chars or 0 if there occured a parsing
   ## error.
diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim
index 969ff8106..6942f97ef 100755
--- a/lib/pure/pegs.nim
+++ b/lib/pure/pegs.nim
@@ -15,6 +15,8 @@
 ## .. include:: ../doc/pegdocs.txt
 ##
 
+include "system/inclrtl"
+
 const
   useUnicode = true ## change this to deactivate proper UTF-8 support
 
@@ -79,7 +81,7 @@ type
   
   TPeg* = TNode ## type that represents a PEG
 
-proc term*(t: string): TPeg =
+proc term*(t: string): TPeg {.nosideEffect, rtl, extern: "npegs$1Str".} =
   ## constructs a PEG from a terminal string
   if t.len != 1:  
     result.kind = pkTerminal
@@ -88,23 +90,25 @@ proc term*(t: string): TPeg =
     result.kind = pkChar
     result.ch = t[0]
 
-proc termIgnoreCase*(t: string): TPeg =
+proc termIgnoreCase*(t: string): TPeg {.
+  nosideEffect, rtl, extern: "npegs$1".} =
   ## constructs a PEG from a terminal string; ignore case for matching
   result.kind = pkTerminalIgnoreCase
   result.term = t
 
-proc termIgnoreStyle*(t: string): TPeg =
+proc termIgnoreStyle*(t: string): TPeg {.
+  nosideEffect, rtl, extern: "npegs$1".} =
   ## constructs a PEG from a terminal string; ignore style for matching
   result.kind = pkTerminalIgnoreStyle
   result.term = t
 
-proc term*(t: char): TPeg =
+proc term*(t: char): TPeg {.nosideEffect, rtl, extern: "npegs$1Char".} =
   ## constructs a PEG from a terminal char
   assert t != '\0'
   result.kind = pkChar
   result.ch = t
   
-proc charSet*(s: set[char]): TPeg =
+proc charSet*(s: set[char]): TPeg {.nosideEffect, rtl, extern: "npegs$1".} =
   ## constructs a PEG from a character set `s`
   assert '\0' notin s
   result.kind = pkCharChoice
@@ -136,7 +140,8 @@ template multipleOp(k: TPegKind, localOpt: expr) =
   if result.len == 1:
     result = result.sons[0]
 
-proc `/`*(a: openArray[TPeg]): TPeg =
+proc `/`*(a: openArray[TPeg]): TPeg {.
+  nosideEffect, rtl, extern: "npegsOrderedChoice".} =
   ## constructs an ordered choice with the PEGs in `a`
   multipleOp(pkOrderedChoice, addChoice)
 
@@ -149,11 +154,12 @@ proc addSequence(dest: var TPeg, elem: TPeg) =
     else: add(dest, elem)
   else: add(dest, elem)
 
-proc sequence*(a: openArray[TPeg]): TPeg =
+proc sequence*(a: openArray[TPeg]): TPeg {.
+  nosideEffect, rtl, extern: "npegs$1".} =
   ## constructs a sequence with all the PEGs from `a`
   multipleOp(pkSequence, addSequence)
  
-proc `?`*(a: TPeg): TPeg =
+proc `?`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsOptional".} =
   ## constructs an optional for the PEG `a`
   if a.kind in {pkOption, pkGreedyRep, pkGreedyAny, pkGreedyRepChar,
                 pkGreedyRepSet}:
@@ -164,7 +170,7 @@ proc `?`*(a: TPeg): TPeg =
     result.kind = pkOption
     result.sons = @[a]
 
-proc `*`*(a: TPeg): TPeg =
+proc `*`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsGreedyRep".} =
   ## constructs a "greedy repetition" for the PEG `a`
   case a.kind
   of pkGreedyRep, pkGreedyRepChar, pkGreedyRepSet, pkGreedyAny, pkOption:
@@ -182,7 +188,7 @@ proc `*`*(a: TPeg): TPeg =
     result.kind = pkGreedyRep
     result.sons = @[a]
 
-proc `@`*(a: TPeg): TPeg =
+proc `@`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsSearch".} =
   ## constructs a "search" for the PEG `a`
   result.kind = pkSearch
   result.sons = @[a]
@@ -199,16 +205,16 @@ when false:
       for i in 0..a.sons.len-1:
         if contains(a.sons[i], k): return true
 
-proc `+`*(a: TPeg): TPeg =
+proc `+`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsGreedyPosRep".} =
   ## constructs a "greedy positive repetition" with the PEG `a`
   return sequence(a, *a)
   
-proc `&`*(a: TPeg): TPeg =
+proc `&`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsAndPredicate".} =
   ## constructs an "and predicate" with the PEG `a`
   result.kind = pkAndPredicate
   result.sons = @[a]
 
-proc `!`*(a: TPeg): TPeg =
+proc `!`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsNotPredicate".} =
   ## constructs a "not predicate" with the PEG `a`
   result.kind = pkNotPredicate
   result.sons = @[a]
@@ -225,24 +231,27 @@ proc newLine*: TPeg {.inline.} =
   ## constructs the PEG `newline`:idx: (``\n``)
   result.kind = pkNewline
 
-proc capture*(a: TPeg): TPeg =
+proc capture*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsCapture".} =
   ## constructs a capture with the PEG `a`
   result.kind = pkCapture
   result.sons = @[a]
 
-proc backref*(index: range[1..MaxSubPatterns]): TPeg = 
+proc backref*(index: range[1..MaxSubPatterns]): TPeg {.
+  nosideEffect, rtl, extern: "npegs$1".} = 
   ## constructs a back reference of the given `index`. `index` starts counting
   ## from 1.
   result.kind = pkBackRef
   result.index = index-1
 
-proc backrefIgnoreCase*(index: range[1..MaxSubPatterns]): TPeg = 
+proc backrefIgnoreCase*(index: range[1..MaxSubPatterns]): TPeg {.
+  nosideEffect, rtl, extern: "npegs$1".} = 
   ## constructs a back reference of the given `index`. `index` starts counting
   ## from 1. Ignores case for matching.
   result.kind = pkBackRefIgnoreCase
   result.index = index-1
 
-proc backrefIgnoreStyle*(index: range[1..MaxSubPatterns]): TPeg = 
+proc backrefIgnoreStyle*(index: range[1..MaxSubPatterns]): TPeg {.
+  nosideEffect, rtl, extern: "npegs$1".}= 
   ## constructs a back reference of the given `index`. `index` starts counting
   ## from 1. Ignores style for matching.
   result.kind = pkBackRefIgnoreStyle
@@ -263,7 +272,8 @@ proc spaceCost(n: TPeg): int =
       inc(result, spaceCost(n.sons[i]))
       if result >= InlineThreshold: break
 
-proc nonterminal*(n: PNonTerminal): TPeg = 
+proc nonterminal*(n: PNonTerminal): TPeg {.
+  nosideEffect, rtl, extern: "npegs$1".} = 
   ## constructs a PEG that consists of the nonterminal symbol
   assert n != nil
   if ntDeclared in n.flags and spaceCost(n.rule) < InlineThreshold:
@@ -273,7 +283,8 @@ proc nonterminal*(n: PNonTerminal): TPeg =
     result.kind = pkNonTerminal
     result.nt = n
 
-proc newNonTerminal*(name: string, line, column: int): PNonTerminal =
+proc newNonTerminal*(name: string, line, column: int): PNonTerminal {.
+  nosideEffect, rtl, extern: "npegs$1".} =
   ## constructs a nonterminal symbol
   new(result)
   result.name = name
@@ -432,7 +443,7 @@ proc toStrAux(r: TPeg, res: var string) =
       toStrAux(r.sons[i], res)
       add(res, "\n")  
 
-proc `$` *(r: TPeg): string =
+proc `$` *(r: TPeg): string {.nosideEffect, rtl, extern: "npegsToString".} =
   ## converts a PEG to its string representation
   result = ""
   toStrAux(r, result)
@@ -598,7 +609,7 @@ proc m(s: string, p: TPeg, start: int, c: var TMatchClosure): int =
   of pkRule, pkList: assert false
 
 proc match*(s: string, pattern: TPeg, matches: var openarray[string],
-            start = 0): bool =
+            start = 0): bool {.nosideEffect, rtl, extern: "npegs$1Capture".} =
   ## returns ``true`` if ``s[start..]`` matches the ``pattern`` and
   ## the captured substrings in the array ``matches``. If it does not
   ## match, nothing is written into ``matches`` and ``false`` is
@@ -609,13 +620,14 @@ proc match*(s: string, pattern: TPeg, matches: var openarray[string],
     for i in 0..c.ml-1:
       matches[i] = copy(s, c.matches[i][0], c.matches[i][1])
 
-proc match*(s: string, pattern: TPeg, start = 0): bool =
+proc match*(s: string, pattern: TPeg, 
+            start = 0): bool {.nosideEffect, rtl, extern: "npegs$1".} =
   ## returns ``true`` if ``s`` matches the ``pattern`` beginning from ``start``.
   var c: TMatchClosure
   result = m(s, pattern, start, c) == len(s)-start
 
 proc matchLen*(s: string, pattern: TPeg, matches: var openarray[string],
-               start = 0): int =
+               start = 0): int {.nosideEffect, rtl, extern: "npegs$1Capture".} =
   ## the same as ``match``, but it returns the length of the match,
   ## if there is no match, -1 is returned. Note that a match length
   ## of zero can happen. It's possible that a suffix of `s` remains
@@ -626,7 +638,8 @@ proc matchLen*(s: string, pattern: TPeg, matches: var openarray[string],
     for i in 0..c.ml-1:
       matches[i] = copy(s, c.matches[i][0], c.matches[i][1])
 
-proc matchLen*(s: string, pattern: TPeg, start = 0): int =
+proc matchLen*(s: string, pattern: TPeg, 
+               start = 0): int {.nosideEffect, rtl, extern: "npegs$1".} =
   ## the same as ``match``, but it returns the length of the match,
   ## if there is no match, -1 is returned. Note that a match length
   ## of zero can happen. It's possible that a suffix of `s` remains
@@ -635,7 +648,7 @@ proc matchLen*(s: string, pattern: TPeg, start = 0): int =
   result = m(s, pattern, start, c)
 
 proc find*(s: string, pattern: TPeg, matches: var openarray[string],
-           start = 0): int =
+           start = 0): int {.nosideEffect, rtl, extern: "npegs$1Capture".} =
   ## returns the starting position of ``pattern`` in ``s`` and the captured
   ## substrings in the array ``matches``. If it does not match, nothing
   ## is written into ``matches`` and -1 is returned.
@@ -644,7 +657,8 @@ proc find*(s: string, pattern: TPeg, matches: var openarray[string],
   return -1
   # could also use the pattern here: (!P .)* P
   
-proc find*(s: string, pattern: TPeg, start = 0): int =
+proc find*(s: string, pattern: TPeg, 
+           start = 0): int {.nosideEffect, rtl, extern: "npegs$1".} =
   ## returns the starting position of ``pattern`` in ``s``. If it does not
   ## match, -1 is returned.
   for i in 0 .. s.len-1:
@@ -675,25 +689,29 @@ template `=~`*(s: string, pattern: TPeg): expr =
 
 # ------------------------- more string handling ------------------------------
 
-proc contains*(s: string, pattern: TPeg, start = 0): bool =
+proc contains*(s: string, pattern: TPeg, start = 0): bool {.
+  nosideEffect, rtl, extern: "npegs$1".} =
   ## same as ``find(s, pattern, start) >= 0``
   return find(s, pattern, start) >= 0
 
 proc contains*(s: string, pattern: TPeg, matches: var openArray[string],
-              start = 0): bool =
+              start = 0): bool {.nosideEffect, rtl, extern: "npegs$1Capture".} =
   ## same as ``find(s, pattern, matches, start) >= 0``
   return find(s, pattern, matches, start) >= 0
 
-proc startsWith*(s: string, prefix: TPeg): bool =
+proc startsWith*(s: string, prefix: TPeg): bool {.
+  nosideEffect, rtl, extern: "npegs$1".} =
   ## returns true if `s` starts with the pattern `prefix`
   result = matchLen(s, prefix) >= 0
 
-proc endsWith*(s: string, suffix: TPeg): bool =
+proc endsWith*(s: string, suffix: TPeg): bool {.
+  nosideEffect, rtl, extern: "npegs$1".} =
   ## returns true if `s` ends with the pattern `prefix`
   for i in 0 .. s.len-1:
     if matchLen(s, suffix, i) == s.len - i: return true
 
-proc replace*(s: string, sub: TPeg, by: string): string =
+proc replace*(s: string, sub: TPeg, by: string): string {.
+  nosideEffect, rtl, extern: "npegs$1".} =
   ## Replaces `sub` in `s` by the string `by`. Captures can be accessed in `by`
   ## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples:
   ##
@@ -720,7 +738,8 @@ proc replace*(s: string, sub: TPeg, by: string): string =
   add(result, copy(s, i))
   
 proc parallelReplace*(s: string, subs: openArray[
-                      tuple[pattern: TPeg, repl: string]]): string = 
+                      tuple[pattern: TPeg, repl: string]]): string {.
+                      nosideEffect, rtl, extern: "npegs$1".} = 
   ## Returns a modified copy of `s` with the substitutions in `subs`
   ## applied in parallel.
   result = ""
@@ -740,7 +759,8 @@ proc parallelReplace*(s: string, subs: openArray[
   add(result, copy(s, i))  
   
 proc transformFile*(infile, outfile: string,
-                    subs: openArray[tuple[pattern: TPeg, repl: string]]) =
+                    subs: openArray[tuple[pattern: TPeg, repl: string]]) {.
+                    rtl, extern: "npegs$1".} =
   ## reads in the file `infile`, performs a parallel replacement (calls
   ## `parallelReplace`) and writes back to `outfile`. Calls ``quit`` if an
   ## error occurs. This is supposed to be used for quick scripting.
@@ -787,7 +807,8 @@ iterator split*(s: string, sep: TPeg): string =
     if first < last:
       yield copy(s, first, last-1)
 
-proc split*(s: string, sep: TPeg): seq[string] {.noSideEffect.} =
+proc split*(s: string, sep: TPeg): seq[string] {.
+  nosideEffect, rtl, extern: "npegs$1".} =
   ## Splits the string `s` into substrings.
   accumulateResult(split(s, sep))
 
@@ -1265,6 +1286,8 @@ proc primary(p: var TPegParser): TPeg =
     of "S": result = charset({'\1'..'\xff'} - {' ', '\9'..'\13'})
     of "w": result = charset({'a'..'z', 'A'..'Z', '_', '0'..'9'})
     of "W": result = charset({'\1'..'\xff'} - {'a'..'z','A'..'Z','_','0'..'9'})
+    of "a": result = charset({'a'..'z', 'A'..'Z'})
+    of "A": result = charset({'\1'..'\xff'} - {'a'..'z', 'A'..'Z'})
     of "ident": result = pegs.ident
     else: pegError(p, "unknown built-in: " & p.tok.literal)
     getTok(p)
diff --git a/lib/pure/ropes.nim b/lib/pure/ropes.nim
index df85baf92..14a01044f 100755
--- a/lib/pure/ropes.nim
+++ b/lib/pure/ropes.nim
@@ -16,6 +16,8 @@
 ## Leaves can be cached for better memory efficiency at the cost of
 ## runtime efficiency.
 
+include "system/inclrtl"
+
 {.deadCodeElim: on.}
 
 {.push debugger:off .} # the user does not want to trace a part
@@ -44,7 +46,7 @@ proc isConc(r: PRope): bool {.inline.} = return isNil(r.data)
 # performance. But for the caching tree we use the leaf's left and right
 # pointers.
 
-proc len*(a: PRope): int =
+proc len*(a: PRope): int {.rtl, extern: "nro$1".} =
   ## the rope's length
   if a == nil: result = 0
   else: result = a.length
@@ -126,7 +128,7 @@ proc insertInCache(s: string, tree: PRope): PRope =
       result.left = t
       t.right = nil
 
-proc rope*(s: string): PRope =
+proc rope*(s: string): PRope {.rtl, extern: "nro$1Str".} =
   ## Converts a string to a rope. 
   if s.len == 0: 
     result = nil
@@ -136,25 +138,25 @@ proc rope*(s: string): PRope =
   else: 
     result = newRope(s)
   
-proc rope*(i: BiggestInt): PRope = 
+proc rope*(i: BiggestInt): PRope {.rtl, extern: "nro$1BiggestInt".} = 
   ## Converts an int to a rope. 
   result = rope($i)
 
-proc rope*(f: BiggestFloat): PRope =
+proc rope*(f: BiggestFloat): PRope {.rtl, extern: "nro$1BiggestFloat".} =
   ## Converts a float to a rope. 
   result = rope($f)
 
-proc disableCache*() =
+proc disableCache*() {.rtl, extern: "nro$1".} =
   ## the cache is discarded and disabled. The GC will reuse its used memory.
   cache = nil
   cacheEnabled = false
   
-proc enableCache*() =
+proc enableCache*() {.rtl, extern: "nro$1".} =
   ## Enables the caching of leaves. This reduces the memory footprint at
   ## the cost of runtime efficiency.
   cacheEnabled = true
 
-proc `&`*(a, b: PRope): PRope =
+proc `&`*(a, b: PRope): PRope {.rtl, extern: "nroConcRopeRope".} =
   ## the concatenation operator for ropes.
   if a == nil: 
     result = b
@@ -174,27 +176,27 @@ proc `&`*(a, b: PRope): PRope =
       result.left = a
       result.right = b
   
-proc `&`*(a: PRope, b: string): PRope = 
+proc `&`*(a: PRope, b: string): PRope {.rtl, extern: "nroConcRopeStr".} = 
   ## the concatenation operator for ropes.
   result = a & rope(b)
   
-proc `&`*(a: string, b: PRope): PRope = 
+proc `&`*(a: string, b: PRope): PRope {.rtl, extern: "nroConcStrRope".} = 
   ## the concatenation operator for ropes.
   result = rope(a) & b
   
-proc `&`*(a: openarray[PRope]): PRope = 
+proc `&`*(a: openarray[PRope]): PRope {.rtl, extern: "nroConcOpenArray".} = 
   ## the concatenation operator for an openarray of ropes.
   for i in countup(0, high(a)): result = result & a[i]
 
-proc add*(a: var PRope, b: PRope) =
+proc add*(a: var PRope, b: PRope) {.rtl, extern: "nro$1Rope".} =
   ## adds `b` to the rope `a`.
   a = a & b
 
-proc add*(a: var PRope, b: string) =
+proc add*(a: var PRope, b: string) {.rtl, extern: "nro$1Str".} =
   ## adds `b` to the rope `a`.
   a = a & b
   
-proc `[]`*(r: PRope, i: int): char =
+proc `[]`*(r: PRope, i: int): char {.rtl, extern: "nroCharAt".} =
   ## returns the character at position `i` in the rope `r`. This is quite
   ## expensive! Worst-case: O(n). If ``i >= r.len``, ``\0`` is returned.
   var x = r
@@ -229,11 +231,11 @@ iterator items*(r: PRope): char =
   for s in leaves(r):
     for c in items(s): yield c
 
-proc write*(f: TFile, r: PRope) =
+proc write*(f: TFile, r: PRope) {.rtl, extern: "nro$1".} =
   ## writes a rope to a file.
   for s in leaves(r): write(f, s)
 
-proc `$`*(r: PRope): string = 
+proc `$`*(r: PRope): string  {.rtl, extern: "nroToString".}= 
   ## converts a rope back to a string.
   result = newString(r.len)
   setLen(result, 0)
@@ -289,7 +291,8 @@ when false:
       if i - 1 >= start: 
         add(result, copy(frmt, start, i-1))
   
-proc `%`*(frmt: string, args: openarray[PRope]): PRope =
+proc `%`*(frmt: string, args: openarray[PRope]): PRope {. 
+  rtl, extern: "nroFormat".} =
   ## `%` substitution operator for ropes. Does not support the ``$identifier``
   ## nor ``${identifier}`` notations.
   var i = 0
@@ -333,11 +336,12 @@ proc `%`*(frmt: string, args: openarray[PRope]): PRope =
     if i - 1 >= start: 
       add(result, copy(frmt, start, i - 1))
 
-proc addf*(c: var PRope, frmt: string, args: openarray[PRope]) =
+proc addf*(c: var PRope, frmt: string, args: openarray[PRope]) {.
+  rtl, extern: "nro$1".} =
   ## shortcut for ``add(c, frmt % args)``.
   add(c, frmt % args)
 
-proc equalsFile*(r: PRope, f: TFile): bool =
+proc equalsFile*(r: PRope, f: TFile): bool {.rtl, extern: "nro$1File".} =
   ## returns true if the contents of the file `f` equal `r`.
   var bufSize = 1024 # reasonable start value
   var buf = alloc(BufSize)
@@ -352,7 +356,7 @@ proc equalsFile*(r: PRope, f: TFile): bool =
     result = readBuffer(f, buf, 1) == 0 # really at the end of file?
   dealloc(buf)
 
-proc equalsFile*(r: PRope, f: string): bool =
+proc equalsFile*(r: PRope, f: string): bool {.rtl, extern: "nro$1Str".} =
   ## returns true if the contents of the file `f` equal `r`. If `f` does not
   ## exist, false is returned.
   var bin: TFile
diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim
index 38be1e983..9779be5ff 100755
--- a/lib/pure/strtabs.nim
+++ b/lib/pure/strtabs.nim
@@ -15,6 +15,8 @@
 import
   os, hashes, strutils
 
+include "system/inclrtl"
+
 type
   TStringTableMode* = enum    ## describes the tables operation mode
     modeCaseSensitive,        ## the table is case sensitive
@@ -29,28 +31,7 @@ type
 
   PStringTable* = ref TStringTable ## use this type to declare string tables
 
-proc newStringTable*(keyValuePairs: openarray[string],
-                     mode: TStringTableMode = modeCaseSensitive): PStringTable
-  ## creates a new string table with given key value pairs.
-  ## Example::
-  ##   var mytab = newStringTable("key1", "val1", "key2", "val2",
-  ##                              modeCaseInsensitive)
-
-proc newStringTable*(mode: TStringTableMode): PStringTable
-  ## creates a new string table that is empty.
-
-proc `[]=`*(t: PStringTable, key, val: string)
-  ## puts a (key, value)-pair into `t`.
-
-proc `[]`*(t: PStringTable, key: string): string
-  ## retrieves the value at ``t[key]``. If `key` is not in `t`, "" is returned
-  ## and no exception is raised. One can check with ``hasKey`` whether the key
-  ## exists.
-
-proc hasKey*(t: PStringTable, key: string): bool
-  ## returns true iff `key` is in the table `t`.
-
-proc len*(t: PStringTable): int =
+proc len*(t: PStringTable): int {.rtl, extern: "nst$1".} =
   ## returns the number of keys in `t`.
   result = t.counter
 
@@ -70,29 +51,12 @@ type
     useKey                    ## do not replace ``$key`` if it is not found
                               ## in the table (or in the environment)
 
-proc `%`*(f: string, t: PStringTable, flags: set[TFormatFlag] = {}): string
-  ## The `%` operator for string tables.
-
 # implementation
 
 const
   growthFactor = 2
   startSize = 64
 
-proc newStringTable(mode: TStringTableMode): PStringTable =
-  new(result)
-  result.mode = mode
-  result.counter = 0
-  newSeq(result.data, startSize)
-
-proc newStringTable(keyValuePairs: openarray[string],
-                    mode: TStringTableMode = modeCaseSensitive): PStringTable =
-  result = newStringTable(mode)
-  var i = 0
-  while i < high(keyValuePairs):
-    result[keyValuePairs[i]] = keyValuePairs[i + 1]
-    inc(i, 2)
-
 proc myhash(t: PStringTable, key: string): THash =
   case t.mode
   of modeCaseSensitive: result = hashes.hash(key)
@@ -121,13 +85,17 @@ proc RawGet(t: PStringTable, key: string): int =
     h = nextTry(h, high(t.data))
   result = - 1
 
-proc `[]`(t: PStringTable, key: string): string =
+proc `[]`*(t: PStringTable, key: string): string {.rtl, extern: "nstGet".} =
+  ## retrieves the value at ``t[key]``. If `key` is not in `t`, "" is returned
+  ## and no exception is raised. One can check with ``hasKey`` whether the key
+  ## exists.
   var index: int
   index = RawGet(t, key)
   if index >= 0: result = t.data[index].val
   else: result = ""
 
-proc hasKey(t: PStringTable, key: string): bool =
+proc hasKey*(t: PStringTable, key: string): bool {.rtl, extern: "nst$1".} =
+  ## returns true iff `key` is in the table `t`.
   result = rawGet(t, key) >= 0
 
 proc RawInsert(t: PStringTable, data: var TKeyValuePairSeq, key, val: string) =
@@ -145,7 +113,8 @@ proc Enlarge(t: PStringTable) =
     if not isNil(t.data[i].key): RawInsert(t, n, t.data[i].key, t.data[i].val)
   swap(t.data, n)
 
-proc `[]=`(t: PStringTable, key, val: string) =
+proc `[]=`*(t: PStringTable, key, val: string) {.rtl, extern: "nstPut".} =
+  ## puts a (key, value)-pair into `t`.
   var index = RawGet(t, key)
   if index >= 0:
     t.data[index].val = val
@@ -168,7 +137,30 @@ proc getValue(t: PStringTable, flags: set[TFormatFlag], key: string): string =
     if useKey in flags: result = '$' & key
     elif not (useEmpty in flags): raiseFormatException(key)
 
-proc `%`(f: string, t: PStringTable, flags: set[TFormatFlag] = {}): string =
+proc newStringTable*(mode: TStringTableMode): PStringTable {.
+  rtl, extern: "nst$1".} =
+  ## creates a new string table that is empty.
+  new(result)
+  result.mode = mode
+  result.counter = 0
+  newSeq(result.data, startSize)
+
+proc newStringTable*(keyValuePairs: openarray[string],
+                     mode: TStringTableMode = modeCaseSensitive): PStringTable {.
+  rtl, extern: "nst$1WithPairs".} =
+  ## creates a new string table with given key value pairs.
+  ## Example::
+  ##   var mytab = newStringTable("key1", "val1", "key2", "val2",
+  ##                              modeCaseInsensitive)
+  result = newStringTable(mode)
+  var i = 0
+  while i < high(keyValuePairs):
+    result[keyValuePairs[i]] = keyValuePairs[i + 1]
+    inc(i, 2)
+
+proc `%`*(f: string, t: PStringTable, flags: set[TFormatFlag] = {}): string {.
+  rtl, extern: "nstFormat".} =
+  ## The `%` operator for string tables.
   const
     PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\x80'..'\xFF'}
   result = ""
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index 9e8798043..f5adf1abb 100755
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -8,7 +8,7 @@
 #

 

 ## This module contains various string utility routines.

-## See the module `regexprs` for regular expression support.

+## See the module `re` for regular expression support.

 ## See the module `pegs` for PEG support.

 

 import parseutils

@@ -18,6 +18,8 @@ import parseutils
 {.push debugger:off .} # the user does not want to trace a part

                        # of the standard library!

 

+include "system/inclrtl"

+

 type

   TCharSet* = set[char] # for compatibility with Nim

 

@@ -40,7 +42,151 @@ const
   IdentStartChars* = {'a'..'z', 'A'..'Z', '_'}

     ## the set of characters an identifier can start with

 

-proc `%` *(formatstr: string, a: openarray[string]): string {.noSideEffect.}

+

+proc toLower*(c: Char): Char {.noSideEffect, procvar,

+  rtl, extern: "nsuToLowerChar".} =

+  ## Converts `c` into lower case. This works only for the letters A-Z.

+  ## See `unicode.toLower` for a version that works for any Unicode character.

+  if c in {'A'..'Z'}:

+    result = chr(ord(c) + (ord('a') - ord('A')))

+  else:

+    result = c

+

+proc toLower*(s: string): string {.noSideEffect, procvar,

+  rtl, extern: "nsuToLowerStr".} =

+  ## Converts `s` into lower case. This works only for the letters A-Z.

+  ## See `unicode.toLower` for a version that works for any Unicode character.

+  result = newString(len(s))

+  for i in 0..len(s) - 1:

+    result[i] = toLower(s[i])

+

+proc toUpper*(c: Char): Char {.noSideEffect, procvar,

+  rtl, extern: "nsuToUpperChar".} =

+  ## Converts `c` into upper case. This works only for the letters a-z.

+  ## See `unicode.toUpper` for a version that works for any Unicode character.

+  if c in {'a'..'z'}:

+    result = Chr(Ord(c) - (Ord('a') - Ord('A')))

+  else:

+    result = c

+

+proc toUpper*(s: string): string {.noSideEffect, procvar,

+  rtl, extern: "nsuToUpperStr".} =

+  ## Converts `s` into upper case. This works only for the letters a-z.

+  ## See `unicode.toUpper` for a version that works for any Unicode character.

+  result = newString(len(s))

+  for i in 0..len(s) - 1:

+    result[i] = toUpper(s[i])

+

+proc capitalize*(s: string): string {.noSideEffect, procvar,

+  rtl, extern: "nsuCapitalize".} =

+  ## Converts the first character of `s` into upper case.

+  ## This works only for the letters a-z.

+  result = toUpper(s[0]) & copy(s, 1)

+

+proc normalize*(s: string): string {.noSideEffect, procvar,

+  rtl, extern: "nsuNormalize".} =

+  ## Normalizes the string `s`. That means to convert it to lower case and

+  ## remove any '_'. This is needed for Nimrod identifiers for example.

+  result = ""

+  for i in 0..len(s) - 1:

+    if s[i] in {'A'..'Z'}:

+      add result, Chr(Ord(s[i]) + (Ord('a') - Ord('A')))

+    elif s[i] != '_':

+      add result, s[i]

+

+proc cmpIgnoreCase*(a, b: string): int {.noSideEffect,

+  rtl, extern: "nsuCmpIgnoreCase".} =

+  ## Compares two strings in a case insensitive manner. Returns:

+  ##

+  ## | 0 iff a == b

+  ## | < 0 iff a < b

+  ## | > 0 iff a > b

+  var i = 0

+  while i < a.len and i < b.len:

+    result = ord(toLower(a[i])) - ord(toLower(b[i]))

+    if result != 0: return

+    inc(i)

+  result = a.len - b.len

+

+{.push checks: off, line_trace: off .} # this is a hot-spot in the compiler!

+                                       # thus we compile without checks here

+

+proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect,

+  rtl, extern: "nsuCmpIgnoreStyle".} =

+  ## Compares two strings normalized (i.e. case and

+  ## underscores do not matter). Returns:

+  ##

+  ## | 0 iff a == b

+  ## | < 0 iff a < b

+  ## | > 0 iff a > b

+  var i = 0

+  var j = 0

+  while True:

+    while a[i] == '_': inc(i)

+    while b[j] == '_': inc(j) # BUGFIX: typo

+    var aa = toLower(a[i])

+    var bb = toLower(b[j])

+    result = ord(aa) - ord(bb)

+    if result != 0 or aa == '\0': break

+    inc(i)

+    inc(j)

+

+{.pop.}

+

+proc findNormalized(x: string, inArray: openarray[string]): int =

+  var i = 0

+  while i < high(inArray):

+    if cmpIgnoreStyle(x, inArray[i]) == 0: return i

+    inc(i, 2) # incrementing by 1 would probably result in a

+              # security hole...

+  return -1

+

+proc addf*(s: var string, formatstr: string, a: openarray[string]) {.

+  noSideEffect, rtl, extern: "nsuAddf".} =

+  ## The same as ``add(s, formatstr % a)``, but more efficient.

+  const PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '\128'..'\255', '_'}

+  var i = 0

+  var num = 0

+  while i < len(formatstr):

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

+      case formatstr[i+1] # again we use the fact that strings

+                          # are zero-terminated here

+      of '#':

+        add s, a[num]

+        inc i, 2

+        inc num

+      of '$':

+        add s, '$'

+        inc(i, 2)

+      of '1'..'9':

+        var j = 0

+        inc(i) # skip $

+        while formatstr[i] in Digits:

+          j = j * 10 + ord(formatstr[i]) - ord('0')

+          inc(i)

+        num = j

+        add s, a[j - 1]

+      of '{':

+        var j = i+1

+        while formatstr[j] notin {'\0', '}'}: inc(j)

+        var x = findNormalized(copy(formatstr, i+2, j-1), a)

+        if x >= 0 and x < high(a): add s, a[x+1]

+        else: raise newException(EInvalidValue, "invalid format string")

+        i = j+1

+      of 'a'..'z', 'A'..'Z', '\128'..'\255', '_':

+        var j = i+1

+        while formatstr[j] in PatternChars: inc(j)

+        var x = findNormalized(copy(formatstr, i+1, j-1), a)

+        if x >= 0 and x < high(a): add s, a[x+1]

+        else: raise newException(EInvalidValue, "invalid format string")

+        i = j

+      else: raise newException(EInvalidValue, "invalid format string")

+    else:

+      add s, formatstr[i]

+      inc(i)

+

+proc `%` *(formatstr: string, a: openarray[string]): string {.noSideEffect,

+  rtl, extern: "nsuFormatOpenArray".} = 

   ## The `substitution`:idx: operator performs string substitutions in

   ## `formatstr` and returns a modified `formatstr`. This is often called

   ## `string interpolation`:idx:.

@@ -77,57 +223,38 @@ proc `%` *(formatstr: string, a: openarray[string]): string {.noSideEffect.}
   ##

   ## The variables are compared with `cmpIgnoreStyle`. `EInvalidValue` is

   ## raised if an ill-formed format string has been passed to the `%` operator.

+  result = ""

+  addf(result, formatstr, a)

 

-proc `%` *(formatstr, a: string): string {.noSideEffect.}

+proc `%` *(formatstr, a: string): string {.noSideEffect, 

+  rtl, extern: "nsuFormatSingleElem".} =

   ## This is the same as ``formatstr % [a]``.

+  return formatstr % [a]

 

-proc addf*(s: var string, formatstr: string, a: openarray[string])

-  ## The same as ``add(s, formatstr % a)``, but more efficient.

-

-proc strip*(s: string, leading = true, trailing = true): string {.noSideEffect.}

+proc strip*(s: string, leading = true, trailing = true): string {.noSideEffect,

+  rtl, extern: "nsuStrip".} =

   ## Strips whitespace from `s` and returns the resulting string.

   ## If `leading` is true, leading whitespace is stripped.

   ## If `trailing` is true, trailing whitespace is stripped.

+  const

+    chars: set[Char] = Whitespace

+  var

+    first = 0

+    last = len(s)-1

+  if leading: 

+    while s[first] in chars: inc(first)

+  if trailing:

+    while last >= 0 and s[last] in chars: dec(last)

+  result = copy(s, first, last)

 

-proc toLower*(s: string): string {.noSideEffect, procvar.}

-  ## Converts `s` into lower case. This works only for the letters A-Z.

-  ## See `unicode.toLower` for a version that works for any Unicode character.

-

-proc toLower*(c: Char): Char {.noSideEffect, procvar.}

-  ## Converts `c` into lower case. This works only for the letters A-Z.

-  ## See `unicode.toLower` for a version that works for any Unicode character.

-

-proc toUpper*(s: string): string {.noSideEffect, procvar.}

-  ## Converts `s` into upper case. This works only for the letters a-z.

-  ## See `unicode.toUpper` for a version that works for any Unicode character.

-

-proc toUpper*(c: Char): Char {.noSideEffect, procvar.}

-  ## Converts `c` into upper case. This works only for the letters a-z.

-  ## See `unicode.toUpper` for a version that works for any Unicode character.

-

-proc capitalize*(s: string): string {.noSideEffect, procvar.}

-  ## Converts the first character of `s` into upper case.

-  ## This works only for the letters a-z.

-

-proc normalize*(s: string): string {.noSideEffect, procvar.}

-  ## Normalizes the string `s`. That means to convert it to lower case and

-  ## remove any '_'. This is needed for Nimrod identifiers for example.

-

-proc find*(s, sub: string, start: int = 0): int {.noSideEffect.}

-  ## Searches for `sub` in `s` starting at position `start`. Searching is

-  ## case-sensitive. If `sub` is not in `s`, -1 is returned.

-

-proc find*(s: string, sub: char, start: int = 0): int {.noSideEffect.}

-  ## Searches for `sub` in `s` starting at position `start`. Searching is

-  ## case-sensitive. If `sub` is not in `s`, -1 is returned.

-

-proc find*(s: string, chars: set[char], start: int = 0): int {.noSideEffect.}

-  ## Searches for `chars` in `s` starting at position `start`. If `s` contains

-  ## none of the characters in `chars`, -1 is returned.

-

-proc toOctal*(c: char): string

+proc toOctal*(c: char): string {.noSideEffect, rtl, extern: "nsuToOctal".} =

   ## Converts a character `c` to its octal representation. The resulting

   ## string may not have a leading zero. Its length is always exactly 3.

+  result = newString(3)

+  var val = ord(c)

+  for i in countdown(2, 0):

+    result[i] = Chr(val mod 8 + ord('0'))

+    val = val div 8

 

 iterator split*(s: string, seps: set[char] = Whitespace): string =

   ## Splits the string `s` into substrings.

@@ -228,86 +355,123 @@ iterator splitLines*(s: string): string =
     else: break # was '\0'

     first = last

 

-proc splitLines*(s: string): seq[string] {.noSideEffect.} =

+proc splitLines*(s: string): seq[string] {.noSideEffect,

+  rtl, extern: "nsuSplitLines".} =

   ## The same as the `splitLines` iterator, but is a proc that returns a 

   ## sequence of substrings.

   accumulateResult(splitLines(s))

 

 proc split*(s: string, seps: set[char] = Whitespace): seq[string] {.

-  noSideEffect.} =

+  noSideEffect, rtl, extern: "nsuSplitCharSet".} =

   ## The same as the `split` iterator, but is a proc that returns a

   ## sequence of substrings.

   accumulateResult(split(s, seps))

 

-proc split*(s: string, sep: char): seq[string] {.noSideEffect.} =

+proc split*(s: string, sep: char): seq[string] {.noSideEffect,

+  rtl, extern: "nsuSplitChar".} =

   ## The same as the `split` iterator, but is a proc that returns a sequence

   ## of substrings.

   accumulateResult(split(s, sep))

 

-proc cmpIgnoreCase*(a, b: string): int {.noSideEffect.}

-  ## Compares two strings in a case insensitive manner. Returns:

-  ##

-  ## | 0 iff a == b

-  ## | < 0 iff a < b

-  ## | > 0 iff a > b

-

-proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect.}

-  ## Compares two strings normalized (i.e. case and

-  ## underscores do not matter). Returns:

-  ##

-  ## | 0 iff a == b

-  ## | < 0 iff a < b

-  ## | > 0 iff a > b

-

-proc contains*(s: string, c: char): bool {.noSideEffect.}

-  ## Same as ``find(s, c) >= 0``.

-

-proc contains*(s, sub: string): bool {.noSideEffect.}

-  ## Same as ``find(s, sub) >= 0``.

-

-proc contains*(s: string, chars: set[char]): bool {.noSideEffect.}

-  ## Same as ``find(s, chars) >= 0``.

-

-proc toHex*(x: BiggestInt, len: int): string {.noSideEffect.}

+proc toHex*(x: BiggestInt, len: int): string {.noSideEffect,

+  rtl, extern: "nsuToHex".} =

   ## Converts `x` to its hexadecimal representation. The resulting string

   ## will be exactly `len` characters long. No prefix like ``0x``

   ## is generated. `x` is treated as an unsigned value.

+  const

+    HexChars = "0123456789ABCDEF"

+  var

+    shift: BiggestInt

+  result = newString(len)

+  for j in countdown(len-1, 0):

+    result[j] = HexChars[toU32(x shr shift) and 0xF'i32]

+    shift = shift + 4

 

-proc intToStr*(x: int, minchars: int = 1): string

+proc intToStr*(x: int, minchars: int = 1): string {.noSideEffect,

+  rtl, extern: "nsuIntToStr".} =

   ## Converts `x` to its decimal representation. The resulting string

   ## will be minimally `minchars` characters long. This is achieved by

   ## adding leading zeros.

+  result = $abs(x)

+  for i in 1 .. minchars - len(result):

+    result = '0' & result

+  if x < 0:

+    result = '-' & result

 

-proc ParseInt*(s: string): int {.noSideEffect, procvar.}

+proc ParseInt*(s: string): int {.noSideEffect, procvar,

+  rtl, extern: "nsuParseInt".} =

   ## Parses a decimal integer value contained in `s`. If `s` is not

   ## a valid integer, `EInvalidValue` is raised.

+  var L = parseutils.parseInt(s, result, 0)

+  if L != s.len: raise newException(EInvalidValue, "invalid integer: " & s)

 

-proc ParseBiggestInt*(s: string): biggestInt {.noSideEffect, procvar.}

+proc ParseBiggestInt*(s: string): biggestInt {.noSideEffect, procvar,

+  rtl, extern: "nsuParseBiggestInt".} =

   ## Parses a decimal integer value contained in `s`. If `s` is not

   ## a valid integer, `EInvalidValue` is raised.

+  var L = parseutils.parseBiggestInt(s, result, 0)

+  if L != s.len: raise newException(EInvalidValue, "invalid integer: " & s)

 

-proc ParseFloat*(s: string): float {.noSideEffect, procvar.}

+proc ParseFloat*(s: string): float {.noSideEffect, procvar,

+  rtl, extern: "nsuParseFloat".} =

   ## Parses a decimal floating point value contained in `s`. If `s` is not

   ## a valid floating point number, `EInvalidValue` is raised. ``NAN``,

   ## ``INF``, ``-INF`` are also supported (case insensitive comparison).

+  var L = parseutils.parseFloat(s, result, 0)

+  if L != s.len: raise newException(EInvalidValue, "invalid float: " & s)

 

-proc ParseHexInt*(s: string): int {.noSideEffect, procvar.} 

+proc ParseHexInt*(s: string): int {.noSideEffect, procvar,

+  rtl, extern: "nsuParseHexInt".} =

   ## Parses a hexadecimal integer value contained in `s`. If `s` is not

   ## a valid integer, `EInvalidValue` is raised. `s` can have one of the

   ## following optional prefixes: ``0x``, ``0X``, ``#``. 

   ## Underscores within `s` are ignored.

+  var i = 0

+  if s[i] == '0' and (s[i+1] == 'x' or s[i+1] == 'X'): inc(i, 2)

+  elif s[i] == '#': inc(i)

+  while true: 

+    case s[i]

+    of '_': inc(i)

+    of '0'..'9': 

+      result = result shl 4 or (ord(s[i]) - ord('0'))

+      inc(i)

+    of 'a'..'f': 

+      result = result shl 4 or (ord(s[i]) - ord('a') + 10)

+      inc(i)

+    of 'A'..'F': 

+      result = result shl 4 or (ord(s[i]) - ord('A') + 10)

+      inc(i)

+    of '\0': break

+    else: raise newException(EInvalidValue, "invalid integer: " & s)

 

-proc repeatChar*(count: int, c: Char = ' '): string

+proc repeatChar*(count: int, c: Char = ' '): string {.noSideEffect,

+  rtl, extern: "nsuRepeatChar".} =

   ## Returns a string of length `count` consisting only of

   ## the character `c`.

+  result = newString(count)

+  for i in 0..count-1:

+    result[i] = c

 

-proc startsWith*(s, prefix: string): bool {.noSideEffect.}

+proc startsWith*(s, prefix: string): bool {.noSideEffect,

+  rtl, extern: "nsuStartsWith".} =

   ## Returns true iff ``s`` starts with ``prefix``.

   ## If ``prefix == ""`` true is returned.

+  var i = 0

+  while true:

+    if prefix[i] == '\0': return true

+    if s[i] != prefix[i]: return false

+    inc(i)

 

-proc endsWith*(s, suffix: string): bool {.noSideEffect.}

+proc endsWith*(s, suffix: string): bool {.noSideEffect,

+  rtl, extern: "nsuEndsWith".} =

   ## Returns true iff ``s`` ends with ``suffix``.

   ## If ``suffix == ""`` true is returned.

+  var i = 0

+  var j = len(s) - len(suffix)

+  while i+j <% s.len:

+    if s[i+j] != suffix[i]: return false

+    inc(i)

+  if suffix[i] == '\0': return true

 

 proc addSep*(dest: var string, sep = ", ", startLen = 0) {.noSideEffect,

                                                            inline.} = 

@@ -335,32 +499,8 @@ proc allCharsInSet*(s: string, theSet: TCharSet): bool =
     if c notin theSet: return false

   return true

 

-proc quoteIfContainsWhite*(s: string): string =

-  ## returns ``'"' & s & '"'`` if `s` contains a space and does not

-  ## start with a quote, else returns `s`

-  if find(s, {' ', '\t'}) >= 0 and s[0] != '"':

-    result = '"' & s & '"'

-  else:

-    result = s

-

-proc startsWith(s, prefix: string): bool =

-  var i = 0

-  while true:

-    if prefix[i] == '\0': return true

-    if s[i] != prefix[i]: return false

-    inc(i)

-

-proc endsWith(s, suffix: string): bool =

-  var

-    i = 0

-    j = len(s) - len(suffix)

-  while i+j <% s.len:

-    if s[i+j] != suffix[i]: return false

-    inc(i)

-  if suffix[i] == '\0': return true

-
-# 012345
-#    345
+# 012345

+#    345

 

 when false:

   proc abbrev(s: string, possibilities: openarray[string]): int = 

@@ -373,112 +513,10 @@ when false:
         if result >= 0: return -2 # ambiguous

         result = i

 

-proc repeatChar(count: int, c: Char = ' '): string =

-  result = newString(count)

-  for i in 0..count-1:

-    result[i] = c

-

-proc intToStr(x: int, minchars: int = 1): string =

-  result = $abs(x)

-  for i in 1 .. minchars - len(result):

-    result = '0' & result

-  if x < 0:

-    result = '-' & result

-

-proc toOctal(c: char): string =

-  result = newString(3)

-  var val = ord(c)

-  for i in countdown(2, 0):

-    result[i] = Chr(val mod 8 + ord('0'))

-    val = val div 8

-

-proc `%`(formatstr: string, a: string): string =

-  return formatstr % [a]

-

-proc findNormalized(x: string, inArray: openarray[string]): int =

-  var i = 0

-  while i < high(inArray):

-    if cmpIgnoreStyle(x, inArray[i]) == 0: return i

-    inc(i, 2) # incrementing by 1 would probably result in a

-              # security hole...

-  return -1

-

-proc addf(s: var string, formatstr: string, a: openarray[string]) =

-  const PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '\128'..'\255', '_'}

-  var i = 0

-  var num = 0

-  while i < len(formatstr):

-    if formatstr[i] == '$':

-      case formatstr[i+1] # again we use the fact that strings

-                          # are zero-terminated here

-      of '#':

-        add s, a[num]

-        inc i, 2

-        inc num

-      of '$':

-        add s, '$'

-        inc(i, 2)

-      of '1'..'9':

-        var j = 0

-        inc(i) # skip $

-        while formatstr[i] in Digits:

-          j = j * 10 + ord(formatstr[i]) - ord('0')

-          inc(i)

-        num = j

-        add s, a[j - 1]

-      of '{':

-        var j = i+1

-        while formatstr[j] notin {'\0', '}'}: inc(j)

-        var x = findNormalized(copy(formatstr, i+2, j-1), a)

-        if x >= 0 and x < high(a): add s, a[x+1]

-        else: raise newException(EInvalidValue, "invalid format string")

-        i = j+1

-      of 'a'..'z', 'A'..'Z', '\128'..'\255', '_':

-        var j = i+1

-        while formatstr[j] in PatternChars: inc(j)

-        var x = findNormalized(copy(formatstr, i+1, j-1), a)

-        if x >= 0 and x < high(a): add s, a[x+1]

-        else: raise newException(EInvalidValue, "invalid format string")

-        i = j

-      else: raise newException(EInvalidValue, "invalid format string")

-    else:

-      add s, formatstr[i]

-      inc(i)

-  

-proc `%`(formatstr: string, a: openarray[string]): string =

-  result = ""

-  addf(result, formatstr, a)

-

-proc cmpIgnoreCase(a, b: string): int =

-  var i = 0

-  while i < a.len and i < b.len:

-    result = ord(toLower(a[i])) - ord(toLower(b[i]))

-    if result != 0: return

-    inc(i)

-  result = a.len - b.len

-

-

-{.push checks: off, line_trace: off .} # this is a hot-spot in the compiler!

-                                       # thus we compile without checks here

-

-proc cmpIgnoreStyle(a, b: string): int =

-  var i = 0

-  var j = 0

-  while True:

-    while a[i] == '_': inc(i)

-    while b[j] == '_': inc(j) # BUGFIX: typo

-    var aa = toLower(a[i])

-    var bb = toLower(b[j])

-    result = ord(aa) - ord(bb)

-    if result != 0 or aa == '\0': break

-    inc(i)

-    inc(j)

-

-{.pop.}

-

 # ---------------------------------------------------------------------------

 

-proc join*(a: openArray[string], sep: string): string =

+proc join*(a: openArray[string], sep: string): string {.

+  noSideEffect, rtl, extern: "nsuJoinSep".} =

   ## concatenates all strings in `a` separating them with `sep`.

   if len(a) > 0:

     var L = sep.len * (a.len-1)

@@ -492,7 +530,8 @@ proc join*(a: openArray[string], sep: string): string =
   else:

     result = ""

   

-proc join*(a: openArray[string]): string =

+proc join*(a: openArray[string]): string {.

+  noSideEffect, rtl, extern: "nsuJoin".} =

   ## concatenates all strings in `a`.

   if len(a) > 0:

     var L = 0

@@ -503,51 +542,6 @@ proc join*(a: openArray[string]): string =
   else:

     result = ""

 

-proc strip(s: string, leading = true, trailing = true): string =

-  const

-    chars: set[Char] = Whitespace

-  var

-    first = 0

-    last = len(s)-1

-  if leading: 

-    while s[first] in chars: inc(first)

-  if trailing:

-    while last >= 0 and s[last] in chars: dec(last)

-  result = copy(s, first, last)

-

-proc toLower(c: Char): Char =

-  if c in {'A'..'Z'}:

-    result = chr(ord(c) + (ord('a') - ord('A')))

-  else:

-    result = c

-

-proc toLower(s: string): string =

-  result = newString(len(s))

-  for i in 0..len(s) - 1:

-    result[i] = toLower(s[i])

-

-proc toUpper(c: Char): Char =

-  if c in {'a'..'z'}:

-    result = Chr(Ord(c) - (Ord('a') - Ord('A')))

-  else:

-    result = c

-

-proc toUpper(s: string): string =

-  result = newString(len(s))

-  for i in 0..len(s) - 1:

-    result[i] = toUpper(s[i])

-

-proc capitalize(s: string): string =

-  result = toUpper(s[0]) & copy(s, 1)

-

-proc normalize(s: string): string =

-  result = ""

-  for i in 0..len(s) - 1:

-    if s[i] in {'A'..'Z'}:

-      add result, Chr(Ord(s[i]) + (Ord('a') - Ord('A')))

-    elif s[i] != '_':

-      add result, s[i]

-

 type

   TSkipTable = array[Char, int]

 

@@ -571,31 +565,52 @@ proc findAux(s, sub: string, start: int, a: TSkipTable): int =
     inc(j, a[s[j+m]])

   return -1

 

-proc find(s, sub: string, start: int = 0): int =

+proc find*(s, sub: string, start: int = 0): int {.noSideEffect,

+  rtl, extern: "nsuFindStr".} =

+  ## Searches for `sub` in `s` starting at position `start`. Searching is

+  ## case-sensitive. If `sub` is not in `s`, -1 is returned.

   var a: TSkipTable

   preprocessSub(sub, a)

   result = findAux(s, sub, start, a)

 

-proc find(s: string, sub: char, start: int = 0): int =

+proc find*(s: string, sub: char, start: int = 0): int {.noSideEffect,

+  rtl, extern: "nsuFindChar".} =

+  ## Searches for `sub` in `s` starting at position `start`. Searching is

+  ## case-sensitive. If `sub` is not in `s`, -1 is returned.

   for i in start..len(s)-1:

     if sub == s[i]: return i

   return -1

- 

-proc find(s: string, chars: set[char], start: int = 0): int =

+

+proc find*(s: string, chars: set[char], start: int = 0): int {.noSideEffect,

+  rtl, extern: "nsuFindCharSet".} =

+  ## Searches for `chars` in `s` starting at position `start`. If `s` contains

+  ## none of the characters in `chars`, -1 is returned.

   for i in start..s.len-1:

     if s[i] in chars: return i

   return -1 

 

-proc contains(s: string, chars: set[char]): bool =

-  return find(s, chars) >= 0

+proc quoteIfContainsWhite*(s: string): string =

+  ## returns ``'"' & s & '"'`` if `s` contains a space and does not

+  ## start with a quote, else returns `s`

+  if find(s, {' ', '\t'}) >= 0 and s[0] != '"':

+    result = '"' & s & '"'

+  else:

+    result = s

 

-proc contains(s: string, c: char): bool =

+proc contains*(s: string, c: char): bool {.noSideEffect.} =

+  ## Same as ``find(s, c) >= 0``.

   return find(s, c) >= 0

 

-proc contains(s, sub: string): bool =

+proc contains*(s, sub: string): bool {.noSideEffect.} =

+  ## Same as ``find(s, sub) >= 0``.

   return find(s, sub) >= 0

 

-proc replace*(s, sub, by: string): string =

+proc contains*(s: string, chars: set[char]): bool {.noSideEffect.} =

+  ## Same as ``find(s, chars) >= 0``.

+  return find(s, chars) >= 0

+

+proc replace*(s, sub, by: string): string {.noSideEffect,

+  rtl, extern: "nsuReplaceStr".} =

   ## Replaces `sub` in `s` by the string `by`.

   var a: TSkipTable

   result = ""

@@ -610,7 +625,8 @@ proc replace*(s, sub, by: string): string =
   # copy the rest:

   add result, copy(s, i)

 

-proc replace*(s: string, sub, by: char): string =

+proc replace*(s: string, sub, by: char): string {.noSideEffect,

+  rtl, extern: "nsuReplaceChar".} =

   ## optimized version for characters.

   result = newString(s.len)

   var i = 0

@@ -619,7 +635,8 @@ proc replace*(s: string, sub, by: char): string =
     else: result[i] = s[i]

     inc(i)

 

-proc delete*(s: var string, first, last: int) =

+proc delete*(s: var string, first, last: int) {.noSideEffect,

+  rtl, extern: "nsuDelete".} =

   ## Deletes in `s` the characters at position `first`..`last`. This modifies

   ## `s` itself, it does not return a copy.

   var i = first

@@ -631,27 +648,12 @@ proc delete*(s: var string, first, last: int) =
     inc(j)

   setlen(s, newLen)

 

-# parsing numbers:

-

-proc toHex(x: BiggestInt, len: int): string =

-  const

-    HexChars = "0123456789ABCDEF"

-  var

-    shift: BiggestInt

-  result = newString(len)

-  for j in countdown(len-1, 0):

-    result[j] = HexChars[toU32(x shr shift) and 0xF'i32]

-    shift = shift + 4

-

-proc parseInt(s: string): int =

-  var L = parseutils.parseInt(s, result, 0)

-  if L != s.len: raise newException(EInvalidValue, "invalid integer: " & s)

-

-proc ParseBiggestInt(s: string): biggestInt =

-  var L = parseutils.parseBiggestInt(s, result, 0)

-  if L != s.len: raise newException(EInvalidValue, "invalid integer: " & s)

-

-proc ParseOctInt*(s: string): int =

+proc ParseOctInt*(s: string): int {.noSideEffect,

+  rtl, extern: "nsuParseOctInt".} =

+  ## Parses an octal integer value contained in `s`. If `s` is not

+  ## a valid integer, `EInvalidValue` is raised. `s` can have one of the

+  ## following optional prefixes: ``0o``, ``0O``.

+  ## Underscores within `s` are ignored.

   var i = 0

   if s[i] == '0' and (s[i+1] == 'o' or s[i+1] == 'O'): inc(i, 2)

   while true: 

@@ -663,30 +665,8 @@ proc ParseOctInt*(s: string): int =
     of '\0': break

     else: raise newException(EInvalidValue, "invalid integer: " & s)

 

-proc ParseHexInt(s: string): int = 

-  var i = 0

-  if s[i] == '0' and (s[i+1] == 'x' or s[i+1] == 'X'): inc(i, 2)

-  elif s[i] == '#': inc(i)

-  while true: 

-    case s[i]

-    of '_': inc(i)

-    of '0'..'9': 

-      result = result shl 4 or (ord(s[i]) - ord('0'))

-      inc(i)

-    of 'a'..'f': 

-      result = result shl 4 or (ord(s[i]) - ord('a') + 10)

-      inc(i)

-    of 'A'..'F': 

-      result = result shl 4 or (ord(s[i]) - ord('A') + 10)

-      inc(i)

-    of '\0': break

-    else: raise newException(EInvalidValue, "invalid integer: " & s)

-

-proc ParseFloat(s: string): float =

-  var L = parseutils.parseFloat(s, result, 0)

-  if L != s.len: raise newException(EInvalidValue, "invalid float: " & s)

-

-proc toOct*(x: BiggestInt, len: int): string =

+proc toOct*(x: BiggestInt, len: int): string {.noSideEffect,

+  rtl, extern: "nsuToOct".} =

   ## converts `x` into its octal representation. The resulting string is

   ## always `len` characters long. No leading ``0o`` prefix is generated.

   var

@@ -699,7 +679,8 @@ proc toOct*(x: BiggestInt, len: int): string =
     shift = shift + 3

     mask = mask shl 3

 

-proc toBin*(x: BiggestInt, len: int): string =

+proc toBin*(x: BiggestInt, len: int): string {.noSideEffect,

+  rtl, extern: "nsuToBin".} =

   ## converts `x` into its binary representation. The resulting string is

   ## always `len` characters long. No leading ``0b`` prefix is generated.

   var

@@ -712,7 +693,8 @@ proc toBin*(x: BiggestInt, len: int): string =
     shift = shift + 1

     mask = mask shl 1

 

-proc insertSep*(s: string, sep = '_', digits = 3): string = 

+proc insertSep*(s: string, sep = '_', digits = 3): string {.noSideEffect,

+  rtl, extern: "nsuInsertSep".} = 

   ## inserts the separator `sep` after `digits` digits from right to left.

   ## Even though the algorithm works with any string `s`, it is only useful 

   ## if `s` contains a number.

@@ -730,7 +712,8 @@ proc insertSep*(s: string, sep = '_', digits = 3): string =
     inc(j)

     dec(L)

 

-proc escape*(s: string, prefix = "\"", suffix = "\""): string =

+proc escape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,

+  rtl, extern: "nsuEscape".} =

   ## Escapes a string `s`. This does these operations (at the same time):

   ## * replaces any ``\`` by ``\\``

   ## * replaces any ``'`` by ``\'``

@@ -752,7 +735,8 @@ proc escape*(s: string, prefix = "\"", suffix = "\""): string =
     else: add(result, c)

   add(result, suffix)

 

-proc validEmailAddress*(s: string): bool = 

+proc validEmailAddress*(s: string): bool {.noSideEffect,

+  rtl, extern: "nsuValidEmailAddress".} = 

   ## returns true if `s` seems to be a valid e-mail address. 

   ## The checking also uses a domain list.

   ## Note: This will be moved into another module soon.

@@ -779,7 +763,8 @@ proc validEmailAddress*(s: string): bool =
      "aero", "jobs", "museum": return true

   return false

   

-proc validIdentifier*(s: string): bool = 

+proc validIdentifier*(s: string): bool {.noSideEffect,

+  rtl, extern: "nsuValidIdentifier".} = 

   ## returns true if `s` is a valid identifier. A valid identifier starts

   ## with a character of the set `IdentStartChars` and is followed by any

   ## number of characters of the set `IdentChars`.

@@ -788,7 +773,8 @@ proc validIdentifier*(s: string): bool =
       if s[i] notin IdentChars: return false

     return true

   

-proc editDistance*(a, b: string): int =

+proc editDistance*(a, b: string): int {.noSideEffect,

+  rtl, extern: "nsuEditDistance".} =

   ## returns the edit distance between `a` and `b`. This uses the Levenshtein

   ## distance algorithm with only a linear memory overhead. This implementation

   ## is highly optimized!

diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index 8af7395dd..d3e2fe7cf 100755
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -11,12 +11,14 @@
 ## This module contains routines and types for dealing with time.
 ## This module is available for the ECMAScript target.
 
-{.push debugger:off .} # the user does not want to trace a part
-                       # of the standard library!
+{.push debugger:off.} # the user does not want to trace a part
+                      # of the standard library!
 
 import
   strutils
 
+include "system/inclrtl"
+
 type
   TMonth* = enum ## represents a month
     mJan, mFeb, mMar, mApr, mMay, mJun, mJul, mAug, mSep, mOct, mNov, mDec
@@ -125,20 +127,17 @@ proc `$` *(timeInfo: TTimeInfo): string
 proc `$` *(time: TTime): string
   ## converts a calendar time to a string representation.
 
-proc getDateStr*(): string
-  ## gets the current date as a string of the format ``YYYY-MM-DD``.
-
-proc getClockStr*(): string
-  ## gets the current clock time as a string of the format ``HH:MM:SS``.
-
-proc `-` *(a, b: TTime): int64
+proc `-` *(a, b: TTime): int64{.
+  rtl, extern: "ntDiffTime".}
   ## computes the difference of two calendar times. Result is in seconds.
 
-proc `<` * (a, b: TTime): bool = 
+proc `<` * (a, b: TTime): bool {.
+  rtl, extern: "ntLtTime".} = 
   ## returns true iff ``a < b``, that is iff a happened before b.
   result = a - b < 0
   
-proc `<=` * (a, b: TTime): bool = 
+proc `<=` * (a, b: TTime): bool {.
+  rtl, extern: "ntLeTime".}= 
   ## returns true iff ``a <= b``.
   result = a - b <= 0
 
@@ -147,12 +146,12 @@ proc getStartMilsecs*(): int {.deprecated.}
   ## version 0.8.10.** Use ``realTime`` or ``cpuTime`` instead.
 
 when not defined(ECMAScript):  
-  proc epochTime*(): float
+  proc epochTime*(): float {.rtl, extern: "nt$1".}
     ## gets time after the UNIX epoch (1970) in seconds. It is a float
     ## because sub-second resolution is likely to be supported (depending 
     ## on the hardware/OS).
 
-  proc cpuTime*(): float 
+  proc cpuTime*(): float {.rtl, extern: "nt$1".}
     ## gets time spent that the CPU spent to run the current process in
     ## seconds. This may be more useful for benchmarking than ``epochTime``.
     ## However, it may measure the real time instead (depending on the OS).
@@ -227,8 +226,9 @@ when not defined(ECMAScript):
     result.yearday = t.yearday
     result.isdst = -1
   
-  proc `-` (a, b: TTime): int64 =
-    return toBiggestInt(difftime(a, b))
+  when not defined(useNimRtl):
+    proc `-` (a, b: TTime): int64 =
+      return toBiggestInt(difftime(a, b))
   
   proc getStartMilsecs(): int =
     #echo "clocks per sec: ", clocksPerSec, "clock: ", int(clock())
@@ -290,24 +290,25 @@ when not defined(ECMAScript):
     ## converts a Windows time to a UNIX `TTime` (``time_t``)
     result = TTime((t - epochDiff) div rateDiff)
     
-  proc epochTime(): float = 
-    when defined(posix):
-      var a: Ttimeval
-      posix_gettimeofday(a)
-      result = toFloat(a.tv_sec) + toFloat(a.tv_usec)*0.001
-      # why 0.001 instead of 0.00_0001? I don't know.
-    elif defined(windows):
-      var f: winlean.Filetime
-      GetSystemTimeAsFileTime(f)
-      var i64 = rdFileTime(f) - epochDiff
-      var secs = i64 div rateDiff
-      var subsecs = i64 mod rateDiff
-      result = toFloat(int(secs)) + toFloat(int(subsecs)) * 0.0000001
-    else:
-      {.error: "unknown OS".}
-    
-  proc cpuTime(): float = 
-    result = toFloat(int(clock())) / toFloat(clocksPerSec)
+  when not defined(useNimRtl):
+    proc epochTime(): float = 
+      when defined(posix):
+        var a: Ttimeval
+        posix_gettimeofday(a)
+        result = toFloat(a.tv_sec) + toFloat(a.tv_usec)*0.001
+        # why 0.001 instead of 0.00_0001? I don't know.
+      elif defined(windows):
+        var f: winlean.Filetime
+        GetSystemTimeAsFileTime(f)
+        var i64 = rdFileTime(f) - epochDiff
+        var secs = i64 div rateDiff
+        var subsecs = i64 mod rateDiff
+        result = toFloat(int(secs)) + toFloat(int(subsecs)) * 0.0000001
+      else:
+        {.error: "unknown OS".}
+      
+    proc cpuTime(): float = 
+      result = toFloat(int(clock())) / toFloat(clocksPerSec)
     
 else:
   proc getTime(): TTime {.importc: "new Date", nodecl.}
@@ -358,12 +359,15 @@ else:
     ## get the miliseconds from the start of the program
     return int(getTime() - startMilsecs)
 
-proc getDateStr(): string =
+
+proc getDateStr*(): string {.rtl, extern: "nt$1".} =
+  ## gets the current date as a string of the format ``YYYY-MM-DD``.
   var ti = getLocalTime(getTime())
   result = $ti.year & '-' & intToStr(ord(ti.month)+1, 2) &
     '-' & intToStr(ti.monthDay, 2)
 
-proc getClockStr(): string =
+proc getClockStr*(): string {.rtl, extern: "nt$1".} =
+  ## gets the current clock time as a string of the format ``HH:MM:SS``.
   var ti = getLocalTime(getTime())
   result = intToStr(ti.hour, 2) & ':' & intToStr(ti.minute, 2) &
     ':' & intToStr(ti.second, 2)
diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim
index 98d5eba2a..0939a3066 100755
--- a/lib/pure/unicode.nim
+++ b/lib/pure/unicode.nim
@@ -11,6 +11,8 @@
 
 {.deadCodeElim: on.}
 
+include "system/inclrtl"
+
 type
   irune = int # underlying type of TRune
   TRune* = distinct irune   ## type that can hold any Unicode character
@@ -22,7 +24,7 @@ proc `==`*(a, b: TRune): bool {.borrow.}
 
 template ones(n: expr): expr = ((1 shl n)-1)
 
-proc runeLen*(s: string): int =
+proc runeLen*(s: string): int {.rtl, extern: "nuc$1".} =
   ## returns the number of Unicode characters of the string `s`.
   var i = 0
   while i < len(s):
@@ -75,7 +77,7 @@ proc runeAt*(s: string, i: int): TRune =
   ## returns the unicode character in `s` at byte index `i`
   fastRuneAt(s, i, result, false)
 
-proc toUTF8*(c: TRune): string = 
+proc toUTF8*(c: TRune): string {.rtl, extern: "nuc$1".} = 
   ## converts a rune into its UTF8 representation
   var i = irune(c)
   if i <=% 127:
@@ -1073,7 +1075,7 @@ proc binarySearch(c: irune, tab: openArray[iRune], len, stride: int): int =
     return t
   return -1
 
-proc toLower*(c: TRune): TRune = 
+proc toLower*(c: TRune): TRune {.rtl, extern: "nuc$1".} = 
   ## Converts `c` into lower case. This works for any Unicode character.
   ## If possible, prefer `toLower` over `toUpper`. 
   var c = irune(c)
@@ -1085,7 +1087,7 @@ proc toLower*(c: TRune): TRune =
     return TRune(c + toLowerSinglets[p+1] - 500)
   return TRune(c)
 
-proc toUpper*(c: TRune): TRune = 
+proc toUpper*(c: TRune): TRune {.rtl, extern: "nuc$1".} = 
   ## Converts `c` into upper case. This works for any Unicode character.
   ## If possible, prefer `toLower` over `toUpper`. 
   var c = irune(c)
@@ -1097,14 +1099,14 @@ proc toUpper*(c: TRune): TRune =
     return TRune(c + toUpperSinglets[p+1] - 500)
   return TRune(c)
 
-proc toTitle*(c: TRune): TRune = 
+proc toTitle*(c: TRune): TRune {.rtl, extern: "nuc$1".} = 
   var c = irune(c)
   var p = binarySearch(c, toTitleSinglets, len(toTitleSinglets) div 2, 2)
   if p >= 0 and c == toTitleSinglets[p]:
     return TRune(c + toTitleSinglets[p+1] - 500)
   return TRune(c)
 
-proc isLower*(c: TRune): bool = 
+proc isLower*(c: TRune): bool {.rtl, extern: "nuc$1".} = 
   ## returns true iff `c` is a lower case Unicode character
   ## If possible, prefer `isLower` over `isUpper`. 
   var c = irune(c)
@@ -1116,7 +1118,7 @@ proc isLower*(c: TRune): bool =
   if p >= 0 and c == toUpperSinglets[p]:
     return true
 
-proc isUpper*(c: TRune): bool = 
+proc isUpper*(c: TRune): bool {.rtl, extern: "nuc$1".} = 
   ## returns true iff `c` is a upper case Unicode character
   ## If possible, prefer `isLower` over `isUpper`. 
   var c = irune(c)
@@ -1128,7 +1130,7 @@ proc isUpper*(c: TRune): bool =
   if p >= 0 and c == toLowerSinglets[p]:
     return true
 
-proc isAlpha*(c: TRune): bool = 
+proc isAlpha*(c: TRune): bool {.rtl, extern: "nuc$1".} = 
   ## returns true iff `c` is an *alpha* Unicode character (i.e. a letter)
   if isUpper(c) or isLower(c): 
     return true
@@ -1140,10 +1142,10 @@ proc isAlpha*(c: TRune): bool =
   if p >= 0 and c == alphaSinglets[p]:
     return true
   
-proc isTitle*(c: TRune): bool = 
+proc isTitle*(c: TRune): bool {.rtl, extern: "nuc$1".} = 
   return isUpper(c) and isLower(c)
 
-proc isWhiteSpace*(c: TRune): bool = 
+proc isWhiteSpace*(c: TRune): bool {.rtl, extern: "nuc$1".} = 
   ## returns true iff `c` is a Unicode whitespace character
   var c = irune(c)
   var p = binarySearch(c, spaceRanges, len(spaceRanges) div 2, 2)
@@ -1159,7 +1161,7 @@ iterator runes*(s: string): TRune =
     fastRuneAt(s, i, result, true)
     yield result
 
-proc cmpRunesIgnoreCase*(a, b: string): int = 
+proc cmpRunesIgnoreCase*(a, b: string): int {.rtl, extern: "nuc$1".} = 
   ## compares two UTF8 strings and ignores the case. Returns:
   ##
   ## | 0 iff a == b
@@ -1175,6 +1177,3 @@ proc cmpRunesIgnoreCase*(a, b: string): int =
     result = irune(toLower(ar)) - irune(toLower(br))
     if result != 0: return
   result = a.len - b.len
-
-#proc substringAt*(s, sub: string, start: int): int = 
-#  
diff --git a/lib/system.nim b/lib/system.nim
index 1addece93..da64b233e 100755
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -14,7 +14,7 @@
 ## explicitly. Because of this there cannot be a user-defined module named
 ## ``system``.
 
-{.push hints: off.}
+{.push hints: on.}
 
 type
   int* {.magic: Int.} ## default integer type; bitwidth depends on
@@ -720,25 +720,6 @@ const
 include "system/inclrtl"
 include "system/cgprocs"
 
-when not defined(ECMAScript):
-  {.push overflow_checks:off}
-  proc add* (x: var string, y: cstring) =
-    var i = 0
-    while y[i] != '\0':
-      add(x, y[i])
-      inc(i)
-  {.pop.}
-else:
-  proc add* (x: var string, y: cstring) {.pure.} =
-    asm """
-      var len = `x`[0].length-1;
-      for (var i = 0; i < `y`.length; ++i) {
-        `x`[0][len] = `y`.charCodeAt(i);
-        ++len;
-      }
-      `x`[0][len] = 0
-    """
-
 proc add *[T](x: var seq[T], y: T) {.magic: "AppendSeqElem", noSideEffect.}
 proc add *[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} =
   ## Generic proc for adding a data item `y` to a container `x`.
@@ -850,10 +831,6 @@ proc toBiggestInt*(f: biggestfloat): biggestint {.
   ## rounds `f` if it does not contain an integer value. If the conversion
   ## fails (because `f` is infinite for example), `EInvalidValue` is raised.
 
-proc `/`*(x, y: int): float {.inline, noSideEffect.} =
-  ## integer division that results in a float.
-  result = toFloat(x) / toFloat(y)
-
 proc addQuitProc*(QuitProc: proc {.noconv.}) {.importc: "atexit", nodecl.}
   ## adds/registers a quit procedure. Each call to ``addQuitProc``
   ## registers another quit procedure. Up to 30 procedures can be
@@ -1004,12 +981,6 @@ const
     ## and expect a reasonable result - use the `classify` procedure
     ## in the module ``math`` for checking for NaN.
 
-var
-  dbgLineHook*: proc = nil
-    ## set this variable to provide a procedure that should be called before
-    ## each executed instruction. This should only be used by debuggers!
-    ## Only code compiled with the ``debugger:on`` switch calls this hook.
-
 # GC interface:
 
 proc getOccupiedMem*(): int {.rtl.}
@@ -1265,6 +1236,35 @@ template accumulateResult*(iter: expr) =
 # however, stack-traces are available for most parts
 # of the code
 
+var
+  dbgLineHook*: proc = nil
+    ## set this variable to provide a procedure that should be called before
+    ## each executed instruction. This should only be used by debuggers!
+    ## Only code compiled with the ``debugger:on`` switch calls this hook.
+
+when not defined(ECMAScript):
+  {.push overflow_checks:off}
+  proc add* (x: var string, y: cstring) =
+    var i = 0
+    while y[i] != '\0':
+      add(x, y[i])
+      inc(i)
+  {.pop.}
+else:
+  proc add* (x: var string, y: cstring) {.pure.} =
+    asm """
+      var len = `x`[0].length-1;
+      for (var i = 0; i < `y`.length; ++i) {
+        `x`[0][len] = `y`.charCodeAt(i);
+        ++len;
+      }
+      `x`[0][len] = 0
+    """
+
+proc `/`*(x, y: int): float {.inline, noSideEffect.} =
+  ## integer division that results in a float.
+  result = toFloat(x) / toFloat(y)
+
 proc echo*[Ty](x: openarray[Ty]) {.magic: "Echo".}
   ## equivalent to ``writeln(stdout, x); flush(stdout)``. BUT: This is
   ## available for the ECMAScript target too!
@@ -1342,7 +1342,7 @@ when not defined(EcmaScript) and not defined(NimrodVM):
     # we use binary mode in Windows:
     setmode(fileno(c_stdin), O_BINARY)
     setmode(fileno(c_stdout), O_BINARY)
-
+  
   when defined(endb):
     proc endbStep()
 
diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim
index 0d3f52b2f..840107440 100755
--- a/lib/system/alloc.nim
+++ b/lib/system/alloc.nim
@@ -531,48 +531,49 @@ proc isAllocatedPtr(a: TAllocator, p: pointer): bool =
 
 # ---------------------- interface to programs -------------------------------
 
-proc alloc(size: int): pointer =
-  result = rawAlloc(allocator, size+sizeof(TFreeCell))
-  cast[ptr TFreeCell](result).zeroField = 1 # mark it as used
-  assert(not isAllocatedPtr(allocator, result))
-  result = cast[pointer](cast[TAddress](result) +% sizeof(TFreeCell))
-
-proc alloc0(size: int): pointer =
-  result = alloc(size)
-  zeroMem(result, size)
-
-proc dealloc(p: pointer) =
-  var x = cast[pointer](cast[TAddress](p) -% sizeof(TFreeCell))
-  assert(cast[ptr TFreeCell](x).zeroField == 1)
-  rawDealloc(allocator, x)
-  assert(not isAllocatedPtr(allocator, x))
-
-proc ptrSize(p: pointer): int =
-  var x = cast[pointer](cast[TAddress](p) -% sizeof(TFreeCell))
-  result = pageAddr(x).size - sizeof(TFreeCell)
-
-proc realloc(p: pointer, newsize: int): pointer =
-  if newsize > 0:
-    result = alloc(newsize)
-    if p != nil:
-      copyMem(result, p, ptrSize(p))
+when not defined(useNimRtl):
+  proc alloc(size: int): pointer =
+    result = rawAlloc(allocator, size+sizeof(TFreeCell))
+    cast[ptr TFreeCell](result).zeroField = 1 # mark it as used
+    assert(not isAllocatedPtr(allocator, result))
+    result = cast[pointer](cast[TAddress](result) +% sizeof(TFreeCell))
+
+  proc alloc0(size: int): pointer =
+    result = alloc(size)
+    zeroMem(result, size)
+
+  proc dealloc(p: pointer) =
+    var x = cast[pointer](cast[TAddress](p) -% sizeof(TFreeCell))
+    assert(cast[ptr TFreeCell](x).zeroField == 1)
+    rawDealloc(allocator, x)
+    assert(not isAllocatedPtr(allocator, x))
+
+  proc ptrSize(p: pointer): int =
+    var x = cast[pointer](cast[TAddress](p) -% sizeof(TFreeCell))
+    result = pageAddr(x).size - sizeof(TFreeCell)
+
+  proc realloc(p: pointer, newsize: int): pointer =
+    if newsize > 0:
+      result = alloc(newsize)
+      if p != nil:
+        copyMem(result, p, ptrSize(p))
+        dealloc(p)
+    elif p != nil:
       dealloc(p)
-  elif p != nil:
-    dealloc(p)
 
-proc countFreeMem(): int =
-  # only used for assertions
-  var it = allocator.freeChunksList
-  while it != nil:
-    inc(result, it.size)
-    it = it.next
+  proc countFreeMem(): int =
+    # only used for assertions
+    var it = allocator.freeChunksList
+    while it != nil:
+      inc(result, it.size)
+      it = it.next
 
-proc getFreeMem(): int = 
-  result = allocator.freeMem
-  #assert(result == countFreeMem())
+  proc getFreeMem(): int = 
+    result = allocator.freeMem
+    #assert(result == countFreeMem())
 
-proc getTotalMem(): int = return allocator.currMem
-proc getOccupiedMem(): int = return getTotalMem() - getFreeMem()
+  proc getTotalMem(): int = return allocator.currMem
+  proc getOccupiedMem(): int = return getTotalMem() - getFreeMem()
 
 when isMainModule:
   const iterations = 4000_000
diff --git a/lib/system/dyncalls.nim b/lib/system/dyncalls.nim
index d7be3d6ef..88870a209 100755
--- a/lib/system/dyncalls.nim
+++ b/lib/system/dyncalls.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nimrod's Runtime Library
-#        (c) Copyright 2009 Andreas Rumpf
+#        (c) Copyright 2010 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -61,11 +61,14 @@ when defined(posix):
   proc dlsym(lib: TLibHandle, name: cstring): TProcAddr {.
       importc, header: "<dlfcn.h>".}
 
+  proc dlerror(): cstring {.importc, header: "<dlfcn.h>".}
+
   proc nimUnloadLibrary(lib: TLibHandle) =
     dlclose(lib)
 
   proc nimLoadLibrary(path: string): TLibHandle =
     result = dlopen(path, RTLD_NOW)
+    #c_fprintf(c_stdout, "%s\n", dlerror())
 
   proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr =
     result = dlsym(lib, name)
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
index 4d7b41da2..673e5a50e 100755
--- a/lib/system/excpt.nim
+++ b/lib/system/excpt.nim
@@ -1,16 +1,14 @@
 #
 #
 #            Nimrod's Runtime Library
-#        (c) Copyright 2009 Andreas Rumpf
+#        (c) Copyright 2010 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
 #
 
-
 # Exception handling code. This is difficult because it has
-# to work if there is no more memory. Do not use ``sprintf``, etc. as they are
-# unsafe!
+# to work if there is no more memory (but it doesn't yet!).
 
 when not defined(windows) or not defined(guiapp):
   proc writeToStdErr(msg: CString) = write(stdout, msg)
diff --git a/lib/system/gc.nim b/lib/system/gc.nim
index 2ad22d8b6..59ddda5e7 100755
--- a/lib/system/gc.nim
+++ b/lib/system/gc.nim
@@ -74,14 +74,6 @@ var
     # This is wasteful but safe. This is a lock against recursive garbage
     # collection, not a lock for threads!
 
-proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerRtl.}
-  # unsureAsgnRef updates the reference counters only if dest is not on the
-  # stack. It is used by the code generator if it cannot decide wether a
-  # reference is in the stack or not (this can happen for var parameters).
-
-proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.}
-proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.}
-
 proc addZCT(s: var TCellSeq, c: PCell) {.noinline.} =
   if (c.refcount and rcZct) == 0:
     c.refcount = c.refcount and not colorMask or rcZct
@@ -105,24 +97,6 @@ proc extGetCellType(c: pointer): PNimType {.compilerproc.} =
 proc internRefcount(p: pointer): int {.exportc: "getRefcount".} =
   result = int(usrToCell(p).refcount) shr rcShift
 
-proc GC_disable() = inc(recGcLock)
-proc GC_enable() =
-  if recGcLock > 0: dec(recGcLock)
-
-proc GC_setStrategy(strategy: TGC_Strategy) =
-  case strategy
-  of gcThroughput: nil
-  of gcResponsiveness: nil
-  of gcOptimizeSpace: nil
-  of gcOptimizeTime: nil
-
-proc GC_enableMarkAndSweep() =
-  cycleThreshold = InitialCycleThreshold
-
-proc GC_disableMarkAndSweep() =
-  cycleThreshold = high(cycleThreshold)-1
-  # set to the max value to suppress the cycle detector
-
 # this that has to equals zero, otherwise we have to round up UnitsPerPage:
 when BitsPerPage mod (sizeof(int)*8) != 0:
   {.error: "(BitsPerPage mod BitsPerUnit) should be zero!".}
@@ -214,8 +188,13 @@ proc prepareDealloc(cell: PCell) =
     (cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
     dec(recGcLock)
 
-proc PossibleRoot(gch: var TGcHeap, c: PCell) {.inline.} =
-  if canbeCycleRoot(c): incl(gch.cycleRoots, c)
+proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} = 
+  # we MUST access gch as a global here, because this crosses DLL boundaries!
+  incl(gch.cycleRoots, c)
+
+proc rtlAddZCT(c: PCell) {.rtl, inl.} =
+  # we MUST access gch as a global here, because this crosses DLL boundaries!
+  addZCT(gch.zct, c)
 
 proc decRef(c: PCell) {.inline.} =
   when stressGC:
@@ -224,19 +203,19 @@ proc decRef(c: PCell) {.inline.} =
   assert(c.refcount >=% rcIncrement)
   c.refcount = c.refcount -% rcIncrement
   if c.refcount <% rcIncrement:
-    addZCT(gch.zct, c)
+    rtlAddZCT(c)
   elif canBeCycleRoot(c):
-    incl(gch.cycleRoots, c) 
+    rtlAddCycleRoot(c) 
 
 proc incRef(c: PCell) {.inline.} = 
   c.refcount = c.refcount +% rcIncrement
   if canBeCycleRoot(c):
-    incl(gch.cycleRoots, c)
+    rtlAddCycleRoot(c)
 
-proc nimGCref(p: pointer) {.compilerRtl, inl.} = incRef(usrToCell(p))
-proc nimGCunref(p: pointer) {.compilerRtl, inl.} = decRef(usrToCell(p))
+proc nimGCref(p: pointer) {.compilerProc, inline.} = incRef(usrToCell(p))
+proc nimGCunref(p: pointer) {.compilerProc, inline.} = decRef(usrToCell(p))
 
-proc asgnRef(dest: ppointer, src: pointer) {.compilerRtl, inl.} =
+proc asgnRef(dest: ppointer, src: pointer) {.compilerProc, inline.} =
   # the code generator calls this proc!
   assert(not isOnStack(dest))
   # BUGFIX: first incRef then decRef!
@@ -244,7 +223,7 @@ proc asgnRef(dest: ppointer, src: pointer) {.compilerRtl, inl.} =
   if dest^ != nil: decRef(usrToCell(dest^))
   dest^ = src
 
-proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerRtl, inl.} =
+proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerProc, inline.} =
   # the code generator calls this proc if it is known at compile time that no 
   # cycle is possible.
   if src != nil: 
@@ -254,30 +233,34 @@ proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerRtl, inl.} =
     var c = usrToCell(dest^)
     c.refcount = c.refcount -% rcIncrement
     if c.refcount <% rcIncrement:
-      addZCT(gch.zct, c)
+      rtlAddZCT(c)
   dest^ = src
 
-proc unsureAsgnRef(dest: ppointer, src: pointer) =
+proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerProc.} =
+  # unsureAsgnRef updates the reference counters only if dest is not on the
+  # stack. It is used by the code generator if it cannot decide wether a
+  # reference is in the stack or not (this can happen for var parameters).
   if not IsOnStack(dest):
     if src != nil: incRef(usrToCell(src))
     if dest^ != nil: decRef(usrToCell(dest^))
   dest^ = src
 
 proc initGC() =
-  when traceGC:
-    for i in low(TCellState)..high(TCellState): Init(states[i])
-  gch.stat.stackScans = 0
-  gch.stat.cycleCollections = 0
-  gch.stat.maxThreshold = 0
-  gch.stat.maxStackSize = 0
-  gch.stat.maxStackCells = 0
-  gch.stat.cycleTableSize = 0
-  # init the rt
-  init(gch.zct)
-  init(gch.tempStack)
-  Init(gch.cycleRoots)
-  Init(gch.decStack)
-  new(gOutOfMem) # reserve space for the EOutOfMemory exception here!
+  when not defined(useNimRtl):
+    when traceGC:
+      for i in low(TCellState)..high(TCellState): Init(states[i])
+    gch.stat.stackScans = 0
+    gch.stat.cycleCollections = 0
+    gch.stat.maxThreshold = 0
+    gch.stat.maxStackSize = 0
+    gch.stat.maxStackCells = 0
+    gch.stat.cycleTableSize = 0
+    # init the rt
+    init(gch.zct)
+    init(gch.tempStack)
+    Init(gch.cycleRoots)
+    Init(gch.decStack)
+    new(gOutOfMem) # reserve space for the EOutOfMemory exception here!
 
 proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
   var d = cast[TAddress](dest)
@@ -325,7 +308,7 @@ proc checkCollection {.inline.} =
   if recGcLock == 0:
     collectCT(gch)
 
-proc newObj(typ: PNimType, size: int): pointer =
+proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
   # generates a new object and sets its reference counter to 0
   assert(typ.kind in {tyRef, tyString, tySequence})
   checkCollection()
@@ -357,7 +340,7 @@ proc newObj(typ: PNimType, size: int): pointer =
   gcTrace(res, csAllocated)
   result = cellToUsr(res)
 
-proc newSeq(typ: PNimType, len: int): pointer =
+proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
   result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
   cast[PGenericSeq](result).len = len
   cast[PGenericSeq](result).space = len
@@ -490,17 +473,18 @@ elif defined(hppa) or defined(hp9000) or defined(hp9000s300) or
 else:
   const stackIncreases = false
 
-proc setStackBottom(theStackBottom: pointer) =
-  #c_fprintf(c_stdout, "stack bottom: %p;\n", theStackBottom)
-  # the first init must be the one that defines the stack bottom:
-  if stackBottom == nil: stackBottom = theStackBottom
-  else:
-    var a = cast[TAddress](theStackBottom) # and not PageMask - PageSize*2
-    var b = cast[TAddress](stackBottom)
-    when stackIncreases:
-      stackBottom = cast[pointer](min(a, b))
+when not defined(useNimRtl):
+  proc setStackBottom(theStackBottom: pointer) =
+    #c_fprintf(c_stdout, "stack bottom: %p;\n", theStackBottom)
+    # the first init must be the one that defines the stack bottom:
+    if stackBottom == nil: stackBottom = theStackBottom
     else:
-      stackBottom = cast[pointer](max(a, b))
+      var a = cast[TAddress](theStackBottom) # and not PageMask - PageSize*2
+      var b = cast[TAddress](stackBottom)
+      when stackIncreases:
+        stackBottom = cast[pointer](min(a, b))
+      else:
+        stackBottom = cast[pointer](max(a, b))
 
 proc stackSize(): int {.noinline.} =
   var stackTop: array[0..1, pointer]
@@ -647,22 +631,41 @@ proc collectCT(gch: var TGcHeap) =
         gch.stat.maxThreshold = max(gch.stat.maxThreshold, cycleThreshold)
     unmarkStackAndRegisters(gch)
 
-proc GC_fullCollect() =
-  var oldThreshold = cycleThreshold
-  cycleThreshold = 0 # forces cycle collection
-  collectCT(gch)
-  cycleThreshold = oldThreshold
-
-proc GC_getStatistics(): string =
-  GC_disable()
-  result = "[GC] total memory: " & $(getTotalMem()) & "\n" &
-           "[GC] occupied memory: " & $(getOccupiedMem()) & "\n" &
-           "[GC] stack scans: " & $gch.stat.stackScans & "\n" &
-           "[GC] stack cells: " & $gch.stat.maxStackCells & "\n" &
-           "[GC] cycle collections: " & $gch.stat.cycleCollections & "\n" &
-           "[GC] max threshold: " & $gch.stat.maxThreshold & "\n" &
-           "[GC] zct capacity: " & $gch.zct.cap & "\n" &
-           "[GC] max cycle table size: " & $gch.stat.cycleTableSize & "\n" &
-           "[GC] max stack size: " & $gch.stat.maxStackSize
-  when traceGC: writeLeakage()
-  GC_enable()
+when not defined(useNimRtl):
+  proc GC_disable() = inc(recGcLock)
+  proc GC_enable() =
+    if recGcLock > 0: dec(recGcLock)
+
+  proc GC_setStrategy(strategy: TGC_Strategy) =
+    case strategy
+    of gcThroughput: nil
+    of gcResponsiveness: nil
+    of gcOptimizeSpace: nil
+    of gcOptimizeTime: nil
+
+  proc GC_enableMarkAndSweep() =
+    cycleThreshold = InitialCycleThreshold
+
+  proc GC_disableMarkAndSweep() =
+    cycleThreshold = high(cycleThreshold)-1
+    # set to the max value to suppress the cycle detector
+
+  proc GC_fullCollect() =
+    var oldThreshold = cycleThreshold
+    cycleThreshold = 0 # forces cycle collection
+    collectCT(gch)
+    cycleThreshold = oldThreshold
+
+  proc GC_getStatistics(): string =
+    GC_disable()
+    result = "[GC] total memory: " & $(getTotalMem()) & "\n" &
+             "[GC] occupied memory: " & $(getOccupiedMem()) & "\n" &
+             "[GC] stack scans: " & $gch.stat.stackScans & "\n" &
+             "[GC] stack cells: " & $gch.stat.maxStackCells & "\n" &
+             "[GC] cycle collections: " & $gch.stat.cycleCollections & "\n" &
+             "[GC] max threshold: " & $gch.stat.maxThreshold & "\n" &
+             "[GC] zct capacity: " & $gch.zct.cap & "\n" &
+             "[GC] max cycle table size: " & $gch.stat.cycleTableSize & "\n" &
+             "[GC] max stack size: " & $gch.stat.maxStackSize
+    when traceGC: writeLeakage()
+    GC_enable()
diff --git a/lib/system/inclrtl.nim b/lib/system/inclrtl.nim
index 3db6a77ca..e4644b969 100755
--- a/lib/system/inclrtl.nim
+++ b/lib/system/inclrtl.nim
@@ -24,7 +24,6 @@ when defined(createNimRtl):
     {.error: "nimrtl must be built as a library!".}
 
 when defined(createNimRtl): 
-  # NOTE: compilerproc cannot make use of name mangling!
   {.pragma: rtl, exportc: "nimrtl_$1", dynlib.}
   {.pragma: inl.}
   {.pragma: compilerRtl, compilerproc, exportc: "nimrtl_$1", dynlib.}
diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim
index f0685c5c3..a85d69b0d 100755
--- a/lib/system/mmdisp.nim
+++ b/lib/system/mmdisp.nim
@@ -187,28 +187,6 @@ elif defined(nogc):
     dest^ = src
 
   include "system/cellsets"
-elif defined(useNimRtl): 
-  proc initGC() = nil
-
-  proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.}
-  proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.}
-  proc growObj(old: pointer, newsize: int): pointer {.rtl.}
-    
-  proc nimGCref(p: pointer) {.compilerRtl.}
-  proc nimGCunref(p: pointer) {.compilerRtl.}
-  
-  # The write barrier is performance critical!
-  # XXX We should ensure that they are inlined here.
-  # Later implementations will do this.
-  
-  proc unsureAsgnRef(dest: ppointer, src: pointer) {.
-    compilerRtl.}
-  proc asgnRef(dest: ppointer, src: pointer) {.
-    compilerRtl.}
-  proc asgnRefNoCycle(dest: ppointer, src: pointer) {.
-    compilerRtl.}
-
-  include "system/cellsets"    
 
 else:
   include "system/alloc"
diff --git a/rod/semtempl.nim b/rod/semtempl.nim
index f866f77d2..cb4288a56 100755
--- a/rod/semtempl.nim
+++ b/rod/semtempl.nim
@@ -57,18 +57,17 @@ proc evalTemplateAux(c: PContext, templ, actual: PNode, sym: PSym): PNode =
       result.sons[i] = evalTemplateAux(c, templ.sons[i], actual, sym)
   
 var evalTemplateCounter: int = 0
+  # to prevend endless recursion in templates instantation
 
 proc evalTemplateArgs(c: PContext, n: PNode, s: PSym): PNode = 
-  # to prevend endless recursion in templates
-  # instantation
   var 
     f, a: int
     arg: PNode
   f = sonsLen(s.typ) # if the template has zero arguments, it can be called without ``()``
                      # `n` is then a nkSym or something similar
   case n.kind
-  of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: a = sonsLen(
-      n)
+  of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: 
+    a = sonsLen(n)
   else: a = 0
   if a > f: liMessage(n.info, errWrongNumberOfArguments)
   result = copyNode(n)
@@ -85,7 +84,8 @@ proc evalTemplate(c: PContext, n: PNode, sym: PSym): PNode =
   var args: PNode
   inc(evalTemplateCounter)
   if evalTemplateCounter > 100: 
-    liMessage(n.info, errTemplateInstantiationTooNested) # replace each param by the corresponding node:
+    liMessage(n.info, errTemplateInstantiationTooNested) 
+  # replace each param by the corresponding node:
   args = evalTemplateArgs(c, n, sym)
   result = evalTemplateAux(c, sym.ast.sons[codePos], args, sym)
   dec(evalTemplateCounter)
diff --git a/todo.txt b/todo.txt
index 773b68a97..19a6a7d06 100755
--- a/todo.txt
+++ b/todo.txt
@@ -1,6 +1,7 @@
 For version 0.8.10
 ==================
 
+- exception propagation across DLLs
 - fix exception handling
 - fix implicit generic routines
 - fix the streams implementation so that they use methods
@@ -61,6 +62,7 @@ Low priority
 - normalize for the DOM
 - tlastmod returns wrong results on BSD (Linux, MacOS X: works)
 - nested tuple unpacking
+- fast assignment optimization for TPeg
 
 
 Library
@@ -129,4 +131,7 @@ RST
 ---
 - footnotes; prefix :i: whitespace before :i:, _reference, `reference`__
   __ anonymous: www.nimrod.org
+- rewrite the parser to use the new better look ahead technique that c2nim
+  uses
+