summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xdoc/astspec.txt12
-rwxr-xr-xdoc/filters.txt4
-rwxr-xr-xdoc/manual.txt46
-rwxr-xr-xdoc/nimrodc.txt26
-rwxr-xr-xdoc/pegdocs.txt21
-rwxr-xr-xdoc/theindex.txt231
-rwxr-xr-xlib/pure/pegs.nim287
-rwxr-xr-xlib/pure/unicode.nim6
-rwxr-xr-xnim/llvmdata.pas139
-rwxr-xr-xnim/pbraces.pas122
-rwxr-xr-xnim/pendx.pas36
-rwxr-xr-xnim/pnimsyn.pas47
-rwxr-xr-xnim/semgnrc.pas287
-rwxr-xr-xnim/semtempl.pas14
-rwxr-xr-xnim/syntaxes.pas10
-rwxr-xr-xnim/vis.pas35
-rwxr-xr-xtools/nimweb.nim2
-rwxr-xr-xweb/question.txt8
18 files changed, 953 insertions, 380 deletions
diff --git a/doc/astspec.txt b/doc/astspec.txt
index eec2808fd..01c1adba3 100755
--- a/doc/astspec.txt
+++ b/doc/astspec.txt
@@ -20,7 +20,7 @@ contains:
 
     PNimrodNode = ref TNimrodNode
     TNimrodNode {.final.} = object
-      case kind                        ## the node's kind
+      case kind: TNimrodNodeKind       ## the node's kind
       of nnkNone, nnkEmpty, nnkNilLit:
         nil                            ## node contains no additional fields
       of nnkCharLit..nnkInt64Lit:
@@ -43,6 +43,11 @@ To specify the AST for the different Nimrod constructs, the notation
 ``nodekind(son1, son2, ...)`` or ``nodekind(value)`` or 
 ``nodekind(field=value)`` is used.
 
+Some child may be missing. Then it is ``nil``. A nil child is equivalent to 
+a node of kind ``nnkEmpty``. This is more or less a (useful) artifact from 
+the implementation. (In the compiler's implementation ``nil`` is of course 
+not the same as ``nnkEmpty``!)
+
 
 Leaf nodes/Atoms
 ================
@@ -72,8 +77,9 @@ Nimrod expression                corresponding AST
 Identifiers are ``nnkIdent`` nodes. After the name lookup pass these nodes
 get transferred into ``nnkSym`` nodes. However, a macro receives an AST that
 has not been checked for semantics and thus the identifiers have not been
-looked up. Thus macros deal with ``nnkIdent`` nodes. 
- 
+looked up. Macros should deal with ``nnkIdent`` nodes and do not need to deal
+with ``nnkSym`` nodes.
+
 
 Calls/expressions
 =================
diff --git a/doc/filters.txt b/doc/filters.txt
index ffeb6808a..0cbb3319d 100755
--- a/doc/filters.txt
+++ b/doc/filters.txt
@@ -4,8 +4,8 @@ Parsers and Filters
 
 .. contents::
 
-The Nimrod compiler contains multiple parsers. (The standard is 
-indentation-based.) Two others are available: The `braces`:idx: parser and the
+The Nimrod compiler contains multiple parsers. The standard is 
+indentation-based. Two others are available: The `braces`:idx: parser and the
 `endX`:idx: parser. Both parsers use the same lexer as the standard parser.
 
 To use a different parser for a source file the *shebang* notation is used:
diff --git a/doc/manual.txt b/doc/manual.txt
index 978ef1496..929b01181 100755
--- a/doc/manual.txt
+++ b/doc/manual.txt
@@ -951,7 +951,7 @@ of the following conditions hold:
 3) The procedure has a calling convention that differs from ``nimcall``. 
 4) The procedure is anonymous.
 
-These rules should prevent the case that extending a non-``procvar`` 
+The rules' purpose is to prevent the case that extending a non-``procvar`` 
 procedure with default parameters breaks client code.
 
 
@@ -1800,7 +1800,7 @@ return values. This can be done in a cleaner way by returning a tuple:
   assert t.res == 1
   assert t.remainder = 3
 
-Even more elegant is to use `tuple unpacking`:idx: to access the tuple's fields:
+One can use `tuple unpacking`:idx: to access the tuple's fields:
 
 .. code-block:: nimrod
   var (x, y) = divmod(8, 5) # tuple unpacking
@@ -1872,7 +1872,7 @@ dispatching:
 
 Invokation of a multi-method cannot be ambiguous: Collide 2 is prefered over 
 collide 1 because the resolution works from left to right. 
-Thus ``TUnit, TThing`` is prefered over ``TThing, TUnit``.
+In the example ``TUnit, TThing`` is prefered over ``TThing, TUnit``.
 
 **Perfomance note**: Nimrod does not produce a virtual method table, but
 generates dispatch trees. This avoids the expensive indirect branch for method
@@ -2112,6 +2112,44 @@ special ``:`` syntax:
 In the example the two ``writeln`` statements are bound to the ``actions``
 parameter. 
 
+Symbol binding within templates happens after template instantation: 
+
+.. code-block:: nimrod
+  # Module A
+  var 
+    lastId = 0
+  
+  template genId*: expr =
+    inc(lastId)
+    lastId
+
+.. code-block:: nimrod
+  # Module B
+  import A
+  
+  echo genId() # Error: undeclared identifier: 'lastId'
+
+Exporting a template is a often a leaky abstraction. However, to compensate for
+this case, the ``bind`` operator can be used: All identifiers
+within a ``bind`` context are bound early (i.e. when the template is parsed).
+The affected identifiers are then always bound early even if the other
+occurences are in no ``bind`` context: 
+
+.. code-block:: nimrod
+  # Module A
+  var 
+    lastId = 0
+  
+  template genId*: expr =
+    inc(bind lastId)
+    lastId
+
+.. code-block:: nimrod
+  # Module B
+  import A
+  
+  echo genId() # Works
+
 
 **Style note**: For code readability, it is the best idea to use the least
 powerful programming construct that still suffices. So the "check list" is:
@@ -2356,7 +2394,7 @@ verify this.
 
 procvar pragma
 --------------
-The `procvar`:idx: pragma is used to mark a proc that it can be passed to a 
+The `procvar`:idx: pragma is used to mark a proc so that it can be passed to a 
 procedural variable. 
 
 
diff --git a/doc/nimrodc.txt b/doc/nimrodc.txt
index 3200b135b..88ca52939 100755
--- a/doc/nimrodc.txt
+++ b/doc/nimrodc.txt
@@ -109,6 +109,21 @@ In general, importing a dynamic library does not require any special linker
 options or linking with import libraries. This also implies that no *devel*
 packages need to be installed.
 
+The ``dynlib`` import mechanism supports a versioning scheme: 
+
+.. code-block:: nimrod 
+  proc Tcl_Eval(interp: pTcl_Interp, script: cstring): int {.cdecl, 
+    importc, dynlib: "libtcl(8.5|8.4|8.3).so.(1|0)".}
+
+At runtime the dynamic library is searched for (in this order)::
+  
+  libtcl8.5.so.1
+  libtcl8.4.so.1
+  libtcl8.3.so.1
+  libtcl8.5.so.0
+  libtcl8.4.so.0
+  libtcl8.3.so.0
+
 
 No_decl Pragma
 ~~~~~~~~~~~~~~
@@ -231,7 +246,7 @@ compiler to activate (or deactivate) dead code elimination for the module the
 pragma appers in.
 
 The ``--dead_code_elim:on`` command line switch has the same effect as marking
-any module with ``{.dead_code_elim:on}``. However, for some modules such as
+every module with ``{.dead_code_elim:on}``. However, for some modules such as
 the GTK wrapper it makes sense to *always* turn on dead code elimination -
 no matter if it is globally active or not.
 
@@ -244,7 +259,7 @@ Example:
 Disabling certain messages
 --------------------------
 Nimrod generates some warnings and hints ("line too long") that may annoy the
-user. Thus a mechanism for disabling certain messages is provided: Each hint
+user. A mechanism for disabling certain messages is provided: Each hint
 and warning message contains a symbol in brackets. This is the message's
 identifier that can be used to enable or disable it:
 
@@ -300,9 +315,10 @@ However it is not efficient to do:
 .. code-block:: Nimrod
   var s = varA    # assignment has to copy the whole string into a new buffer!
 
-String case statements are optimized too. A hashing scheme is used for them
-if several different string constants are used. This is likely to be more
-efficient than any hand-coded scheme.
+..
+  String case statements are optimized too. A hashing scheme is used for them
+  if several different string constants are used. This is likely to be more
+  efficient than any hand-coded scheme.
 
 
 ..
diff --git a/doc/pegdocs.txt b/doc/pegdocs.txt
index 943acc545..e2c228cf3 100755
--- a/doc/pegdocs.txt
+++ b/doc/pegdocs.txt
@@ -60,6 +60,8 @@ notation           meaning
 ``_``              Any Unicode character: If there is an UTF-8 character
                    ahead, consume it and indicate success. Otherwise indicate
                    failure.
+``@E``             Search: Shorthand for ``(!E .)* E``. (Search loop for the
+                   pattern `E`.)
 ``A <- E``         Rule: Bind the expression `E` to the *nonterminal symbol*
                    `A`. **Left recursive rules are not possible and crash the
                    matching engine.**
