diff --git a/build.bat b/build.bat
index 29967f256b..0bcaddd365 100755
--- a/build.bat
+++ b/build.bat
@@ -51,6 +51,8 @@ ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/idents.c -o build/1_1/idents.o
%CC% %COMP_FLAGS% -Ibuild -c build/1_1/idents.c -o build/1_1/idents.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/astalgo.c -o build/1_1/astalgo.o
%CC% %COMP_FLAGS% -Ibuild -c build/1_1/astalgo.c -o build/1_1/astalgo.o
+ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/rodutils.c -o build/1_1/rodutils.o
+%CC% %COMP_FLAGS% -Ibuild -c build/1_1/rodutils.c -o build/1_1/rodutils.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/extccomp.c -o build/1_1/extccomp.o
%CC% %COMP_FLAGS% -Ibuild -c build/1_1/extccomp.c -o build/1_1/extccomp.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/osproc.c -o build/1_1/osproc.o
@@ -146,8 +148,8 @@ ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/transf.c -o build/1_1/transf.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/parseopt.c -o build/1_1/parseopt.o
%CC% %COMP_FLAGS% -Ibuild -c build/1_1/parseopt.c -o build/1_1/parseopt.o
-ECHO %LINKER% %LINK_FLAGS% -o bin\nimrod.exe build/1_1/nim__dat.o build/1_1/system.o build/1_1/nimrod.o build/1_1/times.o build/1_1/strutils.o build/1_1/parseutils.o build/1_1/winlean.o build/1_1/commands.o build/1_1/os.o build/1_1/msgs.o build/1_1/options.o build/1_1/lists.o build/1_1/nstrtabs.o build/1_1/nhashes.o build/1_1/nversion.o build/1_1/condsyms.o build/1_1/ast.o build/1_1/crc.o build/1_1/ropes.o build/1_1/platform.o build/1_1/idents.o build/1_1/astalgo.o build/1_1/extccomp.o build/1_1/osproc.o build/1_1/strtabs.o build/1_1/hashes.o build/1_1/streams.o build/1_1/wordrecg.o build/1_1/scanner.o build/1_1/lexbase.o build/1_1/llstream.o build/1_1/nimconf.o build/1_1/main.o build/1_1/syntaxes.o build/1_1/pnimsyn.o build/1_1/pbraces.o build/1_1/ptmplsyn.o build/1_1/rnimsyn.o build/1_1/filters.o build/1_1/rodread.o build/1_1/rodwrite.o build/1_1/passes.o build/1_1/types.o build/1_1/trees.o build/1_1/math.o build/1_1/magicsys.o build/1_1/nimsets.o build/1_1/bitsets.o build/1_1/importer.o build/1_1/lookups.o build/1_1/semdata.o build/1_1/treetab.o build/1_1/sem.o build/1_1/evals.o build/1_1/semfold.o build/1_1/procfind.o build/1_1/pragmas.o build/1_1/docgen.o build/1_1/rst.o build/1_1/highlite.o build/1_1/cgen.o build/1_1/ccgutils.o build/1_1/cgmeth.o build/1_1/ecmasgen.o build/1_1/interact.o build/1_1/passaux.o build/1_1/depends.o build/1_1/transf.o build/1_1/parseopt.o
-%LINKER% %LINK_FLAGS% -o bin\nimrod.exe build/1_1/nim__dat.o build/1_1/system.o build/1_1/nimrod.o build/1_1/times.o build/1_1/strutils.o build/1_1/parseutils.o build/1_1/winlean.o build/1_1/commands.o build/1_1/os.o build/1_1/msgs.o build/1_1/options.o build/1_1/lists.o build/1_1/nstrtabs.o build/1_1/nhashes.o build/1_1/nversion.o build/1_1/condsyms.o build/1_1/ast.o build/1_1/crc.o build/1_1/ropes.o build/1_1/platform.o build/1_1/idents.o build/1_1/astalgo.o build/1_1/extccomp.o build/1_1/osproc.o build/1_1/strtabs.o build/1_1/hashes.o build/1_1/streams.o build/1_1/wordrecg.o build/1_1/scanner.o build/1_1/lexbase.o build/1_1/llstream.o build/1_1/nimconf.o build/1_1/main.o build/1_1/syntaxes.o build/1_1/pnimsyn.o build/1_1/pbraces.o build/1_1/ptmplsyn.o build/1_1/rnimsyn.o build/1_1/filters.o build/1_1/rodread.o build/1_1/rodwrite.o build/1_1/passes.o build/1_1/types.o build/1_1/trees.o build/1_1/math.o build/1_1/magicsys.o build/1_1/nimsets.o build/1_1/bitsets.o build/1_1/importer.o build/1_1/lookups.o build/1_1/semdata.o build/1_1/treetab.o build/1_1/sem.o build/1_1/evals.o build/1_1/semfold.o build/1_1/procfind.o build/1_1/pragmas.o build/1_1/docgen.o build/1_1/rst.o build/1_1/highlite.o build/1_1/cgen.o build/1_1/ccgutils.o build/1_1/cgmeth.o build/1_1/ecmasgen.o build/1_1/interact.o build/1_1/passaux.o build/1_1/depends.o build/1_1/transf.o build/1_1/parseopt.o
+ECHO %LINKER% %LINK_FLAGS% -o bin\nimrod.exe build/1_1/nim__dat.o build/1_1/system.o build/1_1/nimrod.o build/1_1/times.o build/1_1/strutils.o build/1_1/parseutils.o build/1_1/winlean.o build/1_1/commands.o build/1_1/os.o build/1_1/msgs.o build/1_1/options.o build/1_1/lists.o build/1_1/nstrtabs.o build/1_1/nhashes.o build/1_1/nversion.o build/1_1/condsyms.o build/1_1/ast.o build/1_1/crc.o build/1_1/ropes.o build/1_1/platform.o build/1_1/idents.o build/1_1/astalgo.o build/1_1/rodutils.o build/1_1/extccomp.o build/1_1/osproc.o build/1_1/strtabs.o build/1_1/hashes.o build/1_1/streams.o build/1_1/wordrecg.o build/1_1/scanner.o build/1_1/lexbase.o build/1_1/llstream.o build/1_1/nimconf.o build/1_1/main.o build/1_1/syntaxes.o build/1_1/pnimsyn.o build/1_1/pbraces.o build/1_1/ptmplsyn.o build/1_1/rnimsyn.o build/1_1/filters.o build/1_1/rodread.o build/1_1/rodwrite.o build/1_1/passes.o build/1_1/types.o build/1_1/trees.o build/1_1/math.o build/1_1/magicsys.o build/1_1/nimsets.o build/1_1/bitsets.o build/1_1/importer.o build/1_1/lookups.o build/1_1/semdata.o build/1_1/treetab.o build/1_1/sem.o build/1_1/evals.o build/1_1/semfold.o build/1_1/procfind.o build/1_1/pragmas.o build/1_1/docgen.o build/1_1/rst.o build/1_1/highlite.o build/1_1/cgen.o build/1_1/ccgutils.o build/1_1/cgmeth.o build/1_1/ecmasgen.o build/1_1/interact.o build/1_1/passaux.o build/1_1/depends.o build/1_1/transf.o build/1_1/parseopt.o
+%LINKER% %LINK_FLAGS% -o bin\nimrod.exe build/1_1/nim__dat.o build/1_1/system.o build/1_1/nimrod.o build/1_1/times.o build/1_1/strutils.o build/1_1/parseutils.o build/1_1/winlean.o build/1_1/commands.o build/1_1/os.o build/1_1/msgs.o build/1_1/options.o build/1_1/lists.o build/1_1/nstrtabs.o build/1_1/nhashes.o build/1_1/nversion.o build/1_1/condsyms.o build/1_1/ast.o build/1_1/crc.o build/1_1/ropes.o build/1_1/platform.o build/1_1/idents.o build/1_1/astalgo.o build/1_1/rodutils.o build/1_1/extccomp.o build/1_1/osproc.o build/1_1/strtabs.o build/1_1/hashes.o build/1_1/streams.o build/1_1/wordrecg.o build/1_1/scanner.o build/1_1/lexbase.o build/1_1/llstream.o build/1_1/nimconf.o build/1_1/main.o build/1_1/syntaxes.o build/1_1/pnimsyn.o build/1_1/pbraces.o build/1_1/ptmplsyn.o build/1_1/rnimsyn.o build/1_1/filters.o build/1_1/rodread.o build/1_1/rodwrite.o build/1_1/passes.o build/1_1/types.o build/1_1/trees.o build/1_1/math.o build/1_1/magicsys.o build/1_1/nimsets.o build/1_1/bitsets.o build/1_1/importer.o build/1_1/lookups.o build/1_1/semdata.o build/1_1/treetab.o build/1_1/sem.o build/1_1/evals.o build/1_1/semfold.o build/1_1/procfind.o build/1_1/pragmas.o build/1_1/docgen.o build/1_1/rst.o build/1_1/highlite.o build/1_1/cgen.o build/1_1/ccgutils.o build/1_1/cgmeth.o build/1_1/ecmasgen.o build/1_1/interact.o build/1_1/passaux.o build/1_1/depends.o build/1_1/transf.o build/1_1/parseopt.o
ECHO SUCCESS
diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg
index 541eacced5..d9a5b1ae2c 100755
--- a/config/nimdoc.cfg
+++ b/config/nimdoc.cfg
@@ -45,16 +45,12 @@ doc.body_toc = """
$tableofcontents
$moduledesc
-
Dependencies
- $deps
$content
"""
doc.body_no_toc = """
$moduledesc
-Dependencies
- $deps
$content
"""
diff --git a/config/nimdoc.tex.cfg b/config/nimdoc.tex.cfg
index 2ec5f98cb4..ecb95fe01f 100755
--- a/config/nimdoc.tex.cfg
+++ b/config/nimdoc.tex.cfg
@@ -30,17 +30,11 @@ doc.toc = r"\tableofcontents \newpage"
doc.body_toc = """
$tableofcontents
$moduledesc
-
-Dependencies: $deps
-
$content
"""
doc.body_no_toc = """
$moduledesc
-
-Dependencies: $deps
-
$content
"""
diff --git a/config/nimrod.cfg b/config/nimrod.cfg
index 122980348c..4914d09932 100755
--- a/config/nimrod.cfg
+++ b/config/nimrod.cfg
@@ -1,5 +1,5 @@
# Configuration file for the Nimrod Compiler.
-# (c) 2010 Andreas Rumpf
+# (c) 2011 Andreas Rumpf
# Feel free to edit the default values as you need.
@@ -14,6 +14,7 @@ cc = gcc
lib = "nimlib"
@end
+path="$lib/core"
path="$lib/pure"
path="$lib/impure"
path="$lib/wrappers"
diff --git a/doc/lib.txt b/doc/lib.txt
index 47cd08caba..cefb1a1feb 100644
--- a/doc/lib.txt
+++ b/doc/lib.txt
@@ -31,6 +31,9 @@ Core
implicitly by the compiler. Do not import it directly. It relies on compiler
magic to work.
+* `threads `_
+ Nimrod thread support.
+
* `macros `_
Contains the AST API and documentation of Nimrod for writing macros.
diff --git a/doc/nimrodc.txt b/doc/nimrodc.txt
index 0a0781e368..c4b61a14f6 100755
--- a/doc/nimrodc.txt
+++ b/doc/nimrodc.txt
@@ -70,13 +70,24 @@ 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.
+
+Cross compilation
+=================
+
+To `cross compile`:idx:, use for example::
+
+ nimrod c --cpu:i386 --os:linux --compile_only --gen_script myproject.nim
+
+Then move the C code and the compile script ``compile_myproject.sh`` to your
+Linux i386 machine and run the script.
+
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
+``nimrtl.dll``. This means that every generated Nimrod `DLL`:idx: depends
on ``nimrtl.dll``. To generate the "nimrtl.dll" file, use the command::
nimrod c -d:release lib/nimrtl.nim
diff --git a/install.sh b/install.sh
index 06f5c8a9c3..9367ea95c7 100755
--- a/install.sh
+++ b/install.sh
@@ -321,6 +321,8 @@ if [ $# -eq 1 ] ; then
chmod 644 $libdir/system/sysstr.nim
cp lib/system/systhread.nim $libdir/system/systhread.nim
chmod 644 $libdir/system/systhread.nim
+ cp lib/pure/base64.nim $libdir/pure/base64.nim
+ chmod 644 $libdir/pure/base64.nim
cp lib/pure/browsers.nim $libdir/pure/browsers.nim
chmod 644 $libdir/pure/browsers.nim
cp lib/pure/cgi.nim $libdir/pure/cgi.nim
@@ -329,12 +331,12 @@ if [ $# -eq 1 ] ; then
chmod 644 $libdir/pure/colors.nim
cp lib/pure/complex.nim $libdir/pure/complex.nim
chmod 644 $libdir/pure/complex.nim
+ cp lib/pure/cookies.nim $libdir/pure/cookies.nim
+ chmod 644 $libdir/pure/cookies.nim
cp lib/pure/dynlib.nim $libdir/pure/dynlib.nim
chmod 644 $libdir/pure/dynlib.nim
cp lib/pure/hashes.nim $libdir/pure/hashes.nim
chmod 644 $libdir/pure/hashes.nim
- cp lib/pure/hashtabs.nim $libdir/pure/hashtabs.nim
- chmod 644 $libdir/pure/hashtabs.nim
cp lib/pure/htmlparser.nim $libdir/pure/htmlparser.nim
chmod 644 $libdir/pure/htmlparser.nim
cp lib/pure/httpclient.nim $libdir/pure/httpclient.nim
@@ -347,8 +349,6 @@ if [ $# -eq 1 ] ; then
chmod 644 $libdir/pure/lexbase.nim
cp lib/pure/logging.nim $libdir/pure/logging.nim
chmod 644 $libdir/pure/logging.nim
- cp lib/pure/macros.nim $libdir/pure/macros.nim
- chmod 644 $libdir/pure/macros.nim
cp lib/pure/math.nim $libdir/pure/math.nim
chmod 644 $libdir/pure/math.nim
cp lib/pure/md5.nim $libdir/pure/md5.nim
@@ -377,6 +377,10 @@ if [ $# -eq 1 ] ; then
chmod 644 $libdir/pure/regexprs.nim
cp lib/pure/ropes.nim $libdir/pure/ropes.nim
chmod 644 $libdir/pure/ropes.nim
+ cp lib/pure/scgi.nim $libdir/pure/scgi.nim
+ chmod 644 $libdir/pure/scgi.nim
+ cp lib/pure/smtp.nim $libdir/pure/smtp.nim
+ chmod 644 $libdir/pure/smtp.nim
cp lib/pure/sockets.nim $libdir/pure/sockets.nim
chmod 644 $libdir/pure/sockets.nim
cp lib/pure/streams.nim $libdir/pure/streams.nim
@@ -391,8 +395,6 @@ if [ $# -eq 1 ] ; then
chmod 644 $libdir/pure/times.nim
cp lib/pure/unicode.nim $libdir/pure/unicode.nim
chmod 644 $libdir/pure/unicode.nim
- cp lib/pure/variants.nim $libdir/pure/variants.nim
- chmod 644 $libdir/pure/variants.nim
cp lib/pure/xmldom.nim $libdir/pure/xmldom.nim
chmod 644 $libdir/pure/xmldom.nim
cp lib/pure/xmldomparser.nim $libdir/pure/xmldomparser.nim
@@ -421,10 +423,14 @@ if [ $# -eq 1 ] ; then
chmod 644 $libdir/impure/osinfo_win.nim
cp lib/impure/re.nim $libdir/impure/re.nim
chmod 644 $libdir/impure/re.nim
+ cp lib/impure/ssl.nim $libdir/impure/ssl.nim
+ chmod 644 $libdir/impure/ssl.nim
cp lib/impure/web.nim $libdir/impure/web.nim
chmod 644 $libdir/impure/web.nim
cp lib/impure/zipfiles.nim $libdir/impure/zipfiles.nim
chmod 644 $libdir/impure/zipfiles.nim
+ cp lib/wrappers/claro.nim $libdir/wrappers/claro.nim
+ chmod 644 $libdir/wrappers/claro.nim
cp lib/wrappers/expat.nim $libdir/wrappers/expat.nim
chmod 644 $libdir/wrappers/expat.nim
cp lib/wrappers/iup.nim $libdir/wrappers/iup.nim
@@ -435,6 +441,8 @@ if [ $# -eq 1 ] ; then
chmod 644 $libdir/wrappers/mysql.nim
cp lib/wrappers/odbcsql.nim $libdir/wrappers/odbcsql.nim
chmod 644 $libdir/wrappers/odbcsql.nim
+ cp lib/wrappers/openssl.nim $libdir/wrappers/openssl.nim
+ chmod 644 $libdir/wrappers/openssl.nim
cp lib/wrappers/pcre.nim $libdir/wrappers/pcre.nim
chmod 644 $libdir/wrappers/pcre.nim
cp lib/wrappers/postgres.nim $libdir/wrappers/postgres.nim
diff --git a/lib/pure/macros.nim b/lib/core/macros.nim
similarity index 100%
rename from lib/pure/macros.nim
rename to lib/core/macros.nim
diff --git a/lib/core/marshal.nim b/lib/core/marshal.nim
new file mode 100644
index 0000000000..303b088f89
--- /dev/null
+++ b/lib/core/marshal.nim
@@ -0,0 +1,259 @@
+#
+#
+# Nimrod's Runtime Library
+# (c) Copyright 2011 Andreas Rumpf
+#
+# See the file "copying.txt", included in this
+# distribution, for details about the copyright.
+#
+
+## This module contains procs for serialization and deseralization of
+## arbitrary Nimrod data structures. XXX This is not implemented yet!
+
+import streams
+
+proc load*[T](s: PStream, data: var T) {.magic: "Load".}
+ ## loads `data` from the stream `s`. Raises `EIO` in case of an error.
+
+proc store*[T](s: PStream, data: T) {.magic: "Store".}
+ ## stores `data` into the stream `s`. Raises `EIO` in case of an error.
+
+
+proc reprInt(x: int64): string {.compilerproc.} = return $x
+proc reprFloat(x: float): string {.compilerproc.} = return $x
+
+proc reprPointer(x: pointer): string {.compilerproc.} =
+ var buf: array [0..59, char]
+ c_sprintf(buf, "%p", x)
+ return $buf
+
+proc reprStrAux(result: var string, s: string) =
+ if cast[pointer](s) == nil:
+ add result, "nil"
+ return
+ add result, reprPointer(cast[pointer](s)) & "\""
+ for c in items(s):
+ case c
+ of '"': add result, "\\\""
+ of '\\': add result, "\\\\" # BUGFIX: forgotten
+ of '\10': add result, "\\10\"\n\"" # " \n " # better readability
+ of '\128' .. '\255', '\0'..'\9', '\11'..'\31':
+ add result, "\\" & reprInt(ord(c))
+ else: result.add(c)
+ add result, "\""
+
+proc reprStr(s: string): string {.compilerRtl.} =
+ result = ""
+ reprStrAux(result, s)
+
+proc reprBool(x: bool): string {.compilerRtl.} =
+ if x: result = "true"
+ else: result = "false"
+
+proc reprChar(x: char): string {.compilerRtl.} =
+ result = "\'"
+ case x
+ of '"': add result, "\\\""
+ of '\\': add result, "\\\\"
+ of '\128' .. '\255', '\0'..'\31': add result, "\\" & reprInt(ord(x))
+ else: add result, x
+ add result, "\'"
+
+proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} =
+ if e <% typ.node.len: # BUGFIX
+ result = $typ.node.sons[e].name
+ else:
+ result = $e & " (invalid data!)"
+
+type
+ pbyteArray = ptr array[0.. 0xffff, byte]
+
+proc addSetElem(result: var string, elem: int, typ: PNimType) =
+ case typ.kind
+ of tyEnum: add result, reprEnum(elem, typ)
+ of tyBool: add result, reprBool(bool(elem))
+ of tyChar: add result, reprChar(chr(elem))
+ of tyRange: addSetElem(result, elem, typ.base)
+ of tyInt..tyInt64: add result, reprInt(elem)
+ else: # data corrupt --> inform the user
+ add result, " (invalid data!)"
+
+proc reprSetAux(result: var string, p: pointer, typ: PNimType) =
+ # "typ.slots.len" field is for sets the "first" field
+ var elemCounter = 0 # we need this flag for adding the comma at
+ # the right places
+ add result, "{"
+ var u: int64
+ case typ.size
+ of 1: u = ze64(cast[ptr int8](p)^)
+ of 2: u = ze64(cast[ptr int16](p)^)
+ of 4: u = ze64(cast[ptr int32](p)^)
+ of 8: u = cast[ptr int64](p)^
+ else:
+ var a = cast[pbyteArray](p)
+ for i in 0 .. typ.size*8-1:
+ if (ze(a[i div 8]) and (1 shl (i mod 8))) != 0:
+ if elemCounter > 0: add result, ", "
+ addSetElem(result, i+typ.node.len, typ.base)
+ inc(elemCounter)
+ if typ.size <= 8:
+ for i in 0..sizeof(int64)*8-1:
+ if (u and (1 shl i)) != 0:
+ if elemCounter > 0: add result, ", "
+ addSetElem(result, i+typ.node.len, typ.base)
+ inc(elemCounter)
+ add result, "}"
+
+proc reprSet(p: pointer, typ: PNimType): string {.compilerRtl.} =
+ result = ""
+ reprSetAux(result, p, typ)
+
+type
+ TReprClosure {.final.} = object # we cannot use a global variable here
+ # as this wouldn't be thread-safe
+ marked: TCellSet
+ recdepth: int # do not recurse endless
+ indent: int # indentation
+
+when not defined(useNimRtl):
+ proc initReprClosure(cl: var TReprClosure) =
+ Init(cl.marked)
+ cl.recdepth = -1 # default is to display everything!
+ cl.indent = 0
+
+ proc deinitReprClosure(cl: var TReprClosure) =
+ Deinit(cl.marked)
+
+ proc reprBreak(result: var string, cl: TReprClosure) =
+ add result, "\n"
+ for i in 0..cl.indent-1: add result, ' '
+
+ proc reprAux(result: var string, p: pointer, typ: PNimType,
+ cl: var TReprClosure)
+
+ proc reprArray(result: var string, p: pointer, typ: PNimType,
+ cl: var TReprClosure) =
+ add result, "["
+ var bs = typ.base.size
+ for i in 0..typ.size div bs - 1:
+ if i > 0: add result, ", "
+ reprAux(result, cast[pointer](cast[TAddress](p) + i*bs), typ.base, cl)
+ add result, "]"
+
+ proc reprSequence(result: var string, p: pointer, typ: PNimType,
+ cl: var TReprClosure) =
+ if p == nil:
+ add result, "nil"
+ return
+ result.add(reprPointer(p) & "[")
+ var bs = typ.base.size
+ for i in 0..cast[PGenericSeq](p).len-1:
+ if i > 0: add result, ", "
+ reprAux(result, cast[pointer](cast[TAddress](p) + GenericSeqSize + i*bs),
+ typ.Base, cl)
+ add result, "]"
+
+ proc reprRecordAux(result: var string, p: pointer, n: ptr TNimNode,
+ cl: var TReprClosure) =
+ case n.kind
+ of nkNone: assert(false)
+ of nkSlot:
+ add result, $n.name
+ add result, " = "
+ reprAux(result, cast[pointer](cast[TAddress](p) + n.offset), n.typ, cl)
+ of nkList:
+ for i in 0..n.len-1:
+ if i > 0: add result, ",\n"
+ reprRecordAux(result, p, n.sons[i], cl)
+ of nkCase:
+ var m = selectBranch(p, n)
+ reprAux(result, cast[pointer](cast[TAddress](p) + n.offset), n.typ, cl)
+ if m != nil: reprRecordAux(result, p, m, cl)
+
+ proc reprRecord(result: var string, p: pointer, typ: PNimType,
+ cl: var TReprClosure) =
+ add result, "["
+ reprRecordAux(result, p, typ.node, cl)
+ add result, "]"
+
+ proc reprRef(result: var string, p: pointer, typ: PNimType,
+ cl: var TReprClosure) =
+ # we know that p is not nil here:
+ when defined(boehmGC) or defined(nogc):
+ var cell = cast[PCell](p)
+ else:
+ var cell = usrToCell(p)
+ add result, "ref " & reprPointer(p)
+ if cell notin cl.marked:
+ # only the address is shown:
+ incl(cl.marked, cell)
+ add result, " --> "
+ reprAux(result, p, typ.base, cl)
+
+ proc reprAux(result: var string, p: pointer, typ: PNimType,
+ cl: var TReprClosure) =
+ if cl.recdepth == 0:
+ add result, "..."
+ return
+ dec(cl.recdepth)
+ case typ.kind
+ of tySet: reprSetAux(result, p, typ)
+ of tyArray: reprArray(result, p, typ, cl)
+ of tyTuple, tyPureObject: reprRecord(result, p, typ, cl)
+ of tyObject:
+ var t = cast[ptr PNimType](p)^
+ reprRecord(result, p, t, cl)
+ of tyRef, tyPtr:
+ assert(p != nil)
+ if cast[ppointer](p)^ == nil: add result, "nil"
+ else: reprRef(result, cast[ppointer](p)^, typ, cl)
+ of tySequence:
+ reprSequence(result, cast[ppointer](p)^, typ, cl)
+ of tyInt: add result, $(cast[ptr int](p)^)
+ of tyInt8: add result, $int(cast[ptr Int8](p)^)
+ of tyInt16: add result, $int(cast[ptr Int16](p)^)
+ of tyInt32: add result, $int(cast[ptr Int32](p)^)
+ of tyInt64: add result, $(cast[ptr Int64](p)^)
+ of tyFloat: add result, $(cast[ptr float](p)^)
+ of tyFloat32: add result, $(cast[ptr float32](p)^)
+ of tyFloat64: add result, $(cast[ptr float64](p)^)
+ of tyEnum: add result, reprEnum(cast[ptr int](p)^, typ)
+ of tyBool: add result, reprBool(cast[ptr bool](p)^)
+ of tyChar: add result, reprChar(cast[ptr char](p)^)
+ of tyString: reprStrAux(result, cast[ptr string](p)^)
+ of tyCString: reprStrAux(result, $(cast[ptr cstring](p)^))
+ of tyRange: reprAux(result, p, typ.base, cl)
+ of tyProc, tyPointer:
+ if cast[ppointer](p)^ == nil: add result, "nil"
+ else: add result, reprPointer(cast[ppointer](p)^)
+ else:
+ add result, "(invalid data!)"
+ inc(cl.recdepth)
+
+proc reprOpenArray(p: pointer, length: int, elemtyp: PNimType): string {.
+ compilerRtl.} =
+ var
+ cl: TReprClosure
+ initReprClosure(cl)
+ result = "["
+ var bs = elemtyp.size
+ for i in 0..length - 1:
+ if i > 0: add result, ", "
+ reprAux(result, cast[pointer](cast[TAddress](p) + i*bs), elemtyp, cl)
+ add result, "]"
+ deinitReprClosure(cl)
+
+when not defined(useNimRtl):
+ proc reprAny(p: pointer, typ: PNimType): string =
+ var
+ cl: TReprClosure
+ initReprClosure(cl)
+ result = ""
+ if typ.kind in {tyObject, tyPureObject, tyTuple, tyArray, tySet}:
+ reprAux(result, p, typ, cl)
+ else:
+ var p = p
+ reprAux(result, addr(p), typ, cl)
+ add result, "\n"
+ deinitReprClosure(cl)
+
diff --git a/lib/core/threads.nim b/lib/core/threads.nim
new file mode 100644
index 0000000000..feb026547e
--- /dev/null
+++ b/lib/core/threads.nim
@@ -0,0 +1,174 @@
+#
+#
+# Nimrod's Runtime Library
+# (c) Copyright 2011 Andreas Rumpf
+#
+# See the file "copying.txt", included in this
+# distribution, for details about the copyright.
+#
+
+## Basic thread support for Nimrod. Note that Nimrod's default GC is still
+## single-threaded. This means that either your threads should not allocate
+## GC'ed memory, or you should compile with ``--gc:none`` or ``--gc:boehm``.
+##
+## Example:
+##
+## .. code-block:: nimrod
+##
+## var
+## thr: array [0..4, TThread]
+## L: TLock
+##
+## proc threadFunc(c: pointer) {.procvar.} =
+## for i in 0..9:
+## Aquire(L) # lock stdout
+## echo i
+## Release(L)
+##
+## InitLock(L)
+##
+## for i in 0..high(thr):
+## createThread(thr[i], threadFunc)
+## for i in 0..high(thr):
+## joinThread(thr[i])
+
+
+# We jump through some hops here to ensure that Nimrod thread procs can have
+# the Nimrod calling convention. This is needed because thread procs are
+# ``stdcall`` on Windows and ``noconv`` on UNIX. Alternative would be to just
+# use ``stdcall`` since it is mapped to ``noconv`` on UNIX anyway. However,
+# the current approach will likely result in less problems later when we have
+# GC'ed closures in Nimrod.
+
+type
+ TThreadProc* = proc (closure: pointer) ## Standard Nimrod thread proc.
+ TThreadProcClosure {.pure, final.} = object
+ fn: TThreadProc
+ data: pointer
+
+when defined(Windows):
+ type
+ THandle = int
+ TSysThread = THandle
+ TSysLock {.final, pure.} = object # CRITICAL_SECTION in WinApi
+ DebugInfo: pointer
+ LockCount: int32
+ RecursionCount: int32
+ OwningThread: int
+ LockSemaphore: int
+ Reserved: int32
+
+ TWinThreadProc = proc (x: pointer): int32 {.stdcall.}
+
+ TLock* = TSysLock ## Standard Nimrod Lock type.
+
+ proc InitLock*(L: var TLock) {.stdcall,
+ dynlib: "kernel32", importc: "InitializeCriticalSection".}
+ ## Initializes the lock `L`.
+
+ proc Aquire*(L: var TLock) {.stdcall,
+ dynlib: "kernel32", importc: "EnterCriticalSection".}
+ ## Aquires the lock `L`.
+
+ proc Release*(L: var TLock) {.stdcall,
+ dynlib: "kernel32", importc: "LeaveCriticalSection".}
+ ## Releases the lock `L`.
+
+ proc CreateThread(lpThreadAttributes: Pointer, dwStackSize: int32,
+ lpStartAddress: TWinThreadProc,
+ lpParameter: Pointer,
+ dwCreationFlags: int32, lpThreadId: var int32): THandle {.
+ stdcall, dynlib: "kernel32", importc: "CreateThread".}
+
+ when false:
+ proc winSuspendThread(hThread: TSysThread): int32 {.
+ stdcall, dynlib: "kernel32", importc: "SuspendThread".}
+
+ proc winResumeThread(hThread: TSysThread): int32 {.
+ stdcall, dynlib: "kernel32", importc: "ResumeThread".}
+
+ proc WaitForMultipleObjects(nCount: int32,
+ lpHandles: ptr array[0..10, THandle],
+ bWaitAll: int32,
+ dwMilliseconds: int32): int32 {.
+ stdcall, dynlib: "kernel32", importc: "WaitForMultipleObjects".}
+
+ proc WaitForSingleObject(hHandle: THANDLE, dwMilliseconds: int32): int32 {.
+ stdcall, dynlib: "kernel32", importc: "WaitForSingleObject".}
+
+ proc TerminateThread(hThread: THandle, dwExitCode: int32): int32 {.
+ stdcall, dynlib: "kernel32", importc: "TerminateThread".}
+
+ proc threadProcWrapper(closure: pointer): int32 {.stdcall.} =
+ var c = cast[ptr TThreadProcClosure](closure)
+ c.fn(c.data)
+ # implicitely return 0
+
+else:
+ type
+ TSysLock {.importc: "pthread_mutex_t", header: "".} = int
+ TSysThread {.importc: "pthread_t", header: "".} = int
+
+ TLock* = TSysLock
+
+ proc InitLockAux(L: var TSysLock, attr: pointer = nil) {.
+ importc: "pthread_mutex_init", header: "".}
+
+ proc InitLock*(L: var TLock) {.inline.} =
+ InitLockAux(L)
+ proc Aquire*(L: var TLock) {.
+ importc: "pthread_mutex_lock", header: "".}
+ proc Release*(L: var TLock) {.
+ importc: "pthread_mutex_unlock", header: "".}
+
+ proc pthread_create(a1: var TSysThread, a2: ptr int,
+ a3: proc (x: pointer) {.noconv.},
+ a4: pointer): cint {.importc: "pthread_create",
+ header: "".}
+ proc pthread_join(a1: TSysThread, a2: ptr pointer): cint {.
+ importc, header: "".}
+
+ proc pthread_cancel(a1: TSysThread): cint {.
+ importc: "pthread_cancel", header: "".}
+
+ proc threadProcWrapper(closure: pointer) {.noconv.} =
+ var c = cast[ptr TThreadProcClosure](closure)
+ c.fn(c.data)
+
+ {.passL: "-pthread".}
+ {.passC: "-pthread".}
+
+type
+ TThread* = object of TObject ## Nimrod thread.
+ sys: TSysThread
+ c: TThreadProcClosure
+
+
+proc createThread*(t: var TThread, tp: TThreadProc,
+ closure: pointer = nil) =
+ ## creates a new thread `t` and starts its execution. Entry point is the
+ ## proc `tp`. `closure` is passed to `tp`.
+ t.c.data = closure
+ t.c.fn = tp
+ when defined(windows):
+ var dummyThreadId: int32
+ t.sys = CreateThread(nil, 0'i32, threadProcWrapper, addr(t.c), 0'i32,
+ dummyThreadId)
+ else:
+ discard pthread_create(t.sys, nil, threadProcWrapper, addr(t.c))
+
+proc joinThread*(t: TThread) =
+ ## waits for the thread `t` until it has terminated.
+ when defined(windows):
+ discard WaitForSingleObject(t.sys, -1'i32)
+ else:
+ discard pthread_join(t.sys, nil)
+
+proc destroyThread*(t: var TThread) =
+ ## forces the thread `t` to terminate. This is potentially dangerous if
+ ## you don't have full control over `t` and its aquired ressources.
+ when defined(windows):
+ discard TerminateThread(t.sys, 1'i32)
+ else:
+ discard pthread_cancel(t.sys)
+
diff --git a/lib/nimbase.h b/lib/nimbase.h
index 0251364d14..ab03b97fa7 100755
--- a/lib/nimbase.h
+++ b/lib/nimbase.h
@@ -71,7 +71,11 @@ __TINYC__
# define NIM_CONST const
#endif
-#define NIM_THREADVAR __thread
+#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
+# define NIM_THREADVAR __declspec(thread)
+#else
+# define NIM_THREADVAR __thread
+#endif
/* --------------- how int64 constants should be declared: ----------- */
#if defined(__GNUC__) || defined(__LCC__) || \
@@ -415,8 +419,9 @@ struct TFrame {
NI len;
};
+/*
extern TFrame* framePtr;
-/*extern TSafePoint* excHandler; */
+extern TSafePoint* excHandler; */
#if defined(__cplusplus)
struct NimException {
diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim
index 6bda372bb5..fa8a56dba0 100755
--- a/lib/posix/posix.nim
+++ b/lib/posix/posix.nim
@@ -1,7 +1,7 @@
#
#
# Nimrod's Runtime Library
-# (c) Copyright 2010 Andreas Rumpf
+# (c) Copyright 2011 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -19,11 +19,11 @@
## Coding conventions:
## ALL types are named the same as in the POSIX standard except that they start
-## with 'T' or 'P' (if they are pointers) and without the '_t' prefix to be
+## with 'T' or 'P' (if they are pointers) and without the '_t' suffix to be
## consistent with Nimrod conventions. If an identifier is a Nimrod keyword
## the \`identifier\` notation is used.
##
-## This library relies on the header files of your C compiler. Thus the
+## This library relies on the header files of your C compiler. The
## resulting C code will just include and *not* define the
## symbols declared here.
diff --git a/lib/system.nim b/lib/system.nim
index 262f0926d9..e6ef4fa6f7 100755
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -1259,6 +1259,18 @@ var
## each executed instruction. This should only be used by debuggers!
## Only code compiled with the ``debugger:on`` switch calls this hook.
+type
+ PFrame = ptr TFrame
+ TFrame {.importc, nodecl, final.} = object
+ prev: PFrame
+ procname: CString
+ line: int # current line number
+ filename: CString
+ len: int # length of slots (when not debugging always zero)
+
+var
+ framePtr {.threadvar, compilerproc.}: PFrame
+
when not defined(ECMAScript):
{.push overflow_checks:off}
proc add* (x: var string, y: cstring) =
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
index 9beeb659e2..4e89826918 100755
--- a/lib/system/excpt.nim
+++ b/lib/system/excpt.nim
@@ -1,7 +1,7 @@
#
#
# Nimrod's Runtime Library
-# (c) Copyright 2010 Andreas Rumpf
+# (c) Copyright 2011 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -40,10 +40,10 @@ type
context: C_JmpBuf
var
- excHandler {.compilerproc.}: PSafePoint = nil
+ excHandler {.threadvar, compilerproc.}: PSafePoint = nil
# list of exception handlers
# a global variable for the root of all try blocks
- currException: ref E_Base
+ currException {.threadvar.}: ref E_Base
proc pushSafePoint(s: PSafePoint) {.compilerRtl, inl.} =
s.prev = excHandler
@@ -107,23 +107,11 @@ when nativeStacktrace:
# interested in
enabled = true
-type
- PFrame = ptr TFrame
- TFrame {.importc, nodecl, final.} = object
- prev: PFrame
- procname: CString
- line: int # current line number
- filename: CString
- len: int # length of slots (when not debugging always zero)
-
var
buf: string # cannot be allocated on the stack!
assertBuf: string # we need a different buffer for
# assert, as it raises an exception and
# exception handler needs the buffer too
-
- framePtr {.exportc.}: PFrame
-
tempFrames: array [0..127, PFrame] # cannot be allocated on the stack!
proc auxWriteStackTrace(f: PFrame, s: var string) =
diff --git a/lib/system/gc.nim b/lib/system/gc.nim
index 72ae840965..c5bd56b994 100755
--- a/lib/system/gc.nim
+++ b/lib/system/gc.nim
@@ -61,8 +61,9 @@ type
decStack: TCellSeq # cells in the stack that are to decref again
cycleRoots: TCellSet
tempStack: TCellSeq # temporary stack for recursion elimination
- cycleRootsLock: TSysLock
- zctLock: TSysLock
+ when hasThreadSupport:
+ cycleRootsLock: TSysLock
+ zctLock: TSysLock
stat: TGcStat
var
@@ -281,8 +282,9 @@ proc initGC() =
init(gch.tempStack)
Init(gch.cycleRoots)
Init(gch.decStack)
- InitLock(gch.cycleRootsLock)
- InitLock(gch.zctLock)
+ when hasThreadSupport:
+ InitLock(gch.cycleRootsLock)
+ InitLock(gch.zctLock)
new(gOutOfMem) # reserve space for the EOutOfMemory exception here!
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
diff --git a/lib/system/systhread.nim b/lib/system/systhread.nim
index a124fa92f1..0ffc9605cd 100755
--- a/lib/system/systhread.nim
+++ b/lib/system/systhread.nim
@@ -1,7 +1,7 @@
#
#
# Nimrod's Runtime Library
-# (c) Copyright 2010 Andreas Rumpf
+# (c) Copyright 2011 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -44,72 +44,4 @@ proc atomicDec(memLoc: var int, x: int): int =
else:
dec(memLoc, x)
result = memLoc
-
-when defined(Windows):
- type
- THandle = int
- TSysThread = THandle
- TSysLock {.final, pure.} = object # CRITICAL_SECTION in WinApi
- DebugInfo: pointer
- LockCount: int32
- RecursionCount: int32
- OwningThread: int
- LockSemaphore: int
- Reserved: int32
-
- proc InitLock(L: var TSysLock) {.stdcall,
- dynlib: "kernel32", importc: "InitializeCriticalSection".}
- proc Aquire(L: var TSysLock) {.stdcall,
- dynlib: "kernel32", importc: "EnterCriticalSection".}
- proc Release(L: var TSysLock) {.stdcall,
- dynlib: "kernel32", importc: "LeaveCriticalSection".}
-
- proc CreateThread(lpThreadAttributes: Pointer, dwStackSize: int32,
- lpStartAddress: pointer, lpParameter: Pointer,
- dwCreationFlags: int32, lpThreadId: var int32): THandle {.
- stdcall, dynlib: "kernel32", importc: "CreateThread".}
-
-
-else:
- type
- TSysLock {.importc: "pthread_mutex_t", header: "".} = int
- TSysThread {.importc: "pthread_t", header: "".} = int
-
- proc InitLock(L: var TSysLock, attr: pointer = nil) {.
- importc: "pthread_mutex_init", header: "".}
- proc Aquire(L: var TSysLock) {.
- importc: "pthread_mutex_lock", header: "".}
- proc Release(L: var TSysLock) {.
- importc: "pthread_mutex_unlock", header: "".}
-
-
-type
- TThread* = TSysThread
- TLock* = TSysLock
- TThreadFunc* = proc (closure: pointer) {.cdecl.}
-
-#DWORD WINAPI SuspendThread(
-# __in HANDLE hThread
-#);
-#DWORD WINAPI ResumeThread(
-# __in HANDLE hThread
-#);
-#DWORD WINAPI ThreadProc(
-# __in LPVOID lpParameter
-#);
-
-proc createThread*(t: var TThread, fn: TThreadFunc, closure: pointer) =
- when defined(windows):
- nil
- else:
- nil
- #pthread_create(
-
-proc joinThread*(t: TThread) =
- nil
-
-#proc pthread_exit(void *value_ptr)
-
-proc destroyThread*(t: var TThread) =
- nil
diff --git a/rod/ast.nim b/rod/ast.nim
index 47d3d8621b..1d689deb96 100755
--- a/rod/ast.nim
+++ b/rod/ast.nim
@@ -280,6 +280,7 @@ type
skParam, # a parameter
skGenericParam, # a generic parameter; eq in ``proc x[eq=`==`]()``
skTemp, # a temporary variable (introduced by compiler)
+ skModule, # module identifier
skType, # a type
skConst, # a constant
skVar, # a variable
@@ -293,7 +294,6 @@ type
skField, # a field in a record or object
skEnumField, # an identifier in an enum
skForVar, # a for loop variable
- skModule, # module identifier
skLabel, # a label (for block statement)
skStub # symbol is a stub and not yet loaded from the ROD
# file (it is loaded on demand, which may mean: never)
diff --git a/rod/c2nim/cpp.nim b/rod/c2nim/cpp.nim
index 5507c6116c..f59c860442 100755
--- a/rod/c2nim/cpp.nim
+++ b/rod/c2nim/cpp.nim
@@ -16,7 +16,7 @@ proc eatNewLine(p: var TParser, n: PNode) =
if p.tok.xkind == pxLineComment:
skipCom(p, n)
if p.tok.xkind == pxNewLine: getTok(p)
- else:
+ elif p.tok.xkind == pxNewLine:
eat(p, pxNewLine)
proc skipLine(p: var TParser) =
diff --git a/rod/c2nim/tests/systest.c b/rod/c2nim/tests/systest.c
index 7f689c0025..4ba1d90444 100755
--- a/rod/c2nim/tests/systest.c
+++ b/rod/c2nim/tests/systest.c
@@ -9,6 +9,15 @@ extern "C" {
# endif
#endif
+typedef void (*callback_t) (int rc);
+
+int aw_callback_set (AW_CALLBACK c, callback_t callback );
+int aw_instance_callback_set (AW_CALLBACK c, callback_t callback);
+
+#define AW_BUILD 85 // AW 5.0
+// Limits
+#define AW_MAX_AVCHANGE_PER_SECOND 10
+
#private expatDll
#if !defined(expatDll)
diff --git a/rod/ccgstmts.nim b/rod/ccgstmts.nim
index f98a595801..2ac87824c5 100755
--- a/rod/ccgstmts.nim
+++ b/rod/ccgstmts.nim
@@ -477,7 +477,7 @@ proc genTryStmtCpp(p: BProc, t: PNode) =
rethrowFlag = getTempName()
appf(p.s[cpsLocals], "volatile NIM_BOOL $1 = NIM_FALSE;$n", [rethrowFlag])
if optStackTrace in p.Options:
- app(p.s[cpsStmts], "framePtr = (TFrame*)&F;" & tnl)
+ appcg(p, cpsStmts, "#framePtr = (TFrame*)&F;" & tnl)
app(p.s[cpsStmts], "try {" & tnl)
add(p.nestedTryStmts, t)
genStmts(p, t.sons[0])
@@ -542,7 +542,7 @@ proc genTryStmt(p: BProc, t: PNode) =
appcg(p, cpsStmts, "#pushSafePoint(&$1);$n" &
"$1.status = setjmp($1.context);$n", [safePoint])
if optStackTrace in p.Options:
- app(p.s[cpsStmts], "framePtr = (TFrame*)&F;" & tnl)
+ appcg(p, cpsStmts, "#framePtr = (TFrame*)&F;" & tnl)
appf(p.s[cpsStmts], "if ($1.status == 0) {$n", [safePoint])
var length = sonsLen(t)
add(p.nestedTryStmts, t)
diff --git a/rod/cgen.nim b/rod/cgen.nim
index 360b46a3b7..f99a06a979 100755
--- a/rod/cgen.nim
+++ b/rod/cgen.nim
@@ -386,10 +386,10 @@ proc assignGlobalVar(p: BProc, s: PSym) =
useHeader(p.module, s)
if lfNoDecl in s.loc.flags: return
if sfImportc in s.flags: app(p.module.s[cfsVars], "extern ")
+ if sfThreadVar in s.flags: app(p.module.s[cfsVars], "NIM_THREADVAR ")
app(p.module.s[cfsVars], getTypeDesc(p.module, s.loc.t))
if sfRegister in s.flags: app(p.module.s[cfsVars], " register")
if sfVolatile in s.flags: app(p.module.s[cfsVars], " volatile")
- if sfThreadVar in s.flags: app(p.module.s[cfsVars], " NIM_THREADVAR")
appf(p.module.s[cfsVars], " $1;$n", [s.loc.r])
if {optStackTrace, optEndb} * p.module.module.options ==
{optStackTrace, optEndb}:
@@ -550,19 +550,12 @@ proc retIsNotVoid(s: PSym): bool =
result = (s.typ.sons[0] != nil) and not isInvalidReturnType(s.typ.sons[0])
proc initFrame(p: BProc, procname, filename: PRope): PRope =
- inc(p.labels, 5)
- result = ropeff("F.procname = $1;$n" & "F.prev = framePtr;$n" &
- "F.filename = $2;$n" & "F.line = 0;$n" & "framePtr = (TFrame*)&F;$n",
- "%LOC$3 = getelementptr %TF %F, %NI 1$n" &
- "%LOC$4 = getelementptr %TF %F, %NI 0$n" &
- "%LOC$5 = getelementptr %TF %F, %NI 3$n" &
- "%LOC$6 = getelementptr %TF %F, %NI 2$n" & "store i8* $1, i8** %LOC$3$n" &
- "store %TFrame* @framePtr, %TFrame** %LOC$4$n" &
- "store i8* $2, i8** %LOC$5$n" & "store %NI 0, %NI* %LOC$6$n" &
- "%LOC$7 = bitcast %TF* %F to %TFrame*$n" &
- "store %TFrame* %LOC$7, %TFrame** @framePtr$n", [procname, filename,
- toRope(p.labels), toRope(p.labels - 1), toRope(p.labels - 2),
- toRope(p.labels - 3), toRope(p.labels - 4)])
+ result = ropecg(p.module,
+ "F.procname = $1;$n" &
+ "F.prev = #framePtr;$n" &
+ "F.filename = $2;$n" &
+ "F.line = 0;$n" &
+ "framePtr = (TFrame*)&F;$n", [procname, filename])
proc deinitFrame(p: BProc): PRope =
inc(p.labels, 3)
@@ -693,10 +686,10 @@ proc genVarPrototype(m: BModule, sym: PSym) =
[sym.loc.r, getTypeDesc(m, sym.loc.t)])
else:
app(m.s[cfsVars], "extern ")
+ if sfThreadVar in sym.flags: app(m.s[cfsVars], "NIM_THREADVAR ")
app(m.s[cfsVars], getTypeDesc(m, sym.loc.t))
if sfRegister in sym.flags: app(m.s[cfsVars], " register")
if sfVolatile in sym.flags: app(m.s[cfsVars], " volatile")
- if sfThreadVar in sym.flags: app(m.s[cfsVars], " NIM_THREADVAR")
appf(m.s[cfsVars], " $1;$n", [sym.loc.r])
proc genConstPrototype(m: BModule, sym: PSym) =
diff --git a/rod/docgen.nim b/rod/docgen.nim
index ade2aa93f5..04330bb414 100755
--- a/rod/docgen.nim
+++ b/rod/docgen.nim
@@ -32,7 +32,6 @@ type
filename*: string # filename of the source file; without extension
basedir*: string # base directory (where to put the documentation)
modDesc*: PRope # module description
- deps*: PRope # dependencies
id*: int # for generating IDs
splitAfter*: int # split too long entries in the TOC
tocPart*: seq[TTocEntry]
@@ -765,9 +764,12 @@ proc getModuleFile(n: PNode): string =
result = ""
proc traceDeps(d: PDoc, n: PNode) =
- if d.deps != nil: app(d.deps, ", ")
- app(d.deps, getModuleFile(n))
-
+ const k = skModule
+ if d.section[k] != nil: app(d.section[k], ", ")
+ dispA(d.section[k],
+ "$1",
+ "$1", [toRope(getModuleFile(n))])
+
proc generateDoc(d: PDoc, n: PNode) =
if n == nil: return
case n.kind
@@ -802,8 +804,12 @@ proc generateDoc(d: PDoc, n: PNode) =
else: nil
proc genSection(d: PDoc, kind: TSymKind) =
+ const sectionNames: array[skModule..skTemplate, string] = [
+ "Imports", "Types", "Consts", "Vars", "Procs", "Methods",
+ "Iterators", "Converters", "Macros", "Templates"
+ ]
if d.section[kind] == nil: return
- var title = toRope(copy($kind, 2) & 's')
+ var title = toRope(sectionNames[kind])
d.section[kind] = ropeFormatNamedVars(getConfigVar("doc.section"), [
"sectionid", "sectionTitle", "sectionTitleID", "content"], [
toRope(ord(kind)), title, toRope(ord(kind) + 50), d.section[kind]])
@@ -833,14 +839,14 @@ proc genOutFile(d: PDoc): PRope =
if d.hasToc: bodyname = "doc.body_toc"
else: bodyname = "doc.body_no_toc"
content = ropeFormatNamedVars(getConfigVar(bodyname), ["title",
- "tableofcontents", "moduledesc", "deps", "date", "time", "content"],
- [title, toc, d.modDesc, d.deps, toRope(getDateStr()),
+ "tableofcontents", "moduledesc", "date", "time", "content"],
+ [title, toc, d.modDesc, toRope(getDateStr()),
toRope(getClockStr()), code])
if optCompileOnly notin gGlobalOptions:
code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",
- "tableofcontents", "moduledesc", "deps", "date", "time",
+ "tableofcontents", "moduledesc", "date", "time",
"content", "author", "version"],
- [title, toc, d.modDesc, d.deps, toRope(getDateStr()),
+ [title, toc, d.modDesc, toRope(getDateStr()),
toRope(getClockStr()), content, d.meta[metaAuthor],
d.meta[metaVersion]])
else:
diff --git a/rod/msgs.nim b/rod/msgs.nim
index d6fde38b45..e34631c90c 100755
--- a/rod/msgs.nim
+++ b/rod/msgs.nim
@@ -94,6 +94,7 @@ type
errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProc, errImplOfXNotAllowed,
errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValue,
errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice,
+ errInvalidOrderInArrayConstructor,
errInvalidOrderInEnumX, errEnumXHasWholes, errExceptExpected, errInvalidTry,
errOptionExpected, errXisNoLabel, errNotAllCasesCovered,
errUnkownSubstitionVar, errComplexStmtRequiresInd, errXisNotCallable,
@@ -214,6 +215,7 @@ const
"value returned by statement has to be discarded",
"statement returns no value that can be discarded",
"conversion from $1 to $2 is invalid", "cannot bind parameter \'$1\' twice",
+ "invalid order in array constructor",
"invalid order in enum \'$1\'", "enum \'$1\' has wholes",
"\'except\' or \'finally\' expected",
"after catch all \'except\' or \'finally\' no section may follow",
diff --git a/rod/semexprs.nim b/rod/semexprs.nim
index 10ed6567ed..e6cf097e58 100755
--- a/rod/semexprs.nim
+++ b/rod/semexprs.nim
@@ -260,11 +260,29 @@ proc semArrayConstr(c: PContext, n: PNode): PNode =
if sonsLen(n) == 0:
addSon(result.typ, newTypeS(tyEmpty, c)) # needs an empty basetype!
else:
- addSon(result, semExprWithType(c, n.sons[0]))
+ var x = n.sons[0]
+ var lastIndex: biggestInt = 0
+ var indexType = getSysType(tyInt)
+ if x.kind == nkExprColonExpr:
+ var idx = semConstExpr(c, x.sons[0])
+ lastIndex = getOrdValue(idx)
+ indexType = idx.typ
+ x = x.sons[1]
+
+ addSon(result, semExprWithType(c, x))
var typ = skipTypes(result.sons[0].typ, {tyGenericInst, tyVar, tyOrdinal})
for i in countup(1, sonsLen(n) - 1):
- n.sons[i] = semExprWithType(c, n.sons[i])
+ x = n.sons[i]
+ if x.kind == nkExprColonExpr:
+ var idx = semConstExpr(c, x.sons[0])
+ idx = fitNode(c, indexType, idx)
+ if lastIndex+1 != getOrdValue(idx):
+ liMessage(x.info, errInvalidOrderInArrayConstructor)
+ x = x.sons[1]
+
+ n.sons[i] = semExprWithType(c, x)
addSon(result, fitNode(c, typ, n.sons[i]))
+ inc(lastIndex)
addSon(result.typ, typ)
result.typ.sons[0] = makeRangeType(c, 0, sonsLen(result) - 1, n.info)
diff --git a/tests/accept/run/spec.csv b/tests/accept/run/spec.csv
index 7a3d2bd987..09dbc40b38 100755
--- a/tests/accept/run/spec.csv
+++ b/tests/accept/run/spec.csv
@@ -2,6 +2,7 @@ tack.nim;125
tambsym2.nim;7
tambsys.nim;
tarray.nim;10012
+tarraycons.nim;6
tarray2.nim;[16, 25, 36]
tarray3.nim;3
tassert.nim;assertion failure!this shall be always written
diff --git a/tests/accept/run/tarraycons.nim b/tests/accept/run/tarraycons.nim
new file mode 100644
index 0000000000..12f13ac339
--- /dev/null
+++ b/tests/accept/run/tarraycons.nim
@@ -0,0 +1,17 @@
+
+type
+ TEnum = enum
+ eA, eB, eC, eD, eE, eF
+
+const
+ myMapping: array[TEnum, array[0..1, int]] = [
+ eA: [1, 2],
+ eB: [3, 4],
+ [5, 6],
+ eD: [0: 8, 1: 9],
+ eE: [0: 8, 9],
+ eF: [2, 1: 9]
+ ]
+
+echo myMapping[eC][1]
+
diff --git a/tests/gc/tthreads.nim b/tests/gc/tthreads.nim
new file mode 100644
index 0000000000..2ef599e538
--- /dev/null
+++ b/tests/gc/tthreads.nim
@@ -0,0 +1,21 @@
+
+import threads
+
+var
+ thr: array [0..4, TThread]
+ L: TLock
+
+proc threadFunc(c: pointer) {.procvar.} =
+ for i in 0..9:
+ Aquire(L)
+ echo i
+ Release(L)
+
+InitLock(L)
+
+for i in 0..high(thr):
+ createThread(thr[i], threadFunc)
+for i in 0..high(thr):
+ joinThread(thr[i])
+
+
diff --git a/tests/reject/spec.csv b/tests/reject/spec.csv
index a332096b2a..f2d38f03b7 100755
--- a/tests/reject/spec.csv
+++ b/tests/reject/spec.csv
@@ -3,6 +3,7 @@ tadrdisc.nim;15;for a 'var' type a variable needs to be passed
tambsym.nim;6;ambiguous identifier
tambsym2.nim;4;undeclared identifier: 'CreateRGBSurface'
tambsym3.nim;6;ambiguous identifier
+tarraycons.nim;9;invalid order in array constructor
tatomic.nim;2;identifier expected, but found 'atomic'
tbind2.nim;7;ambiguous call
tbind4.nim;4;undeclared identifier: 'lastId'
diff --git a/tests/reject/tarraycons.nim b/tests/reject/tarraycons.nim
new file mode 100644
index 0000000000..1809f87359
--- /dev/null
+++ b/tests/reject/tarraycons.nim
@@ -0,0 +1,17 @@
+
+type
+ TEnum = enum
+ eA, eB, eC, eD, eE, eF
+
+const
+ myMapping: array[TEnum, array[0..1, int]] = [
+ eA: [1, 2],
+ eC: [3, 4],
+ eB: [5, 6],
+ eD: [0: 8, 1: 9],
+ eE: [0: 8, 9],
+ eF: [2, 1: 9]
+ ]
+
+echo myMapping[eC][1]
+
diff --git a/todo.txt b/todo.txt
index 20f7af41b5..08b1865b19 100755
--- a/todo.txt
+++ b/todo.txt
@@ -1,11 +1,16 @@
+- built-in serialization
+- thread support: threadvar on Windows seems broken;
+ add --deadlock_prevention:on|off switch
+
+- ban ``nil`` from the AST. This might also fix bugs concerning macros.
+
- we need a way to disable tests
- deprecate ^ and make it available as operator
- test branch coverage
- checked exceptions
-- explicit indices for array literals
-- built-in serialization
-- do not ambiguity error for methods if amibiguity only affects the same
+- do not ambiguity error for methods if ambiguity only affects the same
dispatcher anyway
+- slicing
High priority (version 0.9.0)
@@ -23,6 +28,7 @@ Bugs
- proc (x: int) is passable to proc (x: var int) !?
- detected by pegs module 64bit: p(result, result) should use a temporary!
- the parser allows empty object case branches
+- Exception matching needs to take subclasses into account
To implement
diff --git a/web/news.txt b/web/news.txt
index f421f0f70b..e0c436a205 100755
--- a/web/news.txt
+++ b/web/news.txt
@@ -47,6 +47,9 @@ Additions
- A field in an ``enum`` may be given an explicit string representation.
This yields more maintainable code than using a constant
``array[TMyEnum, string]`` mapping.
+- Indices in array literals may be explicitly given, enhancing readability:
+ ``[enumValueA: "a", enumValueB: "b"]``.
+- Added basic thread support via the ``threads`` core module.
diff --git a/web/nimrod.ini b/web/nimrod.ini
index 65fc499362..fc11c00d0f 100644
--- a/web/nimrod.ini
+++ b/web/nimrod.ini
@@ -24,13 +24,14 @@ file: ticker
doc: "endb;intern;apis;lib;manual;tut1;tut2;nimrodc;overview"
doc: "tools;c2nim;niminst"
pdf: "manual;lib;tut1;tut2;nimrodc;c2nim;niminst"
+srcdoc: "core/macros;core/threads;core/marshal"
srcdoc: "impure/graphics;pure/sockets"
srcdoc: "system.nim;pure/os;pure/strutils;pure/math"
srcdoc: "pure/complex;pure/times;pure/osproc;pure/pegs;pure/dynlib"
srcdoc: "pure/parseopt;pure/hashes;pure/strtabs;pure/lexbase"
srcdoc: "pure/parsecfg;pure/parsexml;pure/parsecsv;pure/parsesql"
srcdoc: "pure/streams;pure/terminal;pure/cgi;impure/web;pure/unicode"
-srcdoc: "impure/zipfiles;pure/xmlgen;pure/macros;pure/parseutils;pure/browsers"
+srcdoc: "impure/zipfiles;pure/xmlgen;pure/parseutils;pure/browsers"
srcdoc: "impure/db_postgres;impure/db_mysql;impure/db_sqlite"
srcdoc: "pure/httpserver;pure/httpclient;pure/stmp;impure/ssl"
srcdoc: "pure/ropes;pure/unidecode/unidecode;pure/xmldom;pure/xmldomparser"