summary refs log tree commit diff stats
path: root/lib/system.nim
diff options
context:
space:
mode:
Diffstat (limited to 'lib/system.nim')
-rw-r--r--lib/system.nim626
1 files changed, 344 insertions, 282 deletions
diff --git a/lib/system.nim b/lib/system.nim
index 8e8fc5d6d..285b921f8 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -58,10 +58,10 @@ proc new*[T](a: var ref T) {.magic: "New".}
 proc new*[T](a: var ref T, finalizer: proc (x: ref T)) {.magic: "NewFinalize".}
   ## creates a new object of type ``T`` and returns a safe (traced)
   ## reference to it in ``a``. When the garbage collector frees the object,
-  ## `finalizer` is called. The `finalizer` may not keep a reference to the 
+  ## `finalizer` is called. The `finalizer` may not keep a reference to the
   ## object pointed to by `x`. The `finalizer` cannot prevent the GC from
   ## freeing the object. Note: The `finalizer` refers to the type `T`, not to
-  ## the object! This means that for each object of type `T` the finalizer 
+  ## the object! This means that for each object of type `T` the finalizer
   ## will be called!
 
 # for low and high the return type T may not be correct, but
@@ -86,7 +86,6 @@ type
                                        ## length field.
   seq*{.magic: "Seq".}[T]  ## Generic type to construct sequences.
   set*{.magic: "Set".}[T]  ## Generic type to construct bit sets.
-  tuple*{.magic: "Tuple".}[T]  ## Generic type to construct tuple types.
 
   Byte* = Int8 ## this is an alias for ``int8``, that is a signed
                ## int 8 bits wide.
@@ -104,14 +103,15 @@ type
                     ## objects that have no ancestor are allowed.
   PObject* = ref TObject ## reference to TObject
 
-  E_Base* {.compilerproc.} = object of TObject ## base exception class; 
+  E_Base* {.compilerproc.} = object of TObject ## base exception class;
                                                ## each exception has to
                                                ## inherit from `E_Base`.
     name*: cstring            ## The exception's name is its Nimrod identifier.
                               ## This field is filled automatically in the
                               ## ``raise`` statement.
-    msg*: cstring             ## the exception's message. Not providing an
-                              ## exception message is bad style.
+    msg* {.exportc: "message".}: cstring ## the exception's message. Not
+                                         ## providing an
+                                         ## exception message is bad style.
 
   EAsynch* = object of E_Base ## Abstract exception class for
                               ## *asynchronous exceptions* (interrupts).
@@ -129,18 +129,21 @@ type
                                            ## could not be fullfilled.
   EArithmetic* = object of ESynch       ## raised if any kind of arithmetic
                                         ## error occured.
-  EDivByZero* = object of EArithmetic   ## is the exception class for integer
-                                        ## divide-by-zero errors.
-  EOverflow* = object of EArithmetic    ## is the exception class for integer
-                                        ## calculations whose results are too
-                                        ## large to fit in the provided bits.
-
-  EAccessViolation* = object of ESynch  ## the exception class for
-                                        ## invalid memory access errors
-
-  EAssertionFailed* = object of ESynch  ## is the exception class for Assert
-                                        ## procedures that is raised if the
-                                        ## assertion proves wrong
+  EDivByZero* {.compilerproc.} =
+    object of EArithmetic ## is the exception class for integer divide-by-zero
+                          ## errors.
+  EOverflow* {.compilerproc.} =
+    object of EArithmetic  ## is the exception class for integer calculations
+                           ## whose results are too large to fit in the
+                           ## provided bits.
+
+  EAccessViolation* {.compilerproc.} =
+    object of ESynch ## the exception class for invalid memory access errors
+
+  EAssertionFailed* {.compilerproc.} =
+    object of ESynch  ## is the exception class for Assert
+                      ## procedures that is raised if the
+                      ## assertion proves wrong
 
   EControlC* = object of EAsynch        ## is the exception class for Ctrl+C
                                         ## key presses in console applications.
@@ -154,6 +157,9 @@ type
 
   EInvalidIndex* = object of ESynch     ## is raised if an array index is out
                                         ## of bounds.
+  EInvalidField* = object of ESynch     ## is raised if a record field is not
+                                        ## accessible because its dicriminant's
+                                        ## value does not fit.
 
   EOutOfRange* = object of ESynch       ## is raised if a range check error
                                         ## occured.
@@ -164,13 +170,13 @@ type
   ENoExceptionToReraise* = object of ESynch ## is raised if there is no
                                             ## exception to reraise.
 