@@ -118,14 +120,15 @@ The PEG parser implements this grammar (written in PEG syntax)::
                             "'" ("\\" . / [^'])* "'")
   builtin <- "\\" identifier / [^\13\10]
   
-  comment <- '#' !\n* \n
+  comment <- '#' @ \n
   ig <- (\s / comment)* # things to ignore
   
   rule <- identifier \s* "<-" expr ig
   identNoArrow <- identifier !(\s* "<-")
-  primary <- (ig '&' / ig '!')* ((ig identNoArrow / ig charset / ig stringlit
-                                / ig builtin / ig '.' / ig '_'
-                                / (ig "(" expr ig ")"))
+  primary <- (ig '&' / ig '!' / ig '@')*
+               ((ig identNoArrow / ig charset / ig stringlit
+                                 / ig builtin / ig '.' / ig '_'
+                                 / (ig "(" expr ig ")"))
              (ig '?' / ig '*' / ig '+')*)
   
   # Concatenation has higher priority than choice:
@@ -153,16 +156,16 @@ Determine the ``#include``'ed files of a C file:
 .. code-block:: nimrod
   for line in lines("myfile.c"):
     if line =~ peg"""s <- ws '#include' ws '"' {[^"]+} '"' ws
-                     comment <- '/*' (!'*/' . )* '*/' / '//' .*
-                     ws <- (comment / \s+)* """:    
+                     comment <- '/*' @ '*/' / '//' .*
+                     ws <- (comment / \s+)* """:
       echo matches[0]
 
 PEG vs regular expression
 -------------------------
-As a regular expression ``\[.*\]`` maches longest possible text between ``'['``
-and ``']'``. As a PEG it never matches anything, because a PEG is
+As a regular expression ``\[.*\]`` matches the longest possible text between
+``'['`` and ``']'``. As a PEG it never matches anything, because a PEG is
 deterministic: ``.*`` consumes the rest of the input, so ``\]`` never matches.
-As a PEG this needs to be written as: ``\[ ( !\] . )* \]``
+As a PEG this needs to be written as: ``\[ ( !\] . )* \]`` (or ``\[ @ \]``).
 
 Note that the regular expression does not behave as intended either:
 ``*`` should not be greedy, so ``\[.*?\]`` should be used.
diff --git a/doc/theindex.txt b/doc/theindex.txt
index 922dab769..e9eb5080f 100755
--- a/doc/theindex.txt
+++ b/doc/theindex.txt
@@ -7,7 +7,7 @@ Index
 
 
    `!`:idx:
-     * `pegs.html#114 <pegs.html#114>`_
+     * `pegs.html#115 <pegs.html#115>`_
      * `macros.html#114 <macros.html#114>`_
 
    `!=`:idx:
@@ -24,7 +24,7 @@ Index
      * `system.html#426 <system.html#426>`_
      * `times.html#109 <times.html#109>`_
      * `times.html#110 <times.html#110>`_
-     * `pegs.html#148 <pegs.html#148>`_
+     * `pegs.html#133 <pegs.html#133>`_
      * `macros.html#115 <macros.html#115>`_
 
    `%`:idx:
@@ -47,7 +47,7 @@ Index
      * `system.html#462 <system.html#462>`_
      * `system.html#463 <system.html#463>`_
      * `system.html#464 <system.html#464>`_
-     * `pegs.html#113 <pegs.html#113>`_
+     * `pegs.html#114 <pegs.html#114>`_
 
    `*`:idx:
      * `system.html#212 <system.html#212>`_
@@ -82,7 +82,7 @@ Index
      * `system.html#309 <system.html#309>`_
      * `system.html#320 <system.html#320>`_
      * `complex.html#103 <complex.html#103>`_
-     * `pegs.html#112 <pegs.html#112>`_
+     * `pegs.html#113 <pegs.html#113>`_
 
    `+%`:idx:
      * `system.html#272 <system.html#272>`_
@@ -153,15 +153,15 @@ Index
      * `times.html#114 <times.html#114>`_
 
    `<%`:idx:
-     `unicode.html#104 <unicode.html#104>`_
-
-   `<%`:idx:
      * `system.html#302 <system.html#302>`_
      * `system.html#303 <system.html#303>`_
      * `system.html#304 <system.html#304>`_
      * `system.html#305 <system.html#305>`_
      * `system.html#306 <system.html#306>`_
 
+   `<%`:idx:
+     `unicode.html#104 <unicode.html#104>`_
+
    `<=`:idx:
      * `system.html#257 <system.html#257>`_
      * `system.html#258 <system.html#258>`_
@@ -181,15 +181,15 @@ Index
      `times.html#115 <times.html#115>`_
 
    `<=%`:idx:
+     `unicode.html#103 <unicode.html#103>`_
+
+   `<=%`:idx:
      * `system.html#297 <system.html#297>`_
      * `system.html#298 <system.html#298>`_
      * `system.html#299 <system.html#299>`_
      * `system.html#300 <system.html#300>`_
      * `system.html#301 <system.html#301>`_
 
-   `<=%`:idx:
-     `unicode.html#103 <unicode.html#103>`_
-
    `==`:idx:
      * `md5.html#107 <md5.html#107>`_
      * `system.html#252 <system.html#252>`_
@@ -211,12 +211,13 @@ Index
      * `complex.html#102 <complex.html#102>`_
      * `unicode.html#105 <unicode.html#105>`_
      * `macros.html#116 <macros.html#116>`_
+     * `macros.html#117 <macros.html#117>`_
 
    `=~`:idx:
-     `pegs.html#138 <pegs.html#138>`_
+     `regexprs.html#111 <regexprs.html#111>`_
 
    `=~`:idx:
-     `regexprs.html#108 <regexprs.html#108>`_
+     `pegs.html#140 <pegs.html#140>`_
 
    `>`:idx:
      `system.html#349 <system.html#349>`_
@@ -234,13 +235,14 @@ Index
      `pegs.html#110 <pegs.html#110>`_
 
    `@`:idx:
-     `system.html#357 <system.html#357>`_
+     * `system.html#357 <system.html#357>`_
+     * `pegs.html#112 <pegs.html#112>`_
 
    `[]`:idx:
-     `strtabs.html#107 <strtabs.html#107>`_
+     `macros.html#112 <macros.html#112>`_
 
    `[]`:idx:
-     `macros.html#112 <macros.html#112>`_
+     `strtabs.html#107 <strtabs.html#107>`_
 
    `[]=`:idx:
      `macros.html#113 <macros.html#113>`_
@@ -279,8 +281,8 @@ Index
      * `system.html#368 <system.html#368>`_
      * `system.html#369 <system.html#369>`_
      * `parsesql.html#108 <parsesql.html#108>`_
-     * `macros.html#118 <macros.html#118>`_
      * `macros.html#119 <macros.html#119>`_
+     * `macros.html#120 <macros.html#120>`_
 
    `addf`:idx:
      `strutils.html#111 <strutils.html#111>`_
@@ -332,16 +334,16 @@ Index
      * `system.html#241 <system.html#241>`_
 
    `any`:idx:
-     `pegs.html#116 <pegs.html#116>`_
+     `pegs.html#117 <pegs.html#117>`_
 
    `any character`:idx:
-     `pegs.html#115 <pegs.html#115>`_
+     `pegs.html#116 <pegs.html#116>`_
 
    `any rune`:idx:
-     `pegs.html#117 <pegs.html#117>`_
+     `pegs.html#118 <pegs.html#118>`_
 
    `anyRune`:idx:
-     `pegs.html#118 <pegs.html#118>`_
+     `pegs.html#119 <pegs.html#119>`_
 
    `apostrophe`:idx:
      `manual.html#129 <manual.html#129>`_
@@ -403,7 +405,8 @@ Index
      `xmlgen.html#111 <xmlgen.html#111>`_
 
    `backslash`:idx:
-     `manual.html#127 <manual.html#127>`_
+     * `manual.html#127 <manual.html#127>`_
+     * `regexprs.html#101 <regexprs.html#101>`_
 
    `backspace`:idx:
      `manual.html#132 <manual.html#132>`_
@@ -476,7 +479,7 @@ Index
      `xmlgen.html#118 <xmlgen.html#118>`_
 
    `capture`:idx:
-     `pegs.html#121 <pegs.html#121>`_
+     `pegs.html#122 <pegs.html#122>`_
 
    `card`:idx:
      `system.html#175 <system.html#175>`_
@@ -695,12 +698,12 @@ Index
    `CompileDate`:idx:
      `system.html#390 <system.html#390>`_
 
-   `CompileTime`:idx:
-     `system.html#391 <system.html#391>`_
-
    `compileTime`:idx:
      `manual.html#229 <manual.html#229>`_
 
+   `CompileTime`:idx:
+     `system.html#391 <system.html#391>`_
+
    `complex statements`:idx:
      `manual.html#178 <manual.html#178>`_
 
@@ -719,8 +722,8 @@ Index
      * `strutils.html#137 <strutils.html#137>`_
      * `strutils.html#138 <strutils.html#138>`_
      * `strutils.html#139 <strutils.html#139>`_
-     * `pegs.html#139 <pegs.html#139>`_
-     * `pegs.html#140 <pegs.html#140>`_
+     * `pegs.html#141 <pegs.html#141>`_
+     * `pegs.html#142 <pegs.html#142>`_
 
    `continue`:idx:
      `manual.html#198 <manual.html#198>`_
@@ -736,10 +739,10 @@ Index
      `system.html#407 <system.html#407>`_
 
    `copyNimNode`:idx:
-     `macros.html#135 <macros.html#135>`_
+     `macros.html#136 <macros.html#136>`_
 
    `copyNimTree`:idx:
-     `macros.html#136 <macros.html#136>`_
+     `macros.html#137 <macros.html#137>`_
 
    `coreAttr`:idx:
      `xmlgen.html#103 <xmlgen.html#103>`_
@@ -1185,7 +1188,7 @@ Index
 
    `del`:idx:
      * `xmlgen.html#124 <xmlgen.html#124>`_
-     * `macros.html#120 <macros.html#120>`_
+     * `macros.html#121 <macros.html#121>`_
 
    `delete`:idx:
      `strutils.html#156 <strutils.html#156>`_
@@ -1198,7 +1201,7 @@ Index
      `xmlgen.html#125 <xmlgen.html#125>`_
 
    `digits`:idx:
-     `pegs.html#125 <pegs.html#125>`_
+     `pegs.html#126 <pegs.html#126>`_
 
    `Digits`:idx:
      `strutils.html#104 <strutils.html#104>`_
@@ -1290,10 +1293,10 @@ Index
      `system.html#160 <system.html#160>`_
 
    `EInvalidPeg`:idx:
-     `pegs.html#149 <pegs.html#149>`_
+     `pegs.html#150 <pegs.html#150>`_
 
    `EInvalidRegEx`:idx:
-     `regexprs.html#101 <regexprs.html#101>`_
+     `regexprs.html#104 <regexprs.html#104>`_
 
    `EInvalidSql`:idx:
      `parsesql.html#103 <parsesql.html#103>`_
@@ -1322,7 +1325,7 @@ Index
 
    `endsWith`:idx:
      * `strutils.html#148 <strutils.html#148>`_
-     * `pegs.html#142 <pegs.html#142>`_
+     * `pegs.html#144 <pegs.html#144>`_
 
    `ENoExceptionToReraise`:idx:
      * `manual.html#187 <manual.html#187>`_
@@ -1334,12 +1337,12 @@ Index
    `enum_cursor_type`:idx:
      `mysql.html#237 <mysql.html#237>`_
 
-   `Enumeration`:idx:
-     `manual.html#149 <manual.html#149>`_
-
    `enumeration`:idx:
      `tut1.html#113 <tut1.html#113>`_
 
+   `Enumeration`:idx:
+     `manual.html#149 <manual.html#149>`_
+
    `enum_field_types`:idx:
      `mysql.html#202 <mysql.html#202>`_
 
@@ -1390,7 +1393,7 @@ Index
    `error`:idx:
      * `manual.html#226 <manual.html#226>`_
      * `manual.html#230 <manual.html#230>`_
-     * `macros.html#137 <macros.html#137>`_
+     * `macros.html#138 <macros.html#138>`_
 
    `errorMsg`:idx:
      `parsexml.html#120 <parsexml.html#120>`_
@@ -1478,13 +1481,13 @@ Index
      `os.html#132 <os.html#132>`_
 
    `expectKind`:idx:
-     `macros.html#146 <macros.html#146>`_
+     `macros.html#147 <macros.html#147>`_
 
    `expectLen`:idx:
-     `macros.html#148 <macros.html#148>`_
+     `macros.html#149 <macros.html#149>`_
 
    `expectMinLen`:idx:
-     `macros.html#147 <macros.html#147>`_
+     `macros.html#148 <macros.html#148>`_
 
    `exportc`:idx:
      `nimrodc.html#102 <nimrodc.html#102>`_
@@ -1632,10 +1635,10 @@ Index
      * `strutils.html#119 <strutils.html#119>`_
      * `strutils.html#120 <strutils.html#120>`_
      * `strutils.html#121 <strutils.html#121>`_
-     * `regexprs.html#106 <regexprs.html#106>`_
-     * `regexprs.html#107 <regexprs.html#107>`_
-     * `pegs.html#136 <pegs.html#136>`_
-     * `pegs.html#137 <pegs.html#137>`_
+     * `regexprs.html#109 <regexprs.html#109>`_
+     * `regexprs.html#110 <regexprs.html#110>`_
+     * `pegs.html#138 <pegs.html#138>`_
+     * `pegs.html#139 <pegs.html#139>`_
 
    `float`:idx:
      `system.html#106 <system.html#106>`_
@@ -1647,10 +1650,10 @@ Index
      `system.html#108 <system.html#108>`_
 
    `floatVal`:idx:
-     `macros.html#123 <macros.html#123>`_
+     `macros.html#124 <macros.html#124>`_
 
    `floatVal=`:idx:
-     `macros.html#129 <macros.html#129>`_
+     `macros.html#130 <macros.html#130>`_
 
    `FlushFile`:idx:
      `system.html#503 <system.html#503>`_
@@ -1715,6 +1718,9 @@ Index
    `generalized raw string literal`:idx:
      `manual.html#136 <manual.html#136>`_
 
+   `generic character types`:idx:
+     `regexprs.html#102 <regexprs.html#102>`_
+
    `Generics`:idx:
      * `manual.html#212 <manual.html#212>`_
      * `tut2.html#109 <tut2.html#109>`_
@@ -1987,7 +1993,7 @@ Index
    `hint`:idx:
      * `manual.html#224 <manual.html#224>`_
      * `manual.html#233 <manual.html#233>`_
-     * `macros.html#139 <macros.html#139>`_
+     * `macros.html#140 <macros.html#140>`_
 
    `hostCPU`:idx:
      `system.html#398 <system.html#398>`_
@@ -2001,13 +2007,13 @@ Index
    `hr`:idx:
      `xmlgen.html#140 <xmlgen.html#140>`_
 
+   `html`:idx:
+     `xmlgen.html#139 <xmlgen.html#139>`_
+
    `HTML`:idx:
      * `parsexml.html#102 <parsexml.html#102>`_
      * `xmlgen.html#102 <xmlgen.html#102>`_
 
-   `html`:idx:
-     `xmlgen.html#139 <xmlgen.html#139>`_
-
    `HTTPPOST_BUFFER`:idx:
      `libcurl.html#266 <libcurl.html#266>`_
 
@@ -2033,14 +2039,14 @@ Index
      `xmlgen.html#141 <xmlgen.html#141>`_
 
    `ident`:idx:
-     * `pegs.html#129 <pegs.html#129>`_
-     * `macros.html#125 <macros.html#125>`_
+     * `pegs.html#130 <pegs.html#130>`_
+     * `macros.html#126 <macros.html#126>`_
 
    `ident=`:idx:
-     `macros.html#131 <macros.html#131>`_
+     `macros.html#132 <macros.html#132>`_
 
    `identChars`:idx:
-     `pegs.html#127 <pegs.html#127>`_
+     `pegs.html#128 <pegs.html#128>`_
 
    `IdentChars`:idx:
      `strutils.html#105 <strutils.html#105>`_
@@ -2052,7 +2058,7 @@ Index
      `manual.html#116 <manual.html#116>`_
 
    `identStartChars`:idx:
-     `pegs.html#128 <pegs.html#128>`_
+     `pegs.html#129 <pegs.html#129>`_
 
    `IdentStartChars`:idx:
      `strutils.html#106 <strutils.html#106>`_
@@ -2138,10 +2144,10 @@ Index
      `strutils.html#141 <strutils.html#141>`_
 
    `intVal`:idx:
-     `macros.html#122 <macros.html#122>`_
+     `macros.html#123 <macros.html#123>`_
 
    `intVal=`:idx:
-     `macros.html#128 <macros.html#128>`_
+     `macros.html#129 <macros.html#129>`_
 
    `is`:idx:
      `system.html#353 <system.html#353>`_
@@ -2226,7 +2232,7 @@ Index
 
    `kind`:idx:
      * `parsexml.html#110 <parsexml.html#110>`_
-     * `macros.html#121 <macros.html#121>`_
+     * `macros.html#122 <macros.html#122>`_
 
    `l-values`:idx:
      `manual.html#107 <manual.html#107>`_
@@ -2245,13 +2251,13 @@ Index
      * `system.html#172 <system.html#172>`_
      * `strtabs.html#109 <strtabs.html#109>`_
      * `parsesql.html#107 <parsesql.html#107>`_
-     * `macros.html#117 <macros.html#117>`_
+     * `macros.html#118 <macros.html#118>`_
 
    `Letters`:idx:
      `strutils.html#103 <strutils.html#103>`_
 
    `letters`:idx:
-     `pegs.html#124 <pegs.html#124>`_
+     `pegs.html#125 <pegs.html#125>`_
 
    `li`:idx:
      `xmlgen.html#148 <xmlgen.html#148>`_
@@ -2353,16 +2359,16 @@ Index
      `xmlgen.html#150 <xmlgen.html#150>`_
 
    `match`:idx:
-     * `regexprs.html#103 <regexprs.html#103>`_
-     * `regexprs.html#104 <regexprs.html#104>`_
-     * `pegs.html#132 <pegs.html#132>`_
-     * `pegs.html#133 <pegs.html#133>`_
-
-   `matchLen`:idx:
-     * `regexprs.html#105 <regexprs.html#105>`_
+     * `regexprs.html#106 <regexprs.html#106>`_
+     * `regexprs.html#107 <regexprs.html#107>`_
      * `pegs.html#134 <pegs.html#134>`_
      * `pegs.html#135 <pegs.html#135>`_
 
+   `matchLen`:idx:
+     * `regexprs.html#108 <regexprs.html#108>`_
+     * `pegs.html#136 <pegs.html#136>`_
+     * `pegs.html#137 <pegs.html#137>`_
+
    `max`:idx:
      * `system.html#318 <system.html#318>`_
      * `system.html#444 <system.html#444>`_
@@ -2397,8 +2403,8 @@ Index
      `mysql.html#191 <mysql.html#191>`_
 
    `MaxSubpatterns`:idx:
-     * `regexprs.html#102 <regexprs.html#102>`_
-     * `pegs.html#131 <pegs.html#131>`_
+     * `regexprs.html#105 <regexprs.html#105>`_
+     * `pegs.html#132 <pegs.html#132>`_
 
    `MAX_TINYINT_WIDTH`:idx:
      `mysql.html#190 <mysql.html#190>`_
@@ -2990,13 +2996,13 @@ Index
      `system.html#134 <system.html#134>`_
 
    `natural`:idx:
-     `pegs.html#130 <pegs.html#130>`_
+     `pegs.html#131 <pegs.html#131>`_
 
    `neginf`:idx:
      `system.html#430 <system.html#430>`_
 
    `nestList`:idx:
-     `macros.html#151 <macros.html#151>`_
+     `macros.html#152 <macros.html#152>`_
 
    `NET`:idx:
      `mysql.html#199 <mysql.html#199>`_
@@ -3042,38 +3048,38 @@ Index
      * `system.html#125 <system.html#125>`_
 
    `newCall`:idx:
-     * `macros.html#149 <macros.html#149>`_
      * `macros.html#150 <macros.html#150>`_
+     * `macros.html#151 <macros.html#151>`_
 
    `newFileStream`:idx:
      * `streams.html#120 <streams.html#120>`_
      * `streams.html#121 <streams.html#121>`_
 
    `newFloatLitNode`:idx:
-     `macros.html#142 <macros.html#142>`_
+     `macros.html#143 <macros.html#143>`_
 
    `newIdentNode`:idx:
-     * `macros.html#143 <macros.html#143>`_
      * `macros.html#144 <macros.html#144>`_
+     * `macros.html#145 <macros.html#145>`_
 
    `newIntLitNode`:idx:
-     `macros.html#141 <macros.html#141>`_
+     `macros.html#142 <macros.html#142>`_
+
+   `newLine`:idx:
+     `pegs.html#121 <pegs.html#121>`_
 
    `newline`:idx:
      * `manual.html#121 <manual.html#121>`_
-     * `pegs.html#119 <pegs.html#119>`_
-
-   `newLine`:idx:
-     `pegs.html#120 <pegs.html#120>`_
+     * `pegs.html#120 <pegs.html#120>`_
 
    `NewLines`:idx:
      `lexbase.html#102 <lexbase.html#102>`_
 
    `newNimNode`:idx:
-     `macros.html#134 <macros.html#134>`_
+     `macros.html#135 <macros.html#135>`_
 
    `newNonTerminal`:idx:
-     `pegs.html#123 <pegs.html#123>`_
+     `pegs.html#124 <pegs.html#124>`_
 
    `newSeq`:idx:
      `system.html#167 <system.html#167>`_
@@ -3089,7 +3095,7 @@ Index
      * `strtabs.html#105 <strtabs.html#105>`_
 
    `newStrLitNode`:idx:
-     `macros.html#140 <macros.html#140>`_
+     `macros.html#141 <macros.html#141>`_
 
    `next`:idx:
      * `parseopt.html#105 <parseopt.html#105>`_
@@ -3124,7 +3130,7 @@ Index
      `mysql.html#136 <mysql.html#136>`_
 
    `nonterminal`:idx:
-     `pegs.html#122 <pegs.html#122>`_
+     `pegs.html#123 <pegs.html#123>`_
 
    `normalize`:idx:
      `strutils.html#118 <strutils.html#118>`_
@@ -3238,7 +3244,7 @@ Index
      `strtabs.html#110 <strtabs.html#110>`_
 
    `parallelReplace`:idx:
-     `pegs.html#144 <pegs.html#144>`_
+     `pegs.html#146 <pegs.html#146>`_
 
    `param`:idx:
      `xmlgen.html#158 <xmlgen.html#158>`_
@@ -3268,7 +3274,7 @@ Index
      `strutils.html#142 <strutils.html#142>`_
 
    `parsePeg`:idx:
-     `pegs.html#150 <pegs.html#150>`_
+     `pegs.html#151 <pegs.html#151>`_
 
    `parseSQL`:idx:
      `parsesql.html#109 <parsesql.html#109>`_
@@ -3403,7 +3409,7 @@ Index
      `libcurl.html#122 <libcurl.html#122>`_
 
    `peg`:idx:
-     `pegs.html#151 <pegs.html#151>`_
+     `pegs.html#152 <pegs.html#152>`_
 
    `Pfd_set`:idx:
      `libcurl.html#138 <libcurl.html#138>`_
@@ -3771,16 +3777,16 @@ Index
      `system.html#412 <system.html#412>`_
 
    `reBinary`:idx:
-     `regexprs.html#113 <regexprs.html#113>`_
+     `regexprs.html#116 <regexprs.html#116>`_
 
    `Recursive module dependancies`:idx:
      `manual.html#221 <manual.html#221>`_
 
    `reEmail`:idx:
-     `regexprs.html#116 <regexprs.html#116>`_
+     `regexprs.html#119 <regexprs.html#119>`_
 
    `reFloat`:idx:
-     `regexprs.html#115 <regexprs.html#115>`_
+     `regexprs.html#118 <regexprs.html#118>`_
 
    `REFRESH_DES_KEY_FILE`:idx:
      `mysql.html#154 <mysql.html#154>`_
@@ -3828,13 +3834,13 @@ Index
      `nimrodc.html#112 <nimrodc.html#112>`_
 
    `reHex`:idx:
-     `regexprs.html#112 <regexprs.html#112>`_
+     `regexprs.html#115 <regexprs.html#115>`_
 
    `reIdentifier`:idx:
-     `regexprs.html#109 <regexprs.html#109>`_
+     `regexprs.html#112 <regexprs.html#112>`_
 
    `reInteger`:idx:
-     `regexprs.html#111 <regexprs.html#111>`_
+     `regexprs.html#114 <regexprs.html#114>`_
 
    `removeDir`:idx:
      `os.html#158 <os.html#158>`_
@@ -3843,13 +3849,13 @@ Index
      `os.html#144 <os.html#144>`_
 
    `reNatural`:idx:
-     `regexprs.html#110 <regexprs.html#110>`_
+     `regexprs.html#113 <regexprs.html#113>`_
 
    `renderSQL`:idx:
      `parsesql.html#110 <parsesql.html#110>`_
 
    `reOctal`:idx:
-     `regexprs.html#114 <regexprs.html#114>`_
+     `regexprs.html#117 <regexprs.html#117>`_
 
    `repeatChar`:idx:
      `strutils.html#146 <strutils.html#146>`_
@@ -3857,7 +3863,7 @@ Index
    `replace`:idx:
      * `strutils.html#154 <strutils.html#154>`_
      * `strutils.html#155 <strutils.html#155>`_
-     * `pegs.html#143 <pegs.html#143>`_
+     * `pegs.html#145 <pegs.html#145>`_
 
    `replaceStr`:idx:
      * `strutils.html#122 <strutils.html#122>`_
@@ -3880,7 +3886,7 @@ Index
      `manual.html#192 <manual.html#192>`_
 
    `reURL`:idx:
-     `regexprs.html#117 <regexprs.html#117>`_
+     `regexprs.html#120 <regexprs.html#120>`_
 
    `round`:idx:
      `math.html#121 <math.html#121>`_
@@ -4048,6 +4054,9 @@ Index
      * `system.html#230 <system.html#230>`_
      * `system.html#231 <system.html#231>`_
 
+   `simple assertions`:idx:
+     `regexprs.html#103 <regexprs.html#103>`_
+
    `simple statements`:idx:
      `manual.html#177 <manual.html#177>`_
 
@@ -4074,8 +4083,8 @@ Index
      * `strutils.html#127 <strutils.html#127>`_
      * `strutils.html#133 <strutils.html#133>`_
      * `strutils.html#134 <strutils.html#134>`_
-     * `pegs.html#146 <pegs.html#146>`_
-     * `pegs.html#147 <pegs.html#147>`_
+     * `pegs.html#148 <pegs.html#148>`_
+     * `pegs.html#149 <pegs.html#149>`_
 
    `splitFile`:idx:
      `os.html#129 <os.html#129>`_
@@ -4611,7 +4620,7 @@ Index
 
    `startsWith`:idx:
      * `strutils.html#147 <strutils.html#147>`_
-     * `pegs.html#141 <pegs.html#141>`_
+     * `pegs.html#143 <pegs.html#143>`_
 
    `statement macros`:idx:
      `tut2.html#112 <tut2.html#112>`_
@@ -4702,10 +4711,10 @@ Index
      `manual.html#152 <manual.html#152>`_
 
    `strVal`:idx:
-     `macros.html#127 <macros.html#127>`_
+     `macros.html#128 <macros.html#128>`_
 
    `strVal=`:idx:
-     `macros.html#133 <macros.html#133>`_
+     `macros.html#134 <macros.html#134>`_
 
    `st_udf_args`:idx:
      `mysql.html#258 <mysql.html#258>`_
@@ -4751,10 +4760,10 @@ Index
      `dynlib.html#104 <dynlib.html#104>`_
 
    `symbol`:idx:
-     `macros.html#124 <macros.html#124>`_
+     `macros.html#125 <macros.html#125>`_
 
    `symbol=`:idx:
-     `macros.html#130 <macros.html#130>`_
+     `macros.html#131 <macros.html#131>`_
 
    `syscall`:idx:
      `manual.html#172 <manual.html#172>`_
@@ -5114,7 +5123,7 @@ Index
      `strutils.html#145 <strutils.html#145>`_
 
    `toStrLit`:idx:
-     `macros.html#145 <macros.html#145>`_
+     `macros.html#146 <macros.html#146>`_
 
    `toTitle`:idx:
      `unicode.html#113 <unicode.html#113>`_
@@ -5153,7 +5162,7 @@ Index
      * `tut1.html#121 <tut1.html#121>`_
 
    `transformFile`:idx:
-     `pegs.html#145 <pegs.html#145>`_
+     `pegs.html#147 <pegs.html#147>`_
 
    `TRequestMethod`:idx:
      `cgi.html#105 <cgi.html#105>`_
@@ -5244,10 +5253,10 @@ Index
      `parsexml.html#106 <parsexml.html#106>`_
 
    `typ`:idx:
-     `macros.html#126 <macros.html#126>`_
+     `macros.html#127 <macros.html#127>`_
 
    `typ=`:idx:
-     `macros.html#132 <macros.html#132>`_
+     `macros.html#133 <macros.html#133>`_
 
    `type`:idx:
      * `manual.html#102 <manual.html#102>`_
@@ -5363,7 +5372,7 @@ Index
      * `tut2.html#103 <tut2.html#103>`_
 
    `verbose`:idx:
-     `regexprs.html#118 <regexprs.html#118>`_
+     `regexprs.html#121 <regexprs.html#121>`_
 
    `vertical tabulator`:idx:
      `manual.html#126 <manual.html#126>`_
@@ -5387,7 +5396,7 @@ Index
    `warning`:idx:
      * `manual.html#225 <manual.html#225>`_
      * `manual.html#232 <manual.html#232>`_
-     * `macros.html#138 <macros.html#138>`_
+     * `macros.html#139 <macros.html#139>`_
 
    `when`:idx:
      * `manual.html#185 <manual.html#185>`_
@@ -5400,7 +5409,7 @@ Index
      `strutils.html#102 <strutils.html#102>`_
 
    `whitespace`:idx:
-     `pegs.html#126 <pegs.html#126>`_
+     `pegs.html#127 <pegs.html#127>`_
 
    `winTimeToUnixTime`:idx:
      `times.html#118 <times.html#118>`_
diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim
index c029f92a2..21205bdb2 100755
--- a/lib/pure/pegs.nim
+++ b/lib/pure/pegs.nim
@@ -42,7 +42,7 @@ type
     pkSequence,         ## a b c ... --> Internal DSL: peg(a, b, c)
     pkOrderedChoice,    ## a / b / ... --> Internal DSL: a / b or /[a, b, c]
     pkGreedyRep,        ## a*     --> Internal DSL: *a
-                        ## a+     --> Internal DSL: +a; represented as (a a*)
+                        ## a+     --> (a a*)
     pkGreedyRepChar,    ## x* where x is a single character (superop)
     pkGreedyRepSet,     ## [set]* (superop)
     pkGreedyAny,        ## .* or _* (superop)
@@ -50,6 +50,7 @@ type
     pkAndPredicate,     ## &a     --> Internal DSL: &a
     pkNotPredicate,     ## !a     --> Internal DSL: !a
     pkCapture,          ## {a}    --> Internal DSL: capture(a)
+    pkSearch,           ## @a     --> Internal DSL: @a
     pkRule,             ## a <- b
     pkList              ## a, b
   TNonTerminalFlag = enum
@@ -174,7 +175,24 @@ proc `*`*(a: TPeg): TPeg =
   else:
     result.kind = pkGreedyRep
     result.sons = @[a]
+
+proc `@`*(a: TPeg): TPeg =
+  ## constructs a "search" for the PEG `a`
+  result.kind = pkSearch
+  result.sons = @[a]
   
+when false:
+  proc contains(a: TPeg, k: TPegKind): bool =
+    if a.kind == k: return true
+    case a.kind
+    of pkEmpty, pkAny, pkAnyRune, pkGreedyAny, pkNewLine, pkTerminal,
+       pkTerminalIgnoreCase, pkTerminalIgnoreStyle, pkChar, pkGreedyRepChar,
+       pkCharChoice, pkGreedyRepSet: nil
+    of pkNonTerminal: return true
+    else:
+      for i in 0..a.sons.len-1:
+        if contains(a.sons[i], k): return true
+
 proc `+`*(a: TPeg): TPeg =
   ## constructs a "greedy positive repetition" with the PEG `a`
   return sequence(a, *a)
@@ -271,6 +289,125 @@ const
   MaxSubpatterns* = 10 ## defines the maximum number of subpatterns that
                        ## can be captured. More subpatterns cannot be captured! 
 
+# ------------------------- debugging -----------------------------------------
+
+proc esc(c: char, reserved = {'\0'..'\255'}): string = 
+  case c
+  of '\b': result = "\\b"
+  of '\t': result = "\\t"
+  of '\c': result = "\\c"
+  of '\L': result = "\\l"
+  of '\v': result = "\\v"
+  of '\f': result = "\\f"
+  of '\e': result = "\\e"
+  of '\a': result = "\\a"
+  of '\\': result = "\\\\"
+  of 'a'..'z', 'A'..'Z', '0'..'9', '_': result = $c
+  elif c < ' ' or c >= '\128': result = '\\' & $ord(c)
+  elif c in reserved: result = '\\' & c
+  else: result = $c
+  
+proc singleQuoteEsc(c: Char): string = return "'" & esc(c, {'\''}) & "'"
+
+proc singleQuoteEsc(str: string): string = 
+  result = "'"
+  for c in items(str): add result, esc(c, {'\''})
+  add result, '\''
+  
+proc charSetEscAux(cc: set[char]): string = 
+  const reserved = {'^', '-', ']'}
+  result = ""
+  var c1 = 0
+  while c1 <= 0xff: 
+    if chr(c1) in cc: 
+      var c2 = c1
+      while c2 < 0xff and chr(succ(c2)) in cc: inc(c2)
+      if c1 == c2: 
+        add result, esc(chr(c1), reserved)
+      elif c2 == succ(c1): 
+        add result, esc(chr(c1), reserved) & esc(chr(c2), reserved)
+      else: 
+        add result, esc(chr(c1), reserved) & '-' & esc(chr(c2), reserved)
+      c1 = c2
+    inc(c1)
+  
+proc CharSetEsc(cc: set[char]): string =
+  if card(cc) >= 128+64: 
+    result = "[^" & CharSetEscAux({'\1'..'\xFF'} - cc) & ']'
+  else: 
+    result = '[' & CharSetEscAux(cc) & ']'
+  
+proc toStrAux(r: TPeg, res: var string) = 
+  case r.kind
+  of pkEmpty: add(res, "()")
+  of pkAny: add(res, '.')
+  of pkAnyRune: add(res, '_')
+  of pkNewline: add(res, "\\n")
+  of pkTerminal: add(res, singleQuoteEsc(r.term))
+  of pkTerminalIgnoreCase:
+    add(res, 'i')
+    add(res, singleQuoteEsc(r.term))
+  of pkTerminalIgnoreStyle:
+    add(res, 'y')
+    add(res, singleQuoteEsc(r.term))
+  of pkChar: add(res, singleQuoteEsc(r.ch))
+  of pkCharChoice: add(res, charSetEsc(r.charChoice^))
+  of pkNonTerminal: add(res, r.nt.name)
+  of pkSequence:
+    add(res, '(')
+    toStrAux(r.sons[0], res)
+    for i in 1 .. high(r.sons):
+      add(res, ' ')
+      toStrAux(r.sons[i], res)
+    add(res, ')')
+  of pkOrderedChoice:
+    add(res, '(')
+    toStrAux(r.sons[0], res)
+    for i in 1 .. high(r.sons):
+      add(res, " / ")
+      toStrAux(r.sons[i], res)
+    add(res, ')')
+  of pkGreedyRep:
+    toStrAux(r.sons[0], res)
+    add(res, '*')
+  of pkGreedyRepChar:
+    add(res, singleQuoteEsc(r.ch))
+    add(res, '*')
+  of pkGreedyRepSet:
+    add(res, charSetEsc(r.charChoice^))
+    add(res, '*')
+  of pkGreedyAny:
+    add(res, ".*")
+  of pkOption:
+    toStrAux(r.sons[0], res)
+    add(res, '?')
+  of pkAndPredicate:
+    add(res, '&')
+    toStrAux(r.sons[0], res)
+  of pkNotPredicate:
+    add(res, '!')
+    toStrAux(r.sons[0], res)
+  of pkSearch:
+    add(res, '@')
+    toStrAux(r.sons[0], res)
+  of pkCapture:
+    add(res, '{')
+    toStrAux(r.sons[0], res)    
+    add(res, '}')
+  of pkRule:
+    toStrAux(r.sons[0], res)    
+    add(res, " <- ")
+    toStrAux(r.sons[1], res)
+  of pkList:
+    for i in 0 .. high(r.sons):
+      toStrAux(r.sons[i], res)
+      add(res, "\n")  
+
+proc `$` *(r: TPeg): string =
+  ## converts a PEG to its string representation
+  result = ""
+  toStrAux(r, result)
+
 # --------------------- core engine -------------------------------------------
 
 type
@@ -370,6 +507,17 @@ proc m(s: string, p: TPeg, start: int, c: var TMatchClosure): int =
       result = m(s, p.sons[i], start, c)
       if result >= 0: break
       c.ml = oldMl
+  of pkSearch:
+    var oldMl = c.ml
+    result = 0
+    while start+result < s.len:
+      var x = m(s, p.sons[0], start+result, c)
+      if x >= 0:
+        inc(result, x)
+        return
+      inc(result)
+    result = -1
+    c.ml = oldMl
   of pkGreedyRep:
     result = 0
     while true:
@@ -607,123 +755,6 @@ proc split*(s: string, sep: TPeg): seq[string] {.noSideEffect.} =
   ## Splits the string `s` into substrings.
   accumulateResult(split(s, sep))
 
-# ------------------------- debugging -----------------------------------------
-
-proc esc(c: char, reserved = {'\0'..'\255'}): string = 
-  case c
-  of '\b': result = "\\b"
-  of '\t': result = "\\t"
-  of '\c': result = "\\c"
-  of '\L': result = "\\l"
-  of '\v': result = "\\v"
-  of '\f': result = "\\f"
-  of '\e': result = "\\e"
-  of '\a': result = "\\a"
-  of '\\': result = "\\\\"
-  of 'a'..'z', 'A'..'Z', '0'..'9', '_': result = $c
-  elif c < ' ' or c >= '\128': result = '\\' & $ord(c)
-  elif c in reserved: result = '\\' & c
-  else: result = $c
-  
-proc singleQuoteEsc(c: Char): string = return "'" & esc(c, {'\''}) & "'"
-
-proc singleQuoteEsc(str: string): string = 
-  result = "'"
-  for c in items(str): add result, esc(c, {'\''})
-  add result, '\''
-  
-proc charSetEscAux(cc: set[char]): string = 
-  const reserved = {'^', '-', ']'}
-  result = ""
-  var c1 = 0
-  while c1 <= 0xff: 
-    if chr(c1) in cc: 
-      var c2 = c1
-      while c2 < 0xff and chr(succ(c2)) in cc: inc(c2)
-      if c1 == c2: 
-        add result, esc(chr(c1), reserved)
-      elif c2 == succ(c1): 
-        add result, esc(chr(c1), reserved) & esc(chr(c2), reserved)
-      else: 
-        add result, esc(chr(c1), reserved) & '-' & esc(chr(c2), reserved)
-      c1 = c2
-    inc(c1)
-  
-proc CharSetEsc(cc: set[char]): string =
-  if card(cc) >= 128+64: 
-    result = "[^" & CharSetEscAux({'\1'..'\xFF'} - cc) & ']'
-  else: 
-    result = '[' & CharSetEscAux(cc) & ']'
-  
-proc toStrAux(r: TPeg, res: var string) = 
-  case r.kind
-  of pkEmpty: add(res, "()")
-  of pkAny: add(res, '.')
-  of pkAnyRune: add(res, '_')
-  of pkNewline: add(res, "\\n")
-  of pkTerminal: add(res, singleQuoteEsc(r.term))
-  of pkTerminalIgnoreCase:
-    add(res, 'i')
-    add(res, singleQuoteEsc(r.term))
-  of pkTerminalIgnoreStyle:
-    add(res, 'y')
-    add(res, singleQuoteEsc(r.term))
-  of pkChar: add(res, singleQuoteEsc(r.ch))
-  of pkCharChoice: add(res, charSetEsc(r.charChoice^))
-  of pkNonTerminal: add(res, r.nt.name)
-  of pkSequence:
-    add(res, '(')
-    toStrAux(r.sons[0], res)
-    for i in 1 .. high(r.sons):
-      add(res, ' ')
-      toStrAux(r.sons[i], res)
-    add(res, ')')
-  of pkOrderedChoice:
-    add(res, '(')
-    toStrAux(r.sons[0], res)
-    for i in 1 .. high(r.sons):
-      add(res, " / ")
-      toStrAux(r.sons[i], res)
-    add(res, ')')
-  of pkGreedyRep:
-    toStrAux(r.sons[0], res)
-    add(res, '*')
-  of pkGreedyRepChar:
-    add(res, singleQuoteEsc(r.ch))
-    add(res, '*')
-  of pkGreedyRepSet:
-    add(res, charSetEsc(r.charChoice^))
-    add(res, '*')
-  of pkGreedyAny:
-    add(res, ".*")
-  of pkOption:
-    toStrAux(r.sons[0], res)
-    add(res, '?')
-  of pkAndPredicate:
-    add(res, '&')
-    toStrAux(r.sons[0], res)
-  of pkNotPredicate:
-    add(res, '!')
-    toStrAux(r.sons[0], res)
-  of pkCapture:
-    add(res, '{')
-    toStrAux(r.sons[0], res)    
-    add(res, '}')
-  of pkRule:
-    toStrAux(r.sons[0], res)    
-    add(res, " <- ")
-    toStrAux(r.sons[1], res)
-  of pkList:
-    for i in 0 .. high(r.sons):
-      toStrAux(r.sons[i], res)
-      add(res, "\n")  
-
-proc `$` *(r: TPeg): string =
-  ## converts a PEG to its string representation
-  result = ""
-  toStrAux(r, result)
-
-
 # ------------------- scanner -------------------------------------------------
 
 type
@@ -751,6 +782,7 @@ type
     tkAmp,              ## '&'
     tkNot,              ## '!'
     tkOption,           ## '?'
+    tkAt,               ## '@'
     tkBuiltin,          ## \identifier
     tkEscaped           ## \\
   
@@ -772,7 +804,7 @@ const
   tokKindToStr: array[TTokKind, string] = [
     "invalid", "[EOF]", ".", "_", "identifier", "string literal",
     "character set", "(", ")", "{", "}", "<-", "/", "*", "+", "&", "!", "?",
-    "built-in", "escaped"
+    "@", "built-in", "escaped"
   ]
 
 proc HandleCR(L: var TPegLexer, pos: int): int =
@@ -1063,6 +1095,10 @@ proc getTok(c: var TPegLexer, tok: var TToken) =
     tok.kind = tkAmp
     inc(c.bufpos)
     add(tok.literal, '!')
+  of '@':
+    tok.kind = tkAt
+    inc(c.bufpos)
+    add(tok.literal, '@')
   else:
     add(tok.literal, c.buf[c.bufpos])
     inc(c.bufpos)
@@ -1118,6 +1154,9 @@ proc primary(p: var TPegParser): TPeg =
   of tkNot:
     getTok(p)
     return !primary(p)
+  of tkAt:
+    getTok(p)
+    return @primary(p)
   else: nil
   case p.tok.kind
   of tkIdentifier:
@@ -1187,7 +1226,7 @@ proc seqExpr(p: var TPegParser): TPeg =
   result = primary(p)
   while true:
     case p.tok.kind
-    of tkAmp, tkNot, tkStringLit, tkCharset, tkParLe, tkCurlyLe,
+    of tkAmp, tkNot, tkAt, tkStringLit, tkCharset, tkParLe, tkCurlyLe,
        tkAny, tkAnyRune, tkBuiltin, tkEscaped:
       result = sequence(result, primary(p))
     of tkIdentifier:
@@ -1261,6 +1300,7 @@ proc peg*(pattern: string): TPeg =
   result = parsePeg(pattern, "pattern")
 
 when isMainModule:
+  assert match("(a b c)", peg"'(' @ ')'")
   assert match("W_HI_Le", peg"\y 'while'")
   assert(not match("W_HI_L", peg"\y 'while'"))
   assert(not match("W_HI_Le", peg"\y v'while'"))
@@ -1315,6 +1355,11 @@ when isMainModule:
               """
   assert($g2 == "((A B) / (C D))")
   assert match("cccccdddddd", g2)
-  echo "var1=key; var2=key2".replace(peg"{\ident}'='{\ident}", "$1<-$2$2")
+  assert("var1=key; var2=key2".replace(peg"{\ident}'='{\ident}", "$1<-$2$2") ==
+         "var1<-keykey; var2<-key2key2")
   assert "var1=key; var2=key2".endsWith(peg"{\ident}'='{\ident}")
 
+  if "aaaaaa" =~ peg"'aa' !. / ({'a'})+":
+    assert matches[0] == "a"
+  else:
+    assert false
diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim
index 1edddecd9..2a53d7660 100755
--- a/lib/pure/unicode.nim
+++ b/lib/pure/unicode.nim
@@ -44,15 +44,13 @@ proc runeLenAt*(s: string, i: int): int =
 template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
   ## Returns the unicode character ``s[i]`` in `result`. If ``doInc == true``
   ## `i` is incremented by the number of bytes that have been processed.
-  when not defined(ones):
-    template ones(n: expr): expr = ((1 shl n)-1)
-
   if ord(s[i]) <=% 127:
     result = TRune(ord(s[i]))
     when doInc: inc(i)
   elif ord(s[i]) shr 5 == 0b110:
     assert(ord(s[i+1]) shr 6 == 0b10)
-    result = TRune((ord(s[i]) and ones(5)) shl 6 or (ord(s[i+1]) and ones(6)))
+    result = TRune((ord(s[i]) and (bind ones(5))) shl 6 or 
+                   (ord(s[i+1]) and ones(6)))
     when doInc: inc(i, 2)
   elif ord(s[i]) shr 4 == 0b1110:
     assert(ord(s[i+1]) shr 6 == 0b10)
diff --git a/nim/llvmdata.pas b/nim/llvmdata.pas
new file mode 100755
index 000000000..a8ae0f311
--- /dev/null
+++ b/nim/llvmdata.pas
@@ -0,0 +1,139 @@
+//
+//
+//           The Nimrod Compiler
+//        (c) Copyright 2009 Andreas Rumpf
+//
+//    See the file "copying.txt", included in this
+//    distribution, for details about the copyright.
+//
+unit llvmdata;
+
+// this module implements data structures for emitting LLVM.
+
+interface
+
+{$include 'config.inc'}
+
+uses
+  nsystem, ast, astalgo, idents, lists, passes;
+
+type
+  VTypeKind = (
+    VoidTyID,        ///<  0: type with no size
+    FloatTyID,       ///<  1: 32 bit floating point type
+    DoubleTyID,      ///<  2: 64 bit floating point type
+    X86_FP80TyID,    ///<  3: 80 bit floating point type (X87)
+    FP128TyID,       ///<  4: 128 bit floating point type (112-bit mantissa)
+    PPC_FP128TyID,   ///<  5: 128 bit floating point type (two 64-bits)
+    LabelTyID,       ///<  6: Labels
+    MetadataTyID,    ///<  7: Metadata
+
+    // Derived types... see DerivedTypes.h file...
+    // Make sure FirstDerivedTyID stays up to date!!!
+    IntegerTyID,     ///<  8: Arbitrary bit width integers
+    FunctionTyID,    ///<  9: Functions
+    StructTyID,      ///< 10: Structures
+    ArrayTyID,       ///< 11: Arrays
+    PointerTyID,     ///< 12: Pointers
+    OpaqueTyID,      ///< 13: Opaque: type with unknown structure
+    VectorTyID,      ///< 14: SIMD 'packed' format, or other vector type
+  );
+  VType = ^VTypeDesc;
+  VTypeSeq = array of VType;
+  VTypeDesc = object(TIdObj)
+    k: VTypeKind;
+    s: VTypeSeq;
+    arrayLen: int;
+    name: string;
+  end;
+  
+  VInstrKind = (
+    iNone, 
+    iAdd,
+    iSub,
+    iMul,
+    iDiv,
+    iMod,
+  
+  );
+  VLocalVar = record
+    
+  
+  end;
+  VInstr = record
+    k: VInstrKind;
+    
+  end;
+
+/// This represents a single basic block in LLVM. A basic block is simply a
+/// container of instructions that execute sequentially. Basic blocks are Values
+/// because they are referenced by instructions such as branches and switch
+/// tables. The type of a BasicBlock is "Type::LabelTy" because the basic block
+/// represents a label to which a branch can jump.
+///
+  VBlock = ^VBlockDesc;
+  VBlockDesc = record // LLVM basic block
+    // list of instructions
+  end;
+
+  VLinkage = (
+    ExternalLinkage, // Externally visible function
+    LinkOnceLinkage, // Keep one copy of function when linking (inline)
+    WeakLinkage, // Keep one copy of function when linking (weak)
+    AppendingLinkage, // Special purpose, only applies to global arrays
+    InternalLinkage, // Rename collisions when linking (static functions)
+    DLLImportLinkage, // Function to be imported from DLL
+    DLLExportLinkage, // Function to be accessible from DLL
+    ExternalWeakLinkage, // ExternalWeak linkage description
+    GhostLinkage // Stand-in functions for streaming fns from bitcode
+  );
+  VVisibility = (
+    DefaultVisibility, // The GV is visible
+    HiddenVisibility, // The GV is hidden
+    ProtectedVisibility // The GV is protected
+  );
+  TLLVMCallConv = (
+    CCallConv = 0,
+    FastCallConv = 8,
+    ColdCallConv = 9,
+    X86StdcallCallConv = 64,
+    X86FastcallCallConv = 65
+  );
+  
+  VProc = ^VProcDesc;
+  VProcDesc = record
+    b: VBlock;
+    name: string;
+    sym: PSym; // proc that is generated
+    linkage: VLinkage;
+    vis: VVisibility;
+    callConv: VCallConv;
+    next: VProc;
+  end;
+  VModule = ^VModuleDesc;
+  VModuleDesc = object(TPassContext) // represents a C source file
+    sym: PSym;
+    filename: string;
+    typeCache: TIdTable;     // cache the generated types
+    forwTypeCache: TIdTable; // cache for forward declarations of types
+    declaredThings: TIntSet; // things we have declared in this file
+    declaredProtos: TIntSet; // prototypes we have declared in this file
+    headerFiles: TLinkedList; // needed headers to include
+    typeInfoMarker: TIntSet; // needed for generating type information
+    initProc: VProc;         // code for init procedure
+    typeStack: TTypeSeq;     // used for type generation
+    dataCache: TNodeTable;
+    forwardedProcs: TSymSeq; // keep forwarded procs here
+    typeNodes, nimTypes: int;// used for type info generation
+    typeNodesName, nimTypesName: PRope; // used for type info generation
+    labels: natural;         // for generating unique module-scope names
+    next: VModule; // to stack modules
+  end;
+  
+
+
+implementation
+
+
+end.
+
diff --git a/nim/pbraces.pas b/nim/pbraces.pas
index d362fac65..2e10c50f2 100755
--- a/nim/pbraces.pas
+++ b/nim/pbraces.pas
@@ -146,8 +146,7 @@ begin
   end;
 end;
 
-procedure qualifiedIdentListAux(var p: TParser; endTok: TTokType;
-                                result: PNode);
+procedure qualifiedIdentListAux(var p: TParser; endTok: TTokType; result: PNode);
 var
   a: PNode;
 begin
@@ -216,16 +215,6 @@ begin
   eat(p, tkParRi);
 end;
 
-procedure setBaseFlags(n: PNode; base: TNumericalBase);
-begin
-  case base of
-    base10: begin end;
-    base2: include(n.flags, nfBase2);
-    base8: include(n.flags, nfBase8);
-    base16: include(n.flags, nfBase16);
-  end
-end;
-
 function identOrLiteral(var p: TParser): PNode;
 begin
   case p.tok.tokType of
@@ -542,7 +531,7 @@ begin
   optInd(p, result);
   while (p.tok.tokType = tkSymbol) or (p.tok.tokType = tkAccent) do begin
     a := parseIdentColonEquals(p, {@set}[]);
-    addSon(result, a);        
+    addSon(result, a);
     if p.tok.tokType <> tkComma then break;
     getTok(p);
     optInd(p, a)
@@ -729,12 +718,12 @@ begin
   end
 end;
 
-function parseImportStmt(var p: TParser): PNode;
+function parseImportOrIncludeStmt(var p: TParser; kind: TNodeKind): PNode;
 var
   a: PNode;
 begin
-  result := newNodeP(nkImportStmt, p);
-  getTok(p); // skip `import`
+  result := newNodeP(kind, p);
+  getTok(p); // skip `import` or `include`
   optInd(p, result);
   while true do begin
     case p.tok.tokType of
@@ -764,41 +753,6 @@ begin
   end;
 end;
 
-function parseIncludeStmt(var p: TParser): PNode;
-var
-  a: PNode;
-begin
-  result := newNodeP(nkIncludeStmt, p);
-  getTok(p); // skip `include`
-  optInd(p, result);
-  while true do begin
-    case p.tok.tokType of
-      tkEof, tkSad, tkDed: break;
-      tkSymbol, tkAccent:   a := parseSymbol(p);
-      tkRStrLit:  begin
-        a := newStrNodeP(nkRStrLit, p.tok.literal, p);
-        getTok(p)
-      end;
-      tkStrLit: begin
-        a := newStrNodeP(nkStrLit, p.tok.literal, p);
-        getTok(p);
-      end;
-      tkTripleStrLit: begin
-        a := newStrNodeP(nkTripleStrLit, p.tok.literal, p);
-        getTok(p)
-      end;
-      else begin
-        parMessage(p, errIdentifierExpected, tokToStr(p.tok));
-        break
-      end;
-    end;
-    addSon(result, a);
-    if p.tok.tokType <> tkComma then break;
-    getTok(p);
-    optInd(p, a)
-  end;
-end;
-
 function parseFromStmt(var p: TParser): PNode;
 var
   a: PNode;
@@ -1150,6 +1104,24 @@ begin
   indAndComment(p, result); // XXX: special extension!
 end;
 
+function parseConstSection(var p: TParser): PNode;
+begin
+  result := newNodeP(nkConstSection, p);
+  getTok(p);
+  skipComment(p, result);
+  if p.tok.tokType = tkCurlyLe then begin
+    getTok(p);
+    skipComment(p, result);
+    while (p.tok.tokType <> tkCurlyRi) and (p.tok.tokType <> tkEof) do begin
+      addSon(result, parseConstant(p)) 
+    end;
+    eat(p, tkCurlyRi);
+  end
+  else 
+    addSon(result, parseConstant(p));
+end;
+
+
 function parseEnum(var p: TParser): PNode;
 var
   a, b: PNode;
@@ -1379,9 +1351,9 @@ begin
     tkBreak:    result := parseBreakOrContinue(p, nkBreakStmt);
     tkContinue: result := parseBreakOrContinue(p, nkContinueStmt);
     tkCurlyDotLe: result := parsePragma(p);
-    tkImport: result := parseImportStmt(p);
+    tkImport: result := parseImportOrIncludeStmt(p, nkImportStmt);
     tkFrom: result := parseFromStmt(p);
-    tkInclude: result := parseIncludeStmt(p);
+    tkInclude: result := parseImportOrIncludeStmt(p, nkIncludeStmt);
     tkComment: result := newCommentStmt(p);
     else begin
       if isExprStart(p) then 
@@ -1394,6 +1366,24 @@ begin
     skipComment(p, result);
 end;
 
+function parseType(var p: TParser): PNode;
+begin
+  result := newNodeP(nkTypeSection, p);
+  while true do begin
+    case p.tok.tokType of
+      tkComment: skipComment(p, result);
+      tkType: begin
+        // type alias:
+        
+      end;
+      tkEnum:
+      tkObject:
+      tkTuple:
+      else break;
+    end
+  end
+end;
+
 function complexOrSimpleStmt(var p: TParser): PNode;
 begin
   case p.tok.tokType of
@@ -1410,8 +1400,9 @@ begin
     tkMacro:     result := parseRoutine(p, nkMacroDef);
     tkTemplate:  result := parseRoutine(p, nkTemplateDef);
     tkConverter: result := parseRoutine(p, nkConverterDef);
-    tkType:      result := parseSection(p, nkTypeSection, parseTypeDef);
-    tkConst:     result := parseSection(p, nkConstSection, parseConstant);
+    tkType, tkEnum, tkObject, tkTuple:      
+      result := parseTypeAlias(p, nkTypeSection, parseTypeDef);
+    tkConst:     result := parseConstSection(p);
     tkWhen:      result := parseIfOrWhen(p, nkWhenStmt);
     tkVar:       result := parseSection(p, nkVarSection, parseVariable);
     else         result := simpleStmt(p);
@@ -1422,15 +1413,13 @@ function parseStmt(var p: TParser): PNode;
 var
   a: PNode;
 begin
-  if p.tok.tokType = tkInd then begin
+  if p.tok.tokType = tkCurlyLe then begin
     result := newNodeP(nkStmtList, p);
-    pushInd(p.lex^, p.tok.indent);
     getTok(p);
     while true do begin
       case p.tok.tokType of
-        tkSad: getTok(p);
-        tkEof: break;
-        tkDed: begin getTok(p); break end;
+        tkSad, tkInd, tkDed: getTok(p);
+        tkEof, tkCurlyRi: break;
         else begin
           a := complexOrSimpleStmt(p);
           if a = nil then break;
@@ -1438,7 +1427,7 @@ begin
         end
       end
     end;
-    popInd(p.lex^);
+    eat(p, tkCurlyRi);
   end
   else begin
     // the case statement is only needed for better error messages:
@@ -1451,7 +1440,7 @@ begin
       else begin
         result := simpleStmt(p);
         if result = nil then parMessage(p, errExprExpected, tokToStr(p.tok));
-        if p.tok.tokType = tkSad then getTok(p);
+        if p.tok.tokType in [tkInd, tkDed, tkSad] then getTok(p);
       end
     end
   end
@@ -1464,8 +1453,7 @@ begin
   result := newNodeP(nkStmtList, p);
   while true do begin
     case p.tok.tokType of
-      tkSad: getTok(p);
-      tkDed, tkInd: parMessage(p, errInvalidIndentation);
+      tkDed, tkInd, tkSad: getTok(p);
       tkEof: break;
       else begin
         a := complexOrSimpleStmt(p);
@@ -1481,11 +1469,7 @@ begin
   result := nil;
   while true do begin
     case p.tok.tokType of
-      tkSad: getTok(p);
-      tkDed, tkInd: begin
-        parMessage(p, errInvalidIndentation);
-        break;
-      end;
+      tkDed, tkInd, tkSad: getTok(p);
       tkEof: break;
       else begin
         result := complexOrSimpleStmt(p);
diff --git a/nim/pendx.pas b/nim/pendx.pas
new file mode 100755
index 000000000..e23229e28
--- /dev/null
+++ b/nim/pendx.pas
@@ -0,0 +1,36 @@
+//
+//
+//           The Nimrod Compiler
+//        (c) Copyright 2009 Andreas Rumpf
+//
+//    See the file "copying.txt", included in this
+//    distribution, for details about the copyright.
+//
+unit pendx;
+
+{$include config.inc}
+
+interface
+
+uses
+  nsystem, llstream, scanner, idents, strutils, ast, msgs, pnimsyn;
+
+function ParseAll(var p: TParser): PNode;
+
+function parseTopLevelStmt(var p: TParser): PNode;
+// implements an iterator. Returns the next top-level statement or nil if end
+// of stream.
+
+implementation
+
+function ParseAll(var p: TParser): PNode;
+begin
+  result := nil
+end;
+
+function parseTopLevelStmt(var p: TParser): PNode;
+begin
+  result := nil
+end;
+
+end.
diff --git a/nim/pnimsyn.pas b/nim/pnimsyn.pas
index bf964fda1..eeaf2a6e9 100755
--- a/nim/pnimsyn.pas
+++ b/nim/pnimsyn.pas
@@ -72,6 +72,7 @@ procedure optSad(var p: TParser);
 procedure optInd(var p: TParser; n: PNode);
 procedure indAndComment(var p: TParser; n: PNode);
 
+procedure setBaseFlags(n: PNode; base: TNumericalBase);
 
 function parseSymbol(var p: TParser): PNode;
 function accExpr(var p: TParser): PNode;
@@ -1069,12 +1070,12 @@ begin
   end
 end;
 
-function parseImportStmt(var p: TParser): PNode;
+function parseImportOrIncludeStmt(var p: TParser; kind: TNodeKind): PNode;
 var
   a: PNode;
 begin
-  result := newNodeP(nkImportStmt, p);
-  getTok(p); // skip `import`
+  result := newNodeP(kind, p);
+  getTok(p); // skip `import` or `include`
   optInd(p, result);
   while true do begin
     case p.tok.tokType of
@@ -1104,42 +1105,6 @@ begin
   end;
 end;
 
-function parseIncludeStmt(var p: TParser): PNode;
-var
-  a: PNode;
-begin
-  result := newNodeP(nkIncludeStmt, p);
-  getTok(p); // skip `include`
-  optInd(p, result);
-  while true do begin
-    case p.tok.tokType of
-      tkEof, tkSad, tkDed: break;
-      tkSymbol, tkAccent:   a := parseSymbol(p);
-      tkRStrLit:  begin
-        a := newStrNodeP(nkRStrLit, p.tok.literal, p);
-        getTok(p)
-      end;
-      tkStrLit: begin
-        a := newStrNodeP(nkStrLit, p.tok.literal, p);
-        getTok(p);
-      end;
-      tkTripleStrLit: begin
-        a := newStrNodeP(nkTripleStrLit, p.tok.literal, p);
-        getTok(p)
-      end;
-      else begin
-        parMessage(p, errIdentifierExpected, tokToStr(p.tok));
-        break
-      end;
-    end;
-    addSon(result, a);
-    //optInd(p, a);
-    if p.tok.tokType <> tkComma then break;
-    getTok(p);
-    optInd(p, a)
-  end;
-end;
-
 function parseFromStmt(var p: TParser): PNode;
 var
   a: PNode;
@@ -1717,9 +1682,9 @@ begin
     tkBreak:    result := parseBreakOrContinue(p, nkBreakStmt);
     tkContinue: result := parseBreakOrContinue(p, nkContinueStmt);
     tkCurlyDotLe: result := parsePragma(p);
-    tkImport: result := parseImportStmt(p);
+    tkImport: result := parseImportOrIncludeStmt(p, nkImportStmt);
     tkFrom: result := parseFromStmt(p);
-    tkInclude: result := parseIncludeStmt(p);
+    tkInclude: result := parseImportOrIncludeStmt(p, nkIncludeStmt);
     tkComment: result := newCommentStmt(p);
     else begin
       if isExprStart(p) then 
diff --git a/nim/semgnrc.pas b/nim/semgnrc.pas
new file mode 100755
index 000000000..ee905d444
--- /dev/null
+++ b/nim/semgnrc.pas
@@ -0,0 +1,287 @@
+//
+//
+//           The Nimrod Compiler
+//        (c) Copyright 2009 Andreas Rumpf
+//
+//    See the file "copying.txt", included in this
+//    distribution, for details about the copyright.
+//
+
+
+// This implements the first pass over the generic body; it resolves some
+// symbols. Thus for generics there is a two-phase symbol lookup just like
+// in C++.
+// A problem is that it cannot be detected if the symbol is introduced
+// as in ``var x = ...`` or used because macros/templates can hide this!
+// So we have to eval templates/macros right here so that symbol
+// lookup can be accurate.
+
+type
+  TSemGenericFlag = (withinBind, withinTypeDesc);
+  TSemGenericFlags = set of TSemGenericFlag;
+
+function semGenericStmt(c: PContext; n: PNode; 
+                        flags: TSemGenericFlags = {@set}[]): PNode; forward;
+
+function semGenericStmtScope(c: PContext; n: PNode; 
+                             flags: TSemGenericFlags = {@set}[]): PNode;
+begin
+  openScope(c.tab);
+  result := semGenericStmt(c, n, flags);
+  closeScope(c.tab);
+end;
+
+function semGenericStmtSymbol(c: PContext; n: PNode; s: PSym): PNode;
+begin
+  case s.kind of
+    skUnknown: begin
+      // Introduced in this pass! Leave it as an identifier.
+      result := n;
+    end;
+    skProc, skMethod, skIterator, skConverter: result := symChoice(c, n, s);
+    skTemplate: result := semTemplateExpr(c, n, s, false);
+    skMacro: result := semMacroExpr(c, n, s, false);
+    skGenericParam: result := newSymNode(s);
+    skParam: result := n;
+    skType: begin
+      if (s.typ <> nil) and (s.typ.kind <> tyGenericParam) then
+        result := newSymNode(s)
+      else    
+        result := n
+    end
+    else result := newSymNode(s)
+  end
+end;
+
+function getIdentNode(n: PNode): PNode;
+begin
+  case n.kind of
+    nkPostfix: result := getIdentNode(n.sons[1]);
+    nkPragmaExpr, nkAccQuoted: result := getIdentNode(n.sons[0]);
+    nkIdent: result := n;
+    else begin
+      illFormedAst(n);
+      result := nil
+    end
+  end
+end;
+
+function semGenericStmt(c: PContext; n: PNode; 
+                        flags: TSemGenericFlags = {@set}[]): PNode;
+var
+  i, j, L: int;
+  a: PNode;
+  s: PSym;
+begin
+  result := n;
+  if n = nil then exit;
+  case n.kind of
+    nkIdent, nkAccQuoted: begin
+      s := lookUp(c, n);
+      if withinBind in flags then
+        result := symChoice(c, n, s)
+      else
+        result := semGenericStmtSymbol(c, n, s);
+    end;
+    nkDotExpr: begin
+      s := QualifiedLookUp(c, n, true);
+      if s <> nil then
+        result := semGenericStmtSymbol(c, n, s);
+    end;
+    nkSym..nkNilLit: begin end;
+    nkBind: result := semGenericStmt(c, n.sons[0], {@set}[withinBind]);
+    
+    nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit: begin
+      // check if it is an expression macro:
+      checkMinSonsLen(n, 1);
+      s := qualifiedLookup(c, n.sons[0], false);
+      if (s <> nil) then begin
+        case s.kind of
+          skMacro: begin result := semMacroExpr(c, n, s, false); exit end;
+          skTemplate: begin result := semTemplateExpr(c, n, s, false); exit end;
+          skUnknown, skParam: begin
+            // Leave it as an identifier.
+          end;
+          skProc, skMethod, skIterator, skConverter: begin
+            n.sons[0] := symChoice(c, n.sons[0], s);
+          end;
+          skGenericParam: n.sons[0] := newSymNode(s);
+          skType: begin
+            // bad hack for generics:
+            if (s.typ <> nil) and (s.typ.kind <> tyGenericParam) then begin
+              n.sons[0] := newSymNode(s);
+            end
+          end;
+          else n.sons[0] := newSymNode(s)
+        end
+      end;
+      for i := 1 to sonsLen(n)-1 do
+        n.sons[i] := semGenericStmt(c, n.sons[i], flags);
+    end;
+    nkMacroStmt: begin
+      result := semMacroStmt(c, n, false);
+    end;
+    nkIfStmt: begin
+      for i := 0 to sonsLen(n)-1 do
+        n.sons[i] := semGenericStmtScope(c, n.sons[i]);
+    end;
+    nkWhileStmt: begin
+      openScope(c.tab);
+      for i := 0 to sonsLen(n)-1 do
+        n.sons[i] := semGenericStmt(c, n.sons[i]);
+      closeScope(c.tab);
+    end;
+    nkCaseStmt: begin
+      openScope(c.tab);
+      n.sons[0] := semGenericStmt(c, n.sons[0]);
+      for i := 1 to sonsLen(n)-1 do begin
+        a := n.sons[i];
+        checkMinSonsLen(a, 1);
+        L := sonsLen(a);
+        for j := 0 to L-2 do
+          a.sons[j] := semGenericStmt(c, a.sons[j]);
+        a.sons[L-1] := semGenericStmtScope(c, a.sons[L-1]);
+      end;
+      closeScope(c.tab);
+    end;
+    nkForStmt: begin
+      L := sonsLen(n);
+      openScope(c.tab);
+      n.sons[L-2] := semGenericStmt(c, n.sons[L-2]);
+      for i := 0 to L-3 do
+        addDecl(c, newSymS(skUnknown, n.sons[i], c));
+      n.sons[L-1] := semGenericStmt(c, n.sons[L-1]);
+      closeScope(c.tab);
+    end;
+    nkBlockStmt, nkBlockExpr, nkBlockType: begin
+      checkSonsLen(n, 2);
+      openScope(c.tab);
+      if n.sons[0] <> nil then 
+        addDecl(c, newSymS(skUnknown, n.sons[0], c));
+      n.sons[1] := semGenericStmt(c, n.sons[1]);
+      closeScope(c.tab);
+    end;
+    nkTryStmt: begin
+      checkMinSonsLen(n, 2);
+      n.sons[0] := semGenericStmtScope(c, n.sons[0]);
+      for i := 1 to sonsLen(n)-1 do begin
+        a := n.sons[i];
+        checkMinSonsLen(a, 1);
+        L := sonsLen(a);
+        for j := 0 to L-2 do 
+          a.sons[j] := semGenericStmt(c, a.sons[j], {@set}[withinTypeDesc]);
+        a.sons[L-1] := semGenericStmtScope(c, a.sons[L-1]);
+      end;    
+    end;
+    nkVarSection: begin
+      for i := 0 to sonsLen(n)-1 do begin
+        a := n.sons[i];
+        if a.kind = nkCommentStmt then continue;
+        if (a.kind <> nkIdentDefs) and (a.kind <> nkVarTuple) then
+          IllFormedAst(a);
+        checkMinSonsLen(a, 3);
+        L := sonsLen(a);
+        a.sons[L-2] := semGenericStmt(c, a.sons[L-2], {@set}[withinTypeDesc]);
+        a.sons[L-1] := semGenericStmt(c, a.sons[L-1]);
+        for j := 0 to L-3 do
+          addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c));
+      end
+    end;
+    nkGenericParams: begin
+      for i := 0 to sonsLen(n)-1 do begin
+        a := n.sons[i];
+        if (a.kind <> nkIdentDefs) then IllFormedAst(a);
+        checkMinSonsLen(a, 3);
+        L := sonsLen(a);
+        a.sons[L-2] := semGenericStmt(c, a.sons[L-2], {@set}[withinTypeDesc]);
+        // do not perform symbol lookup for default expressions 
+        for j := 0 to L-3 do
+          addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c));
+      end
+    end;
+    nkConstSection: begin
+      for i := 0 to sonsLen(n)-1 do begin
+        a := n.sons[i];
+        if a.kind = nkCommentStmt then continue;
+        if (a.kind <> nkConstDef) then IllFormedAst(a);
+        checkSonsLen(a, 3);
+        addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[0]), c));
+        a.sons[1] := semGenericStmt(c, a.sons[1], {@set}[withinTypeDesc]);
+        a.sons[2] := semGenericStmt(c, a.sons[2]);
+      end
+    end;
+    nkTypeSection: begin
+      for i := 0 to sonsLen(n)-1 do begin
+        a := n.sons[i];
+        if a.kind = nkCommentStmt then continue;
+        if (a.kind <> nkTypeDef) then IllFormedAst(a);
+        checkSonsLen(a, 3);
+        addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[0]), c));
+      end;
+      for i := 0 to sonsLen(n)-1 do begin
+        a := n.sons[i];
+        if a.kind = nkCommentStmt then continue;
+        if (a.kind <> nkTypeDef) then IllFormedAst(a);
+        checkSonsLen(a, 3);
+        if a.sons[1] <> nil then begin
+          openScope(c.tab);
+          a.sons[1] := semGenericStmt(c, a.sons[1]);
+          a.sons[2] := semGenericStmt(c, a.sons[2], {@set}[withinTypeDesc]);
+          closeScope(c.tab);
+        end
+        else
+          a.sons[2] := semGenericStmt(c, a.sons[2], {@set}[withinTypeDesc]);
+      end
+    end;
+    nkEnumTy: begin
+      checkMinSonsLen(n, 1);
+      if n.sons[0] <> nil then
+        n.sons[0] := semGenericStmt(c, n.sons[0], {@set}[withinTypeDesc]);
+      for i := 1 to sonsLen(n)-1 do begin
+        case n.sons[i].kind of
+          nkEnumFieldDef: a := n.sons[i].sons[0];
+          nkIdent: a := n.sons[i];
+          else illFormedAst(n);
+        end;
+        addDeclAt(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c),
+                  c.tab.tos-1);
+      end
+    end;
+    nkObjectTy, nkTupleTy: begin end;
+    nkFormalParams: begin
+      checkMinSonsLen(n, 1);
+      if n.sons[0] <> nil then 
+        n.sons[0] := semGenericStmt(c, n.sons[0], {@set}[withinTypeDesc]);
+      for i := 1 to sonsLen(n)-1 do begin
+        a := n.sons[i];
+        if (a.kind <> nkIdentDefs) then IllFormedAst(a);
+        checkMinSonsLen(a, 3);
+        L := sonsLen(a);
+        a.sons[L-1] := semGenericStmt(c, a.sons[L-2], {@set}[withinTypeDesc]);
+        a.sons[L-1] := semGenericStmt(c, a.sons[L-1]);
+        for j := 0 to L-3 do begin
+          addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c));
+        end
+      end
+    end;
+    nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
+    nkIteratorDef, nkLambda: begin
+      checkSonsLen(n, codePos+1);
+      addDecl(c, newSymS(skUnknown, getIdentNode(n.sons[0]), c));
+      openScope(c.tab);
+      n.sons[genericParamsPos] := semGenericStmt(c, n.sons[genericParamsPos]);
+      if n.sons[paramsPos] <> nil then begin
+        if n.sons[paramsPos].sons[0] <> nil then
+          addDecl(c, newSym(skUnknown, getIdent('result'), nil));
+        n.sons[paramsPos] := semGenericStmt(c, n.sons[paramsPos]);
+      end;
+      n.sons[pragmasPos] := semGenericStmt(c, n.sons[pragmasPos]);
+      n.sons[codePos] := semGenericStmtScope(c, n.sons[codePos]);
+      closeScope(c.tab);
+    end
+    else begin
+      for i := 0 to sonsLen(n)-1 do
+        result.sons[i] := semGenericStmt(c, n.sons[i], flags);
+    end
+  end
+end;
diff --git a/nim/semtempl.pas b/nim/semtempl.pas
index e639960d3..fc7e12a73 100755
--- a/nim/semtempl.pas
+++ b/nim/semtempl.pas
@@ -147,7 +147,8 @@ begin
   end
 end;
 
