diff --git a/boot.nim b/boot.nim
index b7f3f4ed9..dbcf84399 100755
--- a/boot.nim
+++ b/boot.nim
@@ -23,7 +23,7 @@ char* nimCPU(void) { return "$2"; }
proc exec(cmd: string) =
echo(cmd)
- if executeShellCommand(cmd) != 0: quit("FAILURE")
+ if execShellCmd(cmd) != 0: quit("FAILURE")
proc writePlatdefC =
var f: TFile
@@ -38,19 +38,19 @@ proc rodsrc =
blacklist = ["nsystem", "nmath", "nos", "osproc", "ntime", "strutils"]
cmd = "nimrod boot --skip_proj_cfg -o:rod/$1.nim nim/$1"
for fi in walkFiles("nim/*.pas"):
- var f = extractFileTrunk(fi)
+ var f = splitFile(fi).name
if find(blacklist, f) >= 0: continue
- var r = "rod" / appendFileExt(f, "nim")
+ var r = "rod" / addFileExt(f, "nim")
if not existsFile(r) or fileNewer(fi, r):
Exec(cmd % f)
proc boot(args: string) =
writePlatdefC()
rodsrc()
- var newExe = appendFileExt("rod/nimrod", ExeExt)
- var oldExe = appendFileExt("bin/nimrod", ExeExt)
+ var newExe = addFileExt("rod/nimrod", ExeExt)
+ var oldExe = addFileExt("bin/nimrod", ExeExt)
for i in 0..1:
- Echo("iteration: ", $(i+1))
+ Echo("iteration: ", i+1)
# use the new executable to compile the files in the bootstrap directory:
Exec(Bootcmd[i] % args)
if sameFileContent(newExe, oldExe):
diff --git a/config/nimrod.cfg b/config/nimrod.cfg
index 6f6f89bc8..c1ad11380 100755
--- a/config/nimrod.cfg
+++ b/config/nimrod.cfg
@@ -43,18 +43,20 @@ path="$lib/ecmas"
# additional options always passed to the compiler:
--verbosity: "1"
+--parallel_build: "0" # 0 to auto-detect number of processors
hint[LineTooLong]=off
#hint[XDeclaredButNotUsed]=off
@if unix:
- @if not bsd: passl= "-ldl" @end
+ @if not bsd:
+ gcc.options.linker = "-ldl"
+ @end
@end
-@if icc:
- passl = "-cxxlib"
- passc = "-cxxlib"
-@end
+# Configuration for the Intel C/C++ compiler:
+icc.options.always = "-cxxlib"
+icc.options.linker = "-cxxlib"
# Configuration for the GNU C/C++ compiler:
@if windows:
@@ -77,9 +79,7 @@ llvm_gcc.options.speed = "-O2"
llvm_gcc.options.size = "-Os"
# Configuration for the Visual C/C++ compiler:
-@if vcc:
- passl: r"/F33554432" # set the stack size to 8 MB
-@end
+vcc.options.linker = r"/F33554432" # set the stack size to 8 MB
vcc.options.debug = "/RTC1 /ZI"
vcc.options.always = "/nologo"
vcc.options.speed = "/Ox /arch:SSE2"
diff --git a/data/advopt.txt b/data/advopt.txt
index 72e8ffb7c..975c09af8 100755
--- a/data/advopt.txt
+++ b/data/advopt.txt
@@ -28,9 +28,11 @@ Advanced options:
--checkpoints:on|off turn on|off checkpoints; for debugging Nimrod
--skip_cfg do not read the general configuration file
--skip_proj_cfg do not read the project's configuration file
- --gc:refc|boehm use Nimrod's native GC|Boehm GC
+ --gc:refc|boehm|none use Nimrod's native GC|Boehm GC|no GC
--index:FILE use FILE to generate a documenation index file
--putenv:key=value set an environment variable
--list_cmd list the commands used to execute external programs
+ --parallel_build=0|1|... perform a parallel build
+ value = number of processors (0 for auto-detect)
--verbosity:0|1|2|3 set Nimrod's verbosity level (0 is default)
-v, --version show detailed version information
diff --git a/data/ast.yml b/data/ast.yml
index 805b5dc68..f27b09a18 100755
--- a/data/ast.yml
+++ b/data/ast.yml
@@ -8,7 +8,7 @@
#
{
-'SymFlag': [ # already 29 flags!
+'SymFlag': [ # already 30 flags!
'sfUsed', # read access of sym (for warnings) or simply used
'sfStar', # symbol has * visibility
'sfMinus', # symbol has - visibility
@@ -34,7 +34,7 @@
'sfAddrTaken', # the variable's address is taken (ex- or implicitely)
'sfCompilerProc', # proc is a compiler proc, that is a C proc that is
# needed for the code generator
- 'sfCppMethod', # proc is a C++ method (not implemented yet)
+ 'sfProcvar', # proc can be passed to a proc var
'sfDiscriminant', # field is a discriminant in a record/object
'sfDeprecated', # symbol is deprecated
'sfInClosure', # variable is accessed by a closure
@@ -152,7 +152,6 @@
'nkAccQuoted', # `a` as a node
'nkTableConstr', # a table constructor {expr: expr}
- 'nkQualified', # describes a.b for qualified identifiers
'nkBind', # ``bind expr`` node
'nkSymChoice', # symbol choice node
'nkHiddenStdConv', # an implicit standard type conversion
diff --git a/data/basicopt.txt b/data/basicopt.txt
index c716f7641..af3f541ad 100755
--- a/data/basicopt.txt
+++ b/data/basicopt.txt
@@ -27,7 +27,7 @@ Options:
-a, --assertions:on|off code generation for assertions ON|OFF
--dead_code_elim:on|off whole program dead code elimination ON|OFF
--opt:none|speed|size optimize not at all or for speed|size
- --app:console|gui generate a console|GUI application
+ --app:console|gui|lib generate a console|GUI application|dynamic library
-r, --run run the compiled program with given arguments
--advanced show advanced command line switches
-h, --help show this help
diff --git a/data/messages.yml b/data/messages.yml
index 44e05dca9..ac41b5031 100755
--- a/data/messages.yml
+++ b/data/messages.yml
@@ -92,7 +92,7 @@
{'errCannotEvalXBecauseIncompletelyDefined':
"cannot evalutate '$1' because type is not defined completely"},
{'errChrExpectsRange0_255': "'chr' expects an int in the range 0..255"},
-{'errDotRequiresRecordOrObjectType': "'.' requires a record or object type"},
+{'errDynlibRequiresExportc': "'dynlib' requires 'exportc'"},
{'errUndeclaredFieldX': "undeclared field: '$1'"},
{'errNilAccess': 'attempt to access a nil address'},
{'errIndexOutOfBounds': 'index out of bounds'},
@@ -152,7 +152,7 @@
{'errButExpectedX': "but expected '$1'"},
{'errAmbiguousCallXYZ': 'ambiguous call; both $1 and $2 match for: $3'},
{'errWrongNumberOfArguments': 'wrong number of arguments'},
-{'errInlineProcHasNoAddress': 'an inline proc has no address'},
+{'errXCannotBePassedToProcVar': "'$1' cannot be passed to a procvar"},
{'errXCannotBeInParamDecl': '$1 cannot be declared in parameter declaration'},
{'errPragmaOnlyInHeaderOfProc':
'pragmas are only in the header of a proc allowed'},
@@ -186,7 +186,6 @@
{'errATypeHasNoValue': 'a type has no value'},
{'errXisNoType': "invalid type: '$1'"},
{'errCircumNeedsPointer': "'^' needs a pointer or reference type"},
-{'errInvalidContextForBuiltinX': "invalid context for builtin '$1'"},
{'errInvalidExpression': 'invalid expression'},
{'errInvalidExpressionX': "invalid expression: '$1'"},
{'errEnumHasNoValueX': "enum has no value '$1'"},
@@ -250,6 +249,8 @@
{'warnUnknownSubstitutionX': "unknown substitution '$1'"},
{'warnLanguageXNotSupported': "language '$1' not supported"},
{'warnCommentXIgnored': "comment '$1' ignored"},
+{'warnXisPassedToProcVar': "'$1' is passed to a procvar; deprecated"},
+
# user warning message:
{'warnUser': '$1'},
diff --git a/doc/apis.txt b/doc/apis.txt
old mode 100644
new mode 100755
index 02caa8c24..b926e4988
--- a/doc/apis.txt
+++ b/doc/apis.txt
@@ -66,4 +66,7 @@ function func
coordinate coord
rectangle rect
point point
+symbol sym
+identifier ident
+indentation indent
------------------- ------------ --------------------------------------
diff --git a/doc/effects.txt b/doc/effects.txt
new file mode 100755
index 000000000..85de1ffdf
--- /dev/null
+++ b/doc/effects.txt
@@ -0,0 +1,41 @@
+=====================================================================
+ Side effects in Nimrod
+=====================================================================
+
+Note: Side effects are implicit produced values! Maybe they should be
+explicit like in Haskell?
+
+
+The idea is that side effects and partial evaluation belong together:
+Iff a proc is side effect free and all its argument are evaluable at
+compile time, it can be evaluated by the compiler. However, really
+difficult is the ``newString`` proc: If it is simply wrapped, it
+should not be evaluated at compile time! On other occasions it can
+and should be evaluted:
+
+.. code-block:: nimrod
+ proc toUpper(s: string): string =
+ result = newString(len(s))
+ for i in 0..len(s) - 1:
+ result[i] = toUpper(s[i])
+
+No, it really can always be evaluated. The code generator should transform
+``s = "\0\0\0..."`` back into ``s = newString(...)``.
+
+
+``new`` cannot be evaluated at compile time either.
+
+
+Raise statement
+===============
+
+It is impractical to consider ``raise`` a statement with side effects.
+
+
+Solution
+========
+
+Being side effect free does not suffice for compile time evaluation. However,
+the evaluator can attempt to evaluate at compile time.
+
+
diff --git a/doc/filelist.txt b/doc/filelist.txt
index 0e636652a..c29b3b6aa 100755
--- a/doc/filelist.txt
+++ b/doc/filelist.txt
@@ -8,7 +8,8 @@ nimrod main module: parses the command line and calls
``main.MainCommand``
main implements the top-level command dispatching
nimconf implements the config file reader
-
+syntaxes dispatcher for the different parsers and filters
+ptmplsyn standard template filter (``#! stdtempl``)
lexbase buffer handling of the lexical analyser
scanner lexical analyser
pnimsyn Nimrod's parser
diff --git a/doc/filters.txt b/doc/filters.txt
new file mode 100755
index 000000000..ffeb6808a
--- /dev/null
+++ b/doc/filters.txt
@@ -0,0 +1,232 @@
+===================
+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
+`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:
+
+.. code-block:: nimrod
+ #! braces
+ if (x == 10) {
+ echo "x is ten"
+ } else {
+ echo "x isn't ten"
+ }
+
+The special ``#!`` comment for specifying a parser needs to be in the first
+line with no leading whitespace, unless an UNIX shebang line is used. Then the
+parser shebang can occur in the second line:
+
+.. code-block:: nimrod
+ #! /usr/bin/env nimrod c -r
+ #! braces
+ if (x == 10) {
+ echo "x is ten"
+ } else {
+ echo "x isn't ten"
+ }
+
+An UNIX shebang line is defined by the pattern ``'#!' \s* '/' .*``
+(``#!`` followed by optional whitespace followed by ``/``).
+
+
+Filters
+=======
+
+Nimrod's shebang also supports the invokation of `source filters`:idx: before
+the source code file is passed to the parser::
+
+ #! stdtmpl(subsChar = '$', metaChar = '#')
+ #proc generateXML(name, age: string): string =
+ # result = ""
+
+ $name
+ $age
+
+
+Filters transform the input character stream to an in-memory output stream.
+They are used to provide templating systems or preprocessors.
+
+As the example shows, passing arguments to a filter (or parser) can be done
+just like an ordinary procedure call with named or positional arguments. The
+available parameters depend on the invoked filter/parser.
+
+
+Pipe operator
+-------------
+
+Filters and parsers can be combined with the ``|`` `pipe operator`:idx:. Only
+the last operand can be a parser because a parser returns an abstract syntax
+tree which a filter cannot process::
+
+ #! strip(startswith="<") | stdtmpl | standard
+ #proc generateXML(name, age: string): string =
+ # result = ""
+
+ $name
+ $age
+
+
+
+Available filters
+=================
+
+**Hint:** With ``--verbosity:2`` (or higher) Nimrod lists the processed code
+after each filter application.
+
+Replace filter
+--------------
+
+The `replace`:idx: filter replaces substrings in each line.
+
+Parameters and their defaults:
+
+ ``sub: string = ""``
+ the substring that is searched for
+
+ ``by: string = ""``
+ the string the substring is replaced with
+
+
+Strip filter
+------------
+
+The `strip`:idx: filter simply removes leading and trailing whitespace from
+each line.
+
+Parameters and their defaults:
+
+ ``startswith: string = ""``
+ strip only the lines that start with *startswith* (ignoring leading
+ whitespace). If empty every line is stripped.
+
+ ``leading: bool = true``
+ strip leading whitespace
+
+ ``trailing: bool = true``
+ strip trailing whitespace
+
+
+StdTmpl filter
+--------------
+
+The `stdtmpl`:idx: filter provides a simple templating engine for Nimrod. The
+filter uses a line based parser: Lines prefixed with a *meta character*
+(default: ``#``) contain Nimrod code, other lines are verbatim. Because
+indentation-based parsing is not suited for a templating engine, control flow
+statements need ``end X`` delimiters.
+
+Parameters and their defaults:
+
+ ``metaChar: char = '#'``
+ prefix for a line that contains Nimrod code
+
+ ``subsChar: char = '$'``
+ prefix for a Nimrod expression within a template line
+
+ ``conc: string = " & "``
+ the operation for concatenation
+
+ ``emit: string = "result.add"``
+ the operation to emit a string literal
+
+ ``toString: string = "$"``
+ the operation that is applied to each expression
+
+Example::
+
+ #! stdtmpl | standard
+ #proc generateHTMLPage(title, currentTab, content: string,
+ # tabs: openArray[string]): string =
+ # result = ""
+
$title
+
+
+
+ $content
+ A dollar: $$.
+
+
+
+The filter transforms this into:
+
+.. code-block:: nimrod
+ proc generateHTMLPage(title, currentTab, content: string,
+ tabs: openArray[string]): string =
+ result = ""
+ result.add("" & $(title) & "\n" &
+ "\n" &
+ " \n" &
+ " \n" &
+ " " & $(content) & "\n" &
+ " A dollar: $.\n" &
+ "
\n" &
+ "\n")
+
+
+Each line that does not start with the meta character (ignoring leading
+whitespace) is converted to a string literal that is added to ``result``.
+
+The substitution character introduces a Nimrod expression *e* within the
+string literal. *e* is converted to a string with the *toString* operation
+which defaults to ``$``. For strong type checking, set ``toString`` to the
+empty string. *e* must match this PEG pattern::
+
+ e <- [a-zA-Z\128-\255][a-zA-Z0-9\128-\255_.]* / '{' x '}'
+ x <- '{' x+ '}' / [^}]*
+
+To produce a single substitution character it has to be doubled: ``$$``
+produces ``$``.
+
+The template engine is quite flexible. It is easy to produce a procedure that
+writes the template code directly to a file::
+
+ #! stdtmpl(emit="f.write") | standard
+ #proc writeHTMLPage(f: TFile, title, currentTab, content: string,
+ # tabs: openArray[string]) =
+ $title
+
+
+
+ $content
+ A dollar: $$.
+
+
diff --git a/doc/gramcurl.txt b/doc/gramcurl.txt
new file mode 100755
index 000000000..3ac9294c8
--- /dev/null
+++ b/doc/gramcurl.txt
@@ -0,0 +1,179 @@
+module ::= stmt*
+
+comma ::= ',' [COMMENT] [IND]
+operator ::= OP0 | OR | XOR | AND | OP3 | OP4 | OP5 | OP6 | OP7
+ | 'is' | 'isnot' | 'in' | 'notin'
+ | 'div' | 'mod' | 'shl' | 'shr' | 'not'
+
+prefixOperator ::= OP0 | OP3 | OP4 | OP5 | OP6 | OP7 | 'not'
+
+optInd ::= [COMMENT] [IND]
+
+
+lowestExpr ::= orExpr (OP0 optInd orExpr)*
+orExpr ::= andExpr (OR | 'xor' optInd andExpr)*
+andExpr ::= cmpExpr ('and' optInd cmpExpr)*
+cmpExpr ::= ampExpr (OP3 | 'is' | 'isnot' | 'in' | 'notin' optInd ampExpr)*
+ampExpr ::= plusExpr (OP4 optInd plusExpr)*
+plusExpr ::= mulExpr (OP5 optInd mulExpr)*
+mulExpr ::= dollarExpr (OP6 | 'div' | 'mod' | 'shl' | 'shr' optInd dollarExpr)*
+dollarExpr ::= primary (OP7 optInd primary)*
+
+indexExpr ::= '..' [expr] | expr ['=' expr | '..' expr]
+
+castExpr ::= 'cast' '[' optInd typeDesc [SAD] ']' '(' optInd expr [SAD] ')'
+addrExpr ::= 'addr' '(' optInd expr ')'
+symbol ::= '`' (KEYWORD | IDENT | operator | '(' ')'
+ | '[' ']' | '=' | literal)+ '`'
+ | IDENT
+
+primaryPrefix ::= (prefixOperator | 'bind') optInd
+primarySuffix ::= '.' optInd symbol
+ | '(' optInd namedExprList [SAD] ')'
+ | '[' optInd [indexExpr (comma indexExpr)* [comma]] [SAD] ']'
+ | '^'
+ | pragma
+
+primary ::= primaryPrefix* (symbol | constructor | castExpr | addrExpr)
+ primarySuffix*
+
+literal ::= INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
+ | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
+ | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
+ | CHAR_LIT
+ | NIL
+
+constructor ::= literal
+ | '[' optInd colonExprList [SAD] ']'
+ | '{' optInd sliceExprList [SAD] '}'
+ | '(' optInd colonExprList [SAD] ')'
+
+colonExpr ::= expr [':' expr]
+colonExprList ::= [colonExpr (comma colonExpr)* [comma]]
+
+namedExpr ::= expr ['=' expr]
+namedExprList ::= [namedExpr (comma namedExpr)* [comma]]
+
+sliceExpr ::= expr ['..' expr]
+sliceExprList ::= [sliceExpr (comma sliceExpr)* [comma]]
+
+exprOrType ::= lowestExpr
+ | 'if' '(' expr ')' expr ('elif' '(' expr ')' expr)* 'else' expr
+ | 'var' exprOrType
+ | 'ref' exprOrType
+ | 'ptr' exprOrType
+ | 'type' exprOrType
+ | 'tuple' tupleDesc
+
+expr ::= exprOrType
+ | 'proc' paramList [pragma] ['=' stmt]
+
+qualifiedIdent ::= symbol ['.' symbol]
+
+typeDesc ::= exprOrType
+ | 'proc' paramList [pragma]
+
+macroStmt ::= '{' [stmt] '}' ('of' [sliceExprList] stmt
+ |'elif' '(' expr ')' stmt
+ |'except' '(' exceptList ')' stmt )*
+ ['else' stmt]
+
+simpleStmt ::= returnStmt
+ | yieldStmt
+ | discardStmt
+ | raiseStmt
+ | breakStmt
+ | continueStmt
+ | pragma
+ | importStmt
+ | fromStmt
+ | includeStmt
+ | exprStmt
+complexStmt ::= ifStmt | whileStmt | caseStmt | tryStmt | forStmt
+ | blockStmt | asmStmt
+ | procDecl | iteratorDecl | macroDecl | templateDecl | methodDecl
+ | constSection | typeSection | whenStmt | varSection
+
+stmt ::= simpleStmt
+ | indPush (complexStmt | simpleStmt) (';' (complexStmt | simpleStmt))*
+ DED indPop
+
+exprStmt ::= lowestExpr ['=' expr | [expr (comma expr)*] [macroStmt]]
+returnStmt ::= 'return' [expr]
+yieldStmt ::= 'yield' expr
+discardStmt ::= 'discard' expr
+raiseStmt ::= 'raise' [expr]
+breakStmt ::= 'break' [symbol]
+continueStmt ::= 'continue'
+ifStmt ::= 'if' '(' expr ')' stmt ('elif' '(' expr ')' stmt)* ['else' stmt]
+whenStmt ::= 'when' '(' expr ')' stmt ('elif' '(' expr ')' stmt)* ['else' stmt]
+caseStmt ::= 'case' '(' expr ')' ('of' sliceExprList ':' stmt)*
+ ('elif' '(' expr ')' stmt)*
+ ['else' stmt]
+whileStmt ::= 'while' '(' expr ')' stmt
+forStmt ::= 'for' '(' symbol (comma symbol)* 'in' expr ['..' expr] ')' stmt
+exceptList ::= [qualifiedIdent (comma qualifiedIdent)*]
+
+tryStmt ::= 'try' stmt
+ ('except' '(' exceptList ')' stmt)*
+ ['finally' stmt]
+asmStmt ::= 'asm' [pragma] (STR_LIT | RSTR_LIT | TRIPLESTR_LIT)
+blockStmt ::= 'block' [symbol] stmt
+filename ::= symbol | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
+importStmt ::= 'import' filename (comma filename)*
+includeStmt ::= 'include' filename (comma filename)*
+fromStmt ::= 'from' filename 'import' symbol (comma symbol)*
+
+pragma ::= '{.' optInd (colonExpr [comma])* [SAD] ('.}' | '}')
+
+param ::= symbol (comma symbol)* (':' typeDesc ['=' expr] | '=' expr)
+paramList ::= ['(' [param (comma param)*] [SAD] ')'] [':' typeDesc]
+
+genericParam ::= symbol [':' typeDesc] ['=' expr]
+genericParams ::= '[' genericParam (comma genericParam)* [SAD] ']'
+
+
+routineDecl := symbol ['*'] [genericParams] paramList [pragma] ['=' stmt]
+procDecl ::= 'proc' routineDecl
+macroDecl ::= 'macro' routineDecl
+iteratorDecl ::= 'iterator' routineDecl
+templateDecl ::= 'template' routineDecl
+methodDecl ::= 'method' routineDecl
+
+colonAndEquals ::= [':' typeDesc] '=' expr
+
+constDecl ::= symbol ['*'] [pragma] colonAndEquals ';' [COMMENT]
+constSection ::= 'const' [COMMENT] (constDecl | '{' constDecl+ '}')
+
+typeDef ::= typeDesc | objectDef | enumDef | 'distinct' typeDesc
+
+objectField ::= symbol ['*'] [pragma]
+objectIdentPart ::= objectField (comma objectField)* ':' typeDesc
+ [COMMENT|IND COMMENT]
+
+objectWhen ::= 'when' expr ':' [COMMENT] objectPart
+ ('elif' expr ':' [COMMENT] objectPart)*
+ ['else' ':' [COMMENT] objectPart]
+objectCase ::= 'case' expr ':' typeDesc [COMMENT]
+ ('of' sliceExprList ':' [COMMENT] objectPart)*
+ ['else' ':' [COMMENT] objectPart]
+
+objectPart ::= objectWhen | objectCase | objectIdentPart | 'nil'
+ | indPush objectPart (SAD objectPart)* DED indPop
+tupleDesc ::= '[' optInd [param (comma param)*] [SAD] ']'
+
+objectDef ::= 'object' [pragma] ['of' typeDesc] objectPart
+enumField ::= symbol ['=' expr]
+enumDef ::= 'enum' ['of' typeDesc] (enumField [comma] [COMMENT | IND COMMENT])+
+
+typeDecl ::= COMMENT
+ | symbol ['*'] [genericParams] ['=' typeDef] [COMMENT | IND COMMENT]
+
+typeSection ::= 'type' indPush typeDecl (SAD typeDecl)* DED indPop
+
+colonOrEquals ::= ':' typeDesc ['=' expr] | '=' expr
+varField ::= symbol ['*'] [pragma]
+varPart ::= symbol (comma symbol)* colonOrEquals [COMMENT | IND COMMENT]
+varSection ::= 'var' (varPart
+ | indPush (COMMENT|varPart)
+ (SAD (COMMENT|varPart))* DED indPop)
diff --git a/doc/grammar.txt b/doc/grammar.txt
index 2fcb68236..18722116e 100755
--- a/doc/grammar.txt
+++ b/doc/grammar.txt
@@ -19,25 +19,23 @@ plusExpr ::= mulExpr (OP5 optInd mulExpr)*
mulExpr ::= dollarExpr (OP6 | 'div' | 'mod' | 'shl' | 'shr' optInd dollarExpr)*
dollarExpr ::= primary (OP7 optInd primary)*
-namedTypeOrExpr ::=
- '..' [expr]
- | expr ['=' (expr ['..' expr] | typeDescK | '..' [expr]) | '..' [expr]]
- | typeDescK
+indexExpr ::= '..' [expr] | expr ['=' expr | '..' expr]
castExpr ::= 'cast' '[' optInd typeDesc [SAD] ']' '(' optInd expr [SAD] ')'
addrExpr ::= 'addr' '(' optInd expr ')'
symbol ::= '`' (KEYWORD | IDENT | operator | '(' ')'
| '[' ']' | '=' | literal)+ '`'
| IDENT
-primary ::= ((prefixOperator | 'bind') optInd)* (symbol | constructor |
- castExpr | addrExpr) (
- '.' optInd symbol
- | '(' optInd namedExprList [SAD] ')'
- | '[' optInd
- [namedTypeOrExpr (comma namedTypeOrExpr)* [comma]]
- [SAD] ']'
- | '^'
- | pragma)*
+
+primaryPrefix ::= (prefixOperator | 'bind') optInd
+primarySuffix ::= '.' optInd symbol
+ | '(' optInd namedExprList [SAD] ')'
+ | '[' optInd [indexExpr (comma indexExpr)* [comma]] [SAD] ']'
+ | '^'
+ | pragma
+
+primary ::= primaryPrefix* (symbol | constructor | castExpr | addrExpr)
+ primarySuffix*
literal ::= INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
| FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
@@ -59,24 +57,21 @@ namedExprList ::= [namedExpr (comma namedExpr)* [comma]]
sliceExpr ::= expr ['..' expr]
sliceExprList ::= [sliceExpr (comma sliceExpr)* [comma]]
-anonymousProc ::= 'lambda' paramList [pragma] '=' stmt
-expr ::= lowestExpr
- | anonymousProc
- | 'if' expr ':' expr ('elif' expr ':' expr)* 'else' ':' expr
+exprOrType ::= lowestExpr
+ | 'if' expr ':' expr ('elif' expr ':' expr)* 'else' ':' expr
+ | 'var' exprOrType
+ | 'ref' exprOrType
+ | 'ptr' exprOrType
+ | 'type' exprOrType
+ | 'tuple' tupleDesc
-namedTypeDesc ::= typeDescK | expr ['=' (typeDescK | expr)]
-namedTypeDescList ::= [namedTypeDesc (comma namedTypeDesc)* [comma]]
+expr ::= exprOrType
+ | 'proc' paramList [pragma] ['=' stmt]
qualifiedIdent ::= symbol ['.' symbol]
-typeDescK ::= 'var' typeDesc
- | 'ref' typeDesc
- | 'ptr' typeDesc
- | 'type' expr
- | 'tuple' tupleDesc
- | 'proc' paramList [pragma]
-
-typeDesc ::= typeDescK | primary
+typeDesc ::= exprOrType
+ | 'proc' paramList [pragma]
macroStmt ::= ':' [stmt] ('of' [sliceExprList] ':' stmt
|'elif' expr ':' stmt
@@ -84,20 +79,20 @@ macroStmt ::= ':' [stmt] ('of' [sliceExprList] ':' stmt
['else' ':' stmt]
simpleStmt ::= returnStmt
- | yieldStmt
- | discardStmt
- | raiseStmt
- | breakStmt
- | continueStmt
- | pragma
- | importStmt
- | fromStmt
- | includeStmt
- | exprStmt
+ | yieldStmt
+ | discardStmt
+ | raiseStmt
+ | breakStmt
+ | continueStmt
+ | pragma
+ | importStmt
+ | fromStmt
+ | includeStmt
+ | exprStmt
complexStmt ::= ifStmt | whileStmt | caseStmt | tryStmt | forStmt
- | blockStmt | asmStmt
- | procDecl | iteratorDecl | macroDecl | templateDecl
- | constSection | typeSection | whenStmt | varSection
+ | blockStmt | asmStmt
+ | procDecl | iteratorDecl | macroDecl | templateDecl | methodDecl
+ | constSection | typeSection | whenStmt | varSection
indPush ::= IND # and push indentation onto the stack
indPop ::= # pop indentation from the stack
@@ -141,25 +136,24 @@ paramList ::= ['(' [param (comma param)*] [SAD] ')'] [':' typeDesc]
genericParam ::= symbol [':' typeDesc] ['=' expr]
genericParams ::= '[' genericParam (comma genericParam)* [SAD] ']'
-procDecl ::= 'proc' symbol ['*'] [genericParams] paramList [pragma]
- ['=' stmt]
-macroDecl ::= 'macro' symbol ['*'] [genericParams] paramList [pragma]
- ['=' stmt]
-iteratorDecl ::= 'iterator' symbol ['*'] [genericParams] paramList [pragma]
- ['=' stmt]
-templateDecl ::= 'template' symbol ['*'] [genericParams] paramList [pragma]
- ['=' stmt]
+
+routineDecl := symbol ['*'] [genericParams] paramList [pragma] ['=' stmt]
+procDecl ::= 'proc' routineDecl
+macroDecl ::= 'macro' routineDecl
+iteratorDecl ::= 'iterator' routineDecl
+templateDecl ::= 'template' routineDecl
+methodDecl ::= 'method' routineDecl
colonAndEquals ::= [':' typeDesc] '=' expr
constDecl ::= symbol ['*'] [pragma] colonAndEquals [COMMENT | IND COMMENT]
| COMMENT
constSection ::= 'const' indPush constDecl (SAD constDecl)* DED indPop
-typeDef ::= typeDesc | objectDef | enumDef | 'abstract' typeDesc
+typeDef ::= typeDesc | objectDef | enumDef | 'distinct' typeDesc
objectField ::= symbol ['*'] [pragma]
-objectIdentPart ::=
- objectField (comma objectField)* ':' typeDesc [COMMENT|IND COMMENT]
+objectIdentPart ::= objectField (comma objectField)* ':' typeDesc
+ [COMMENT|IND COMMENT]
objectWhen ::= 'when' expr ':' [COMMENT] objectPart
('elif' expr ':' [COMMENT] objectPart)*
diff --git a/doc/lib.txt b/doc/lib.txt
index c15303b99..b75dd446b 100755
--- a/doc/lib.txt
+++ b/doc/lib.txt
@@ -66,8 +66,7 @@ Generic Operating System Services
* `os `_
Basic operating system facilities like retrieving environment variables,
reading command line arguments, working with directories, running shell
- commands, etc. This module is -- like any other basic library --
- platform independant.
+ commands, etc.
* `osproc `_
Module for process communication beyond ``os.execShellCmd``.
diff --git a/doc/manual.txt b/doc/manual.txt
index 3c24e4b1a..9cf1f3bc2 100755
--- a/doc/manual.txt
+++ b/doc/manual.txt
@@ -342,7 +342,7 @@ Syntax
======
This section lists Nimrod's standard syntax in ENBF. How the parser receives
-indentation tokens is already described in the Lexical Analysis section.
+indentation tokens is already described in the `Lexical Analysis`_ section.
Nimrod allows user-definable operators.
Binary operators have 8 different levels of precedence. For user-defined
@@ -363,8 +363,7 @@ Precedence level Operators First characte
================ ============================================== ================== ===============
-The grammar's start symbol is ``module``. The grammar is LL(1) and therefore
-not ambiguous.
+The grammar's start symbol is ``module``.
.. include:: grammar.txt
:literal:
@@ -875,8 +874,7 @@ Procedural type
~~~~~~~~~~~~~~~
A `procedural type`:idx: is internally a pointer to a procedure. ``nil`` is
an allowed value for variables of a procedural type. Nimrod uses procedural
-types to achieve `functional`:idx: programming techniques. Dynamic dispatch
-for OOP constructs can also be implemented with procedural types.
+types to achieve `functional`:idx: programming techniques.
Example:
@@ -946,6 +944,16 @@ each other:
Most calling conventions exist only for the Windows 32-bit platform.
+Assigning/passing a procedure to a procedural variable is only allowed if one
+of the following conditions hold:
+1) The procedure that is accessed resists in the current module.
+2) The procedure is marked with the ``procvar`` pragma (see `procvar pragma`_).
+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``
+procedure with default parameters breaks client code.
+
Distinct type
~~~~~~~~~~~~~
@@ -1054,7 +1062,7 @@ describe the type checking done by the compiler.
Type equality
~~~~~~~~~~~~~
Nimrod uses structural type equivalence for most types. Only for objects,
-enumerations and abstract types name equivalence is used. The following
+enumerations and distinct types name equivalence is used. The following
algorithm determines type equality:
.. code-block:: nimrod
@@ -1800,6 +1808,77 @@ Even more elegant is to use `tuple unpacking`:idx: to access the tuple's fields:
assert y == 3
+Multi-methods
+~~~~~~~~~~~~~
+
+Procedures always use static dispatch. Dynamic dispatch is achieved by
+`multi-methods`:idx:.
+
+.. code-block:: nimrod
+ type
+ TExpr = object ## abstract base class for an expression
+ TLiteral = object of TExpr
+ x: int
+ TPlusExpr = object of TExpr
+ a, b: ref TExpr
+
+ method eval(e: ref TExpr): int =
+ # override this base method
+ quit "to override!"
+
+ method eval(e: ref TLiteral): int = return e.x
+
+ method eval(e: ref TPlusExpr): int =
+ # watch out: relies on dynamic binding
+ return eval(e.a) + eval(e.b)
+
+ proc newLit(x: int): ref TLiteral =
+ new(result)
+ result.x = x
+
+ proc newPlus(a, b: ref TExpr): ref TPlusExpr =
+ new(result)
+ result.a = a
+ result.b = b
+
+ echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4)))
+
+In the example the constructors ``newLit`` and ``newPlus`` are procs
+because they should use static binding, but ``eval`` is a method because it
+requires dynamic binding.
+
+In a multi-method all parameters that have an object type are used for the
+dispatching:
+
+.. code-block:: nimrod
+ type
+ TThing = object
+ TUnit = object of TThing
+ x: int
+
+ method collide(a, b: TThing) {.inline.} =
+ quit "to override!"
+
+ method collide(a: TThing, b: TUnit) {.inline.} =
+ echo "1"
+
+ method collide(a: TUnit, b: TThing) {.inline.} =
+ echo "2"
+
+ var
+ a, b: TUnit
+ collide(a, b) # output: 2
+
+
+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``.
+
+**Perfomance note**: Nimrod does not produce a virtual method table, but
+generates dispatch trees. This avoids the expensive indirect branch for method
+calls and enables inlining. However, other optimizations like compile time
+evaluation or dead code elimination do not work with methods.
+
Iterators and the for statement
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2275,6 +2354,12 @@ error to mark a proc/iterator to have no side effect if the compiler cannot
verify this.
+procvar pragma
+--------------
+The `procvar`:idx: pragma is used to mark a proc that it can be passed to a
+procedural variable.
+
+
compileTime pragma
------------------
The `compileTime`:idx: pragma is used to mark a proc to be used at compile
diff --git a/doc/nimrodc.txt b/doc/nimrodc.txt
index 26bf38a0b..f43994cb8 100755
--- a/doc/nimrodc.txt
+++ b/doc/nimrodc.txt
@@ -72,8 +72,7 @@ New Pragmas and Options
-----------------------
Because Nimrod generates C code it needs some "red tape" to work properly.
-Thus lots of options and pragmas for tweaking the generated C code are
-available.
+Lots of options and pragmas for tweaking the generated C code are available.
Importc Pragma
~~~~~~~~~~~~~~
@@ -137,7 +136,7 @@ and instead the generated code should contain an ``#include``:
PFile {.importc: "FILE*", header: "".} = distinct pointer
# import C's FILE* type; Nimrod will treat it as a new pointer type
-The ``header`` pragma expects always a string constant. The string contant
+The ``header`` pragma always expects a string constant. The string contant
contains the header file: As usual for C, a system header file is enclosed
in angle brackets: ``<>``. If no angle brackets are given, Nimrod
encloses the header file in ``""`` in the generated C code.
@@ -145,9 +144,9 @@ encloses the header file in ``""`` in the generated C code.
Varargs Pragma
~~~~~~~~~~~~~~
-The `varargs`:idx: pragma can be applied to procedures only. It tells Nimrod
-that the proc can take a variable number of parameters after the last
-specified parameter. Nimrod string values will be converted to C
+The `varargs`:idx: pragma can be applied to procedures only (and procedure
+types). It tells Nimrod that the proc can take a variable number of parameters
+after the last specified parameter. Nimrod string values will be converted to C
strings automatically:
.. code-block:: Nimrod
@@ -218,7 +217,7 @@ collector to not consider objects of this type as part of a cycle:
data: string
In the example a tree structure is declared with the ``TNode`` type. Note that
-the type definition is recursive thus the GC has to assume that objects of
+the type definition is recursive and the GC has to assume that objects of
this type may form a cyclic graph. The ``acyclic`` pragma passes the
information that this cannot happen to the GC. If the programmer uses the
``acyclic`` pragma for data types that are in reality cyclic, the GC may leak
diff --git a/doc/pegdocs.txt b/doc/pegdocs.txt
new file mode 100755
index 000000000..943acc545
--- /dev/null
+++ b/doc/pegdocs.txt
@@ -0,0 +1,180 @@
+PEG syntax and semantics
+========================
+
+A PEG (Parsing expression grammar) is a simple deterministic grammar, that can
+be directly used for parsing. The current implementation has been designed as
+a more powerful replacement for regular expressions. UTF-8 is supported.
+
+The notation used for a PEG is similar to that of EBNF:
+
+=============== ============================================================
+notation meaning
+=============== ============================================================
+``A / ... / Z`` Ordered choice: Apply expressions `A`, ..., `Z`, in this
+ order, to the text ahead, until one of them succeeds and
+ possibly consumes some text. Indicate success if one of
+ expressions succeeded. Otherwise do not consume any text
+ and indicate failure.
+``A ... Z`` Sequence: Apply expressions `A`, ..., `Z`, in this order,
+ to consume consecutive portions of the text ahead, as long
+ as they succeed. Indicate success if all succeeded.
+ Otherwise do not consume any text and indicate failure.
+ The sequence's precedence is higher than that of ordered
+ choice: ``A B / C`` means ``(A B) / Z`` and
+ not ``A (B / Z)``.
+``(E)`` Grouping: Parenthesis can be used to change
+ operator priority.
+``{E}`` Capture: Apply expression `E` and store the substring
+ that matched `E` into a *capture* that can be accessed
+ after the matching process.
+``&E`` And predicate: Indicate success if expression `E` matches
+ the text ahead; otherwise indicate failure. Do not consume
+ any text.
+``!E`` Not predicate: Indicate failure if expression E matches the
+ text ahead; otherwise indicate success. Do not consume any
+ text.
+``E+`` One or more: Apply expression `E` repeatedly to match
+ the text ahead, as long as it succeeds. Consume the matched
+ text (if any) and indicate success if there was at least
+ one match. Otherwise indicate failure.
+``E*`` Zero or more: Apply expression `E` repeatedly to match
+ the text ahead, as long as it succeeds. Consume the matched
+ text (if any). Always indicate success.
+``E?`` Zero or one: If expression `E` matches the text ahead,
+ consume it. Always indicate success.
+``[s]`` Character class: If the character ahead appears in the
+ string `s`, consume it and indicate success. Otherwise
+ indicate failure.
+``[a-b]`` Character range: If the character ahead is one from the
+ range `a` through `b`, consume it and indicate success.
+ Otherwise indicate failure.
+``'s'`` String: If the text ahead is the string `s`, consume it
+ and indicate success. Otherwise indicate failure.
+``i's'`` String match ignoring case.
+``y's'`` String match ignoring style.
+``v's'`` Verbatim string match: Use this to override a global
+ ``\i`` or ``\y`` modifier.
+``.`` Any character: If there is a character ahead, consume it
+ and indicate success. Otherwise (that is, at the end of
+ input) indicate failure.
+``_`` Any Unicode character: If there is an UTF-8 character
+ ahead, consume it and indicate success. Otherwise indicate
+ failure.
+``A <- E`` Rule: Bind the expression `E` to the *nonterminal symbol*
+ `A`. **Left recursive rules are not possible and crash the
+ matching engine.**
+``\identifier`` Built-in macro for a longer expression.
+``\ddd`` Character with decimal code *ddd*.
+``\"``, etc Literal ``"``, etc.
+=============== ============================================================
+
+
+Built-in macros
+---------------
+
+============== ============================================================
+macro meaning
+============== ============================================================
+``\d`` any decimal digit: ``[0-9]``
+``\D`` any character that is not a decimal digit: ``[^0-9]``
+``\s`` any whitespace character: ``[ \9-\13]``
+``\S`` any character that is not a whitespace character:
+ ``[^ \9-\13]``
+``\w`` any "word" character: ``[a-zA-Z_]``
+``\W`` any "non-word" character: ``[^a-zA-Z_]``
+``\n`` any newline combination: ``\10 / \13\10 / \13``
+``\i`` ignore case for matching; use this at the start of the PEG
+``\y`` ignore style for matching; use this at the start of the PEG
+``\ident`` a standard ASCII identifier: ``[a-zA-Z_][a-zA-Z_0-9]*``
+============== ============================================================
+
+A backslash followed by a letter is a built-in macro, otherwise it
+is used for ordinary escaping:
+
+============== ============================================================
+notation meaning
+============== ============================================================
+``\\`` a single backslash
+``\*`` same as ``'*'``
+``\t`` not a tabulator, but an (unknown) built-in
+============== ============================================================
+
+
+Supported PEG grammar
+---------------------
+
+The PEG parser implements this grammar (written in PEG syntax)::
+
+ # Example grammar of PEG in PEG syntax.
+ # Comments start with '#'.
+ # First symbol is the start symbol.
+
+ grammar <- rule* / expr
+
+ identifier <- [A-Za-z][A-Za-z0-9_]*
+ charsetchar <- "\\" . / [^\]]
+ charset <- "[" "^"? (charsetchar ("-" charsetchar)?)+ "]"
+ stringlit <- identifier? ("\"" ("\\" . / [^"])* "\"" /
+ "'" ("\\" . / [^'])* "'")
+ builtin <- "\\" identifier / [^\13\10]
+
+ comment <- '#' !\n* \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 ")"))
+ (ig '?' / ig '*' / ig '+')*)
+
+ # Concatenation has higher priority than choice:
+ # ``a b / c`` means ``(a b) / c``
+
+ seqExpr <- primary+
+ expr <- seqExpr (ig "/" expr)*
+
+
+Examples
+--------
+
+Check if `s` matches Nimrod's "while" keyword:
+
+.. code-block:: nimrod
+ s =~ peg" y'while'"
+
+Exchange (key, val)-pairs:
+
+.. code-block:: nimrod
+ "key: val; key2: val2".replace(peg"{\ident} \s* ':' \s* {\ident}", "$2: $1")
+
+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+)* """:
+ 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
+deterministic: ``.*`` consumes the rest of the input, so ``\]`` never matches.
+As a PEG this needs to be written as: ``\[ ( !\] . )* \]``
+
+Note that the regular expression does not behave as intended either:
+``*`` should not be greedy, so ``\[.*?\]`` should be used.
+
+
+PEG construction
+----------------
+There are two ways to construct a PEG in Nimrod code:
+(1) Parsing a string into an AST which consists of `TPeg` nodes with the
+ `peg` proc.
+(2) Constructing the AST directly with proc calls. This method does not
+ support constructing rules, only simple expressions and is not as
+ convenient. It's only advantage is that it does not pull in the whole PEG
+ parser into your executable.
+
diff --git a/doc/theindex.txt b/doc/theindex.txt
index 7eb5f84e3..922dab769 100755
--- a/doc/theindex.txt
+++ b/doc/theindex.txt
@@ -8,13 +8,12 @@ Index
`!`:idx:
* `pegs.html#114 `_
- * `macros.html#113 `_
+ * `macros.html#114 `_
`!=`:idx:
`system.html#347 `_
`$`:idx:
- * `system.html#418 `_
* `system.html#419 `_
* `system.html#420 `_
* `system.html#421 `_
@@ -22,10 +21,11 @@ Index
* `system.html#423 `_
* `system.html#424 `_
* `system.html#425 `_
+ * `system.html#426 `_
* `times.html#109 `_
* `times.html#110 `_
* `pegs.html#148 `_
- * `macros.html#114 `_
+ * `macros.html#115 `_
`%`:idx:
* `strutils.html#109 `_
@@ -44,7 +44,6 @@ Index
* `system.html#362 `_
* `system.html#363 `_
* `system.html#364 `_
- * `system.html#461 `_
* `system.html#462 `_
* `system.html#463 `_
* `system.html#464 `_
@@ -181,9 +180,6 @@ Index
`<=`:idx:
`times.html#115 `_
- `<=%`:idx:
- `unicode.html#103 `_
-
`<=%`:idx:
* `system.html#297 `_
* `system.html#298 `_
@@ -191,6 +187,9 @@ Index
* `system.html#300 `_
* `system.html#301 `_
+ `<=%`:idx:
+ `unicode.html#103 `_
+
`==`:idx:
* `md5.html#107 `_
* `system.html#252 `_
@@ -211,25 +210,25 @@ Index
* `system.html#465 `_
* `complex.html#102 `_
* `unicode.html#105 `_
- * `macros.html#115 `_
-
- `=~`:idx:
- `regexprs.html#111 `_
+ * `macros.html#116 `_
`=~`:idx:
`pegs.html#138 `_
+ `=~`:idx:
+ `regexprs.html#108 `_
+
`>`:idx:
`system.html#349 `_
`>%`:idx:
- `system.html#417 `_
+ `system.html#418 `_
`>=`:idx:
`system.html#348 `_
`>=%`:idx:
- `system.html#416 `_
+ `system.html#417 `_
`?`:idx:
`pegs.html#110 `_
@@ -241,14 +240,14 @@ Index
`strtabs.html#107 `_
`[]`:idx:
- `macros.html#111 `_
+ `macros.html#112 `_
+
+ `[]=`:idx:
+ `macros.html#113 `_
`[]=`:idx:
`strtabs.html#106 `_
- `[]=`:idx:
- `macros.html#112 `_
-
`[ESC]`:idx:
`manual.html#134 `_
@@ -280,8 +279,8 @@ Index
* `system.html#368 `_
* `system.html#369 `_
* `parsesql.html#108 `_
- * `macros.html#117 `_
* `macros.html#118 `_
+ * `macros.html#119 `_
`addf`:idx:
`strutils.html#111 `_
@@ -301,13 +300,13 @@ Index
`xmlgen.html#109 `_
`addSep`:idx:
- `strutils.html#152 `_
+ `strutils.html#149 `_
`alert`:idx:
`manual.html#131 `_
`allCharsInSet`:idx:
- `strutils.html#153 `_
+ `strutils.html#150 `_
`alloc`:idx:
`system.html#410 `_
@@ -382,7 +381,7 @@ Index
`manual.html#199 `_
`assert`:idx:
- `system.html#414 `_
+ `system.html#415 `_
`AST`:idx:
`macros.html#101 `_
@@ -404,8 +403,7 @@ Index
`xmlgen.html#111 `_
`backslash`:idx:
- * `manual.html#127 `_
- * `regexprs.html#101 `_
+ `manual.html#127 `_
`backspace`:idx:
`manual.html#132 `_
@@ -657,10 +655,10 @@ Index
* `system.html#356 `_
`cmpIgnoreCase`:idx:
- `strutils.html#138 `_
+ `strutils.html#135 `_
`cmpIgnoreStyle`:idx:
- `strutils.html#139 `_
+ `strutils.html#136 `_
`cmpPaths`:idx:
`os.html#139 `_
@@ -701,7 +699,7 @@ Index
`system.html#391 `_
`compileTime`:idx:
- `manual.html#227 `_
+ `manual.html#229 `_
`complex statements`:idx:
`manual.html#178 `_
@@ -718,9 +716,9 @@ Index
`contains`:idx:
* `system.html#350 `_
- * `strutils.html#140 `_
- * `strutils.html#141 `_
- * `strutils.html#142 `_
+ * `strutils.html#137 `_
+ * `strutils.html#138 `_
+ * `strutils.html#139 `_
* `pegs.html#139 `_
* `pegs.html#140 `_
@@ -738,10 +736,10 @@ Index
`system.html#407 `_
`copyNimNode`:idx:
- `macros.html#134 `_
+ `macros.html#135 `_
`copyNimTree`:idx:
- `macros.html#135 `_
+ `macros.html#136 `_
`coreAttr`:idx:
`xmlgen.html#103 `_
@@ -756,16 +754,19 @@ Index
`math.html#109 `_
`countdown`:idx:
- `system.html#435 `_
+ `system.html#436 `_
+
+ `countProcessors`:idx:
+ `osproc.html#117 `_
`countup`:idx:
- `system.html#436 `_
+ `system.html#437 `_
`cpuEndian`:idx:
`system.html#396 `_
`createDir`:idx:
- * `os.html#156 `_
+ * `os.html#159 `_
* `zipfiles.html#104 `_
`create_random_string`:idx:
@@ -1156,7 +1157,7 @@ Index
`manual.html#179 `_
`dbgLineHook`:idx:
- `system.html#431 `_
+ `system.html#432 `_
`dd`:idx:
`xmlgen.html#123 `_
@@ -1184,24 +1185,24 @@ Index
`del`:idx:
* `xmlgen.html#124 `_
- * `macros.html#119 `_
+ * `macros.html#120 `_
`delete`:idx:
- `strutils.html#159 `_
+ `strutils.html#156 `_
`deleteStr`:idx:
- * `strutils.html#127 `_
- * `strutils.html#160 `_
+ * `strutils.html#124 `_
+ * `strutils.html#157 `_
`dfn`:idx:
`xmlgen.html#125 `_
- `Digits`:idx:
- `strutils.html#104 `_
-
`digits`:idx:
`pegs.html#125 `_
+ `Digits`:idx:
+ `strutils.html#104 `_
+
`DirSep`:idx:
`os.html#103 `_
@@ -1220,7 +1221,7 @@ Index
`xmlgen.html#127 `_
`domain specific languages`:idx:
- `manual.html#215 `_
+ `manual.html#216 `_
`dt`:idx:
`xmlgen.html#128 `_
@@ -1265,7 +1266,7 @@ Index
`system.html#151 `_
`editDistance`:idx:
- `strutils.html#166 `_
+ `strutils.html#163 `_
`EDivByZero`:idx:
`system.html#147 `_
@@ -1292,7 +1293,7 @@ Index
`pegs.html#149 `_
`EInvalidRegEx`:idx:
- `regexprs.html#104 `_
+ `regexprs.html#101 `_
`EInvalidSql`:idx:
`parsesql.html#103 `_
@@ -1320,7 +1321,7 @@ Index
* `lexbase.html#101 `_
`endsWith`:idx:
- * `strutils.html#151 `_
+ * `strutils.html#148 `_
* `pegs.html#142 `_
`ENoExceptionToReraise`:idx:
@@ -1387,9 +1388,9 @@ Index
`system.html#145 `_
`error`:idx:
- * `manual.html#225 `_
- * `manual.html#228 `_
- * `macros.html#136 `_
+ * `manual.html#226 `_
+ * `manual.html#230 `_
+ * `macros.html#137 `_
`errorMsg`:idx:
`parsexml.html#120 `_
@@ -1405,7 +1406,7 @@ Index
`escape`:idx:
* `manual.html#133 `_
- * `strutils.html#163 `_
+ * `strutils.html#160 `_
`escape sequences`:idx:
`manual.html#120 `_
@@ -1435,7 +1436,7 @@ Index
`system.html#174 `_
`exclFilePermissions`:idx:
- `os.html#162 `_
+ `os.html#165 `_
`execCmd`:idx:
`osproc.html#105 `_
@@ -1443,6 +1444,9 @@ Index
`execProcess`:idx:
`osproc.html#103 `_
+ `execProcesses`:idx:
+ `osproc.html#118 `_
+
`execShellCmd`:idx:
`os.html#146 `_
@@ -1474,13 +1478,13 @@ Index
`os.html#132 `_
`expectKind`:idx:
- `macros.html#145 `_
+ `macros.html#146 `_
`expectLen`:idx:
- `macros.html#147 `_
+ `macros.html#148 `_
`expectMinLen`:idx:
- `macros.html#146 `_
+ `macros.html#147 `_
`exportc`:idx:
`nimrodc.html#102 `_
@@ -1516,7 +1520,7 @@ Index
`unicode.html#108 `_
`fatal`:idx:
- `manual.html#229 `_
+ `manual.html#231 `_
`fieldset`:idx:
`xmlgen.html#130 `_
@@ -1625,20 +1629,13 @@ Index
`find`:idx:
* `system.html#466 `_
- * `strutils.html#122 `_
- * `strutils.html#123 `_
- * `strutils.html#124 `_
- * `regexprs.html#109 `_
- * `regexprs.html#110 `_
- * `pegs.html#136 `_
- * `pegs.html#137 `_
-
- `findChars`:idx:
- `strutils.html#121 `_
-
- `findSubStr`:idx:
* `strutils.html#119 `_
* `strutils.html#120 `_
+ * `strutils.html#121 `_
+ * `regexprs.html#106 `_
+ * `regexprs.html#107 `_
+ * `pegs.html#136 `_
+ * `pegs.html#137 `_
`float`:idx:
`system.html#106 `_
@@ -1650,16 +1647,16 @@ Index
`system.html#108 `_
`floatVal`:idx:
- `macros.html#122 `_
+ `macros.html#123 `_
`floatVal=`:idx:
- `macros.html#128 `_
+ `macros.html#129 `_
`FlushFile`:idx:
`system.html#503 `_
`for`:idx:
- * `manual.html#207 `_
+ * `manual.html#208 `_
* `tut1.html#105 `_
`form`:idx:
@@ -1718,18 +1715,15 @@ Index
`generalized raw string literal`:idx:
`manual.html#136 `_
- `generic character types`:idx:
- `regexprs.html#102 `_
-
`Generics`:idx:
- * `manual.html#211 `_
+ * `manual.html#212 `_
* `tut2.html#109 `_
`getApplicationDir`:idx:
- `os.html#166 `_
+ `os.html#169 `_
`getApplicationFilename`:idx:
- `os.html#165 `_
+ `os.html#168 `_
`getClockStr`:idx:
`times.html#112 `_
@@ -1742,7 +1736,7 @@ Index
* `parsexml.html#117 `_
`getConfigDir`:idx:
- `os.html#164 `_
+ `os.html#167 `_
`getContentLength`:idx:
`cgi.html#110 `_
@@ -1757,7 +1751,7 @@ Index
`os.html#120 `_
`getCurrentExceptionMsg`:idx:
- `system.html#427 `_
+ `system.html#428 `_
`getCurrentLine`:idx:
`lexbase.html#106 `_
@@ -1776,7 +1770,7 @@ Index
* `parsexml.html#119 `_
`getFilePermissions`:idx:
- `os.html#159 `_
+ `os.html#162 `_
`getFilePos`:idx:
`system.html#523 `_
@@ -1785,7 +1779,7 @@ Index
`system.html#515 `_
`getFreeMem`:idx:
- `system.html#433 `_
+ `system.html#434 `_
`getGatewayInterface`:idx:
`cgi.html#113 `_
@@ -1794,7 +1788,7 @@ Index
`times.html#107 `_
`getHomeDir`:idx:
- `os.html#163 `_
+ `os.html#166 `_
`getHttpAccept`:idx:
`cgi.html#114 `_
@@ -1840,7 +1834,7 @@ Index
`md5.html#106 `_
`getOccupiedMem`:idx:
- `system.html#432 `_
+ `system.html#433 `_
`getopt`:idx:
`parseopt.html#108 `_
@@ -1855,7 +1849,7 @@ Index
`cgi.html#125 `_
`getRefcount`:idx:
- `system.html#426 `_
+ `system.html#427 `_
`getRemoteAddr`:idx:
`cgi.html#126 `_
@@ -1924,7 +1918,7 @@ Index
`times.html#105 `_
`getTotalMem`:idx:
- `system.html#434 `_
+ `system.html#435 `_
`get_tty_password`:idx:
`mysql.html#282 `_
@@ -1991,9 +1985,9 @@ Index
`system.html#126 `_
`hint`:idx:
- * `manual.html#223 `_
- * `manual.html#231 `_
- * `macros.html#138