-  EInvalidObjectAssignment* = object of ESynch ## is raised if an object
-                                               ## gets assigned to its
-                                               ## farther's object.
+  EInvalidObjectAssignment* =
+    object of ESynch ## is raised if an object gets assigned to its
+                     ## farther's object.
 
-  EInvalidObjectConversion* = object of ESynch ## is raised if an object is
-                                               ## converted to an incompatible
-                                               ## object type.
+  EInvalidObjectConversion* =
+    object of ESynch ## is raised if an object is converted to an incompatible
+                     ## object type.
 
   TResult* = enum Failure, Success
 
@@ -394,7 +400,7 @@ proc in_Operator*[T](x: set[T], y: T): bool {.magic: "InSet", noSideEffect.}
   ##   writeln(stdout, 'b' in s)
   ##
   ## If ``in`` had been declared as ``[T](elem: T, s: set[T])`` then ``T`` would
-  ## have been bound to ``char``. But ``s`` is not compatible with type
+  ## have been bound to ``char``. But ``s`` is not compatible to type
   ## ``set[char]``! The solution is to bind ``T`` to ``range['a'..'z']``. This
   ## is achieved by reversing the parameters for ``in_operator``; ``in`` then
   ## passes its arguments in reverse order.
@@ -418,25 +424,31 @@ proc cmp*(x, y: string): int {.noSideEffect.}
   ## Compare proc for strings. More efficient than the generic version.
 
 # concat operator:
-proc `&` * (x: string, y: char): string {.
-  magic: "ConStrStr", noSideEffect, returnsNew.}
-proc `&` * (x: char, y: char): string {.
-  magic: "ConStrStr", noSideEffect, returnsNew.}
-proc `&` * (x, y: string): string {.
-  magic: "ConStrStr", noSideEffect, returnsNew.}
-proc `&` * (x: char, y: string): string {.
-  magic: "ConStrStr", noSideEffect, returnsNew.}
-  ## is the `concatenation operator`. It
-  ## concatenates `x` and `y`.
+proc `&` * (x: string, y: char): string {.magic: "ConStrStr", noSideEffect.}
+proc `&` * (x: char, y: char): string {.magic: "ConStrStr", noSideEffect.}
+proc `&` * (x, y: string): string {.magic: "ConStrStr", noSideEffect.}
+proc `&` * (x: char, y: string): string {.magic: "ConStrStr", noSideEffect.}
+  ## is the `concatenation operator`. It concatenates `x` and `y`.
 
 proc add * (x: var string, y: char) {.magic: "AppendStrCh".}
 proc add * (x: var string, y: string) {.magic: "AppendStrStr".}
 
-proc add* (x: var string, y: cstring) =
-  var i = 0
-  while y[i] != '\0':
-    add(x, y[i])
-    inc(i)
+when not defined(ECMAScript):
+  proc add* (x: var string, y: cstring) =
+    var i = 0
+    while y[i] != '\0':
+      add(x, y[i])
+      inc(i)
+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".}
 proc add *[T](x: var seq[T], y: seq[T]) {.magic: "AppendSeqSeq".}
@@ -493,7 +505,7 @@ type # these work for most platforms:
 
   TEndian* = enum ## is a type describing the endianness of a processor.
     littleEndian, bigEndian
-    
+
   PFloat32* = ptr Float32 ## an alias for ``ptr float32``
   PFloat64* = ptr Float64 ## an alias for ``ptr float64``
   PInt64* = ptr Int64 ## an alias for ``ptr int64``
@@ -675,20 +687,27 @@ proc swap*[T](a, b: var T) {.magic: "Swap".}
   ## swaps the values `a` and `b`. This is often more efficient than
   ## ``tmp = a; a = b; b = tmp``. Particularly useful for sorting algorithms.
 
-proc ze*(x: int8): int {.magic: "Ze", noSideEffect.}
+proc ze*(x: int8): int {.magic: "Ze8ToI", noSideEffect.}
   ## zero extends a smaller integer type to ``int``. This treats `x` as
   ## unsigned.
-proc ze*(x: int16): int {.magic: "Ze", noSideEffect.}
+proc ze*(x: int16): int {.magic: "Ze16ToI", noSideEffect.}
   ## zero extends a smaller integer type to ``int``. This treats `x` as
   ## unsigned.
 
-proc ze64*(x: int32): int64 {.magic: "Ze64", noSideEffect.}
+proc ze64*(x: int8): int64 {.magic: "Ze8ToI64", noSideEffect.}
   ## zero extends a smaller integer type to ``int64``. This treats `x` as
   ## unsigned.