-function resolveTemplateParams(c: PContext; n: PNode; withinBind: bool): PNode;
+function resolveTemplateParams(c: PContext; n: PNode; withinBind: bool;
+                               var toBind: TIntSet): PNode;
 var
   i: int;
   s: PSym;
@@ -155,7 +156,7 @@ begin
   if n = nil then begin result := nil; exit end;
   case n.kind of
     nkIdent: begin
-      if not withinBind then begin
+      if not withinBind and not IntSetContains(toBind, n.ident.id) then begin
         s := SymTabLocalGet(c.Tab, n.ident);
         if (s <> nil) then begin
           result := newSymNode(s);
@@ -165,17 +166,18 @@ begin
           result := n
       end
       else begin
+        IntSetIncl(toBind, n.ident.id);
         result := symChoice(c, n, lookup(c, n))
       end
     end;
     nkSym..nkNilLit: // atom
       result := n;
     nkBind: 
-      result := resolveTemplateParams(c, n.sons[0], true);
+      result := resolveTemplateParams(c, n.sons[0], true, toBind);
     else begin
       result := n;
       for i := 0 to sonsLen(n)-1 do
-        result.sons[i] := resolveTemplateParams(c, n.sons[i], withinBind);
+        result.sons[i] := resolveTemplateParams(c, n.sons[i], withinBind, toBind);
     end
   end
 end;
@@ -211,6 +213,7 @@ end;
 function semTemplateDef(c: PContext; n: PNode): PNode;
 var
   s: PSym;
+  toBind: TIntSet;
 begin
   if c.p.owner.kind = skModule then begin
     s := semIdentVis(c, skTemplate, n.sons[0], {@set}[sfStar]);
@@ -248,7 +251,8 @@ begin
   addParams(c, s.typ.n);
   
   // resolve parameters:
-  n.sons[codePos] := resolveTemplateParams(c, n.sons[codePos], false);
+  IntSetInit(toBind);
+  n.sons[codePos] := resolveTemplateParams(c, n.sons[codePos], false, toBind);
   if not (s.typ.sons[0].kind in [tyStmt, tyTypeDesc]) then
     n.sons[codePos] := transformToExpr(n.sons[codePos]);
 
diff --git a/nim/syntaxes.pas b/nim/syntaxes.pas
index 19035028e..158ab8ea2 100755
--- a/nim/syntaxes.pas
+++ b/nim/syntaxes.pas
@@ -15,7 +15,7 @@ interface
 
 uses
   nsystem, strutils, llstream, ast, astalgo, idents, scanner, options, msgs, 
-  pnimsyn, ptmplsyn, filters, rnimsyn;
+  pnimsyn, pbraces, ptmplsyn, filters, rnimsyn;
 
 type
   TFilterKind = (filtNone, filtTemplate, filtReplace, filtStrip);