-proc ze*(x: int): int64 {.magic: "Ze", noDecl, noSideEffect.}
+proc ze64*(x: int16): int64 {.magic: "Ze16ToI64", noSideEffect.}
+  ## zero extends a smaller integer type to ``int64``. This treats `x` as
+  ## unsigned.
+
+proc ze64*(x: int32): int64 {.magic: "Ze32ToI64", noSideEffect.}
+  ## zero extends a smaller integer type to ``int64``. This treats `x` as
+  ## unsigned.
+proc ze64*(x: int): int64 {.magic: "ZeIToI64", noDecl, noSideEffect.}
   ## zero extends a smaller integer type to ``int64``. This treats `x` as
   ## unsigned. Does nothing if the size of an ``int`` is the same as ``int64``.
-  ## (This is the case an 64 bit processors.)
+  ## (This is the case on 64 bit processors.)
 
 proc toU8*(x: int): int8 {.magic: "ToU8", noSideEffect.}
   ## treats `x` as unsigned and converts it to a byte by taking the last 8 bits
@@ -749,39 +768,39 @@ template `>%` *(x, y: expr): expr = y <% x
   ## treats `x` and `y` as unsigned and compares them.
   ## Returns true iff ``unsigned(x) > unsigned(y)``.
 
-proc `$` *(x: int): string {.noSideEffect.}
+proc `$` *(x: int): string {.magic: "IntToStr", noSideEffect.}
   ## The stingify operator for an integer argument. Returns `x`
   ## converted to a decimal string.
 
-proc `$` *(x: int64): string {.noSideEffect.}
+proc `$` *(x: int64): string {.magic: "Int64ToStr", noSideEffect.}
   ## The stingify operator for an integer argument. Returns `x`
   ## converted to a decimal string.
 
-proc `$` *(x: float): string {.noSideEffect.}
+proc `$` *(x: float): string {.magic: "FloatToStr", noSideEffect.}
   ## The stingify operator for a float argument. Returns `x`
   ## converted to a decimal string.
 
-proc `$` *(x: bool): string {.noSideEffect.}
+proc `$` *(x: bool): string {.magic: "BoolToStr", noSideEffect.}
   ## The stingify operator for a boolean argument. Returns `x`
   ## converted to the string "false" or "true".
 
-proc `$` *(x: char): string {.noSideEffect.}
+proc `$` *(x: char): string {.magic: "CharToStr", noSideEffect.}
   ## The stingify operator for a character argument. Returns `x`
   ## converted to a string.
 
-proc `$` *(x: Cstring): string {.noSideEffect, importc: "cstrToNimstr".}
+proc `$` *(x: Cstring): string {.magic: "CStrToStr", noSideEffect.}
   ## The stingify operator for a CString argument. Returns `x`
   ## converted to a string.
 
-proc `$` *(x: string): string {.noSideEffect.}
+proc `$` *(x: string): string {.magic: "StrToStr", noSideEffect.}
   ## The stingify operator for a string argument. Returns `x`
   ## as it is. This operator is useful for generic code, so
-  ## that ``$expr`` works if ``expr`` is already a string.
+  ## that ``$expr`` also works if ``expr`` is already a string.
 
 # undocumented:
 proc getRefcount*[T](x: ref T): int {.importc: "getRefcount".}
   ## retrieves the reference count of an heap-allocated object. The
-  ## value is implementation-dependant. 
+  ## value is implementation-dependant.
 
 #proc writeStackTrace() {.export: "writeStackTrace".}
 proc getCurrentExceptionMsg*(): string {.exportc.}
@@ -790,10 +809,12 @@ proc getCurrentExceptionMsg*(): string {.exportc.}
 
 # new constants:
 const
-  inf* = 1.0 / 0.0
+  inf* {.magic: "Inf".} = 0.0
     ## contains the IEEE floating point value of positive infinity.
-  nan* = 0.0 / 0.0
-    ## contains the IEEE floating point value of *Not A Number*. Note
+  neginf* {.magic: "NegInf".} = 0.0
+    ## contains the IEEE floating point value of negative infinity.
+  nan* {.magic: "NaN".} = 0.0
+    ## contains an IEEE floating point value of *Not A Number*. Note
     ## that you cannot compare a floating point value to this value
     ## and expect a reasonable result - use the `classify` procedure
     ## in the module ``math`` for checking for NaN.
@@ -805,18 +826,18 @@ var
     ## Only code compiled with the ``debugger:on`` switch calls this hook.
 
 # GC interface:
-when defined(Unix) and not defined(macosX) and not defined(linux): 
+when defined(Unix) and not defined(macosX) and not defined(linux):
   # BUGFIX for macosX
   {.define: nativeDL.}
 
 when defined(useDL) or defined(nativeDL):
   proc getOccupiedMem*(): int
     ## returns the number of bytes that are owned by the process and hold data.