@@ -68,8 +68,8 @@ function parseAll(var p: TParsers): PNode;
 begin
   case p.skin of
     skinStandard: result := pnimsyn.parseAll(p.parser);
-    skinBraces, skinEndX: InternalError('parser to implement');
-    // skinBraces: result := pbraces.parseAll(p.parser);
+    skinBraces: result := pbraces.parseAll(p.parser);
+    skinEndX: InternalError('parser to implement');
     // skinEndX: result := pendx.parseAll(p.parser);
   end
 end;
@@ -78,8 +78,8 @@ function parseTopLevelStmt(var p: TParsers): PNode;
 begin
   case p.skin of
     skinStandard: result := pnimsyn.parseTopLevelStmt(p.parser);
-    skinBraces, skinEndX: InternalError('parser to implement');
-    //skinBraces: result := pbraces.parseTopLevelStmt(p.parser);
+    skinBraces: result := pbraces.parseTopLevelStmt(p.parser); 
+    skinEndX: InternalError('parser to implement');
     //skinEndX: result := pendx.parseTopLevelStmt(p.parser);
   end
 end;
diff --git a/nim/vis.pas b/nim/vis.pas
new file mode 100755
index 000000000..b8ba0fc5b
--- /dev/null
+++ b/nim/vis.pas
@@ -0,0 +1,35 @@
+//
+//
+//           The Nimrod Compiler
+//        (c) Copyright 2009 Andreas Rumpf
+//
+//    See the file "copying.txt", included in this
+//    distribution, for details about the copyright.
+//
+unit vis;
+
+// Virtual instruction set for Nimrod. This is used for LLVM code generation.
+
+interface
+
+{$include 'config.inc'}
+
+uses
+  nsystem, ast, astalgo, strutils, nhashes, trees, platform, magicsys,
+  extccomp, options, nversion, nimsets, msgs, crc, bitsets, idents,
+  lists, types, ccgutils, nos, ntime, ropes, nmath, passes, rodread,
+  wordrecg, rnimsyn, treetab;
+  
+type
+  TInstrKind = (
+    insAddi,
+  
+  );
+  TInstruction = record
+    
+  end;
+  
+
+implementation
+
+end.
diff --git a/tools/nimweb.nim b/tools/nimweb.nim
index 249ec5f61..05b575d16 100755
--- a/tools/nimweb.nim
+++ b/tools/nimweb.nim
@@ -178,7 +178,7 @@ proc buildPdfDoc(c: var TConfigData, destPath: string) =
       Exec("pdflatex " & changeFileExt(d, "tex"))
       Exec("pdflatex " & changeFileExt(d, "tex"))
       # delete all the crappy temporary files:
-      var pdf = extractFileTrunk(d) & ".pdf"
+      var pdf = splitFile(d).name & ".pdf"
       moveFile(destPath / pdf, pdf)
       removeFile(changeFileExt(pdf, "aux"))
       if existsFile(changeFileExt(pdf, "toc")):
diff --git a/web/question.txt b/web/question.txt
index 83edfda72..17a1abfcf 100755
--- a/web/question.txt
+++ b/web/question.txt
@@ -17,6 +17,14 @@ feature that Nimrod inherited from Lisp is that Nimrod's abstract syntax tree
 can be used to create domain specific languages. Nimrod does not sacrifice
 flexibility for speed. You get both.
 
+..
+  Don't give me that marketing crap. What is Nimrod?
+  --------------------------------------------------
+
+  Nimrod = Mutable value based datatypes + static binding + sugar to make 
+    this programming modell as convenient as possible
+
+
 How is Nimrod licensed?
 -----------------------