-  
+
   proc getFreeMem*(): int
     ## returns the number of bytes that are owned by the process, but do not
     ## hold any meaningful data.
-  
+
   proc getTotalMem*(): int
     ## returns the number of bytes that are owned by the process.
 
@@ -885,11 +906,22 @@ iterator items*(a: cstring): char {.inline.} =
     yield a[i]
     inc(i)
 
+
+proc isNil*[T](x: seq[T]): bool {.noSideEffect, magic: "IsNil".}
+proc isNil*[T](x: ref T): bool {.noSideEffect, magic: "IsNil".}
+proc isNil*(x: string): bool {.noSideEffect, magic: "IsNil".}
+proc isNil*[T](x: ptr T): bool {.noSideEffect, magic: "IsNil".}
+proc isNil*(x: pointer): bool {.noSideEffect, magic: "IsNil".}
+proc isNil*(x: cstring): bool {.noSideEffect, magic: "IsNil".}
+  ## Fast check whether `x` is nil. This is sometimes more efficient than
+  ## ``== nil``.
+
+
 # Fixup some magic symbols here:
 {.fixup_system.} # This is an undocumented pragma that can only be used
                  # once in the system module.
 
-proc `&` *[T](x, y: seq[T]): seq[T] {.noSideEffect, returnsNew.} =
+proc `&` *[T](x, y: seq[T]): seq[T] {.noSideEffect.} =
   result = []
   setLen(result, x.len + y.len)
   for i in 0..x.len-1:
@@ -897,110 +929,74 @@ proc `&` *[T](x, y: seq[T]): seq[T] {.noSideEffect, returnsNew.} =
   for i in 0..y.len-1:
     result[i] = y[i]
 
-proc `&` *[T](x: seq[T], y: T): seq[T] {.noSideEffect, returnsNew.} =
+proc `&` *[T](x: seq[T], y: T): seq[T] {.noSideEffect.} =
   result = []
   setLen(x.len + 1)
   for i in 0..x.len-1:
     result[i] = x[i]
   result[x.len] = y
 
-proc `&` *[T](x: T, y: seq[T]): seq[T] {.noSideEffect, returnsNew.} =
+proc `&` *[T](x: T, y: seq[T]): seq[T] {.noSideEffect.} =
   result = []
   setLen(y.len + 1)
   for i in 0..y.len-1:
     result[i] = y[i]
   result[y.len] = x
 
-proc `&` *[T](x, y: T): seq[T] {.noSideEffect, returnsNew.} =
+proc `&` *[T](x, y: T): seq[T] {.noSideEffect.} =
   return [x, y]
 
+when not defined(ECMAScript): # XXX make this local procs
+  proc seqToPtr*[T](x: seq[T]): pointer {.inline, nosideeffect.} =
+    result = cast[pointer](x)
+else:
+  proc seqToPtr*[T](x: seq[T]): pointer {.pure, nosideeffect.} =
+    asm """return `x`"""
+
 proc `==` *[T](x, y: seq[T]): bool {.noSideEffect.} =
   ## Generic equals operator for sequences: relies on a equals operator for
   ## the element type `T`.
-  if cast[pointer](x) == cast[pointer](y):
+  if seqToPtr(x) == seqToPtr(y):
     result = true
-  elif cast[pointer](x) == nil or cast[pointer](y) == nil:
+  elif seqToPtr(x) == nil or seqToPtr(y) == nil:
     result = false
   elif x.len == y.len:
     for i in 0..x.len-1:
       if x[i] != y[i]: return false
     result = true
 
-{.push checks: off, line_dir: off, debugger: off,
-  assertions: on.}  # obviously we cannot generate checking operations here :-)
-                    # because it would yield into an endless recursion
-                    # however, stack-traces are available for most parts
-                    # of the code
-
-include hti
-
-proc initGC()
-
-var
-  strDesc: TNimType
-
-strDesc.size = sizeof(string)
-strDesc.kind = tyString
-initGC() # BUGFIX: need to be called here!
-
-{.push stack_trace: off.}
+# ----------------- FPU ------------------------------------------------------
 
-include ansi_c
+#proc disableFPUExceptions*()
+# disables all floating point unit exceptions
 
-proc cmp(x, y: string): int =
-  return c_strcmp(x, y)
+#proc enableFPUExceptions*()
+# enables all floating point unit exceptions
 
-when defined(windows):
-  # work-around C's sucking abstraction:
-  # BUGFIX: stdin and stdout should be binary files!
-  const pccHack = if defined(pcc): "_" else: "" # Hack for PCC
-  proc setmode(handle, mode: int) {.importc: pccHack & "setmode",
-                                    header: "<io.h>".}
-  proc fileno(f: C_TextFileStar): int {.importc: pccHack & "fileno",
-                                        header: "<fcntl.h>".}
-  var
-    O_BINARY {.importc: pccHack & "O_BINARY", nodecl.}: int
-
-  # we use binary mode in Windows:
-  setmode(fileno(c_stdin), O_BINARY)
-  setmode(fileno(c_stdout), O_BINARY)
-
-when defined(endb):
-  proc endbStep()
-
-
-template newException(exceptn, message: expr): expr =
-  block: # open a new scope
-    var
-      e: ref exceptn
-    new(e)
-    e.msg = message
-    e
-    
 # ----------------- GC interface ---------------------------------------------
 
-proc GC_disable*() 
+proc GC_disable*()
   ## disables the GC. If called n-times, n calls to `GC_enable` are needed to
   ## reactivate the GC. Note that in most circumstances one should only disable
-  ## the mark and sweep phase with `GC_disableMarkAndSweep`. 
+  ## the mark and sweep phase with `GC_disableMarkAndSweep`.
 
-proc GC_enable*() 
+proc GC_enable*()
   ## enables the GC again.
-  
+
 proc GC_fullCollect*()
-  ## forces a full garbage collection pass. 
+  ## forces a full garbage collection pass.
   ## Ordinary code does not need to call this.
 
 type
   TGC_Strategy* = enum ## the strategy the GC should use for the application
-    gcThroughput ,     ## optimize for throughput
+    gcThroughput,      ## optimize for throughput
     gcResponsiveness,  ## optimize for responsiveness (default)
     gcOptimizeTime,    ## optimize for speed
     gcOptimizeSpace    ## optimize for memory footprint
 
 proc GC_setStrategy*(strategy: TGC_Strategy)
   ## tells the GC the desired strategy for the application.
-  
+
 proc GC_enableMarkAndSweep*()
 proc GC_disableMarkAndSweep*()
   ## the current implementation uses a reference counting garbage collector
@@ -1009,176 +1005,242 @@ proc GC_disableMarkAndSweep*()
   ## does not create cycles. Thus the mark and sweep phase can be deactivated
   ## and activated separately from the rest of the GC.
 
-    
-# ----------------- IO Part --------------------------------------------------
 
-type
-  CFile {.importc: "FILE", nodecl.} = record  # empty record for
-                                              # data hiding
-  TFile* = ptr CFile ## The type representing a file handle.
-
-  TFileMode* = enum           ## The file mode when opening a file.
-    fmRead,                   ## Open the file for read access only.
-    fmWrite,                  ## Open the file for write access only.
-    fmReadWrite,              ## Open the file for read and write access.
-                              ## If the file does not exist, it will be
-                              ## created.
-    fmReadWriteExisting,      ## Open the file for read and write access.
-                              ## If the file does not exist, it will not be
-                              ## created.
-    fmAppend                  ## Open the file for writing only; append data
-                              ## at the end.
-
-# text file handling:
-var
-  stdin* {.importc: "stdin", noDecl.}: TFile   ## The standard input stream.
-  stdout* {.importc: "stdout", noDecl.}: TFile ## The standard output stream.
-  stderr* {.importc: "stderr", noDecl.}: TFile
-    ## The standard error stream.
-    ##
-    ## Note: In my opinion, this should not be used -- the concept of a
-    ## separate error stream is a design flaw of UNIX. A seperate *message
-    ## stream* is a good idea, but since it is named ``stderr`` there are few
-    ## programs out there that distinguish properly between ``stdout`` and
-    ## ``stderr``. So, that's what you get if you don't name your variables
-    ## appropriately. It also annoys people if redirection via ``>output.txt``
-    ## does not work because the program writes to ``stderr``.
-
-proc OpenFile*(f: var TFile, filename: string,
-               mode: TFileMode = fmRead, bufSize: int = -1): Bool
-  ## Opens a file named `filename` with given `mode`.
-  ##
-  ## Default mode is readonly. Returns true iff the file could be opened.
-  ## This throws no exception if the file could not be opened. The reason is
-  ## that the programmer needs to provide an appropriate error message anyway
-  ## (yes, even in scripts).
-
-proc CloseFile*(f: TFile) {.importc: "fclose", nodecl.}
-  ## Closes the file.
-proc EndOfFile*(f: TFile): Bool
-  ## Returns true iff `f` is at the end.
-proc readChar*(f: TFile): char {.importc: "fgetc", nodecl.}
-  ## Reads a single character from the stream `f`. If the stream
-  ## has no more characters, `EEndOfFile` is raised.
-proc FlushFile*(f: TFile) {.importc: "fflush", noDecl.}
-  ## Flushes `f`'s buffer.
-
-proc readFile*(filename: string): string
-  ## Opens a file name `filename` for reading. Then reads the
-  ## file's content completely into a string and
-  ## closes the file afterwards. Returns the string. Returns nil if there was
-  ## an error. Does not throw an IO exception.
-
-proc write*(f: TFile, r: float)
-proc write*(f: TFile, i: int)
-proc write*(f: TFile, s: string)
-proc write*(f: TFile, b: Bool)
-proc write*(f: TFile, c: char)
-proc write*(f: TFile, c: cstring)
-  ## Writes a value to the file `f`. May throw an IO exception.
-
-proc readLine*(f: TFile): string
-  ## reads a line of text from the file `f`. May throw an IO exception.
-  ## Reading from an empty file buffer, does not throw an exception, but
-  ## returns nil. A line of text may be delimited by ``CR``, ``LF`` or
-  ## ``CRLF``. The newline character(s) are not part of the returned string.
-
-proc writeln*[Ty](f: TFile, x: Ty) {.inline.}
-  ## writes a value `x` to `f` and then writes "\n". May throw an IO exception.
+{.push checks: off, line_dir: off, debugger: off,
+  assertions: on.}  # obviously we cannot generate checking operations here :-)
+                    # because it would yield into an endless recursion
+                    # however, stack-traces are available for most parts
+                    # of the code
+
 proc echo*[Ty](x: Ty) {.inline.}
-  ## equivalent to ``writeln(stdout, x); flush(stdout)``.
-
-proc getFileSize*(f: TFile): int64
-  ## retrieves the file size (in bytes) of `f`.
-
-proc ReadBytes*(f: TFile, a: var openarray[byte], start, len: int): int
-  ## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
-  ## the actual number of bytes that have been read which may be less than
-  ## `len` (if not as many bytes are remaining), but not greater.
-
-proc ReadChars*(f: TFile, a: var openarray[char], start, len: int): int
-  ## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
-  ## the actual number of bytes that have been read which may be less than
-  ## `len` (if not as many bytes are remaining), but not greater.
-
-proc readBuffer*(f: TFile, buffer: pointer, len: int): int
-  ## reads `len` bytes into the buffer pointed to by `buffer`. Returns
-  ## the actual number of bytes that have been read which may be less than
-  ## `len` (if not as many bytes are remaining), but not greater.
-
-proc writeBytes*(f: TFile, a: openarray[byte], start, len: int): int
-  ## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
-  ## the number of actual written bytes, which may be less than `len` in case
-  ## of an error.
-
-proc writeChars*(f: tFile, a: openarray[char], start, len: int): int
-  ## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
-  ## the number of actual written bytes, which may be less than `len` in case
-  ## of an error.
-
-proc writeBuffer*(f: TFile, buffer: pointer, len: int): int
-  ## writes the bytes of buffer pointed to by the parameter `buffer` to the
-  ## file `f`. Returns the number of actual written bytes, which may be less
-  ## than `len` in case of an error.
-
-proc setFilePos*(f: TFile, pos: int64)
-  ## sets the position of the file pointer that is used for read/write
-  ## operations. The file's first byte has the index zero.
-
-proc getFilePos*(f: TFile): int64
-  ## retrieves the current position of the file pointer that is used to
-  ## read from the file `f`. The file's first byte has the index zero.
-
-include sysio
-
-iterator lines*(filename: string): string =
-  ## Iterate over any line in the file named `filename`.
-  ## If the file does not exist `EIO` is raised.
-  var
-    f: TFile
-  if not openFile(f, filename):
-    raise newException(EIO, "cannot open: " & filename)
-  var res = ""
-  while not endOfFile(f):
-    rawReadLine(f, res)
-    yield res
-  CloseFile(f)
+  ## equivalent to ``writeln(stdout, x); flush(stdout)``. BUT: This is
+  ## available for the ECMAScript target too!
+
+
+template newException(exceptn, message: expr): expr =
+  block: # open a new scope
+    var
+      e: ref exceptn
+    new(e)
+    e.msg = message
+    e
 
-# ----------------------------------------------------------------------------
+when not defined(EcmaScript):
 
-include excpt
-# we cannot compile this with stack tracing on
-# as it would recurse endlessly!
-include arithm
-{.pop.} # stack trace
+  include hti
 
-# sequence type declarations here because the GC needs them too:
-type
-  TGenericSeq {.importc, nodecl.} = record
-    len, space: int
+  proc initGC()
 
-  PGenericSeq {.importc, nodecl.} = ptr TGenericSeq
+  var
+    strDesc: TNimType
 
-const
-  GenericSeqSize = (2 * sizeof(int))
+  strDesc.size = sizeof(string)
+  strDesc.kind = tyString
+  initGC() # BUGFIX: need to be called here!
 
-when not defined(boehmgc) and not defined(nogc):
-  include gc
+  {.push stack_trace: off.}
 
-include sysstr
-include assign
-include dyncalls
-include repr
+  include ansi_c
 
-# we have to implement it here after gentostr for the cstrToNimStrDummy proc
-proc getCurrentExceptionMsg(): string =
-  if excHandler == nil: return ""
-  return $excHandler.exc.msg
+  proc cmp(x, y: string): int =
+    return c_strcmp(x, y)
 
-{.push stack_trace: off.}
-when defined(endb):
-  include debugger
-{.pop.} # stacktrace
-{.pop.} # checks
+  when defined(windows):
+    # work-around C's sucking abstraction:
+    # BUGFIX: stdin and stdout should be binary files!
+    const pccHack = if defined(pcc): "_" else: "" # Hack for PCC
+    proc setmode(handle, mode: int) {.importc: pccHack & "setmode",
+                                      header: "<io.h>".}
+    proc fileno(f: C_TextFileStar): int {.importc: pccHack & "fileno",
+                                          header: "<fcntl.h>".}
+    var
+      O_BINARY {.importc: pccHack & "O_BINARY", nodecl.}: int
+
+    # we use binary mode in Windows:
+    setmode(fileno(c_stdin), O_BINARY)
+    setmode(fileno(c_stdout), O_BINARY)
+
+  when defined(endb):
+    proc endbStep()
+
+  # ----------------- IO Part --------------------------------------------------
+
+  type
+    CFile {.importc: "FILE", nodecl, final.} = object  # empty record for
+                                                       # data hiding
+    TFile* = ptr CFile ## The type representing a file handle.
+
+    TFileMode* = enum           ## The file mode when opening a file.
+      fmRead,                   ## Open the file for read access only.
+      fmWrite,                  ## Open the file for write access only.
+      fmReadWrite,              ## Open the file for read and write access.
+                                ## If the file does not exist, it will be
+                                ## created.
+      fmReadWriteExisting,      ## Open the file for read and write access.
+                                ## If the file does not exist, it will not be
+                                ## created.
+      fmAppend                  ## Open the file for writing only; append data
+                                ## at the end.
+
+  # text file handling:
+  var
+    stdin* {.importc: "stdin", noDecl.}: TFile   ## The standard input stream.
+    stdout* {.importc: "stdout", noDecl.}: TFile ## The standard output stream.
+    stderr* {.importc: "stderr", noDecl.}: TFile
+      ## The standard error stream.
+      ##
+      ## Note: In my opinion, this should not be used -- the concept of a
+      ## separate error stream is a design flaw of UNIX. A seperate *message
+      ## stream* is a good idea, but since it is named ``stderr`` there are few
+      ## programs out there that distinguish properly between ``stdout`` and
+      ## ``stderr``. So, that's what you get if you don't name your variables
+      ## appropriately. It also annoys people if redirection via ``>output.txt``
+      ## does not work because the program writes to ``stderr``.
+
+  proc OpenFile*(f: var TFile, filename: string,
+                 mode: TFileMode = fmRead, bufSize: int = -1): Bool
+    ## Opens a file named `filename` with given `mode`.
+    ##
+    ## Default mode is readonly. Returns true iff the file could be opened.
+    ## This throws no exception if the file could not be opened. The reason is
+    ## that the programmer needs to provide an appropriate error message anyway
+    ## (yes, even in scripts).
+
+  proc CloseFile*(f: TFile) {.importc: "fclose", nodecl.}
+    ## Closes the file.
+  proc EndOfFile*(f: TFile): Bool
+    ## Returns true iff `f` is at the end.
+  proc readChar*(f: TFile): char {.importc: "fgetc", nodecl.}
+    ## Reads a single character from the stream `f`. If the stream
+    ## has no more characters, `EEndOfFile` is raised.
+  proc FlushFile*(f: TFile) {.importc: "fflush", noDecl.}
+    ## Flushes `f`'s buffer.
+
+  proc readFile*(filename: string): string
+    ## Opens a file name `filename` for reading. Then reads the
+    ## file's content completely into a string and
+    ## closes the file afterwards. Returns the string. Returns nil if there was
+    ## an error. Does not throw an IO exception.
+
+  proc write*(f: TFile, r: float)
+  proc write*(f: TFile, i: int)
+  proc write*(f: TFile, s: string)
+  proc write*(f: TFile, b: Bool)
+  proc write*(f: TFile, c: char)
+  proc write*(f: TFile, c: cstring)
+  proc write*(f: TFile, a: openArray[string])
+    ## Writes a value to the file `f`. May throw an IO exception.
+
+  proc readLine*(f: TFile): string
+    ## reads a line of text from the file `f`. May throw an IO exception.
+    ## Reading from an empty file buffer, does not throw an exception, but
+    ## returns nil. A line of text may be delimited by ``CR``, ``LF`` or
+    ## ``CRLF``. The newline character(s) are not part of the returned string.
+
+  proc writeln*[Ty](f: TFile, x: Ty) {.inline.}
+    ## writes a value `x` to `f` and then writes "\n".
+    ## May throw an IO exception.
+
+  proc writeln*[Ty](f: TFile, x: openArray[Ty]) {.inline.}
+    ## writes a value `x` to `f` and then writes "\n".
+    ## May throw an IO exception.
+
+  proc getFileSize*(f: TFile): int64
+    ## retrieves the file size (in bytes) of `f`.
+
+  proc ReadBytes*(f: TFile, a: var openarray[byte], start, len: int): int
+    ## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
+    ## the actual number of bytes that have been read which may be less than
+    ## `len` (if not as many bytes are remaining), but not greater.
+
+  proc ReadChars*(f: TFile, a: var openarray[char], start, len: int): int
+    ## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
+    ## the actual number of bytes that have been read which may be less than
+    ## `len` (if not as many bytes are remaining), but not greater.
+
+  proc readBuffer*(f: TFile, buffer: pointer, len: int): int
+    ## reads `len` bytes into the buffer pointed to by `buffer`. Returns
+    ## the actual number of bytes that have been read which may be less than
+    ## `len` (if not as many bytes are remaining), but not greater.
+
+  proc writeBytes*(f: TFile, a: openarray[byte], start, len: int): int
+    ## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
+    ## the number of actual written bytes, which may be less than `len` in case
+    ## of an error.
+
+  proc writeChars*(f: tFile, a: openarray[char], start, len: int): int
+    ## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
+    ## the number of actual written bytes, which may be less than `len` in case
+    ## of an error.
+
+  proc writeBuffer*(f: TFile, buffer: pointer, len: int): int
+    ## writes the bytes of buffer pointed to by the parameter `buffer` to the
+    ## file `f`. Returns the number of actual written bytes, which may be less
+    ## than `len` in case of an error.
+
+  proc setFilePos*(f: TFile, pos: int64)
+    ## sets the position of the file pointer that is used for read/write
+    ## operations. The file's first byte has the index zero.
+
+  proc getFilePos*(f: TFile): int64
+    ## retrieves the current position of the file pointer that is used to
+    ## read from the file `f`. The file's first byte has the index zero.
+
+  include sysio
+
+  iterator lines*(filename: string): string =
+    ## Iterate over any line in the file named `filename`.
+    ## If the file does not exist `EIO` is raised.
+    var
+      f: TFile
+    if not openFile(f, filename):
+      raise newException(EIO, "cannot open: " & filename)
+    var res = ""
+    while not endOfFile(f):
+      rawReadLine(f, res)
+      yield res
+    CloseFile(f)
+
+  # ----------------------------------------------------------------------------
+
+  include excpt
+  # we cannot compile this with stack tracing on
+  # as it would recurse endlessly!
+  include arithm
+  {.pop.} # stack trace
+
+  # sequence type declarations here because the GC needs them too:
+  type
+    TGenericSeq {.importc, nodecl, final.} = object
+      len, space: int
+
+    PGenericSeq {.importc, nodecl.} = ptr TGenericSeq
+
+  const
+    GenericSeqSize = (2 * sizeof(int))
+
+  when not defined(boehmgc) and not defined(nogc):
+    include gc
+
+  include sysstr
+  include assign
+  include dyncalls
+  include repr
+
+  # we have to implement it here after gentostr for the cstrToNimStrDummy proc
+  proc getCurrentExceptionMsg(): string =
+    if excHandler == nil: return ""
+    return $excHandler.exc.msg
+
+  {.push stack_trace: off.}
+  when defined(endb):
+    include debugger
+  {.pop.} # stacktrace
 
+else:
+  include ecmasys
+
+include macros
+
+{.pop.} # checks
 {.pop.} # hints