From db4f617afcd095db087dcb52e3ea603cca111da7 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 8 May 2009 16:36:06 +0200 Subject: [PATCH] version 0.7.8 --- boot.nim | 13 +- config/nimrod.cfg | 27 +- data/advopt.txt | 1 + data/magic.yml | 3 + data/messages.yml | 6 +- doc/filelist.txt | 2 + doc/grammar.txt | 2 +- doc/intern.txt | 31 +- doc/lib.txt | 13 + doc/manual.txt | 2 +- doc/theindex.txt | 500 +++++++++++-- doc/tut2.txt | 5 +- examples/hallo.nim | 6 +- examples/htmlrefs.nim | 3 +- examples/htmltitle.nim | 3 +- examples/statcsv.nim | 60 ++ ide/nimide.nim | 140 ++-- install.txt | 133 ++-- koch.py | 80 ++- lib/alloc.nim | 217 +++--- lib/ansi_c.nim | 6 +- lib/assign.nim | 8 +- lib/base/cgi.nim | 131 ++-- lib/excpt.nim | 20 +- lib/gc.nim | 368 ++++------ lib/lexbase.nim | 2 +- lib/macros.nim | 18 +- lib/math.nim | 35 + lib/memman.nim | 698 ------------------ lib/mm.nim | 187 +++++ lib/os.nim | 2 +- lib/osproc.nim | 92 ++- lib/parsecsv.nim | 176 +++++ lib/parsexml.nim | 2 +- lib/ptrset.nim | 205 ------ lib/repr.nim | 6 +- lib/strutils.nim | 9 + lib/sysio.nim | 9 +- lib/sysstr.nim | 23 +- lib/system.nim | 98 +-- lib/windows/windows.nim | 2 +- lib/winlean.nim | 108 +++ lib/wz_jsgraphics.js | 1107 ----------------------------- lib/xmlgen.nim | 406 +++++++++++ nim/ast.pas | 52 +- nim/astalgo.pas | 2 +- nim/ccgexprs.pas | 27 +- nim/ccgstmts.pas | 4 +- nim/ccgutils.pas | 2 +- nim/cgen.pas | 2 +- nim/commands.pas | 971 +++++++++++++------------ nim/condsyms.pas | 2 +- nim/docgen.pas | 16 +- nim/ecmasgen.pas | 2 +- nim/evals.pas | 63 +- nim/extccomp.pas | 6 +- nim/hashtest.pas | 2 +- nim/highlite.pas | 2 +- nim/idents.pas | 2 +- nim/interact.pas | 2 +- nim/magicsys.pas | 2 +- nim/main.pas | 2 +- nim/msgs.pas | 10 +- nim/{hashes.pas => nhashes.pas} | 2 +- nim/{strtabs.pas => nstrtabs.pas} | 10 +- nim/nversion.pas | 80 +-- nim/options.pas | 6 +- nim/osproc.pas | 30 + nim/parsecfg.pas | 2 +- nim/paslex.pas | 2 +- nim/pragmas.pas | 4 +- nim/ropes.pas | 2 +- nim/rst.pas | 24 +- nim/scanner.pas | 2 +- nim/sem.pas | 43 +- nim/semdata.pas | 1 + nim/semfold.pas | 28 +- nim/semstmts.pas | 3 +- nim/tigen.pas | 2 +- nim/transf.pas | 2 +- nim/treetab.pas | 2 +- nim/wordrecg.pas | 2 +- objdata.txt | 8 - rod/nimrod.ini | 1 + tests/csvtest.csv | 8 + tests/data.csv | 6 + tests/gctest.nim | 25 +- tests/toop1.nim | 2 +- todo.txt | 118 +-- tools/niminst | Bin 311978 -> 295608 bytes tools/nimweb.nim | 10 +- tools/sunset.tmpl | 4 +- 92 files changed, 3088 insertions(+), 3477 deletions(-) create mode 100644 examples/statcsv.nim delete mode 100644 lib/memman.nim create mode 100644 lib/mm.nim create mode 100644 lib/parsecsv.nim delete mode 100644 lib/ptrset.nim create mode 100644 lib/winlean.nim delete mode 100644 lib/wz_jsgraphics.js create mode 100644 lib/xmlgen.nim rename nim/{hashes.pas => nhashes.pas} (99%) rename nim/{strtabs.pas => nstrtabs.pas} (96%) create mode 100644 nim/osproc.pas delete mode 100644 objdata.txt create mode 100644 tests/csvtest.csv create mode 100644 tests/data.csv diff --git a/boot.nim b/boot.nim index 7b1745391..b7e2b221f 100644 --- a/boot.nim +++ b/boot.nim @@ -11,7 +11,10 @@ import os, strutils const - BootCmd = "nimrod cc --compile:build/platdef.c $1 rod/nimrod.nim" + BootCmd = [ + "nimrod cc --compile:build/platdef.c $1 rod/nimrod.nim", + "bin/nimrod cc --compile:build/platdef.c $1 rod/nimrod.nim" + ] PlatdefCTmpl = """ /* Generated by boot.nim */ char* nimOS(void) { return "$1"; } @@ -32,7 +35,7 @@ proc writePlatdefC = proc rodsrc = const - blacklist = ["nsystem", "nmath", "nos", "ntime", "strutils"] + 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) @@ -46,10 +49,10 @@ proc boot(args: string) = rodsrc() var newExe = appendFileExt("rod/nimrod", ExeExt) var oldExe = appendFileExt("bin/nimrod", ExeExt) - for i in 1..2: - Echo("iteration: ", $i) + for i in 0..1: + Echo("iteration: ", $(i+1)) # use the new executable to compile the files in the bootstrap directory: - Exec(Bootcmd % args) + Exec(Bootcmd[i] % args) if sameFileContent(newExe, oldExe): Echo("executables are equal: SUCCESS!") return diff --git a/config/nimrod.cfg b/config/nimrod.cfg index e06472cf5..4eb7b785b 100644 --- a/config/nimrod.cfg +++ b/config/nimrod.cfg @@ -51,6 +51,20 @@ hint[LineTooLong]=off passc = "-cxxlib" @end +# Configuration for the GNU C/C++ compiler: +@if windows: + gcc.path = r"$nimrod\dist\mingw\bin" +@end +gcc.options.debug = "-g" +@if macosx: + gcc.options.always = "-w -fasm-blocks" +@else: + gcc.options.always = "-w" +@end +gcc.options.speed = "-O3 -fno-strict-aliasing" +gcc.options.size = "-Os" +#passl = "-pg" + # Configuration for the LLVM GCC compiler: llvm_gcc.options.debug = "-g" llvm_gcc.options.always = "-w" @@ -66,19 +80,6 @@ vcc.options.always = "/nologo" vcc.options.speed = "/Ox /arch:SSE2" vcc.options.size = "/O1" -# Configuration for the GNU C/C++ compiler: -@if windows: - gcc.path = r"$nimrod\dist\mingw\bin" -@end -gcc.options.debug = "-g" -@if macosx: - gcc.options.always = "-w -fasm-blocks" -@else: - gcc.options.always = "-w" -@end -gcc.options.speed = "-O3 -fno-strict-aliasing" -gcc.options.size = "-Os" - # Configuration for the Digital Mars C/C++ compiler: @if windows: dmc.path = r"$nimrod\dist\dm\bin" diff --git a/data/advopt.txt b/data/advopt.txt index 1fc1f4845..4cdbc5d0f 100644 --- a/data/advopt.txt +++ b/data/advopt.txt @@ -27,6 +27,7 @@ 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 --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 diff --git a/data/magic.yml b/data/magic.yml index b569159e4..19013ccc4 100644 --- a/data/magic.yml +++ b/data/magic.yml @@ -176,6 +176,9 @@ 'Swap', 'IsNil', 'ArrToSeq', +'CopyStr', +'CopyStrLast', +'NewString', # magic types: 'Array', diff --git a/data/messages.yml b/data/messages.yml index b5b37c6c5..4a2154613 100644 --- a/data/messages.yml +++ b/data/messages.yml @@ -46,7 +46,7 @@ {'errExceptionExpected': 'exception expected'}, {'errExceptionAlreadyHandled': 'exception already handled'}, {'errReturnNotAllowedHere': "'return' only allowed in routine"}, -{'errYieldNotAllowedHere': "'yield' only allowed in iterator"}, +{'errYieldNotAllowedHere': "'yield' only allowed in a loop of an iterator"}, {'errInvalidNumberOfYieldExpr': "invalid number of 'yield' expresions"}, {'errReturnInvalidInIterator': "'return' not allowed in iterator"}, {'errCannotReturnExpr': 'current routine cannot return an expression'}, @@ -54,10 +54,10 @@ {'errStmtInvalidAfterReturn': "statement not allowed after 'return', 'break' or 'raise'"}, {'errStmtExpected': 'statement expected'}, -{'errYieldOnlyInInterators': "'yield' statement is only allowed in iterators"}, {'errInvalidLabel': "'$1' is no label"}, {'errInvalidCmdLineOption': "invalid command line option: '$1'"}, {'errCmdLineArgExpected': "argument for command line option expected: '$1'"}, +{'errCmdLineNoArgExpected': "invalid argument for command line option: '$1'"}, {'errInvalidVarSubstitution': "invalid variable substitution in '$1'"}, {'errUnknownVar': "unknown variable: '$1'"}, {'errUnknownCcompiler': "unknown C compiler: '$1'"}, @@ -105,7 +105,7 @@ "argument to 'staticAssert' cannot be evaluated at compile time"}, {'errDotRequiresRecordOrObjectType': "'.' requires a record or object type"}, {'errUndeclaredFieldX': "undeclared field: '$1'"}, -{'errIndexNoIntType': 'index has to be an integer type'}, +{'errNilAccess': 'attempt to access a nil address'}, {'errIndexOutOfBounds': 'index out of bounds'}, {'errIndexTypesDoNotMatch': 'index types do not match'}, {'errBracketsInvalidForType': "'[]' operator invalid for this type"}, diff --git a/doc/filelist.txt b/doc/filelist.txt index e094b6fb3..0e636652a 100644 --- a/doc/filelist.txt +++ b/doc/filelist.txt @@ -7,6 +7,8 @@ Module Description nimrod main module: parses the command line and calls ``main.MainCommand`` main implements the top-level command dispatching +nimconf implements the config file reader + lexbase buffer handling of the lexical analyser scanner lexical analyser pnimsyn Nimrod's parser diff --git a/doc/grammar.txt b/doc/grammar.txt index 9fbd1eb15..11e26e33f 100644 --- a/doc/grammar.txt +++ b/doc/grammar.txt @@ -30,7 +30,7 @@ symbol ::= '`' (KEYWORD | IDENT | operator | '(' ')' | '[' ']' | '=' | literal)+ '`' | IDENT primary ::= (prefixOperator optInd)* (symbol | constructor | - | castExpr | addrExpr) ( + castExpr | addrExpr) ( '.' optInd symbol | '(' optInd namedExprList [SAD] ')' | '[' optInd diff --git a/doc/intern.txt b/doc/intern.txt index 6496e0e29..646cb9d9c 100644 --- a/doc/intern.txt +++ b/doc/intern.txt @@ -18,6 +18,7 @@ The Nimrod project's directory structure is: Path Purpose ============ ============================================== ``bin`` binary files go into here +``build`` generated C code for the installation ``nim`` Pascal sources of the Nimrod compiler; this should be modified, not the Nimrod version in ``rod``! @@ -28,7 +29,7 @@ Path Purpose code go into here ``doc`` the documentation lives here; it is a bunch of reStructuredText files -``dist`` download packages as zip archives go into here +``dist`` additional packages for the distribution ``config`` configuration files for Nimrod go into here ``lib`` the Nimrod library lives here; ``rod`` depends on it! @@ -45,8 +46,8 @@ The compiler is written in a subset of Pascal with special annotations so that it can be translated to Nimrod code automatically. This conversion is done by Nimrod itself via the undocumented ``boot`` command. Thus both Nimrod and Free Pascal can compile the Nimrod compiler. However, the Pascal version -has no garbage collector and leaks memory like crazy! So the Pascal version -should only be used for bootstrapping. +has no garbage collector and leaks memory! So the Pascal version should only +be used for bootstrapping. Requirements for bootstrapping: @@ -214,7 +215,7 @@ address within this page. So including a cell is done as follows: Removing a cell is analogous - the bit has to be set to zero. Single page descriptors are never deleted from the hash table. This is not -needed as the data structures need to be periodically rebuilt anyway. +needed as the data structures needs to be rebuilt periodically anyway. Complete traversal is done in this way:: @@ -288,11 +289,8 @@ The synax tree consists of nodes which may have an arbitrary number of children. Types and symbols are represented by other nodes, because they may contain cycles. The AST changes its shape after semantic checking. This is needed to make life easier for the code generators. See the "ast" module -for the type definitions. - -I use the notation ``nodeKind(fields, [sons])`` for describing -nodes. ``nodeKind[sons]`` is a short-cut for ``nodeKind([sons])``. -XXX: Description of the language's syntax and the corresponding trees. +for the type definitions. The `macros `_ module contains many +examples how the AST represents each syntactic structure. How the RTL is compiled @@ -310,6 +308,21 @@ semantic checking, a ``compilerproc`` is a proc that is used by the code generator. +Debugging Nimrod's memory management +==================================== + +The following paragraphs are mostly a reminder for myself. Things to keep +in mind: + +* Segmentation faults can have multiple reasons: One that is frequently + forgotten is that *stack overflow* can trigger one! +* If an assertion in Nimrod's memory manager or GC fails, the stack trace + keeps allocating memory! Thus a stack overflow may happen, hiding the + real issue. +* What seem to be C code generation problems is often a bug resulting from + not producing prototypes, so that some types default to ``cint``. Testing + without the ``-w`` option helps! + Generation of dynamic link libraries ==================================== diff --git a/doc/lib.txt b/doc/lib.txt index b45c02262..0b11c28cc 100644 --- a/doc/lib.txt +++ b/doc/lib.txt @@ -22,6 +22,9 @@ Pure libraries implicitly by the compiler. Do not import it directly. It relies on compiler magic to work. +* `macros `_ + Contains the AST API and documentation of Nimrod for writing macros. + * `strutils `_ This module contains common string handling operations like converting a string into uppercase, splitting a string into substrings, searching for @@ -33,6 +36,9 @@ Pure libraries commands, etc. This module is -- like any other basic library -- platform independant. +* `osproc `_ + Module for process communication beyond ``os.executeShellCommand``. + * `math `_ Mathematical operations like cosine, square root. @@ -60,6 +66,9 @@ Pure libraries to be somewhat error correcting, so that even some "wild HTML" found on the web can be parsed with it. +* `parsecsv `_ + The ``parsecsv`` module implements a simple high performance CSV parser. + * `strtabs `_ The ``strtabs`` module implements an efficient hash table that is a mapping from strings to strings. Supports a case-sensitive, case-insensitive and @@ -98,6 +107,10 @@ Pure libraries * `md5 `_ This module implements the MD5 checksum algorithm. +* `xmlgen `_ + This module implements macros for HTML code generation. + + Impure libraries ================ diff --git a/doc/manual.txt b/doc/manual.txt index 2fa24f756..9acaae3cd 100644 --- a/doc/manual.txt +++ b/doc/manual.txt @@ -1649,7 +1649,7 @@ possible within a single ``type`` section. Generics ~~~~~~~~ -`Version 0.7.6: Generic types like in the example do not work.`:red: +`Version 0.7.8: Generic types like in the example do not work.`:red: Example: diff --git a/doc/theindex.txt b/doc/theindex.txt index 6aeb786fa..06be1fc5d 100644 --- a/doc/theindex.txt +++ b/doc/theindex.txt @@ -6,6 +6,9 @@ Index .. index:: + `!`:idx: + `macros.html#115 `_ + `!=`:idx: `system.html#351 `_ @@ -20,6 +23,7 @@ Index * `system.html#429 `_ * `times.html#109 `_ * `times.html#110 `_ + * `macros.html#116 `_ `%`:idx: * `strutils.html#111 `_ @@ -176,6 +180,7 @@ Index * `system.html#305 `_ `==`:idx: + * `md5.html#107 `_ * `system.html#246 `_ * `system.html#247 `_ * `system.html#248 `_ @@ -193,7 +198,7 @@ Index * `system.html#335 `_ * `system.html#458 `_ * `complex.html#102 `_ - * `md5.html#107 `_ + * `macros.html#117 `_ `=~`:idx: `regexprs.html#111 `_ @@ -216,12 +221,21 @@ Index `[]`:idx: `strtabs.html#107 `_ + `[]`:idx: + `macros.html#113 `_ + `[]=`:idx: `strtabs.html#106 `_ + `[]=`:idx: + `macros.html#114 `_ + `[ESC]`:idx: `manual.html#134 `_ + `a`:idx: + `xmlgen.html#107 `_ + `abs`:idx: * `system.html#261 `_ * `system.html#262 `_ @@ -231,6 +245,9 @@ Index * `system.html#320 `_ * `complex.html#108 `_ + `acronym`:idx: + `xmlgen.html#108 `_ + `acyclic`:idx: `nimrodc.html#113 `_ @@ -240,6 +257,8 @@ Index * `system.html#368 `_ * `system.html#369 `_ * `system.html#370 `_ + * `macros.html#119 `_ + * `macros.html#120 `_ `addf`:idx: `strutils.html#113 `_ @@ -252,6 +271,9 @@ Index `addQuitProc`:idx: `system.html#404 `_ + `address`:idx: + `xmlgen.html#109 `_ + `addSep`:idx: `strutils.html#151 `_ @@ -302,6 +324,9 @@ Index `arctan2`:idx: `math.html#125 `_ + `area`:idx: + `xmlgen.html#110 `_ + `arithmetic bit shifts`:idx: `tut1.html#110 `_ @@ -321,6 +346,9 @@ Index `assert`:idx: `system.html#418 `_ + `AST`:idx: + `macros.html#101 `_ + `attrKey`:idx: `parsexml.html#113 `_ @@ -334,6 +362,9 @@ Index * `manual.html#144 `_ * `tut1.html#111 `_ + `b`:idx: + `xmlgen.html#111 `_ + `backslash`:idx: * `manual.html#127 `_ * `regexprs.html#101 `_ @@ -341,6 +372,12 @@ Index `backspace`:idx: `manual.html#132 `_ + `base`:idx: + `xmlgen.html#112 `_ + + `big`:idx: + `xmlgen.html#113 `_ + `BiggestFloat`:idx: `system.html#374 `_ @@ -362,6 +399,12 @@ Index `block`:idx: `manual.html#192 `_ + `blockquote`:idx: + `xmlgen.html#114 `_ + + `body`:idx: + `xmlgen.html#115 `_ + `bool`:idx: `system.html#109 `_ @@ -369,12 +412,18 @@ Index * `manual.html#146 `_ * `tut1.html#107 `_ + `br`:idx: + `xmlgen.html#116 `_ + `break`:idx: `manual.html#193 `_ `breakpoint`:idx: `endb.html#103 `_ + `button`:idx: + `xmlgen.html#117 `_ + `Byte`:idx: `system.html#128 `_ @@ -384,6 +433,9 @@ Index `capitalize`:idx: `strutils.html#119 `_ + `caption`:idx: + `xmlgen.html#118 `_ + `card`:idx: `system.html#169 `_ @@ -450,6 +502,9 @@ Index `cint`:idx: `system.html#378 `_ + `cite`:idx: + `xmlgen.html#119 `_ + `classify`:idx: `math.html#104 `_ @@ -532,6 +587,7 @@ Index * `lexbase.html#105 `_ * `parsecfg.html#105 `_ * `parsexml.html#108 `_ + * `parsecsv.html#109 `_ * `zipfiles.html#103 `_ `CloseFile`:idx: @@ -556,6 +612,18 @@ Index `cmpRunesIgnoreCase`:idx: `unicode.html#115 `_ + `code`:idx: + `xmlgen.html#120 `_ + + `col`:idx: + `xmlgen.html#121 `_ + + `colgroup`:idx: + `xmlgen.html#122 `_ + + `comma separated value`:idx: + `parsecsv.html#102 `_ + `comment pieces`:idx: * `manual.html#115 `_ * `tut1.html#103 `_ @@ -564,6 +632,9 @@ Index * `manual.html#114 `_ * `tut1.html#102 `_ + `commonAttr`:idx: + `xmlgen.html#105 `_ + `COMP_HEADER_SIZE`:idx: `mysql.html#266 `_ @@ -605,6 +676,15 @@ Index `copyMem`:idx: `system.html#410 `_ + `copyNimNode`:idx: + `macros.html#136 `_ + + `copyNimTree`:idx: + `macros.html#137 `_ + + `coreAttr`:idx: + `xmlgen.html#103 `_ + `cos`:idx: `math.html#126 `_ @@ -642,6 +722,9 @@ Index `cstringArray`:idx: `system.html#384 `_ + `CSV`:idx: + `parsecsv.html#101 `_ + `cuint`:idx: `mysql.html#109 `_ @@ -1014,6 +1097,9 @@ Index `dbgLineHook`:idx: `system.html#435 `_ + `dd`:idx: + `xmlgen.html#123 `_ + `dead_code_elim`:idx: `nimrodc.html#114 `_ @@ -1026,15 +1112,25 @@ Index `dec`:idx: `system.html#160 `_ + `decodeData`:idx: + `cgi.html#107 `_ + `define`:idx: `manual.html#222 `_ `defined`:idx: `system.html#114 `_ + `del`:idx: + * `xmlgen.html#124 `_ + * `macros.html#121 `_ + `deleteStr`:idx: `strutils.html#129 `_ + `dfn`:idx: + `xmlgen.html#125 `_ + `Digits`:idx: `strutils.html#104 `_ @@ -1050,6 +1146,10 @@ Index * `system.html#213 `_ * `system.html#214 `_ * `system.html#215 `_ + * `xmlgen.html#126 `_ + + `dl`:idx: + `xmlgen.html#127 `_ `dom`:idx: `nimrodc.html#120 `_ @@ -1058,6 +1158,9 @@ Index * `manual.html#211 `_ * `tut2.html#111 `_ + `dt`:idx: + `xmlgen.html#128 `_ + `dynamic type`:idx: `manual.html#104 `_ @@ -1099,11 +1202,14 @@ Index `system.html#145 `_ `editDistance`:idx: - `strutils.html#158 `_ + `strutils.html#159 `_ `EDivByZero`:idx: `system.html#141 `_ + `EInvalidCsv`:idx: + `parsecsv.html#105 `_ + `EInvalidField`:idx: `system.html#149 `_ @@ -1128,6 +1234,9 @@ Index `elementName`:idx: `parsexml.html#111 `_ + `em`:idx: + `xmlgen.html#129 `_ + `Embedded Nimrod Debugger`:idx: `endb.html#101 `_ @@ -1204,6 +1313,7 @@ Index `error`:idx: * `manual.html#221 `_ * `manual.html#224 `_ + * `macros.html#138 `_ `errorMsg`:idx: `parsexml.html#120 `_ @@ -1230,6 +1340,9 @@ Index `ESystem`:idx: `system.html#136 `_ + `eventAttr`:idx: + `xmlgen.html#104 `_ + `except`:idx: `manual.html#187 `_ @@ -1263,9 +1376,21 @@ Index `expandFilename`:idx: `os.html#116 `_ + `expectKind`:idx: + `macros.html#147 `_ + + `expectLen`:idx: + `macros.html#149 `_ + + `expectMinLen`:idx: + `macros.html#148 `_ + `exportc`:idx: `nimrodc.html#102 `_ + `expr`:idx: + `macros.html#111 `_ + `expression macros`:idx: `tut2.html#112 `_ @@ -1293,6 +1418,9 @@ Index `fatal`:idx: `manual.html#225 `_ + `fieldset`:idx: + `xmlgen.html#130 `_ + `FIELD_TYPE_BIT`:idx: `mysql.html#231 `_ @@ -1419,6 +1547,12 @@ Index `float64`:idx: `system.html#108 `_ + `floatVal`:idx: + `macros.html#124 `_ + + `floatVal=`:idx: + `macros.html#130 `_ + `FlushFile`:idx: `system.html#492 `_ @@ -1426,6 +1560,9 @@ Index * `manual.html#203 `_ * `tut1.html#105 `_ + `form`:idx: + `xmlgen.html#131 `_ + `form feed`:idx: `manual.html#124 `_ @@ -1503,10 +1640,10 @@ Index `os.html#115 `_ `getContentLength`:idx: - `cgi.html#109 `_ + `cgi.html#110 `_ `getContentType`:idx: - `cgi.html#110 `_ + `cgi.html#111 `_ `getCurrentDir`:idx: `os.html#112 `_ @@ -1521,7 +1658,7 @@ Index `times.html#111 `_ `getDocumentRoot`:idx: - `cgi.html#111 `_ + `cgi.html#112 `_ `getEnv`:idx: `os.html#143 `_ @@ -1540,7 +1677,7 @@ Index `system.html#437 `_ `getGatewayInterface`:idx: - `cgi.html#112 `_ + `cgi.html#113 `_ `getGMTime`:idx: `times.html#107 `_ @@ -1549,32 +1686,32 @@ Index `os.html#114 `_ `getHttpAccept`:idx: - `cgi.html#113 `_ - - `getHttpAcceptCharset`:idx: `cgi.html#114 `_ - `getHttpAcceptEncoding`:idx: + `getHttpAcceptCharset`:idx: `cgi.html#115 `_ - `getHttpAcceptLanguage`:idx: + `getHttpAcceptEncoding`:idx: `cgi.html#116 `_ - `getHttpConnection`:idx: + `getHttpAcceptLanguage`:idx: `cgi.html#117 `_ - `getHttpCookie`:idx: + `getHttpConnection`:idx: `cgi.html#118 `_ - `getHttpHost`:idx: + `getHttpCookie`:idx: `cgi.html#119 `_ - `getHttpReferer`:idx: + `getHttpHost`:idx: `cgi.html#120 `_ - `getHttpUserAgent`:idx: + `getHttpReferer`:idx: `cgi.html#121 `_ + `getHttpUserAgent`:idx: + `cgi.html#122 `_ + `getLastModificationTime`:idx: `os.html#140 `_ @@ -1595,38 +1732,38 @@ Index `parseopt.html#106 `_ `getPathInfo`:idx: - `cgi.html#122 `_ - - `getPathTranslated`:idx: `cgi.html#123 `_ - `getQueryString`:idx: + `getPathTranslated`:idx: `cgi.html#124 `_ + `getQueryString`:idx: + `cgi.html#125 `_ + `getRefcount`:idx: `system.html#430 `_ `getRemoteAddr`:idx: - `cgi.html#125 `_ - - `getRemoteHost`:idx: `cgi.html#126 `_ - `getRemoteIdent`:idx: + `getRemoteHost`:idx: `cgi.html#127 `_ - `getRemotePort`:idx: + `getRemoteIdent`:idx: `cgi.html#128 `_ - `getRemoteUser`:idx: + `getRemotePort`:idx: `cgi.html#129 `_ - `getRequestMethod`:idx: + `getRemoteUser`:idx: `cgi.html#130 `_ - `getRequestURI`:idx: + `getRequestMethod`:idx: `cgi.html#131 `_ + `getRequestURI`:idx: + `cgi.html#132 `_ + `getRestOfCommandLine`:idx: `parseopt.html#105 `_ @@ -1637,32 +1774,32 @@ Index `mysql.html#274 `_ `getScriptFilename`:idx: - `cgi.html#132 `_ - - `getScriptName`:idx: `cgi.html#133 `_ - `getServerAddr`:idx: + `getScriptName`:idx: `cgi.html#134 `_ - `getServerAdmin`:idx: + `getServerAddr`:idx: `cgi.html#135 `_ - `getServerName`:idx: + `getServerAdmin`:idx: `cgi.html#136 `_ - `getServerPort`:idx: + `getServerName`:idx: `cgi.html#137 `_ - `getServerProtocol`:idx: + `getServerPort`:idx: `cgi.html#138 `_ - `getServerSignature`:idx: + `getServerProtocol`:idx: `cgi.html#139 `_ - `getServerSoftware`:idx: + `getServerSignature`:idx: `cgi.html#140 `_ + `getServerSoftware`:idx: + `cgi.html#141 `_ + `getStartMilsecs`:idx: `times.html#116 `_ @@ -1684,6 +1821,24 @@ Index `GROUP_FLAG`:idx: `mysql.html#139 `_ + `h1`:idx: + `xmlgen.html#132 `_ + + `h2`:idx: + `xmlgen.html#133 `_ + + `h3`:idx: + `xmlgen.html#134 `_ + + `h4`:idx: + `xmlgen.html#135 `_ + + `h5`:idx: + `xmlgen.html#136 `_ + + `h6`:idx: + `xmlgen.html#137 `_ + `HandleCR`:idx: `lexbase.html#108 `_ @@ -1712,6 +1867,9 @@ Index `hasKey`:idx: `strtabs.html#108 `_ + `head`:idx: + `xmlgen.html#138 `_ + `header`:idx: `nimrodc.html#105 `_ @@ -1721,6 +1879,7 @@ Index `hint`:idx: * `manual.html#219 `_ * `manual.html#227 `_ + * `macros.html#140 `_ `hostCPU`:idx: `system.html#399 `_ @@ -1731,8 +1890,15 @@ Index `hostOS`:idx: `system.html#398 `_ + `hr`:idx: + `xmlgen.html#140 `_ + + `html`:idx: + `xmlgen.html#139 `_ + `HTML`:idx: - `parsexml.html#102 `_ + * `parsexml.html#102 `_ + * `xmlgen.html#102 `_ `HTTPPOST_BUFFER`:idx: `libcurl.html#266 `_ @@ -1755,6 +1921,15 @@ Index `hypot`:idx: `math.html#128 `_ + `i`:idx: + `xmlgen.html#141 `_ + + `ident`:idx: + `macros.html#126 `_ + + `ident=`:idx: + `macros.html#132 `_ + `IdentChars`:idx: `strutils.html#105 `_ @@ -1770,6 +1945,9 @@ Index `if`:idx: `manual.html#180 `_ + `img`:idx: + `xmlgen.html#142 `_ + `implicit block`:idx: `manual.html#205 `_ @@ -1808,6 +1986,12 @@ Index `inline`:idx: `manual.html#167 `_ + `input`:idx: + `xmlgen.html#143 `_ + + `ins`:idx: + `xmlgen.html#144 `_ + `int`:idx: `system.html#101 `_ @@ -1829,6 +2013,12 @@ Index `intToStr`:idx: `strutils.html#143 `_ + `intVal`:idx: + `macros.html#123 `_ + + `intVal=`:idx: + `macros.html#129 `_ + `is`:idx: `system.html#357 `_ @@ -1903,15 +2093,25 @@ Index * `os.html#118 `_ * `os.html#120 `_ + `kbd`:idx: + `xmlgen.html#145 `_ + `keywords`:idx: `manual.html#117 `_ `kind`:idx: - `parsexml.html#110 `_ + * `parsexml.html#110 `_ + * `macros.html#122 `_ `l-values`:idx: `manual.html#107 `_ + `label`:idx: + `xmlgen.html#146 `_ + + `legend`:idx: + `xmlgen.html#147 `_ + `len`:idx: * `system.html#162 `_ * `system.html#163 `_ @@ -1919,10 +2119,14 @@ Index * `system.html#165 `_ * `system.html#166 `_ * `strtabs.html#109 `_ + * `macros.html#118 `_ `Letters`:idx: `strutils.html#103 `_ + `li`:idx: + `xmlgen.html#148 `_ + `LIBCURL_VERSION`:idx: `libcurl.html#272 `_ @@ -1950,6 +2154,9 @@ Index `line_trace`:idx: `nimrodc.html#109 `_ + `link`:idx: + `xmlgen.html#149 `_ + `Literal strings`:idx: `manual.html#119 `_ @@ -2014,6 +2221,9 @@ Index `MANAGER_OK`:idx: `mysql.html#334 `_ + `map`:idx: + `xmlgen.html#150 `_ + `match`:idx: * `regexprs.html#106 `_ * `regexprs.html#107 `_ @@ -2083,6 +2293,9 @@ Index `MEM_ROOT`:idx: `mysql.html#325 `_ + `meta`:idx: + `xmlgen.html#151 `_ + `method call syntax`:idx: `tut2.html#104 `_ @@ -2643,6 +2856,9 @@ Index `neginf`:idx: `system.html#433 `_ + `nestList`:idx: + `macros.html#152 `_ + `NET`:idx: `mysql.html#199 `_ @@ -2686,16 +2902,33 @@ Index * `system.html#119 `_ * `system.html#120 `_ + `newCall`:idx: + * `macros.html#150 `_ + * `macros.html#151 `_ + `newFileStream`:idx: * `streams.html#120 `_ * `streams.html#121 `_ + `newFloatLitNode`:idx: + `macros.html#143 `_ + + `newIdentNode`:idx: + * `macros.html#144 `_ + * `macros.html#145 `_ + + `newIntLitNode`:idx: + `macros.html#142 `_ + `newline`:idx: `manual.html#121 `_ `NewLines`:idx: `lexbase.html#102 `_ + `newNimNode`:idx: + `macros.html#135 `_ + `newSeq`:idx: `system.html#161 `_ @@ -2709,6 +2942,9 @@ Index * `strtabs.html#104 `_ * `strtabs.html#105 `_ + `newStrLitNode`:idx: + `macros.html#141 `_ + `next`:idx: * `parseopt.html#104 `_ * `parsecfg.html#106 `_ @@ -2747,6 +2983,9 @@ Index `normalize`:idx: `strutils.html#120 `_ + `noscript`:idx: + `xmlgen.html#152 `_ + `not`:idx: * `system.html#115 `_ * `system.html#191 `_ @@ -2771,11 +3010,15 @@ Index `mysql.html#137 `_ `object`:idx: - `manual.html#155 `_ + * `manual.html#155 `_ + * `xmlgen.html#153 `_ `octet2hex`:idx: `mysql.html#276 `_ + `ol`:idx: + `xmlgen.html#154 `_ + `ONLY_KILL_QUERY`:idx: `mysql.html#189 `_ @@ -2783,6 +3026,7 @@ Index * `lexbase.html#104 `_ * `parsecfg.html#104 `_ * `parsexml.html#107 `_ + * `parsecsv.html#106 `_ * `zipfiles.html#102 `_ `openarray`:idx: @@ -2799,6 +3043,12 @@ Index `Operators`:idx: `manual.html#202 `_ + `optgroup`:idx: + `xmlgen.html#155 `_ + + `option`:idx: + `xmlgen.html#156 `_ + `or`:idx: * `system.html#117 `_ * `system.html#236 `_ @@ -2819,12 +3069,18 @@ Index `OSError`:idx: `os.html#147 `_ + `p`:idx: + `xmlgen.html#157 `_ + `packet_error`:idx: `mysql.html#201 `_ `pairs`:idx: `strtabs.html#110 `_ + `param`:idx: + `xmlgen.html#158 `_ + `paramCount`:idx: `os.html#145 `_ @@ -3062,6 +3318,15 @@ Index `PNET`:idx: `mysql.html#200 `_ + `PNimrodNode`:idx: + `macros.html#110 `_ + + `PNimrodSymbol`:idx: + `macros.html#109 `_ + + `PNimrodType`:idx: + `macros.html#108 `_ + `PObject`:idx: `system.html#132 `_ @@ -3102,6 +3367,9 @@ Index `Prand_struct`:idx: `mysql.html#253 `_ + `pre`:idx: + `xmlgen.html#159 `_ + `pred`:idx: `system.html#158 `_ @@ -3115,6 +3383,9 @@ Index `procedures`:idx: `manual.html#199 `_ + `processedRows`:idx: + `parsecsv.html#107 `_ + `Psockaddr`:idx: `mysql.html#250 `_ @@ -3199,6 +3470,9 @@ Index `PUSED_MEM`:idx: `mysql.html#322 `_ + `push`:idx: + `math.html#134 `_ + `push/pop`:idx: `manual.html#228 `_ @@ -3211,6 +3485,9 @@ Index `PZipFileStream`:idx: `zipfiles.html#108 `_ + `q`:idx: + `xmlgen.html#160 `_ + `quit`:idx: * `system.html#479 `_ * `system.html#480 `_ @@ -3262,7 +3539,7 @@ Index `system.html#506 `_ `readData`:idx: - `cgi.html#107 `_ + `cgi.html#108 `_ `readFile`:idx: `system.html#493 `_ @@ -3289,6 +3566,9 @@ Index * `system.html#501 `_ * `streams.html#114 `_ + `readRow`:idx: + `parsecsv.html#108 `_ + `readStr`:idx: `streams.html#113 `_ @@ -3420,6 +3700,9 @@ Index `sameFileContent`:idx: `os.html#149 `_ + `samp`:idx: + `xmlgen.html#161 `_ + `scope`:idx: * `manual.html#106 `_ * `manual.html#217 `_ @@ -3442,9 +3725,15 @@ Index `SCRAMBLE_LENGTH_323`:idx: `mysql.html#121 `_ + `script`:idx: + `xmlgen.html#162 `_ + `ScriptExt`:idx: `os.html#108 `_ + `select`:idx: + `xmlgen.html#163 `_ + `separate compilation`:idx: * `manual.html#214 `_ * `tut1.html#127 `_ @@ -3528,7 +3817,7 @@ Index * `system.html#417 `_ `setTestData`:idx: - `cgi.html#141 `_ + `cgi.html#142 `_ `shl`:idx: * `system.html#226 `_ @@ -3556,9 +3845,15 @@ Index `sizeof`:idx: `system.html#156 `_ + `small`:idx: + `xmlgen.html#164 `_ + `sockaddr`:idx: `mysql.html#251 `_ + `span`:idx: + `xmlgen.html#165 `_ + `split`:idx: * `strutils.html#131 `_ * `strutils.html#132 `_ @@ -4084,6 +4379,9 @@ Index `stack_trace`:idx: `nimrodc.html#108 `_ + `standardDeviation`:idx: + `math.html#136 `_ + `startsWith`:idx: `strutils.html#149 `_ @@ -4117,6 +4415,9 @@ Index `st_mem_root`:idx: `mysql.html#324 `_ + `stmt`:idx: + `macros.html#112 `_ + `st_mysql`:idx: `mysql.html#356 `_ @@ -4163,6 +4464,9 @@ Index `strip`:idx: `strutils.html#114 `_ + `strong`:idx: + `xmlgen.html#166 `_ + `strStart`:idx: `strutils.html#107 `_ @@ -4172,6 +4476,12 @@ Index `strutils`:idx: `nimrodc.html#117 `_ + `strVal`:idx: + `macros.html#128 `_ + + `strVal=`:idx: + `macros.html#134 `_ + `st_udf_args`:idx: `mysql.html#258 `_ @@ -4181,9 +4491,15 @@ Index `st_used_mem`:idx: `mysql.html#320 `_ + `style`:idx: + `xmlgen.html#167 `_ + `style-insensitive`:idx: `manual.html#118 `_ + `sub`:idx: + `xmlgen.html#168 `_ + `subrange`:idx: * `manual.html#149 `_ * `tut1.html#115 `_ @@ -4197,15 +4513,27 @@ Index `sum`:idx: `math.html#110 `_ + `sup`:idx: + `xmlgen.html#169 `_ + `swap`:idx: `system.html#419 `_ + `symbol`:idx: + `macros.html#125 `_ + + `symbol=`:idx: + `macros.html#131 `_ + `syscall`:idx: `manual.html#171 `_ `system`:idx: `manual.html#218 `_ + `table`:idx: + `xmlgen.html#170 `_ + `tabulator`:idx: `manual.html#125 `_ @@ -4227,6 +4555,9 @@ Index `Tbind_destructor_func`:idx: `sqlite3.html#183 `_ + `tbody`:idx: + `xmlgen.html#171 `_ + `TCfgEvent`:idx: `parsecfg.html#102 `_ @@ -4254,6 +4585,12 @@ Index `Tcreate_function_step_func`:idx: `sqlite3.html#184 `_ + `TCsvParser`:idx: + `parsecsv.html#104 `_ + + `TCsvRow`:idx: + `parsecsv.html#103 `_ + `TCurl`:idx: `libcurl.html#140 `_ @@ -4407,12 +4744,18 @@ Index `Tcurl_write_callback`:idx: `libcurl.html#143 `_ + `td`:idx: + `xmlgen.html#172 `_ + `template`:idx: `manual.html#209 `_ `TEndian`:idx: `system.html#385 `_ + `textarea`:idx: + `xmlgen.html#173 `_ + `TFile`:idx: `system.html#481 `_ @@ -4428,6 +4771,9 @@ Index `TFloatClass`:idx: `math.html#103 `_ + `tfoot`:idx: + `xmlgen.html#174 `_ + `TForegroundColor`:idx: `terminal.html#113 `_ @@ -4437,9 +4783,15 @@ Index `TGC_Strategy`:idx: `system.html#464 `_ + `th`:idx: + `xmlgen.html#175 `_ + `THash`:idx: `hashes.html#101 `_ + `thead`:idx: + `xmlgen.html#176 `_ + `TimeInfoToTime`:idx: `times.html#108 `_ @@ -4449,9 +4801,30 @@ Index `TIMESTAMP_FLAG`:idx: `mysql.html#134 `_ + `title`:idx: + `xmlgen.html#177 `_ + `TMonth`:idx: `times.html#101 `_ + `TNimNodeKinds`:idx: + `macros.html#103 `_ + + `TNimrodNodeKind`:idx: + `macros.html#102 `_ + + `TNimrodSymKind`:idx: + `macros.html#106 `_ + + `TNimrodTypeKind`:idx: + `macros.html#104 `_ + + `TNimSymKinds`:idx: + `macros.html#107 `_ + + `TNimTypeKinds`:idx: + `macros.html#105 `_ + `toBiggestFloat`:idx: `system.html#401 `_ @@ -4490,6 +4863,9 @@ Index `toString`:idx: `strutils.html#147 `_ + `toStrLit`:idx: + `macros.html#146 `_ + `toTitle`:idx: `unicode.html#108 `_ @@ -4513,6 +4889,9 @@ Index `TPathComponent`:idx: `os.html#152 `_ + `tr`:idx: + `xmlgen.html#178 `_ + `traced`:idx: * `manual.html#159 `_ * `tut1.html#121 `_ @@ -4529,6 +4908,9 @@ Index `TRune16`:idx: `unicode.html#102 `_ + `TRunningStat`:idx: + `math.html#133 `_ + `try`:idx: * `manual.html#185 `_ * `tut2.html#107 `_ @@ -4560,6 +4942,9 @@ Index `TStyle`:idx: `terminal.html#111 `_ + `tt`:idx: + `xmlgen.html#179 `_ + `TTime`:idx: `times.html#103 `_ @@ -4584,6 +4969,12 @@ Index `TXmlParser`:idx: `parsexml.html#106 `_ + `typ`:idx: + `macros.html#127 `_ + + `typ=`:idx: + `macros.html#133 `_ + `type`:idx: * `manual.html#102 `_ * `manual.html#140 `_ @@ -4611,6 +5002,9 @@ Index `UDF_INIT`:idx: `mysql.html#263 `_ + `ul`:idx: + `xmlgen.html#180 `_ + `unchecked runtime error`:idx: `manual.html#111 `_ @@ -4660,11 +5054,17 @@ Index `mysql.html#112 `_ `validateData`:idx: - `cgi.html#108 `_ + `cgi.html#109 `_ `validEmailAddress`:idx: `strutils.html#157 `_ + `validIdentifier`:idx: + `strutils.html#158 `_ + + `var`:idx: + `xmlgen.html#181 `_ + `Var`:idx: `manual.html#178 `_ @@ -4672,7 +5072,8 @@ Index `nimrodc.html#106 `_ `variance`:idx: - `math.html#112 `_ + * `math.html#112 `_ + * `math.html#135 `_ `variant`:idx: * `manual.html#156 `_ @@ -4694,6 +5095,7 @@ Index `warning`:idx: * `manual.html#220 `_ * `manual.html#226 `_ + * `macros.html#139 `_ `when`:idx: * `manual.html#182 `_ @@ -4726,7 +5128,7 @@ Index `system.html#509 `_ `writeContentType`:idx: - `cgi.html#142 `_ + `cgi.html#143 `_ `writeln`:idx: * `system.html#502 `_ @@ -4736,7 +5138,11 @@ Index `terminal.html#112 `_ `XML`:idx: - `parsexml.html#101 `_ + * `parsexml.html#101 `_ + * `xmlgen.html#101 `_ + + `xmlCheckedTag`:idx: + `xmlgen.html#106 `_ `XMLencode`:idx: `cgi.html#103 `_ diff --git a/doc/tut2.txt b/doc/tut2.txt index 0bea28a8f..6d2fd3094 100644 --- a/doc/tut2.txt +++ b/doc/tut2.txt @@ -396,7 +396,7 @@ is not executed (if an exception occurs). Generics ======== -`Version 0.7.6: Complex generic types like in the example do not work.`:red: +`Version 0.7.8: Complex generic types like in the example do not work.`:red: `Generics`:idx: are Nimrod's means to parametrize procs, iterators or types with `type parameters`:idx:. They are most useful for efficient type safe @@ -596,7 +596,8 @@ Nimrod's syntax is flexible enough anyway. `Macros`:idx: can be used to implement `domain specific languages`:idx:. To write macros, one needs to know how the Nimrod concrete syntax is converted -to an abstract syntax tree (AST). (Unfortunately the AST is not documented yet.) +to an abstract syntax tree (AST). The AST is documented in the +`macros `_ module. There are two ways to invoke a macro: (1) invoking a macro like a procedure call (`expression macros`:idx:) diff --git a/examples/hallo.nim b/examples/hallo.nim index 73ef2cb95..20aa4695c 100644 --- a/examples/hallo.nim +++ b/examples/hallo.nim @@ -1,7 +1,3 @@ # Hallo world program -import strutils - -echo($(parseFloat("0.5")* toFloat(5000) / toFloat(parseInt("5000")))) - -echo("Hallo world!") +echo "Hallo world!" diff --git a/examples/htmlrefs.nim b/examples/htmlrefs.nim index cf1b3be28..b1695ee7a 100644 --- a/examples/htmlrefs.nim +++ b/examples/htmlrefs.nim @@ -1,7 +1,6 @@ # Example program to show the new parsexml module # This program reads an HTML file and writes all its used links to stdout. # Errors and whitespace are ignored. -# (c) 2009 Andreas Rumpf import os, streams, parsexml, strutils @@ -15,7 +14,7 @@ if paramCount() < 1: var links = 0 # count the number of links var filename = appendFileExt(ParamStr(1), "html") var s = newFileStream(filename, fmRead) -if s == nil: quit("cannot open the file" & filename) +if s == nil: quit("cannot open the file " & filename) var x: TXmlParser open(x, s, filename) next(x) # get first event diff --git a/examples/htmltitle.nim b/examples/htmltitle.nim index 6cdfd90eb..ae023e379 100644 --- a/examples/htmltitle.nim +++ b/examples/htmltitle.nim @@ -1,7 +1,6 @@ # Example program to show the new parsexml module # This program reads an HTML file and writes its title to stdout. # Errors and whitespace are ignored. -# (c) 2009 Andreas Rumpf import os, streams, parsexml, strutils @@ -10,7 +9,7 @@ if paramCount() < 1: var filename = appendFileExt(ParamStr(1), "html") var s = newFileStream(filename, fmRead) -if s == nil: quit("cannot open the file" & filename) +if s == nil: quit("cannot open the file " & filename) var x: TXmlParser open(x, s, filename) while true: diff --git a/examples/statcsv.nim b/examples/statcsv.nim new file mode 100644 index 000000000..9c1ebd113 --- /dev/null +++ b/examples/statcsv.nim @@ -0,0 +1,60 @@ +# Example program to show the parsecsv module +# This program reads a CSV file and computes sum, mean, minimum, maximum and +# the standard deviation of its columns. +# The CSV file can have a header which is then used for the output. + +import os, streams, parsecsv, strutils, math + +if paramCount() < 1: + quit("Usage: sumcsv filename[.csv]") + +var filename = appendFileExt(ParamStr(1), "csv") +var s = newFileStream(filename, fmRead) +if s == nil: quit("cannot open the file " & filename) + +var + x: TCsvParser + header: seq[string] + res: seq[TRunningStat] +open(x, s, filename, separator=';', skipInitialSpace = true) +while readRow(x): + if processedRows(x) == 1: + newSeq(res, x.row.len) # allocate space for the result + if validIdentifier(x.row[0]): + # header line: + header = x.row + else: + newSeq(header, x.row.len) + for i in 0..x.row.len-1: header[i] = "Col " & $(i+1) + else: + # data line: + for i in 0..x.row.len-1: + push(res[i], parseFloat(x.row[i])) +x.close() + +# Write results: +for i in 0..header.len-1: + stdout.write("\t") + stdout.write(header[i]) +stdout.write("\nSum") +for i in 0..header.len-1: + stdout.write("\t") + stdout.write(res[i].sum) +stdout.write("\nMean") +for i in 0..header.len-1: + stdout.write("\t") + stdout.write(res[i].mean) +stdout.write("\nMin") +for i in 0..header.len-1: + stdout.write("\t") + stdout.write(res[i].min) +stdout.write("\nMax") +for i in 0..header.len-1: + stdout.write("\t") + stdout.write(res[i].max) +stdout.write("\nStdDev") +for i in 0..header.len-1: + stdout.write("\t") + stdout.write(res[i].standardDeviation) +stdout.write("\n") + diff --git a/ide/nimide.nim b/ide/nimide.nim index 671405bbc..741f71afb 100644 --- a/ide/nimide.nim +++ b/ide/nimide.nim @@ -26,14 +26,14 @@ type currTab: int PEditor = ptr TEditor -proc on_window_destroy(obj: PGtkObject, event: PGdkEvent, - data: pointer): gboolean {.cdecl.} = - gtk_main_quit() +proc onWindowDestroy(obj: PGtkObject, event: PGdkEvent, + data: pointer): gboolean {.cdecl.} = + gtkMainQuit() -proc on_about_menu_item_activate(menuItem: PGtkMenuItem, e: PEditor) {.cdecl.} = - gtk_show_about_dialog(e.window, +proc onAboutMenuItemActivate(menuItem: PGtkMenuItem, e: PEditor) {.cdecl.} = + gtkShowAboutDialog(e.window, "comments", "A fast and leight-weight IDE for Nimrod", - "copyright", "Copyright \xc2\xa9 2008 Andreas Rumpf", + "copyright", "Copyright \xc2\xa9 2009 Andreas Rumpf", "version", "0.1", "website", "http://nimrod.ethexor.com", "program-name", "Nimrod IDE", @@ -42,9 +42,9 @@ proc on_about_menu_item_activate(menuItem: PGtkMenuItem, e: PEditor) {.cdecl.} = proc getTabIndex(e: PEditor, tab: PTab): int = var i = 0 while true: - var w = gtk_notebook_get_nth_page(e.notebook, i) + var w = gtkNotebookGetNthPage(e.notebook, i) if w == nil: return -1 - var v = gtk_notebook_get_tab_label(e.notebook, w) + var v = gtkNotebookGetTabLabel(e.notebook, w) if tab.hbox == v: return i inc(i) @@ -56,12 +56,11 @@ type answerYes, answerNo, answerCancel proc askWhetherToSave(e: PEditor): TAnswer = - var dialog = gtk_dialog_new_with_buttons("Should the changes be saved?", - e.window, GTK_DIALOG_MODAL, GTK_STOCK_SAVE, 1, - "gtk-discard", 2, - GTK_STOCK_CANCEL, 3, nil) - result = TAnswer(gtk_dialog_run(dialog)+1) - gtk_widget_destroy(dialog) + var dialog = gtkDialogNewWithButtons("Should the changes be saved?", + e.window, GTK_DIALOG_MODAL, GTK_STOCK_SAVE, 1, "gtk-discard", 2, + GTK_STOCK_CANCEL, 3, nil) + result = TAnswer(gtkDialogRun(dialog)+1) + gtkWidgetDestroy(dialog) proc saveTab(tab: PTab) = if tab.untitled: @@ -76,13 +75,13 @@ proc OnCloseTab(button: PGtkButton, tab: PTab) {.cdecl.} = idx = i break if idx >= 0: - if gtk_text_buffer_get_modified(gtk_text_view_get_buffer(tab.textView)): + if gtkTextBufferGetModified(gtkTextViewGetBuffer(tab.textView)): case askWhetherToSave(tab.e) of answerCancel: return of answerYes: saveTab(tab) of answerNo: nil - gtk_notebook_remove_page(tab.e.notebook, idx) + gtkNotebookRemovePage(tab.e.notebook, idx) if idx < high(tab.e.tabs): for i in idx..high(tab.e.tabs)-1: tab.e.tabs[i] = tab.e.tabs[i+1] @@ -95,95 +94,96 @@ proc OnCloseTab(button: PGtkButton, tab: PTab) {.cdecl.} = proc createTab(e: PEditor, filename: string, untitled: bool) = var t = cast[PTab](alloc0(sizeof(TTab))) - t.textview = gtk_text_view_new_with_buffer(gtk_text_buffer_new(nil)) - var font_desc = pango_font_description_from_string("monospace 10") - gtk_widget_modify_font(t.textview, font_desc) - pango_font_description_free(font_desc) + t.textview = gtkTextViewNewWithBuffer(gtkTextBufferNew(nil)) + var fontDesc = pangoFontDescriptionFromString("monospace 10") + gtkWidgetModifyFont(t.textview, fontDesc) + pangoFontDescriptionFree(fontDesc) t.filename = filename t.untitled = untitled - gtk_widget_show(t.textview) - var scroll = gtk_scrolled_window_new(nil, nil) - gtk_container_add(scroll, t.textview) - gtk_widget_show(scroll) + gtkWidgetShow(t.textview) + var scroll = gtkScrolledWindowNew(nil, nil) + gtkContainerAdd(scroll, t.textview) + gtkWidgetShow(scroll) t.e = e - t.hbox = gtk_hbox_new(false, 0) - var image = gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU) - var button = gtk_button_new() - var lab = gtk_label_new(filename) - gtk_button_set_image(button, image) - gtk_button_set_relief(button, GTK_RELIEF_NONE) - gtk_box_pack_start(t.hbox, lab, false, false, 2) - gtk_box_pack_end(t.hbox, button, false, false, 0) + t.hbox = gtkHboxNew(false, 0) + var image = gtkImageNewFromStock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU) + var button = gtkButtonNew() + var lab = gtkLabelNew(filename) + gtkButtonSetImage(button, image) + gtkButtonSetRelief(button, GTK_RELIEF_NONE) + gtkBoxPackStart(t.hbox, lab, false, false, 2) + gtkBoxPackEnd(t.hbox, button, false, false, 0) - discard g_signal_connect(button, "clicked", G_Callback(onCloseTab), t) - gtk_widget_show(button) - gtk_widget_show(lab) + discard gSignalConnect(button, "clicked", G_Callback(onCloseTab), t) + gtkWidgetShow(button) + gtkWidgetShow(lab) - var idx = gtk_notebook_append_page(e.notebook, scroll, t.hbox) + var idx = gtkNotebookAppendPage(e.notebook, scroll, t.hbox) e.currTab = idx add(e.tabs, t) - gtk_notebook_set_current_page(e.notebook, idx) + gtkNotebookSetCurrentPage(e.notebook, idx) -proc on_open_menu_item_activate(menuItem: PGtkMenuItem, e: PEditor) {.cdecl.} = +proc onOpenMenuItemActivate(menuItem: PGtkMenuItem, e: PEditor) {.cdecl.} = var files = ChooseFilesToOpen(e.window, getRoot(getActiveTab(e))) for f in items(files): createTab(e, f, untitled=false) -proc on_save_menu_item_activate(menuItem: PGtkMenuItem, e: PEditor) {.cdecl.} = - var cp = gtk_notebook_get_current_page(e.notebook) +proc onSaveMenuItemActivate(menuItem: PGtkMenuItem, e: PEditor) {.cdecl.} = + var cp = gtkNotebookGetCurrentPage(e.notebook) -proc on_save_as_menu_item_activate(menuItem: PGtkMenuItem, e: PEditor) {.cdecl.} = +proc onSaveAsMenuItemActivate(menuItem: PGtkMenuItem, e: PEditor) {.cdecl.} = nil -proc on_new_menu_item_activate(menuItem: PGtkMenuItem, e: PEditor) {.cdecl.} = +proc onNewMenuItemActivate(menuItem: PGtkMenuItem, e: PEditor) {.cdecl.} = inc(e.tabname) createTab(e, "untitled-" & $e.tabname, true) proc main(e: PEditor) = - var builder = glade_xml_new(getApplicationDir() / GuiTemplate, nil, nil) + var builder = gladeXmlNew(getApplicationDir() / GuiTemplate, nil, nil) if builder == nil: quit("cannot open: " & GuiTemplate) # get the components: - e.window = GTK_WINDOW(glade_xml_get_widget(builder, "window")) - e.statusbar = GTK_STATUSBAR(glade_xml_get_widget(builder, "statusbar")) - e.notebook = GTK_NOTEBOOK(glade_xml_get_widget(builder, "notebook")) + e.window = GTK_WINDOW(gladeXmlGetWidget(builder, "window")) + e.statusbar = GTK_STATUSBAR(gladeXmlGetWidget(builder, "statusbar")) + e.notebook = GTK_NOTEBOOK(gladeXmlGetWidget(builder, "notebook")) e.tabs = @[] e.currTab = -1 setHomogeneous(e.notebook^, 1) # connect the signal handlers: - glade_xml_signal_connect(builder, "on_window_destroy", - GCallback(on_window_destroy)) - var about = GTK_MENU_ITEM(glade_xml_get_widget(builder, "about_menu_item")) - discard g_signal_connect(about, "activate", - G_CALLBACK(on_about_menu_item_activate), e) + gladeXmlSignalConnect(builder, "on_window_destroy", + GCallback(onWindowDestroy)) + var about = GTK_MENU_ITEM(gladeXmlGetWidget(builder, "about_menu_item")) + discard gSignalConnect(about, "activate", + G_CALLBACK(onAboutMenuItemActivate), e) - var newItem = GTK_MENU_ITEM(glade_xml_get_widget(builder, "new_menu_item")) - discard g_signal_connect(newItem, "activate", - G_CALLBACK(on_new_menu_item_activate), e) + var newItem = GTK_MENU_ITEM(gladeXmlGetWidget(builder, "new_menu_item")) + discard gSignalConnect(newItem, "activate", + G_CALLBACK(onNewMenuItemActivate), e) - var quitItem = GTK_MENU_ITEM(glade_xml_get_widget(builder, "quit_menu_item")) - discard g_signal_connect(quitItem, "activate", - G_CALLBACK(on_window_destroy), e) + var quitItem = GTK_MENU_ITEM(gladeXmlGetWidget(builder, "quit_menu_item")) + discard gSignalConnect(quitItem, "activate", + G_CALLBACK(onWindowDestroy), e) - var openItem = GTK_MENU_ITEM(glade_xml_get_widget(builder, "open_menu_item")) - discard g_signal_connect(openItem, "activate", - G_CALLBACK(on_open_menu_item_activate), e) + var openItem = GTK_MENU_ITEM(gladeXmlGetWidget(builder, "open_menu_item")) + discard gSignalConnect(openItem, "activate", + G_CALLBACK(onOpenMenuItemActivate), e) - var saveItem = GTK_MENU_ITEM(glade_xml_get_widget(builder, "save_menu_item")) - discard g_signal_connect(saveItem, "activate", - G_CALLBACK(on_save_menu_item_activate), e) + var saveItem = GTK_MENU_ITEM(gladeXmlGetWidget(builder, "save_menu_item")) + discard gSignalConnect(saveItem, "activate", + G_CALLBACK(onSaveMenuItemActivate), e) - var saveAsItem = GTK_MENU_ITEM(glade_xml_get_widget(builder, "save_as_menu_item")) - discard g_signal_connect(saveAsItem, "activate", - G_CALLBACK(on_save_as_menu_item_activate), e) + var saveAsItem = GTK_MENU_ITEM(gladeXmlGetWidget(builder, "save_as_menu_item")) + discard gSignalConnect(saveAsItem, "activate", + G_CALLBACK(onSaveAsMenuItemActivate), e) - gtk_window_set_default_icon_name(GTK_STOCK_EDIT) - gtk_widget_show(e.window) - gtk_main() + gtkWindowSetDefaultIconName(GTK_STOCK_EDIT) + gtkWidgetShow(e.window) + gtkMain() -gtk_nimrod_init() +gtkNimrodInit() var e = cast[PEditor](alloc0(sizeof(TEditor))) main(e) + diff --git a/install.txt b/install.txt index 568c54282..a5aef4cbe 100644 --- a/install.txt +++ b/install.txt @@ -1,66 +1,67 @@ -Installation -============ - - -Installation on Linux/UNIX --------------------------- - -Note: - A C compiler is required - knowledge of C is not! - -The GNU C Compiler is fully supported, other compilers may work. The C compiler -should be in your ``$PATH`` (most likely the case). Note that some few Linux -distributions do not ship with a GCC compiler preinstalled - then you have to -install it. - -Install Nimrod by downloading the appropriate ``.zip`` file and extracting it -to a directory of your choice. The Nimrod Compiler will stay in this -directory (unless you copy it somewhere else). The compiler does not need -write access to its directory anymore, so copying the nimrod folder to ``/opt`` -does work. - -Then run the following command:: - - sh build.sh - -Unlike other software, Nimrod does not distribute its files over the whole file -hierarchy. This has the advantage that you can deinstall it by just deleting -its folder. The disadvantage is that you have to add it to your ``PATH`` -manually. An alternative is to create a symbolic link in ``/usr/bin``:: - - [sudo] ln -s $your_install_dir/bin/nimrod /usr/bin/nimrod - - -Installation on the Macintosh ------------------------------ - -Only MacOS X is supported. -Since MacOS X is UNIX based too, it works like the installation on Linux. You -need to install Apple's developer's tools for the GNU Compiler Collection -though. - - -Installation on Windows ------------------------ - -Install Nimrod by downloading and running -the ``nimrod_$version.exe`` file. As default, the ``LLVM-GCC`` -compiler is used that is bundled with this installer. You can change -the configuration file to use another C compiler. - -Currently, the following C compilers are supported under Windows: - -- | Microsoft's Visual C++ - | http://msdn.microsoft.com/visualc - | (You need the SDK too - but not the full one: Essential are only - the win32api header files and import libraries.) -- | Gnu C Compiler (the mingw version; the cygwin version has not been tested!) - | http://www.mingw.org/download.shtml -- | LLVM with GNU C/C++ frontend - | http://llvm.org/releases/download.html#2.2 -- | Digital Mars C++ - | http://www.digitalmars.com/download/freecompiler.html - -For better compile times I recommend Digital Mars C++ -- it is easy to install -and a small package. - +Installation +============ + + +Installation on Linux/UNIX +-------------------------- + +Note: + A C compiler is required - knowledge of C is not! + +The GNU C Compiler is fully supported, other compilers may work. The C compiler +should be in your ``$PATH`` (most likely the case). Note that some few Linux +distributions do not ship with a GCC compiler preinstalled - then you have to +install it. + +Install Nimrod by downloading the appropriate ``.zip`` file and extracting it +to a directory of your choice. The Nimrod Compiler will stay in this +directory (unless you copy it somewhere else). The compiler does not need +write access to its directory, so copying the nimrod folder to ``/opt`` +does work. + +Then run the following command:: + + sh build.sh + +Unlike other software, Nimrod does not distribute its files over the whole file +hierarchy. This has the advantage that you can deinstall it by just deleting +its folder. The disadvantage is that you have to add it to your ``PATH`` +manually. An alternative is to create a symbolic link in ``/usr/bin``:: + + [sudo] ln -s $your_install_dir/bin/nimrod /usr/bin/nimrod + + +Installation on the Macintosh +----------------------------- + +Only MacOS X is supported. +Since MacOS X is UNIX based too, it works like the installation on Linux. You +need to install Apple's developer's tools for the GNU Compiler Collection +though. + + +Installation on Windows +----------------------- + +Install Nimrod by downloading and running +the ``nimrod_$version.exe`` file. As default, the ``GCC`` +compiler is used that is bundled with this installer. **You can change +the configuration file** ``config/nimrod.cfg`` **to use another C compiler +or change the path to GCC.** + +Currently, the following C compilers are supported under Windows: + +- | Microsoft's Visual C++ + | http://msdn.microsoft.com/visualc + | (You need the SDK too - but not the full one: Only + the win32api header files and import libraries are essential.) +- | Gnu C Compiler (the mingw version; the cygwin version has not been tested!) + | http://www.mingw.org/download.shtml +- | LLVM with GNU C/C++ frontend + | http://llvm.org/releases/download.html#2.2 +- | Digital Mars C++ + | http://www.digitalmars.com/download/freecompiler.html + +For better compile times I recommend Digital Mars C++ -- it is easy to install +and a small package. + diff --git a/koch.py b/koch.py index 5b6cf8cff..6fcb1336d 100644 --- a/koch.py +++ b/koch.py @@ -12,7 +12,7 @@ from pycompab import * # --------------------- constants ---------------------------------------- -NIMROD_VERSION = '0.7.6' +NIMROD_VERSION = '0.7.8' # This string contains Nimrod's version. It is the only place # where the version needs to be updated. The rest is done by # the build process automatically. It is replaced **everywhere**! @@ -34,6 +34,46 @@ USE_FPC = true BOOTCMD = "$1 cc --compile:build/platdef.c $2 rod/nimrod.nim" # the command used for bootstrapping +# ---------------------- compiler detection -------------------------------- + +def detect(cmd, lookFor="version"): + try: + pipe = os.popen4(cmd)[1] + except AttributeError: + pipe = os.popen(cmd) + result = None + for line in pipe.readlines(): + if find(lower(line), lookFor) >= 0: + result = line[:-1] + break + pipe.close() + if not result: + # don't give up yet; it may have written to stderr + if os.system(cmd) == 0: + result = cmd + return result + +def detectNimrod(): + if detect("nimrod"): + return "nimrod" + elif detect("bin/nimrod"): + return "bin/nimrod" + else: + Error("could not find a working nimrod executable") + +def detectNim(): + if USE_FPC and detect("fpc -h"): + # workaround a bug in the macosx version of nim: + if getHost() == "macosx": return "nim" + else: return "bin/nim" + return detectNimrod() + +def detectAndCompileNim(): + result = detectNim() + if result == "bin/nim" or result == "nim": + cmd_nim() + return result + # -------------------------------------------------------------------------- def Error(msg): sys.exit("[Koch] *** ERROR: " + msg) @@ -453,12 +493,8 @@ def genBootDiff(genA, genB): def cmd_rodsrc(): "converts the src/*.pas files into Nimrod syntax" - PAS_FILES_BLACKLIST = split("""nsystem nmath nos ntime strutils""") - if USE_FPC and detect("fpc -h"): - cmd_nim() - compiler = "nim" - else: - compiler = "nimrod" + PAS_FILES_BLACKLIST = split("""nsystem nmath nos osproc ntime strutils""") + compiler = detectAndCompileNim() CMD = "$1 boot --skip_proj_cfg -o:rod/$2.nim nim/$3" result = false for fi in Glob("nim/*.pas"): @@ -484,14 +520,7 @@ def cmd_boot(args): Move(ExeExt("rod/nimcache/nimrod"), ExeExt("rod/nimrod")) writePlatdefC(getNimrodPath()) - d = detect("fpc -h") - if USE_FPC and d: - Echo(Subs("'$1' detected", d)) - cmd_nim() - compiler = "nim" - else: - compiler = "nimrod" - + compiler = detectAndCompileNim() cmd_rodsrc() # regenerate nimrod version of the files # move the new executable to bin directory (is done by cmd_rod()) @@ -501,7 +530,7 @@ def cmd_boot(args): # move the new executable to bin directory: moveExes() # compile again and compare: - myExec("nimrod") + myExec("bin/nimrod") # here we always use the new executable genB = readCFiles() # second generation of generated C files diff = genBootDiff(genA, genB) if diff: @@ -517,7 +546,7 @@ def cmd_boot(args): # move the new executable to bin directory: moveExes() # use the new executable to compile Nimrod: - myExec("nimrod") + myExec("bin/nimrod") if SameFileContent(Path(ExeExt("rod/nimrod")), Path(ExeExt("bin/nimrod"))): Echo("executables are equal: SUCCESS!") @@ -614,23 +643,6 @@ def writePlatdefC(nimrodpath): '\n', host, processor)) f.close() -def detect(cmd, lookFor="version"): - try: - pipe = os.popen4(cmd)[1] - except AttributeError: - pipe = os.popen(cmd) - result = None - for line in pipe.readlines(): - if find(lower(line), lookFor) >= 0: - result = line[:-1] - break - pipe.close() - if not result: - # don't give up yet; it may have written to stderr - if os.system(cmd) == 0: - result = cmd - return result - def getNimrodPath(): if os.name == "posix": # Does not work 100% reliably. It is the best solution though. diff --git a/lib/alloc.nim b/lib/alloc.nim index 8648b322a..e4d828449 100644 --- a/lib/alloc.nim +++ b/lib/alloc.nim @@ -7,29 +7,27 @@ # distribution, for details about the copyright. # -# Low level allocator for Nimrod. +# Low level allocator for Nimrod. Has been designed to support the GC. # TODO: # - eliminate "used" field # - make searching for block O(1) -proc raiseOutOfMem {.noinline.} = - assert false - quit(1) - # ------------ platform specific chunk allocation code ----------------------- when defined(posix): - const # XXX: make these variables for portability? + const PROT_READ = 1 # page can be read PROT_WRITE = 2 # page can be written MAP_PRIVATE = 2 # Changes are private - when defined(linux): + when defined(linux) or defined(aix): const MAP_ANONYMOUS = 0x20 # don't use a file - elif defined(macosx): + elif defined(macosx) or defined(bsd): const MAP_ANONYMOUS = 0x1000 + elif defined(solaris): + const MAP_ANONYMOUS = 0x100 else: - const MAP_ANONYMOUS = 0 # other operating systems may not know about this + {.error: "Port memory manager to your platform".} proc mmap(adr: pointer, len: int, prot, flags, fildes: cint, off: int): pointer {.header: "".} @@ -43,7 +41,7 @@ when defined(posix): raiseOutOfMem() proc osDeallocPages(p: pointer, size: int) {.inline} = - munmap(p, size) + when reallyOsDealloc: munmap(p, size) elif defined(windows): const @@ -69,7 +67,7 @@ elif defined(windows): proc osDeallocPages(p: pointer, size: int) {.inline.} = # according to Microsoft, 0 is the only correct value here: - VirtualFree(p, 0, MEM_RELEASE) + when reallyOsDealloc: VirtualFree(p, 0, MEM_RELEASE) else: {.error: "Port memory manager to your platform".} @@ -77,48 +75,14 @@ else: # --------------------- end of non-portable code ----------------------------- # We manage *chunks* of memory. Each chunk is a multiple of the page size. -# The page size may or may not the operating system's page size. Each chunk -# starts at an address that is divisible by the page size. Chunks that are -# bigger than ``ChunkOsReturn`` are returned back to the operating system -# immediately. - - -# Guess the page size of the system; if it is the -# wrong value, performance may be worse (this is not -# for sure though), but GC still works; must be a power of two! -when defined(linux) or defined(windows) or defined(macosx): - const - PageShift = 12 - PageSize = 1 shl PageShift # on 32 bit systems 4096 -else: - {.error: "unkown page size".} +# Each chunk starts at an address that is divisible by the page size. Chunks +# that are bigger than ``ChunkOsReturn`` are returned back to the operating +# system immediately. const - PageMask = PageSize-1 - - SmallChunkSize = PageSize # * 4 - - MemAlign = 8 # minimal memory block that can be allocated - - BitsPerPage = PageSize div MemAlign - UnitsPerPage = BitsPerPage div (sizeof(int)*8) - # how many ints do we need to describe a page: - # on 32 bit systems this is only 16 (!) - - ChunkOsReturn = 64 * PageSize + ChunkOsReturn = 256 * PageSize InitialMemoryRequest = ChunkOsReturn div 2 # < ChunkOsReturn! - - # Compile time options: - coalescRight = true - coalescLeft = true - -const - TrunkShift = 9 - BitsPerTrunk = 1 shl TrunkShift # needs to be a power of 2 and divisible by 64 - TrunkMask = BitsPerTrunk - 1 - IntsPerTrunk = BitsPerTrunk div (sizeof(int)*8) - IntShift = 5 + ord(sizeof(int) == 8) # 5 or 6, depending on int width - IntMask = 1 shl IntShift - 1 + SmallChunkSize = PageSize type PTrunk = ptr TTrunk @@ -132,10 +96,11 @@ type data: TTrunkBuckets type - TAlignType = float + TAlignType = biggestFloat TFreeCell {.final, pure.} = object next: ptr TFreeCell # next free cell in chunk (overlaid with refcount) - zeroField: pointer # nil means cell is not used (overlaid with typ field) + zeroField: int # 0 means cell is not used (overlaid with typ field) + # 1 means cell is manually managed pointer PChunk = ptr TBaseChunk PBigChunk = ptr TBigChunk @@ -155,15 +120,20 @@ type TBigChunk = object of TBaseChunk # not necessarily > PageSize! next: PBigChunk # chunks of the same (or bigger) size prev: PBigChunk + align: int data: TAlignType # start of usable memory template smallChunkOverhead(): expr = sizeof(TSmallChunk)-sizeof(TAlignType) template bigChunkOverhead(): expr = sizeof(TBigChunk)-sizeof(TAlignType) -proc roundup(x, v: int): int {.inline.} = return ((-x) and (v-1)) +% x +proc roundup(x, v: int): int {.inline.} = + result = (x + (v-1)) and not (v-1) + assert(result >= x) + #return ((-x) and (v-1)) +% x assert(roundup(14, PageSize) == PageSize) assert(roundup(15, 8) == 16) +assert(roundup(65, 8) == 72) # ------------- chunk table --------------------------------------------------- # We use a PtrSet of chunk starts and a table[Page, chunksize] for chunk @@ -180,7 +150,7 @@ type TAllocator {.final, pure.} = object llmem: PLLChunk - currMem, maxMem: int # currently and maximum used memory size (allocated from OS) + currMem, maxMem, freeMem: int # memory sizes (allocated from OS) freeSmallChunks: array[0..SmallChunkSize div MemAlign-1, PSmallChunk] freeChunksList: PBigChunk # XXX make this a datastructure with O(1) access chunkStarts: TIntSet @@ -277,8 +247,10 @@ var lastSize = PageSize proc requestOsChunks(a: var TAllocator, size: int): PBigChunk = incCurrMem(a, size) + inc(a.freeMem, size) result = cast[PBigChunk](osAllocPages(size)) assert((cast[TAddress](result) and PageMask) == 0) + #zeroMem(result, size) result.next = nil result.prev = nil result.used = false @@ -312,11 +284,28 @@ proc freeOsChunks(a: var TAllocator, p: pointer, size: int) = excl(a.chunkStarts, pageIndex(p)) osDeallocPages(p, size) decCurrMem(a, size) + dec(a.freeMem, size) + #c_fprintf(c_stdout, "[Alloc] back to OS: %ld\n", size) proc isAccessible(p: pointer): bool {.inline.} = result = Contains(allocator.chunkStarts, pageIndex(p)) +proc contains[T](list, x: T): bool = + var it = list + while it != nil: + if it == x: return true + it = it.next + +proc writeFreeList(a: TAllocator) = + var it = a.freeChunksList + c_fprintf(c_stdout, "freeChunksList: %p\n", it) + while it != nil: + c_fprintf(c_stdout, "it: %p, next: %p, prev: %p\n", + it, it.next, it.prev) + it = it.next + proc ListAdd[T](head: var T, c: T) {.inline.} = + assert(c notin head) assert c.prev == nil assert c.next == nil c.next = head @@ -326,6 +315,7 @@ proc ListAdd[T](head: var T, c: T) {.inline.} = head = c proc ListRemove[T](head: var T, c: T) {.inline.} = + assert(c in head) if c == head: head = c.next assert c.prev == nil @@ -344,13 +334,22 @@ proc isSmallChunk(c: PChunk): bool {.inline.} = proc chunkUnused(c: PChunk): bool {.inline.} = result = not c.used +proc updatePrevSize(a: var TAllocator, c: PBigChunk, + prevSize: int) {.inline.} = + var ri = cast[PChunk](cast[TAddress](c) +% c.size) + assert((cast[TAddress](ri) and PageMask) == 0) + if isAccessible(ri): + ri.prevSize = prevSize + proc freeBigChunk(a: var TAllocator, c: PBigChunk) = var c = c assert(c.size >= PageSize) + inc(a.freeMem, c.size) when coalescRight: var ri = cast[PChunk](cast[TAddress](c) +% c.size) assert((cast[TAddress](ri) and PageMask) == 0) if isAccessible(ri) and chunkUnused(ri): + assert(not isSmallChunk(ri)) if not isSmallChunk(ri): ListRemove(a.freeChunksList, cast[PBigChunk](ri)) inc(c.size, ri.size) @@ -360,6 +359,7 @@ proc freeBigChunk(a: var TAllocator, c: PBigChunk) = var le = cast[PChunk](cast[TAddress](c) -% c.prevSize) assert((cast[TAddress](le) and PageMask) == 0) if isAccessible(le) and chunkUnused(le): + assert(not isSmallChunk(le)) if not isSmallChunk(le): ListRemove(a.freeChunksList, cast[PBigChunk](le)) inc(le.size, c.size) @@ -367,6 +367,8 @@ proc freeBigChunk(a: var TAllocator, c: PBigChunk) = c = cast[PBigChunk](le) if c.size < ChunkOsReturn: + incl(a.chunkStarts, pageIndex(c)) + updatePrevSize(a, c, c.size) ListAdd(a.freeChunksList, c) c.used = false else: @@ -374,11 +376,16 @@ proc freeBigChunk(a: var TAllocator, c: PBigChunk) = proc splitChunk(a: var TAllocator, c: PBigChunk, size: int) = var rest = cast[PBigChunk](cast[TAddress](c) +% size) + if rest in a.freeChunksList: + c_fprintf(c_stdout, "to add: %p\n", rest) + writeFreeList(allocator) + assert false rest.size = c.size - size rest.used = false - rest.next = nil # XXX + rest.next = nil rest.prev = nil rest.prevSize = size + updatePrevSize(a, c, rest.size) c.size = size incl(a.chunkStarts, pageIndex(rest)) ListAdd(a.freeChunksList, rest) @@ -386,26 +393,32 @@ proc splitChunk(a: var TAllocator, c: PBigChunk, size: int) = proc getBigChunk(a: var TAllocator, size: int): PBigChunk = # use first fit for now: assert((size and PageMask) == 0) + assert(size > 0) result = a.freeChunksList block search: while result != nil: + #if not chunkUnused(result): + # c_fprintf(c_stdout, "%lld\n", int(result.used)) assert chunkUnused(result) if result.size == size: ListRemove(a.freeChunksList, result) break search elif result.size > size: - splitChunk(a, result, size) + #c_fprintf(c_stdout, "res size: %lld; size: %lld\n", result.size, size) ListRemove(a.freeChunksList, result) + splitChunk(a, result, size) break search result = result.next + assert result != a.freeChunksList if size < InitialMemoryRequest: result = requestOsChunks(a, InitialMemoryRequest) splitChunk(a, result, size) else: result = requestOsChunks(a, size) - result.prevSize = 0 + result.prevSize = 0 # XXX why is this needed? result.used = true incl(a.chunkStarts, pageIndex(result)) + dec(a.freeMem, size) proc getSmallChunk(a: var TAllocator): PSmallChunk = var res = getBigChunk(a, PageSize) @@ -419,8 +432,11 @@ proc getCellSize(p: pointer): int {.inline.} = var c = pageAddr(p) result = c.size -proc alloc(a: var TAllocator, requestedSize: int): pointer = - var size = roundup(max(requestedSize, sizeof(TFreeCell)), MemAlign) +proc rawAlloc(a: var TAllocator, requestedSize: int): pointer = + assert(roundup(65, 8) == 72) + assert requestedSize >= sizeof(TFreeCell) + var size = roundup(requestedSize, MemAlign) + #c_fprintf(c_stdout, "alloc; size: %ld; %ld\n", requestedSize, size) if size <= SmallChunkSize-smallChunkOverhead(): # allocate a small block: for small chunks, we use only its next pointer var s = size div MemAlign @@ -436,8 +452,11 @@ proc alloc(a: var TAllocator, requestedSize: int): pointer = c.prev = nil ListAdd(a.freeSmallChunks[s], c) result = addr(c.data) + assert((cast[TAddress](result) and (MemAlign-1)) == 0) else: assert c.next != c + #if c.size != size: + # c_fprintf(c_stdout, "csize: %lld; size %lld\n", c.size, size) assert c.size == size if c.freeList == nil: assert(c.acc + smallChunkOverhead() + size <= SmallChunkSize) @@ -445,9 +464,10 @@ proc alloc(a: var TAllocator, requestedSize: int): pointer = inc(c.acc, size) else: result = c.freeList - assert(c.freeList.zeroField == nil) + assert(c.freeList.zeroField == 0) c.freeList = c.freeList.next dec(c.free, size) + assert((cast[TAddress](result) and (MemAlign-1)) == 0) if c.free < size: ListRemove(a.freeSmallChunks[s], c) else: @@ -458,16 +478,10 @@ proc alloc(a: var TAllocator, requestedSize: int): pointer = assert c.next == nil assert c.size == size result = addr(c.data) - cast[ptr TFreeCell](result).zeroField = cast[ptr TFreeCell](1) # make it != nil - #echo("setting to one: ", $cast[TAddress](addr(cast[ptr TFreeCell](result).zeroField))) + assert((cast[TAddress](result) and (MemAlign-1)) == 0) + assert(isAccessible(result)) -proc contains(list, x: PSmallChunk): bool = - var it = list - while it != nil: - if it == x: return true - it = it.next - -proc dealloc(a: var TAllocator, p: pointer) = +proc rawDealloc(a: var TAllocator, p: pointer) = var c = pageAddr(p) if isSmallChunk(c): # `p` is within a small chunk: @@ -475,8 +489,8 @@ proc dealloc(a: var TAllocator, p: pointer) = var s = c.size var f = cast[ptr TFreeCell](p) #echo("setting to nil: ", $cast[TAddress](addr(f.zeroField))) - assert(f.zeroField != nil) - f.zeroField = nil + assert(f.zeroField != 0) + f.zeroField = 0 f.next = c.freeList c.freeList = f # check if it is not in the freeSmallChunks[s] list: @@ -495,23 +509,64 @@ proc dealloc(a: var TAllocator, p: pointer) = # free big chunk freeBigChunk(a, cast[PBigChunk](c)) -proc realloc(a: var TAllocator, p: pointer, size: int): pointer = - # could be made faster, but this is unnecessary, the GC does not use it anyway - result = alloc(a, size) - copyMem(result, p, getCellSize(p)) - dealloc(a, p) - proc isAllocatedPtr(a: TAllocator, p: pointer): bool = if isAccessible(p): var c = pageAddr(p) if not chunkUnused(c): if isSmallChunk(c): - result = (cast[TAddress](p) -% cast[TAddress](c) -% - smallChunkOverhead()) %% c.size == 0 and - cast[ptr TFreeCell](p).zeroField != nil + var c = cast[PSmallChunk](c) + var offset = (cast[TAddress](p) and (PageSize-1)) -% + smallChunkOverhead() + result = (c.acc >% offset) and (offset %% c.size == 0) and + (cast[ptr TFreeCell](p).zeroField >% 1) else: var c = cast[PBigChunk](c) - result = p == addr(c.data) + result = p == addr(c.data) and cast[ptr TFreeCell](p).zeroField >% 1 + +# ---------------------- interface to programs ------------------------------- + +proc alloc(size: int): pointer = + result = rawAlloc(allocator, size+sizeof(TFreeCell)) + cast[ptr TFreeCell](result).zeroField = 1 # mark it as used + assert(not isAllocatedPtr(allocator, result)) + result = cast[pointer](cast[TAddress](result) +% sizeof(TFreeCell)) + +proc alloc0(size: int): pointer = + result = alloc(size) + zeroMem(result, size) + +proc dealloc(p: pointer) = + var x = cast[pointer](cast[TAddress](p) -% sizeof(TFreeCell)) + assert(cast[ptr TFreeCell](x).zeroField == 1) + rawDealloc(allocator, x) + assert(not isAllocatedPtr(allocator, x)) + +proc ptrSize(p: pointer): int = + var x = cast[pointer](cast[TAddress](p) -% sizeof(TFreeCell)) + result = pageAddr(x).size - sizeof(TFreeCell) + +proc realloc(p: pointer, newsize: int): pointer = + if newsize > 0: + result = alloc(newsize) + if p != nil: + copyMem(result, p, ptrSize(p)) + dealloc(p) + elif p != nil: + dealloc(p) + +proc countFreeMem(): int = + # only used for assertions + var it = allocator.freeChunksList + while it != nil: + inc(result, it.size) + it = it.next + +proc getFreeMem(): int = + result = allocator.freeMem + #assert(result == countFreeMem()) + +proc getTotalMem(): int = return allocator.currMem +proc getOccupiedMem(): int = return getTotalMem() - getFreeMem() when isMainModule: const iterations = 4000_000 diff --git a/lib/ansi_c.nim b/lib/ansi_c.nim index 8e39c9e39..81abd2a3e 100644 --- a/lib/ansi_c.nim +++ b/lib/ansi_c.nim @@ -1,7 +1,7 @@ # # # Nimrod's Runtime Library -# (c) Copyright 2006 Andreas Rumpf +# (c) Copyright 2009 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -82,3 +82,7 @@ proc c_ferror(stream: C_TextFileStar): bool {.importc: "ferror", nodecl.} proc c_fflush(stream: C_TextFileStar) {.importc: "fflush", nodecl.} proc c_abort() {.importc: "abort", nodecl.} proc c_feof(stream: C_TextFileStar): bool {.importc: "feof", nodecl.} + +proc c_malloc(size: int): pointer {.importc: "malloc", nodecl.} +proc c_free(p: pointer) {.importc: "free", nodecl.} +proc c_realloc(p: pointer, newsize: int): pointer {.importc: "realloc", nodecl.} diff --git a/lib/assign.nim b/lib/assign.nim index 17b4f5949..3d4bf4d61 100644 --- a/lib/assign.nim +++ b/lib/assign.nim @@ -43,12 +43,8 @@ proc genericAssign(dest, src: Pointer, mt: PNimType) = x^ = nil return assert(dest != nil) - when defined(boehmGC): - unsureAsgnRef(cast[ppointer](dest), - newObj(seq.len * mt.base.size + GenericSeqSize)) - else: - unsureAsgnRef(cast[ppointer](dest), - newObj(mt, seq.len * mt.base.size + GenericSeqSize)) + unsureAsgnRef(cast[ppointer](dest), + newObj(mt, seq.len * mt.base.size + GenericSeqSize)) var dst = cast[taddress](cast[ppointer](dest)^) for i in 0..seq.len-1: genericAssign( diff --git a/lib/base/cgi.nim b/lib/base/cgi.nim index 0dc3a4394..5cf6d0bfa 100644 --- a/lib/base/cgi.nim +++ b/lib/base/cgi.nim @@ -103,71 +103,77 @@ proc cgiError*(msg: string) {.noreturn.} = e.msg = msg raise e +proc getEncodedData(allowedMethods: set[TRequestMethod]): string = + case getenv("REQUEST_METHOD") + of "POST": + if methodPost notin allowedMethods: + cgiError("'REQUEST_METHOD' 'POST' is not supported") + var L = parseInt(getenv("CONTENT_LENGTH")) + result = newString(L) + if readBuffer(stdin, addr(result[0]), L) != L: + cgiError("cannot read from stdin") + of "GET": + if methodGet notin allowedMethods: + cgiError("'REQUEST_METHOD' 'GET' is not supported") + result = getenv("QUERY_STRING") + else: + if methodNone notin allowedMethods: + cgiError("'REQUEST_METHOD' must be 'POST' or 'GET'") + +iterator decodeData*(allowedMethods: set[TRequestMethod] = + {methodNone, methodPost, methodGet}): tuple[key, value: string] = + ## Reads and decodes CGI data and yields the (name, value) pairs the + ## data consists of. If the client does not use a method listed in the + ## `allowedMethods` set, an `ECgi` exception is raised. + var enc = getEncodedData(allowedMethods) + if not isNil(enc): + # decode everything in one pass: + var i = 0 + var name = "" + var value = "" + while enc[i] != '\0': + setLen(name, 0) # reuse memory + while true: + case enc[i] + of '\0': break + of '%': + var x = 0 + handleHexChar(enc[i+1], x) + handleHexChar(enc[i+2], x) + inc(i, 2) + add(name, chr(x)) + of '+': add(name, ' ') + of '=', '&': break + else: add(name, enc[i]) + inc(i) + if enc[i] != '=': cgiError("'=' expected") + inc(i) # skip '=' + setLen(value, 0) # reuse memory + while true: + case enc[i] + of '%': + var x = 0 + handleHexChar(enc[i+1], x) + handleHexChar(enc[i+2], x) + inc(i, 2) + add(value, chr(x)) + of '+': add(value, ' ') + of '&', '\0': break + else: add(value, enc[i]) + inc(i) + yield (name, value) + if enc[i] == '&': inc(i) + elif enc[i] == '\0': break + else: cgiError("'&' expected") + proc readData*(allowedMethods: set[TRequestMethod] = {methodNone, methodPost, methodGet}): PStringTable = ## Read CGI data. If the client does not use a method listed in the ## `allowedMethods` set, an `ECgi` exception is raised. result = newStringTable() - var enc: string # encoded data - case getenv("REQUEST_METHOD") - of "POST": - if methodPost notin allowedMethods: - cgiError("'REQUEST_METHOD' 'POST' is not supported") - # read from stdin: - var L = parseInt(getenv("CONTENT_LENGTH")) - enc = newString(L) - if readBuffer(stdin, addr(enc[0]), L) != L: - cgiError("cannot read from stdin") - of "GET": - if methodGet notin allowedMethods: - cgiError("'REQUEST_METHOD' 'GET' is not supported") - # read from the QUERY_STRING environment variable: - enc = getenv("QUERY_STRING") - else: - if methodNone in allowedMethods: - return result - else: - cgiError("'REQUEST_METHOD' must be 'POST' or 'GET'") - - # decode everything in one pass: - var i = 0 - var name = "" - var value = "" - while true: - setLen(name, 0) # reuse memory - while true: - case enc[i] - of '\0': return - of '%': - var x = 0 - handleHexChar(enc[i+1], x) - handleHexChar(enc[i+2], x) - inc(i, 2) - add(name, chr(x)) - of '+': add(name, ' ') - of '=', '&': break - else: add(name, enc[i]) - inc(i) - if enc[i] != '=': cgiError("'=' expected") - inc(i) # skip '=' - setLen(value, 0) # reuse memory - while true: - case enc[i] - of '%': - var x = 0 - handleHexChar(enc[i+1], x) - handleHexChar(enc[i+2], x) - inc(i, 2) - add(value, chr(x)) - of '+': add(value, ' ') - of '&', '\0': break - else: add(value, enc[i]) - inc(i) + for name, value in decodeData(allowedMethods): result[name] = value - if enc[i] == '&': inc(i) - elif enc[i] == '\0': break - else: cgiError("'&' expected") - + proc validateData*(data: PStringTable, validKeys: openarray[string]) = ## validates data; raises `ECgi` if this fails. This checks that each variable ## name of the CGI `data` occurs in the `validKeys` array. @@ -323,8 +329,13 @@ proc setTestData*(keysvalues: openarray[string]) = proc writeContentType*() = ## call this before starting to send your HTML data to `stdout`. This - ## is just a shorthand for: + ## implements this part of the CGI protocol: ## ## .. code-block:: Nimrod ## write(stdout, "Content-type: text/html\n\n") + ## + ## It also modifies the debug stack traces so that they contain + ## ``
`` and are easily readable in a browser. write(stdout, "Content-type: text/html\n\n") + system.stackTraceNewLine = "
\n" + diff --git a/lib/excpt.nim b/lib/excpt.nim index 38d34f3f4..293491fe9 100644 --- a/lib/excpt.nim +++ b/lib/excpt.nim @@ -70,6 +70,8 @@ var framePtr {.exportc.}: PFrame tempFrames: array [0..127, PFrame] # cannot be allocated on the stack! + + stackTraceNewLine* = "\n" ## undocumented feature proc auxWriteStackTrace(f: PFrame, s: var string) = const @@ -101,19 +103,21 @@ proc auxWriteStackTrace(f: PFrame, s: var string) = if tempFrames[j] == nil: add(s, "(") add(s, $(total-i-1)) - add(s, " calls omitted) ...\n") + add(s, " calls omitted) ...") else: add(s, $tempFrames[j].procname) if tempFrames[j].line > 0: add(s, ", line: ") add(s, $tempFrames[j].line) - add(s, "\n") + add(s, stackTraceNewLine) proc rawWriteStackTrace(s: var string) = if framePtr == nil: - add(s, "No stack traceback available\n") + add(s, "No stack traceback available") + add(s, stackTraceNewLine) else: - add(s, "Traceback (most recent call last)\n") + add(s, "Traceback (most recent call last)") + add(s, stackTraceNewLine) auxWriteStackTrace(framePtr, s) proc quitOrDebug() {.inline.} = @@ -151,6 +155,8 @@ var proc internalAssert(file: cstring, line: int, cond: bool) {.compilerproc.} = if not cond: + #c_fprintf(c_stdout, "Assertion failure: file %s line %ld\n", file, line) + #quit(1) GC_disable() # BUGFIX: `$` allocates a new string object! if not isNil(assertBuf): # BUGFIX: when debugging the GC, assertBuf may be nil @@ -162,7 +168,11 @@ proc internalAssert(file: cstring, line: int, cond: bool) {.compilerproc.} = add(assertBuf, "\n") gAssertionFailed.msg = assertBuf GC_enable() - raise gAssertionFailed # newException(EAssertionFailed, assertBuf) + if gAssertionFailed != nil: + raise gAssertionFailed + else: + c_fprintf(c_stdout, "Assertion failure: file %s line %ld\n", file, line) + quit(1) proc WriteStackTrace() = var s = "" diff --git a/lib/gc.nim b/lib/gc.nim index aaef70c03..1c353b559 100644 --- a/lib/gc.nim +++ b/lib/gc.nim @@ -9,23 +9,17 @@ # Garbage Collector -# Current Features: -# * incremental -# * non-recursive -# * generational - +# +# The basic algorithm is *Deferrent Reference Counting* with cycle detection. +# Special care has been taken to avoid recursion as far as possible to avoid +# stack overflows when traversing deep datastructures. This is comparable to +# an incremental and generational GC. It should be well-suited for soft real +# time applications (like games). +# # Future Improvements: # * Support for multi-threading. However, locks for the reference counting # might turn out to be too slow. -# --------------------------------------------------------------------------- - -proc getOccupiedMem(): int = return tlsfUsed() -proc getFreeMem(): int = return tlsfMax() - tlsfUsed() -proc getTotalMem(): int = return tlsfMax() - -# --------------------------------------------------------------------------- - const CycleIncrease = 2 # is a multiplicative increase InitialCycleThreshold = 4*1024*1024 # X MB because cycle checking is slow @@ -36,14 +30,14 @@ const const rcIncrement = 0b1000 # so that lowest 3 bits are not touched # NOTE: Most colors are currently unused - rcBlack = 0b000 # cell is colored black; in use or free - rcGray = 0b001 # possible member of a cycle - rcWhite = 0b010 # member of a garbage cycle + rcBlack = 0b000 # cell is colored black; in use or free + rcGray = 0b001 # possible member of a cycle + rcWhite = 0b010 # member of a garbage cycle rcPurple = 0b011 # possible root of a cycle - rcZct = 0b100 # in ZCT - rcRed = 0b101 # Candidate cycle undergoing sigma-computation + rcZct = 0b100 # in ZCT + rcRed = 0b101 # Candidate cycle undergoing sigma-computation rcOrange = 0b110 # Candidate cycle awaiting epoch boundary - rcShift = 3 # shift by rcShift to get the reference counter + rcShift = 3 # shift by rcShift to get the reference counter colorMask = 0b111 type TWalkOp = enum @@ -52,21 +46,22 @@ type TFinalizer {.compilerproc.} = proc (self: pointer) # A ref type can have a finalizer that is called before the object's # storage is freed. - TGcHeap {.final, pure.} = object # this contains the zero count and - # non-zero count table - mask: TAddress # mask for fast pointer detection - zct: TCellSeq # the zero count table - stackCells: TCellSet # cells and addresses that look like a cell but - # aren't of the hardware stack + TGcStat {.final, pure.} = object stackScans: int # number of performed stack scans (for statistics) cycleCollections: int # number of performed full collections maxThreshold: int # max threshold that has been set maxStackSize: int # max stack size - maxStackPages: int # max number of pages in stack - cycleTableSize: int # max entries in cycle table + maxStackCells: int # max stack cells in ``decStack`` + cycleTableSize: int # max entries in cycle table + + TGcHeap {.final, pure.} = object # this contains the zero count and + # non-zero count table + zct: TCellSeq # the zero count table + decStack: TCellSeq # cells in the stack that are to decref again cycleRoots: TCellSet tempStack: TCellSeq # temporary stack for recursion elimination + stat: TGcStat var stackBottom: pointer @@ -82,13 +77,13 @@ var proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerproc.} # unsureAsgnRef updates the reference counters only if dest is not on the # stack. It is used by the code generator if it cannot decide wether a - # reference is in the stack or not (this can happen for out/var parameters). + # reference is in the stack or not (this can happen for var parameters). #proc growObj(old: pointer, newsize: int): pointer {.compilerproc.} proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} proc addZCT(s: var TCellSeq, c: PCell) {.noinline.} = - if (c.refcount and colorMask) != rcZct: + if (c.refcount and rcZct) == 0: c.refcount = c.refcount and not colorMask or rcZct add(s, c) @@ -131,7 +126,7 @@ proc GC_disableMarkAndSweep() = # set to the max value to suppress the cycle detector # this that has to equals zero, otherwise we have to round up UnitsPerPage: -when BitsPerPage mod BitsPerUnit != 0: +when BitsPerPage mod (sizeof(int)*8) != 0: {.error: "(BitsPerPage mod BitsPerUnit) should be zero!".} when debugGC: @@ -203,8 +198,7 @@ template gcTrace(cell, state: expr): stmt = # ----------------------------------------------------------------------------- # forward declarations: -proc updateZCT() -proc collectCT(gch: var TGcHeap, zctUpdated: bool) +proc collectCT(gch: var TGcHeap) proc IsOnStack(p: pointer): bool {.noinline.} proc forAllChildren(cell: PCell, op: TWalkOp) proc doOperation(p: pointer, op: TWalkOp) @@ -232,7 +226,7 @@ proc decRef(c: PCell) {.inline.} = when stressGC: if c.refcount <% rcIncrement: writeCell("broken cell", c) - assert(c.refcount >% rcIncrement) + assert(c.refcount >=% rcIncrement) c.refcount = c.refcount -% rcIncrement if c.refcount <% rcIncrement: addZCT(gch.zct, c) @@ -242,7 +236,6 @@ proc decRef(c: PCell) {.inline.} = proc incRef(c: PCell) {.inline.} = c.refcount = c.refcount +% rcIncrement if canBeCycleRoot(c): - # OPT: the code generator should special case this incl(gch.cycleRoots, c) proc nimGCref(p: pointer) {.compilerproc, inline.} = incRef(usrToCell(p)) @@ -277,19 +270,18 @@ proc unsureAsgnRef(dest: ppointer, src: pointer) = proc initGC() = when traceGC: - for i in low(TCellState)..high(TCellState): CellSetInit(states[i]) - gch.stackScans = 0 - gch.cycleCollections = 0 - gch.maxThreshold = 0 - gch.maxStackSize = 0 - gch.maxStackPages = 0 - gch.cycleTableSize = 0 + for i in low(TCellState)..high(TCellState): Init(states[i]) + gch.stat.stackScans = 0 + gch.stat.cycleCollections = 0 + gch.stat.maxThreshold = 0 + gch.stat.maxStackSize = 0 + gch.stat.maxStackCells = 0 + gch.stat.cycleTableSize = 0 # init the rt init(gch.zct) init(gch.tempStack) - CellSetInit(gch.cycleRoots) - CellSetInit(gch.stackCells) - gch.mask = 0 + Init(gch.cycleRoots) + Init(gch.decStack) new(gOutOfMem) # reserve space for the EOutOfMemory exception here! proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) = @@ -333,54 +325,63 @@ proc forAllChildren(cell: PCell, op: TWalkOp) = of tyString: nil else: assert(false) -proc checkCollection(zctUpdated: bool) {.inline.} = +proc checkCollection {.inline.} = # checks if a collection should be done if recGcLock == 0: - collectCT(gch, zctUpdated) + collectCT(gch) proc newObj(typ: PNimType, size: int): pointer = # generates a new object and sets its reference counter to 0 assert(typ.kind in {tyRef, tyString, tySequence}) - var zctUpdated = false - if gch.zct.len >= ZctThreshold: - updateZCT() - zctUpdated = true - # check if we have to collect: - checkCollection(zctUpdated) - var res = cast[PCell](gcAlloc(size + sizeof(TCell))) - when stressGC: assert((cast[TAddress](res) and (MemAlignment-1)) == 0) + checkCollection() + var res = cast[PCell](rawAlloc(allocator, size + sizeof(TCell))) + zeroMem(res, size+sizeof(TCell)) + assert((cast[TAddress](res) and (MemAlign-1)) == 0) # now it is buffered in the ZCT res.typ = typ when debugGC: if framePtr != nil and framePtr.prev != nil: res.filename = framePtr.prev.filename res.line = framePtr.prev.line - res.refcount = rcZct # refcount is zero, but mark it to be in the ZCT - add(gch.zct, res) # its refcount is zero, so add it to the ZCT - gch.mask = gch.mask or cast[TAddress](res) + res.refcount = rcZct # refcount is zero, but mark it to be in the ZCT + assert(isAllocatedPtr(allocator, res)) + # its refcount is zero, so add it to the ZCT: + block addToZCT: + # we check the last 8 entries (cache line) for a slot + # that could be reused + var L = gch.zct.len + var d = gch.zct.d + for i in countdown(L-1, max(0, L-8)): + var c = d[i] + if c.refcount >=% rcIncrement: + c.refcount = c.refcount and not colorMask + d[i] = res + break addToZCT + add(gch.zct, res) when logGC: writeCell("new cell", res) gcTrace(res, csAllocated) result = cellToUsr(res) proc newSeq(typ: PNimType, len: int): pointer = - # XXX: overflow checks! - result = newObj(typ, len * typ.base.size + GenericSeqSize) + result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize)) cast[PGenericSeq](result).len = len cast[PGenericSeq](result).space = len proc growObj(old: pointer, newsize: int): pointer = - checkCollection(false) + checkCollection() var ol = usrToCell(old) assert(ol.typ != nil) assert(ol.typ.kind in {tyString, tySequence}) - var res = cast[PCell](gcAlloc(newsize + sizeof(TCell))) + var res = cast[PCell](rawAlloc(allocator, newsize + sizeof(TCell))) var elemSize = 1 if ol.typ.kind != tyString: elemSize = ol.typ.base.size - copyMem(res, ol, cast[PGenericSeq](old).len*elemSize + - GenericSeqSize + sizeof(TCell)) - - assert((cast[TAddress](res) and (MemAlignment-1)) == 0) + + var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize + copyMem(res, ol, oldsize + sizeof(TCell)) + zeroMem(cast[pointer](cast[TAddress](res)+% oldsize +% sizeof(TCell)), + newsize-oldsize) + assert((cast[TAddress](res) and (MemAlign-1)) == 0) assert(res.refcount shr rcShift <=% 1) #if res.refcount <% rcIncrement: # add(gch.zct, res) @@ -395,13 +396,12 @@ proc growObj(old: pointer, newsize: int): pointer = break dec(j) if canBeCycleRoot(ol): excl(gch.cycleRoots, ol) - gch.mask = gch.mask or cast[TAddress](res) when logGC: writeCell("growObj old cell", ol) writeCell("growObj new cell", res) gcTrace(ol, csZctFreed) gcTrace(res, csAllocated) - when reallyDealloc: tlsf_free(ol) + when reallyDealloc: rawDealloc(allocator, ol) else: assert(ol.typ != nil) zeroMem(ol, sizeof(TCell)) @@ -409,13 +409,6 @@ proc growObj(old: pointer, newsize: int): pointer = # ---------------- cycle collector ------------------------------------------- -# When collecting cycles, we have to consider the following: -# * there may still be references in the stack -# * some cells may still be in the ZCT, because they are referenced from -# the stack (!), so their refcounts are zero -# the ZCT is a subset of stackCells here, so we only need to care -# for stackcells - proc doOperation(p: pointer, op: TWalkOp) = if p == nil: return var c: PCell = usrToCell(p) @@ -438,36 +431,25 @@ proc collectCycles(gch: var TGcHeap) = for c in elements(gch.cycleRoots): inc(tabSize) forallChildren(c, waCycleDecRef) - gch.cycleTableSize = max(gch.cycleTableSize, tabSize) + gch.stat.cycleTableSize = max(gch.stat.cycleTableSize, tabSize) # restore reference counts (a depth-first traversal is needed): - var marker, newRoots: TCellSet - CellSetInit(marker) - CellSetInit(newRoots) + var marker: TCellSet + Init(marker) for c in elements(gch.cycleRoots): - var needsRestore = false - if c in gch.stackCells: - needsRestore = true - incl(newRoots, c) - # we need to scan this later again; maybe stack changes - # NOTE: adding to ZCT here does NOT work - elif c.refcount >=% rcIncrement: - needsRestore = true - if needsRestore: - if c notin marker: - incl(marker, c) + if c.refcount >=% rcIncrement: + if not containsOrIncl(marker, c): gch.tempStack.len = 0 forAllChildren(c, waPush) while gch.tempStack.len > 0: dec(gch.tempStack.len) var d = gch.tempStack.d[gch.tempStack.len] d.refcount = d.refcount +% rcIncrement - if d notin marker and d in gch.cycleRoots: - incl(marker, d) + if d in gch.cycleRoots and not containsOrIncl(marker, d): forAllChildren(d, waPush) # remove cycles: for c in elements(gch.cycleRoots): - if c.refcount <% rcIncrement and c notin gch.stackCells: + if c.refcount <% rcIncrement: gch.tempStack.len = 0 forAllChildren(c, waPush) while gch.tempStack.len > 0: @@ -480,21 +462,23 @@ proc collectCycles(gch: var TGcHeap) = prepareDealloc(c) gcTrace(c, csCycFreed) when logGC: writeCell("cycle collector dealloc cell", c) - when reallyDealloc: tlsf_free(c) + when reallyDealloc: rawDealloc(allocator, c) else: assert(c.typ != nil) zeroMem(c, sizeof(TCell)) - CellSetDeinit(gch.cycleRoots) - gch.cycleRoots = newRoots + Deinit(gch.cycleRoots) + Init(gch.cycleRoots) -proc gcMark(p: pointer) {.noinline.} = +proc gcMark(p: pointer) {.inline.} = # the addresses are not as objects on the stack, so turn them to objects: var cell = usrToCell(p) var c = cast[TAddress](cell) - if ((c and gch.mask) == c) and c >% 1024: + if c >% PageSize: # fast check: does it look like a cell? - when logGC: cfprintf(cstdout, "in stackcells %p\n", cell) - incl(gch.stackCells, cell) # yes: mark it + if isAllocatedPtr(allocator, cell): + # mark the cell: + cell.refcount = cell.refcount +% rcIncrement + add(gch.decStack, cell) # ----------------- stack management -------------------------------------- # inspired from Smart Eiffel @@ -560,53 +544,6 @@ elif defined(hppa) or defined(hp9000) or defined(hp9000s300) or gcMark(sp^) sp = cast[ppointer](cast[TAddress](sp) -% sizeof(pointer)) -elif defined(I386) and asmVersion: - # addresses decrease as the stack grows: - proc isOnStack(p: pointer): bool = - var - stackTop: array [0..1, pointer] - result = p >= addr(stackTop[0]) and p <= stackBottom - - proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} = - # This code should be safe even for aggressive optimizers. The try - # statement safes all registers into the safepoint, which we - # scan additionally to the stack. - type - TPtrArray = array[0..0xffffff, pointer] - try: - var pa = cast[ptr TPtrArray](excHandler) - for i in 0 .. sizeof(TSafePoint) - 1: - gcMark(pa[i]) - finally: - # iterate over the stack: - var max = cast[TAddress](stackBottom) - var stackTop{.volatile.}: array [0..15, pointer] - var sp {.volatile.} = cast[TAddress](addr(stackTop[0])) - while sp <= max: - gcMark(cast[ppointer](sp)^) - sp = sp +% sizeof(pointer) - when false: - var counter = 0 - #mov ebx, OFFSET `stackBottom` - #mov ebx, [ebx] - asm """ - pusha - mov edi, esp - call `getStackBottom` - mov ebx, eax - L1: - cmp edi, ebx - ja L2 - mov eax, [edi] - call `gcMark` - add edi, 4 - inc [`counter`] - jmp L1 - L2: - popa - """ - cfprintf(cstdout, "stack %ld\n", counter) - else: # --------------------------------------------------------------------------- # Generic code for architectures where addresses decrease as the stack grows. @@ -617,82 +554,47 @@ else: result = p >= addr(stackTop[0]) and p <= stackBottom var - gRegisters: C_JmpBuf jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int # a little hack to get the size of a TJmpBuf in the generated C code # in a platform independant way proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} = - when false: - # new version: several C compilers are too smart here - var - max = cast[TAddress](stackBottom) - stackTop: array [0..15, pointer] - if c_setjmp(gregisters) == 0'i32: # To fill the C stack with registers. - # iterate over the registers: - var sp = cast[TAddress](addr(gregisters)) - while sp < cast[TAddress](addr(gregisters))+%jmpbufSize: - gcMark(cast[ppointer](sp)^) - sp = sp +% sizeof(pointer) - # iterate over the stack: - sp = cast[TAddress](addr(stackTop[0])) - while sp <= max: - gcMark(cast[ppointer](sp)^) - sp = sp +% sizeof(pointer) - else: - c_longjmp(gregisters, 42) - # this can never happen, but should trick any compiler that is - # not as smart as a human - else: - var - max = stackBottom - registers: C_JmpBuf # The jmp_buf buffer is in the C stack. - sp: PPointer # Used to traverse the stack and registers assuming - # that 'setjmp' will save registers in the C stack. - if c_setjmp(registers) == 0'i32: # To fill the C stack with registers. - sp = cast[ppointer](addr(registers)) - while sp <= max: - gcMark(sp^) - sp = cast[ppointer](cast[TAddress](sp) +% sizeof(pointer)) + var + max = stackBottom + registers: C_JmpBuf # The jmp_buf buffer is in the C stack. + sp: PPointer # Used to traverse the stack and registers assuming + # that 'setjmp' will save registers in the C stack. + if c_setjmp(registers) == 0'i32: # To fill the C stack with registers. + sp = cast[ppointer](addr(registers)) + while sp <= max: + gcMark(sp^) + sp = cast[ppointer](cast[TAddress](sp) +% sizeof(pointer)) # ---------------------------------------------------------------------------- # end of non-portable code # ---------------------------------------------------------------------------- -proc updateZCT() = - # We have to make an additional pass over the ZCT unfortunately, because - # the ZCT may be out of date, which means it contains cells with a - # refcount > 0. The reason is that ``incRef`` does not bother to remove - # the cell from the ZCT as this might be too slow. - var j = 0 - var L = gch.zct.len # because globals make it hard for the optimizer - var d = gch.zct.d - while j < L: - var c = d[j] - if c.refcount >=% rcIncrement: - when logGC: writeCell("remove from ZCT", c) - # remove from ZCT: - dec(L) - d[j] = d[L] - c.refcount = c.refcount and not colorMask - # we have a new cell at position j, so don't increment j - else: - inc(j) - gch.zct.len = L - proc CollectZCT(gch: var TGcHeap) = - var i = 0 - while i < gch.zct.len: - var c = gch.zct.d[i] - assert(c.refcount <% rcIncrement) + # Note: Freeing may add child objects to the ZCT! So essentially we do + # deep freeing, which is bad for incremental operation. In order to + # avoid a deep stack, we move objects to keep the ZCT small. + # This is performance critical! + var L = addr(gch.zct.len) + while L^ > 0: + var c = gch.zct.d[0] + # remove from ZCT: assert((c.refcount and colorMask) == rcZct) - if canBeCycleRoot(c): excl(gch.cycleRoots, c) - if c notin gch.stackCells: - # remove from ZCT: - c.refcount = c.refcount and not colorMask - gch.zct.d[i] = gch.zct.d[gch.zct.len-1] - # we have a new cell at position i, so don't increment i - dec(gch.zct.len) + c.refcount = c.refcount and not colorMask + gch.zct.d[0] = gch.zct.d[L^ - 1] + dec(L^) + if c.refcount <% rcIncrement: + # It may have a RC > 0, if it is in the hardware stack or + # it has not been removed yet from the ZCT. This is because + # ``incref`` does not bother to remove the cell from the ZCT + # as this might be too slow. + # In any case, it should be removed from the ZCT. But not + # freed. **KEEP THIS IN MIND WHEN MAKING THIS INCREMENTAL!** + if canBeCycleRoot(c): excl(gch.cycleRoots, c) when logGC: writeCell("zct dealloc cell", c) gcTrace(c, csZctFreed) # We are about to free the object, call the finalizer BEFORE its @@ -700,51 +602,53 @@ proc CollectZCT(gch: var TGcHeap) = # access invalid memory. This is done by prepareDealloc(): prepareDealloc(c) forAllChildren(c, waZctDecRef) - when reallyDealloc: tlsf_free(c) + when reallyDealloc: rawDealloc(allocator, c) else: assert(c.typ != nil) zeroMem(c, sizeof(TCell)) - else: - inc(i) - when stressGC: - for j in 0..gch.zct.len-1: assert(gch.zct.d[j] in gch.stackCells) -proc collectCT(gch: var TGcHeap, zctUpdated: bool) = +proc unmarkStackAndRegisters(gch: var TGcHeap) = + var d = gch.decStack.d + for i in 0..gch.decStack.len-1: + assert isAllocatedPtr(allocator, d[i]) + decRef(d[i]) # OPT: cannot create a cycle! + gch.decStack.len = 0 + +proc collectCT(gch: var TGcHeap) = if gch.zct.len >= ZctThreshold or (cycleGC and - getOccupiedMem() >= cycleThreshold) or stressGC: - if not zctUpdated: updateZCT() - gch.maxStackSize = max(gch.maxStackSize, stackSize()) - CellSetInit(gch.stackCells) + getOccupiedMem() >= cycleThreshold) or stressGC: + gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize()) + assert(gch.decStack.len == 0) markStackAndRegisters(gch) - gch.maxStackPages = max(gch.maxStackPages, gch.stackCells.counter) - inc(gch.stackScans) + gch.stat.maxStackCells = max(gch.stat.maxStackCells, gch.decStack.len) + inc(gch.stat.stackScans) collectZCT(gch) when cycleGC: if getOccupiedMem() >= cycleThreshold or stressGC: collectCycles(gch) collectZCT(gch) - inc(gch.cycleCollections) + inc(gch.stat.cycleCollections) cycleThreshold = max(InitialCycleThreshold, getOccupiedMem() * cycleIncrease) - gch.maxThreshold = max(gch.maxThreshold, cycleThreshold) - CellSetDeinit(gch.stackCells) + gch.stat.maxThreshold = max(gch.stat.maxThreshold, cycleThreshold) + unmarkStackAndRegisters(gch) proc GC_fullCollect() = var oldThreshold = cycleThreshold cycleThreshold = 0 # forces cycle collection - collectCT(gch, false) + collectCT(gch) cycleThreshold = oldThreshold proc GC_getStatistics(): string = GC_disable() result = "[GC] total memory: " & $(getTotalMem()) & "\n" & "[GC] occupied memory: " & $(getOccupiedMem()) & "\n" & - "[GC] stack scans: " & $gch.stackScans & "\n" & - "[GC] stack pages: " & $gch.maxStackPages & "\n" & - "[GC] cycle collections: " & $gch.cycleCollections & "\n" & - "[GC] max threshold: " & $gch.maxThreshold & "\n" & + "[GC] stack scans: " & $gch.stat.stackScans & "\n" & + "[GC] stack cells: " & $gch.stat.maxStackCells & "\n" & + "[GC] cycle collections: " & $gch.stat.cycleCollections & "\n" & + "[GC] max threshold: " & $gch.stat.maxThreshold & "\n" & "[GC] zct capacity: " & $gch.zct.cap & "\n" & - "[GC] max cycle table size: " & $gch.cycleTableSize & "\n" & - "[GC] max stack size: " & $gch.maxStackSize + "[GC] max cycle table size: " & $gch.stat.cycleTableSize & "\n" & + "[GC] max stack size: " & $gch.stat.maxStackSize when traceGC: writeLeakage() GC_enable() diff --git a/lib/lexbase.nim b/lib/lexbase.nim index f6861a5b6..bb207e92a 100644 --- a/lib/lexbase.nim +++ b/lib/lexbase.nim @@ -1,7 +1,7 @@ # # # The Nimrod Compiler -# (c) Copyright 2008 Andreas Rumpf +# (c) Copyright 2009 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. diff --git a/lib/macros.nim b/lib/macros.nim index 2c71f31c8..2b75a1545 100644 --- a/lib/macros.nim +++ b/lib/macros.nim @@ -1,15 +1,17 @@ # # # Nimrod's Runtime Library -# (c) Copyright 2008 Andreas Rumpf +# (c) Copyright 2009 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -## This module contains the interface to the compiler's abstract syntax tree. -## Abstract syntax trees should be modified in macros. +## This module contains the interface to the compiler's abstract syntax +## tree (`AST`:idx:). Macros operate on this tree. + +## .. include:: ../doc/astspec.txt #[[[cog #def toEnum(name, elems): @@ -235,3 +237,13 @@ proc newCall*(theProc: string, result.add(newIdentNode(theProc)) result.add(args) +proc nestList*(theProc: TNimrodIdent, + x: PNimrodNode): PNimrodNode {.compileTime.} = + ## nests the list `x` into a tree of call expressions: + ## ``[a, b, c]`` is transformed into ``theProc(a, theProc(c, d))`` + var L = x.len + result = newCall(theProc, x[L-2], x[L-1]) + var a = result + for i in countdown(L-3, 0): + a = newCall(theProc, x[i], copyNimTree(a)) + diff --git a/lib/math.nim b/lib/math.nim index 31783efce..bc180f72c 100644 --- a/lib/math.nim +++ b/lib/math.nim @@ -208,5 +208,40 @@ else: var y = exp(2.0*x) return (y-1.0)/(y+1.0) + +type + TRunningStat* = object ## an accumulator for statistical data + n*: int ## number of pushed data + sum*, min*, max*, mean*: float ## self-explaining + oldM, oldS, newS: float + +proc push*(s: var TRunningStat, x: float) = + ## pushes a value `x` for processing + inc(s.n) + # See Knuth TAOCP vol 2, 3rd edition, page 232 + if s.n == 1: + s.oldM = x + s.mean = x + s.oldS = 0.0 + else: + s.mean = s.oldM + (x - s.oldM)/toFloat(s.n) + s.newS = s.oldS + (x - s.oldM)*(x - s.mean) + + # set up for next iteration: + s.oldM = s.mean + s.oldS = s.newS + + s.sum = s.sum + x + if s.min > x: s.min = x + if s.max < x: s.max = x + +proc variance*(s: TRunningStat): float = + ## computes the current variance of `s` + if s.n > 1: result = s.newS / (toFloat(s.n - 1)) + +proc standardDeviation*(s: TRunningStat): float = + ## computes the current standard deviation of `s` + result = sqrt(variance(s)) + {.pop.} {.pop.} diff --git a/lib/memman.nim b/lib/memman.nim deleted file mode 100644 index 249607e2d..000000000 --- a/lib/memman.nim +++ /dev/null @@ -1,698 +0,0 @@ -# -# -# Nimrod's Runtime Library -# (c) Copyright 2008 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - - -# Memory manager. Based on: -# Two Levels Segregate Fit memory allocator (TLSF) -# Version 2.4.2 -# -# Written by Miguel Masmano Tello -# -# Thanks to Ismael Ripoll for his suggestions and reviews -# -# Copyright (C) 2008, 2007, 2006, 2005, 2004 -# -# This code is released using a dual license strategy: GPL/LGPL -# You can choose the licence that better fits your requirements. -# -# Released under the terms of the GNU General Public License Version 2.0 -# Released under the terms of the GNU Lesser General Public License Version 2.1 - - -# Some IMPORTANT TLSF parameters -const - blockAlign = sizeof(pointer) * 2 - maxFli = 30 - maxLog2Sli = 5 - maxSli = 1 shl maxLog2Sli - - fliOffset = 6 # tlsf structure just will manage blocks bigger than 128 bytes - smallBlock = 128 - realFli = MaxFli - fliOffset - -type - TFreePtr {.final.} = object - prev, next: PBhdr - Pbhdr = ptr Tbhdr - Tbhdr {.final.} = object - prevHdr: Pbhdr # this is just valid if the first bit of size is set - size: int # the size is stored in bytes - # bit 0 indicates whether the block is used and - # bit 1 allows to know whether the previous block is free - freePtr: TFreePtr # at this offset bhdr.buffer starts (was a union in the - # C version) - TAreaInfo {.final.} = object # This structure is embedded at the beginning - # of each area, giving us enough information - # to cope with a set of areas - theEnd: Pbhdr - next: PAreaInfo - PAreaInfo = ptr TAreaInfo - - TLSF {.final.} = object - tlsf_signature: int32 # the TLSF's structure signature - usedSize, maxSize: int - areaHead: PAreaInfo # A linked list holding all the existing areas - - flBitmap: int32 # the first-level bitmap - # This array should have a size of REAL_FLI bits - slBitmap: array[0..realFli, int32] # the second-level bitmap - matrix: array [0..realFli, array[0..maxSli, PBhdr]] - -const - minBlockSize = sizeof(TFreePtr) - bhdrOverhead = sizeof(Tbhdr) - minBlockSize - tlsfSignature = 0x2A59FA59 - ptrMask = sizeof(pointer) - 1 - blockSize = 0xFFFFFFFF - ptrMask - memAlign = blockAlign - 1 - blockState = 0x1 - prevState = 0x2 - - freeBlock = 0x1 # bit 0 of the block size - usedBlock = 0x0 - - prevFree = 0x2 # bit 1 of the block size - prevUsed = 0x0 - - defaultAreaSize = 64*1024 # 1024*10 - pageSize = if defined(cpu32): 4096 else: 4096*2 - - -proc getNextBlock(adr: pointer, r: int): PBhdr {.inline.} = - return cast[PBhdr](cast[TAddress](adr) +% r) - -proc roundupSize(r: int): int = return (r +% memAlign) and not memAlign -proc rounddownSize(r: int): int = return r and not memAlign -proc roundup(x, v: int): int = return (((not x)+%1) and (v-%1)) +% x - -proc addSize(s: PTLSF, b: Pbhdr) = - inc(s.usedSize, (b.size and blockSize) + bhdrOverhead) - s.maxSize = max(s.maxSize, s.usedSize) - -proc removeSize(s: PTLSF, b: Pbhdr) = - dec(s.usedSize, (b.size and blockSize) + bhdrOverhead) - -# ------------ platform specific code ----------------------------------------- - -when defined(posix): - const # XXX: make these variables for portability? - PROT_READ = 1 # page can be read - PROT_WRITE = 2 # page can be written - PROT_EXEC = 4 # page can be executed - PROT_NONE = 0 # page can not be accessed - - MAP_SHARED = 1 # Share changes - MAP_PRIVATE = 2 # Changes are private - MAP_TYPE = 0xf # Mask for type of mapping - MAP_FIXED = 0x10 # Interpret addr exactly - MAP_ANONYMOUS = 0x20 # don't use a file - - MAP_GROWSDOWN = 0x100 # stack-like segment - MAP_DENYWRITE = 0x800 # ETXTBSY - MAP_EXECUTABLE = 0x1000 # mark it as an executable - MAP_LOCKED = 0x2000 # pages are locked - MAP_NORESERVE = 0x4000 # don't check for reservations - - proc mmap(adr: pointer, len: int, prot, flags, fildes: cint, - off: int): pointer {.header: "".} - - proc getNewArea(size: var int): pointer {.inline.} = - size = roundup(size, PageSize) - result = mmap(0, size, PROT_READ or PROT_WRITE, - MAP_PRIVATE or MAP_ANONYMOUS, -1, 0) - if result == nil or result == cast[pointer](-1): - raiseOutOfMem() - -elif defined(windows): - const - MEM_RESERVE = 0x2000 - MEM_COMMIT = 0x1000 - MEM_TOP_DOWN = 0x100000 - PAGE_READWRITE = 0x04 - - proc VirtualAlloc(lpAddress: pointer, dwSize: int, flAllocationType, - flProtect: int32): pointer {. - header: "", stdcall.} - - proc getNewArea(size: var int): pointer {.inline.} = - size = roundup(size, PageSize) - result = VirtualAlloc(nil, size, MEM_RESERVE or MEM_COMMIT or MEM_TOP_DOWN, - PAGE_READWRITE) - if result == nil: raiseOutOfMem() - -else: - {.warning: "Generic code for allocating pages is used".} - # generic implementation relying on malloc: - proc malloc(size: int): pointer {.nodecl, importc.} - - proc getNewArea(size: var int): pointer {.inline.} = - size = roundup(size, PageSize) - result = malloc(size) - if result == nil: raiseOutOfMem() - -# --------------------------------------------------------------------------- -# small fixed size allocator: - -# Design: We manage pages. A page is of constant size, but not necessarily -# the OS's page size. Pages are managed in a hash table taking advantage of -# the fact that the OS is likely to give us pages with contingous numbers. -# A page contains either small fixed size objects of the same size or -# variable length objects. An object's size is always aligned at 16 byte -# boundary. Huge objects are dealt with the TLSF algorithm. -# The design supports iterating over any object in a fast way. - -# A bitset contains any page that starts an allocated page. The page may be -# empty however. This bitset can be used to quickly determine if a given -# page belongs to the GC heap. The design of the memory allocator makes it -# simple to return unused pages back to the OS. - - -# Small bocks -# ----------- -# -# If we use a list in the free object's space. Allocation and deallocation are -# O(1). Since any object is of the same size, iteration is quite efficient too. -# However, pointer detection is easy too: Just check if the type-field is nil. -# Deallocation sets it to nil. -# Algorithm: - -# i = 0 -# f = b.f # first free address -# while i < max: -# if a[i] == f: # not a valid block -# f = f.next # next free address -# else: -# a[i] is a valid object of size s -# inc(i) - -# The zero count table is an array. Since we know that the RC is zero, we can -# use the bits for an index into this array. Thus multiple ZCT tables are not -# difficult to support and insertion and removal is O(1). We use negative -# indexes for this. This makes it even fast enough (and necessary!) to do a ZCT -# removal if the RC is incremented. -# - -# Huge blocks -# ----------- -# -# Huge blocks are always rounded up to a multiple of the page size. These are -# called *strides*. We also need to keep an index structure -# of (stridesize, pagelist). -# - -const - MemAlign = 8 - PageShift = if sizeof(int) == 4: 12 else: 13 - PageSize = 1 shl PageShift -type - TFreeList {.final.} = object - next, prev: ptr TFreeList - - TPageDesc {.final.} = object # the start of a stride always starts with this! - size: int # lowest bit is set, if it is a huge block - free: ptr TFreeList # only used if it manages multiple cells - snext, sprev: ptr TPageDesc # next and prev pagedescs with the same size - - TCellArray {.final.} = object - i: int # length - d: ptr array [0..1000_000, TCell] - - TPageManager = table[page, ptr TPageDesc] - - TGcHeap {.final.} = object - # structure that manages the garbage collected heap - zct: TCellArray - stackCells: TCellArray - smallBlocks: array [PageSize div MemAlign, ptr TPageDesc] - freeLists: array [PageSize div MemAlign, ptr TFreeList] - pages: TPageManager - usedPages: TPageList - freePages: TPageList - -# small blocks: -proc allocSmall(var h: TGcHeap, size: int): pointer = - var s = align(size) - var f = h.freeLists[s] - if f != nil: - f.prev = f.next # remove from list - f.next.prev = f.prev - return f - var p = h.smallBlocks[s] - if p == nil or p.free == nil: - p = newSmallBlock(s, p) - h.smallBlocks[s] = p - - - -proc decRef(cell: PCell) {.inline.} = - assert(cell in ct.AT) - assert(cell.refcount > 0) # this should be the case! - assert(seqCheck(cell)) - dec(cell.refcount) - if cell.refcount == 0: - # add to zero count table: - zct.d[zct.i] = cell - cell.recfcount = -zct.i - inc(zct.i) - -proc incRef(cell: PCell) {.inline.} = - assert(seqCheck(cell)) - if cell.refcount < 0: - # remove from zero count table: - zct.d[-cell.refcount] = zct.d[zct.i-1] - dec(zct.i) - cell.refcount = 1 - else: - inc(cell.refcount) - -proc asgnRef(dest: ppointer, src: pointer) = - # the code generator calls this proc! - assert(not isOnStack(dest)) - # BUGFIX: first incRef then decRef! - if src != nil: incRef(usrToCell(src)) - if dest^ != nil: decRef(usrToCell(dest^)) - dest^ = src - - -# ---------------------------------------------------------------------------- -# helpers - -const - table: array[0..255, int8] = [ - -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7 - ] - -proc ls_bit(i: int32): int {.inline.} = - var - a: int = 0 - x: int = i and -i - if x <=% 0xffff: - if x <=% ff: a = 0 - else: a = 8 - elif x <=% 0xffffff: a = 16 - else: a = 24 - return table[x shr a] + a - -proc ms_bit(i: int): int {.inline.} = - var - a = if i <=% 0xffff: (if i <=% 0xff: 0 else: 8) elif - i <=% 0xffffff: 16 else: 24 - return table[i shr a] + a - -proc set_bit[IX](nr: int, adr: var array[IX, int32]) {.inline.} = - adr[nr shr 5] = adr[nr shr 5] or (1 shl (nr and 0x1f)) - -proc clear_bit[IX](nr: int, adr: var array[IX, int32]) {.inline.} = - adr[nr shr 5] = adr[nr shr 5] and not (1 shl (nr and 0x1f)) - -proc mappingSearch(r, fl, sl: var int) {.inline.} = - if r < smallBlock: - fl = 0 - sl = r div (smallBlock div maxSli) - else: - var t = (1 shl (ms_bit(r) - maxLog2Sli)) - 1 - r = r + t - fl = ms_bit(r) - sl = (r shl (fl - maxLog2Sli)) - maxSli - fl = fl - fliOffset - r = r and not t - -proc mappingInsert(r: int, fl, sl: var int) {.inline.} = - if r < smallBlock: - fl = 0 - sl = r div (smallBlock div maxSli) - else: - fl = ms_bit(r) - sl = (r shr (fl - maxLog2Sli)) - maxSli - fl = fl - fliOffset - -proc findSuitableBlock(t: var TLSF, fl, sl: var int): Pbhdr = - var tmp = t.slBitmap[fl] and ((not 0) shl sl) - if tmp != 0: - sl = ls_bit(tmp) - result = t.matrix[fl][sl] - else: - fl = ls_bit(t.flBitmap and (not 0 shl (fl + 1))) - if fl > 0: # likely - sl = ls_bit(t.slBitmap[fl]) - result = t.matrix[fl][sl] - -proc extractBlockHdr(b: Pbhdr, t: var TLSF, fl, sl: int) {.inline.} = - t.matrix[fl][sl] = b.freePtr.next - if t.matrix[fl][sl] != nil: - t.matrix[fl][sl].freePtr.prev = nil - else: - clear_bit(sl, t.slBitmap[fl]) - if t.slBitmap[fl] == 0: - clear_bit(fl, t.flBitmap) - b.freePtr.prev = nil - b.freePtr.next = nil - -proc extractBlock(b: Pbhdr, t: var TLSF, fl, sl: int) {.inline.} = - if b.freePtr.next != nil: - b.freePtr.next.freePtr.prev = b.freePtr.prev - if b.freePtr.prev != nil: - b.freePtr.prev.freePtr.next = b.freePtr.next - if t.matrix[fl][sl] == b: - t.matrix[fl][sl] = b.freePtr.next - if t.matrix[fl][sl] == nil: - clear_bit(sl, t.slBitmap[fl]) - if t.slBitmap[fl] == 0: - clear_bit(fl, t.flBitmap) - b.freePtr.prev = nil - b.freePtr.next = nil - -proc insertBlock(b: Pbhdr, t: var TLSF, fl, sl: int) {.inline.} = - b.freePtr.prev = nil - b.freePtr.next = t.matrix[fl][sl] - if t.matrix[fl][sl] != nil: - t.matrix[fl][sl].freePtr.prev = b - t.matrix[fl][sl] = b - set_bit(sl, t.slBitmap[fl]) - set_bit(fl, t.flBitmap) - -proc getBuffer(b: Pbhdr): pointer {.inline.} = - result = cast[pointer](addr(b.freePtr)) - -proc processArea(area: pointer, size: int): Pbhdr = - var - b, lb, ib: Pbhdr - ai: PAreaInfo - ib = cast[Pbhdr](area) - if sizeof(TAreaInfo) < minBlockSize: - ib.size = minBlockSize or usedBlock or prevUsed - else - ib.size = roundupSize(sizeof(TAreaInfo)) or usedBlock or prevUsed - b = getNextBlock(getBuffer(ib), ib.size and blockSize) - b.size = rounddownSize(size - 3 * bhdrOverhead - (ib.size and blockSize)) or - usedBlock or prevUsed - b.freePtr.prev = nil - b.freePtr.next = nil - lb = getNextBlock(getBuffer(b), b.size and blockSize) - lb.prevHdr = b - lb.size = 0 or usedBlock or prevFree - ai = cast[PAreaInfo](getBuffer(ib)) - ai.next = nil - ai.theEnd = lb - return ib - -# ---------------------------------------------------------------------------- -# Begin of the allocator code - -proc initMemoryPool(memPoolSize: int, memPool: pointer): int = - var - t: PLSF - b, ib: Pbhdr - - if memPool == nil or memPoolSize < sizeof(TLSF) + bhdrOverhead * 8: - writeToStdErr("initMemoryPool(): memory_pool invalid\n") - return -1 - - if (cast[TAddress](memPool) and ptrMask) != 0: - writeToStdErr("initMemoryPool(): memPool must be aligned to a word\n") - return -1 - t = cast[PLSF](memPool) - # Check if already initialised - if t.signature == tlsfSignature: - b = getNextBlock(memPool, roundupSize(sizeof(TLSF))) - return b.size and blockSize - zeroMem(memPool, sizeof(TLSF)) - - t.signature = tlsfSignature - ib = processArea(getNextBlock(memPool, roundupSize(sizeof(TLSF))), - rounddownSize(memPoolSize - sizeof(TLSF))) - b = getNextBlock(getBuffer(ib), ib.size and blockSize) - freeEx(getBuffer(b), t) - t.areaHead = cast[PAreaInfo](getBuffer(ib)) - - t.used_size = memPoolSize - (b.size and blockSize) - t.max_size = t.used_size - return b.size and blockSize - - -proc addNewArea(area: pointer, areaSize: int, t: var TLSF): int = - var - p, ptrPrev, ai: PAreaInfo - ib0, b0, lb0, ib1, b1, lb1, nextB: Pbhdr - - zeroMem(area, areaSize) - p = t.areaHead - ptrPrev = 0 - - ib0 = processArea(area, areaSize) - b0 = getNextBlock(getBuffer(ib0), ib0.size and blockSize) - lb0 = getNextBlock(getBuffer(b0), b0.size and blockSize) - - # Before inserting the new area, we have to merge this area with the - # already existing ones - while p != nil: - ib1 = cast[Pbhdr](cast[TAddress](p) -% bhdrOverhead) - b1 = getNextBlock(getBuffer(ib1), ib1.size and blockSize) - lb1 = p.theEnd - - # Merging the new area with the next physically contigous one - if cast[TAddress](ib1) == cast[TAddress](lb0) +% bhdrOverhead: - if t.areaHead == p: - t.areaHead = p.next - p = p.next - else: - ptrPrev.next = p.next - p = p.next - b0.size = rounddownSize((b0.size and blockSize) + - (ib1.size and blockSize) + 2 * bhdrOverhead) or - usedBlock or prevUsed - b1.prevHdr = b0 - lb0 = lb1 - continue - - # Merging the new area with the previous physically contigous one - if getBuffer(lb1) == pointer(ib0): - if t.areaHead == p: - t.areaHead = p.next - p = p.next - else: - ptrPrev.next = p.next - p = p.next - lb1->size = rounddownSize((b0.size and blockSize) + - (ib0.size and blockSize) + 2 * bhdrOverhead) or - usedBlock or (lb1.size and prevState) - nextB = getNextBlock(getBuffer(lb1), lb1.size and blockSize) - nextB.prevHdr = lb1 - b0 = lb1 - ib0 = ib1 - continue - ptrPrev = p - p = p.next - - # Inserting the area in the list of linked areas - ai = cast[PAreaInfo](getBuffer(ib0)) - ai.next = t.areaHead - ai.theEnd = lb0 - t.areaHead = ai - freeEx(getBuffer(b0), memPool) - return (b0.size and blockSize) - -proc mallocEx(asize: int, t: var TLSF): pointer = - var - b, b2, nextB: Pbhdr - fl, sl, tmpSize, size: int - - size = if asize < minBlockSize: minBlockSize else: roundupSize(asize) - - # Rounding up the requested size and calculating fl and sl - mappingSearch(size, fl, sl) - - # Searching a free block, recall that this function changes the values - # of fl and sl, so they are not longer valid when the function fails - b = findSuitableBlock(tlsf, fl, sl) - if b == nil: - # Growing the pool size when needed - # size plus enough room for the required headers: - var areaSize = max(size + bhdrOverhead * 8, defaultAreaSize) - var area = getNewArea(areaSize) - addNewArea(area, areaSize, t) - # Rounding up the requested size and calculating fl and sl - mappingSearch(size, fl, sl) - # Searching a free block - b = findSuitableBlock(t, fl, sl) - if b == nil: - raiseOutOfMem() - - extractBlockHdr(b, t, fl, sl) - - #-- found: - nextB = getNextBlock(getBuffer(b), b.size and blockSize) - # Should the block be split? - tmpSize = (b.size and blockSize) - size - if tmpSize >= sizeof(Tbhdr): - dec(tmpSize, bhdrOverhead) - b2 = getNextBlock(getBuffer(b), size) - b2.size = tmpSize or freeBlock or prevUsed - nextB.prevHdr = b2 - mappingInsert(tmpSize, fl, sl) - insertBlock(b2, t, fl, sl) - - b.size = size or (b.size and prevState) - else: - nextB.size = nextB.size and not prevFree - b.size = b.size and not freeBlock # Now it's used - - addSize(t, b) - return getBuffer(b) - - -proc freeEx(p: pointer, t: var TLSF) = - var - fl = 0 - sl = 0 - b, tmpB: Pbhdr - - assert(p != nil) - b = cast[Pbhdr](cast[TAddress](p) -% bhdrOverhead) - b.size = b.size or freeBlock - - removeSize(t, b) - b.freePtr.prev = nil - b.freePtr.next = nil - tmpB = getNextBlock(getBuffer(b), b.size and blockSize) - if (tmpB.size and freeBlock) != 0: - mappingInsert(tmpB.size and blockSize, fl, sl) - extractBlock(tmpB, t, fl, sl) - inc(b.size, (tmpB.size and blockSize) + bhdrOverhead) - if (b.size and prevFree) != 0: - tmpB = b.prevHdr - mappingInsert(tmpB.size and blockSize, fl, sl) - extractBlock(tmpB, t, fl, sl) - inc(tmpB.size, (b.size and blockSize) + bhdrOverhead) - b = tmpB - mappingInsert(b.size and blockSize, fl, sl) - insertBlock(b, t, fl, sl) - - tmpB = getNextBlock(getBuffer(b), b.size and blockSize) - tmpB.size = tmpB.size or prevFree - tmpB.prevHdr = b - -proc reallocEx(p: pointer, newSize: int, t: var TLSF): pointer = - var - cpsize, fl, sl, tmpSize: int - b, tmpB, nextB: Pbhdr - - assert(p != nil) - assert(newSize > 0) - - b = cast[Pbhdr](cast[TAddress](p) -% bhdrOverhead) - nextB = getNextBlock(getBuffer(b), b.size and blockSize) - newSize = if newSize < minBlockSize: minBlockSize else: roundupSize(newSize) - tmpSize = b.size and blockSize - if newSize <= tmpSize: - removeSize(t, b) - if (nextB.size and freeBlock) != 0: - mappingInsert(nextB.size and blockSize, fl, sl) - extractBlock(nextB, t, fl, sl) - inc(tmpSize, (nextB.size and blockSize) + bhdrOverhead) - nextB = getNextBlock(getBuffer(nextB), nextB.size and blockSize) - # We always reenter this free block because tmpSize will - # be greater then sizeof(Tbhdr) - dec(tmpSize, newSize) - if tmpSize >= sizeof(Tbhdr): - dec(tmpSize, bhdrOverhead) - tmpB = getNextBlock(getBuffer(b), newSize) - tmpB.size = tmpSize or freeBlock or prevUsed - nextB.prevHdr = tmpB - nextB.size = nextB.size or prevFree - mappingInsert(tmpSize, fl, sl) - insertBlock(tmpB, t, fl, sl) - b.size = newSize or (b.size and prevState) - addSize(t, b) - return getBuffer(b) - - if (nextB.size and freeBlock) != 0: - if newSize <= tmpSize + (nextB.size and blockSize): - removeSize(t, b) - mappingInsert(nextB.size and blockSize, fl, sl) - extractBlock(nextB, t, fl, sl) - inc(b.size, (nextB.size and blockSize) + bhdrOverhead) - nextB = getNextBlock(getBuffer(b), b.size and blockSize) - nextB.prevHdr = b - nextB.size = nextB.size and not prevFree - tmpSize = (b.size and blockSize) - newSize - if tmpSize >= sizeof(Tbhdr): - dec(tmpSize, bhdrOverhead) - tmpB = getNextBlock(getBuffer(b), newSize) - tmpB.size = tmpSize or freeBlock or prevUsed - nextB.prevHdr = tmpB - nextB.size = nextB.size or prevFree - mappingInsert(tmpSize, fl, sl) - insertBlock(tmpB, t, fl, sl) - b.size = newSize or (b.size and prevState) - addSize(t, b) - return getBuffer(b) - - var ptrAux = mallocEx(newSize, t) - cpsize = if (b.size and blockSize) > newSize: newSize else: - (b.size and blockSize) - copyMem(ptrAux, p, cpsize) - freeEx(p, memPool) - return ptrAux - - -proc ansiCrealloc(p: pointer, newSize: int, t: var TLSF): pointer = - if p == nil: - if newSize > 0: - result = mallocEx(newSize, t) - else: - result = nil - elif newSize <= 0: - freeEx(p, t) - result = nil - else: - result = reallocEx(p, newSize, t) - -proc InitTLSF(t: var TLSF) = - var areaSize = sizeof(TLSF) + BHDR_OVERHEAD * 8 # Just a safety constant - areaSize = max(areaSize, DEFAULT_areaSize) - var area = getNewArea(areaSize) - - - initMemoryPool(areaSize, area) - - var - t: PLSF - b, ib: Pbhdr - - t = cast[PLSF](memPool) - - zeroMem(area, areaSize) - - t.signature = tlsfSignature - var ib = processArea(getNextBlock(memPool, roundupSize(sizeof(TLSF))), - rounddownSize(memPoolSize - sizeof(TLSF))) - var b = getNextBlock(getBuffer(ib), ib.size and blockSize) - freeEx(getBuffer(b), t) - t.areaHead = cast[PAreaInfo](getBuffer(ib)) - - t.used_size = memPoolSize - (b.size and blockSize) - t.max_size = t.used_size - - # XXX diff --git a/lib/mm.nim b/lib/mm.nim new file mode 100644 index 000000000..5f16f7304 --- /dev/null +++ b/lib/mm.nim @@ -0,0 +1,187 @@ +# +# +# Nimrod's Runtime Library +# (c) Copyright 2009 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +# Nimrod high-level memory manager: It supports Boehm's GC, no GC and the +# native Nimrod GC. The native Nimrod GC is the default. + +#{.push checks:on, assertions:on.} +{.push checks:off.} + +const + debugGC = false # we wish to debug the GC... + logGC = false + traceGC = false # extensive debugging + reallyDealloc = true # for debugging purposes this can be set to false + cycleGC = true # (de)activate the cycle GC + stressGC = false + reallyOsDealloc = true + coalescRight = true + coalescLeft = true + +type + PPointer = ptr pointer + TByteArray = array[0..1000_0000, byte] + PByte = ptr TByteArray + PString = ptr string + +# Page size of the system; in most cases 4096 bytes. For exotic OS or +# CPU this needs to be changed: +const + PageShift = 12 + PageSize = 1 shl PageShift + PageMask = PageSize-1 + + MemAlign = 8 # also minimal allocatable memory block + + BitsPerPage = PageSize div MemAlign + UnitsPerPage = BitsPerPage div (sizeof(int)*8) + # how many ints do we need to describe a page: + # on 32 bit systems this is only 16 (!) + + TrunkShift = 9 + BitsPerTrunk = 1 shl TrunkShift # needs to be power of 2 and divisible by 64 + TrunkMask = BitsPerTrunk - 1 + IntsPerTrunk = BitsPerTrunk div (sizeof(int)*8) + IntShift = 5 + ord(sizeof(int) == 8) # 5 or 6, depending on int width + IntMask = 1 shl IntShift - 1 + +var + gOutOfMem: ref EOutOfMemory + +proc raiseOutOfMem() {.noreturn.} = + if gOutOfMem == nil: quit("out of memory; cannot even throw an exception") + gOutOfMem.msg = "out of memory" + raise gOutOfMem + +when defined(boehmgc): + when defined(windows): + const boehmLib = "boehmgc.dll" + else: + const boehmLib = "/usr/lib/libgc.so.1" + + proc boehmGC_disable {.importc: "GC_disable", dynlib: boehmLib.} + proc boehmGC_enable {.importc: "GC_enable", dynlib: boehmLib.} + proc boehmGCincremental {. + importc: "GC_enable_incremental", dynlib: boehmLib.} + proc boehmGCfullCollect {.importc: "GC_gcollect", dynlib: boehmLib.} + proc boehmAlloc(size: int): pointer {. + importc: "GC_malloc", dynlib: boehmLib.} + proc boehmAllocAtomic(size: int): pointer {. + importc: "GC_malloc_atomic", dynlib: boehmLib.} + proc boehmRealloc(p: pointer, size: int): pointer {. + importc: "GC_realloc", dynlib: boehmLib.} + proc boehmDealloc(p: pointer) {.importc: "GC_free", dynlib: boehmLib.} + + proc alloc(size: int): pointer = + result = boehmAlloc(size) + if result == nil: raiseOutOfMem() + proc alloc0(size: int): pointer = + result = alloc(size) + zeroMem(result, size) + proc realloc(p: Pointer, newsize: int): pointer = + result = boehmRealloc(p, newsize) + if result == nil: raiseOutOfMem() + proc dealloc(p: Pointer) = + boehmDealloc(p) + + proc initGC() = nil + + #boehmGCincremental() + + proc GC_disable() = boehmGC_disable() + proc GC_enable() = boehmGC_enable() + proc GC_fullCollect() = boehmGCfullCollect() + proc GC_setStrategy(strategy: TGC_Strategy) = nil + proc GC_enableMarkAndSweep() = nil + proc GC_disableMarkAndSweep() = nil + proc GC_getStatistics(): string = return "" + + proc getOccupiedMem(): int = return -1 + proc getFreeMem(): int = return -1 + proc getTotalMem(): int = return -1 + + proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} = + result = alloc(size) + proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} = + result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize)) + cast[PGenericSeq](result).len = len + cast[PGenericSeq](result).space = len + + proc growObj(old: pointer, newsize: int): pointer = + result = realloc(old, newsize) + + proc setStackBottom(theStackBottom: pointer) {.compilerproc.} = nil + proc nimGCref(p: pointer) {.compilerproc, inline.} = nil + proc nimGCunref(p: pointer) {.compilerproc, inline.} = nil + + proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} = + dest^ = src + proc asgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} = + dest^ = src + proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerproc, inline.} = + dest^ = src + + include cellsets +elif defined(nogc): + proc alloc(size: int): pointer = + result = c_malloc(size) + if result == nil: raiseOutOfMem() + proc alloc0(size: int): pointer = + result = alloc(size) + zeroMem(result, size) + proc realloc(p: Pointer, newsize: int): pointer = + result = c_realloc(p, newsize) + if result == nil: raiseOutOfMem() + proc dealloc(p: Pointer) = + c_free(p) + + proc initGC() = nil + proc GC_disable() = nil + proc GC_enable() = nil + proc GC_fullCollect() = nil + proc GC_setStrategy(strategy: TGC_Strategy) = nil + proc GC_enableMarkAndSweep() = nil + proc GC_disableMarkAndSweep() = nil + proc GC_getStatistics(): string = return "" + + proc getOccupiedMem(): int = return -1 + proc getFreeMem(): int = return -1 + proc getTotalMem(): int = return -1 + + proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} = + result = alloc0(size) + proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} = + result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize)) + cast[PGenericSeq](result).len = len + cast[PGenericSeq](result).space = len + proc growObj(old: pointer, newsize: int): pointer = + result = realloc(old, newsize) + # XXX BUG: we need realloc0 here, but C does not support this... + + proc setStackBottom(theStackBottom: pointer) {.compilerproc.} = nil + proc nimGCref(p: pointer) {.compilerproc, inline.} = nil + proc nimGCunref(p: pointer) {.compilerproc, inline.} = nil + + proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} = + dest^ = src + proc asgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} = + dest^ = src + proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerproc, inline.} = + dest^ = src + + include cellsets +else: + include alloc + include cellsets + assert(sizeof(TCell) == sizeof(TFreeCell)) + include gc + +{.pop.} + + diff --git a/lib/os.nim b/lib/os.nim index b69002715..20e803ec0 100644 --- a/lib/os.nim +++ b/lib/os.nim @@ -546,7 +546,7 @@ proc getApplicationFilename(): string = # Solaris: # /proc//object/a.out (filename only) # /proc//path/a.out (complete pathname) - # *BSD (and maybe Darwing too): + # *BSD (and maybe Darwin too): # /proc//file when defined(windows): result = newString(256) diff --git a/lib/osproc.nim b/lib/osproc.nim index 2282e802d..205460614 100644 --- a/lib/osproc.nim +++ b/lib/osproc.nim @@ -1,20 +1,21 @@ # # # Nimrod's Runtime Library -# (c) Copyright 2008 Andreas Rumpf +# (c) Copyright 2009 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -## This module implements an advanced facility for executing OS processes. -## On Windows this module is currently broken. Please help! +## This module implements an advanced facility for executing OS processes +## and process communication. +## **On Windows this module does not work properly. Please help!** import os, strtabs, streams when defined(windows): - import windows + import winlean type TProcess = object of TObject @@ -41,6 +42,10 @@ proc executeProcess*(command: string, ## A convience procedure that executes ``command`` with ``startProcess`` ## and returns its output as a string. +proc executeCommand*(command: string): int + ## Executes ``command`` and returns its error code. Standard input, output, + ## error streams are inherited from the calling process. + proc startProcess*(command: string, workingDir: string = "", args: openarray[string] = [], @@ -133,14 +138,14 @@ when defined(Windows): proc hsReadData(s: PFileHandleStream, buffer: pointer, bufLen: int): int = var br: int32 - var a = windows.ReadFile(s.handle, buffer, bufLen, br, nil) + var a = winlean.ReadFile(s.handle, buffer, bufLen, br, nil) if a == 0: OSError() result = br #atEnd = bytesRead < bufLen proc hsWriteData(s: PFileHandleStream, buffer: pointer, bufLen: int) = var bytesWritten: int32 - var a = windows.writeFile(s.handle, buffer, bufLen, bytesWritten, nil) + var a = winlean.writeFile(s.handle, buffer, bufLen, bytesWritten, nil) if a == 0: OSError() proc newFileHandleStream(handle: THandle): PFileHandleStream = @@ -180,12 +185,12 @@ when defined(Windows): # O_WRONLY {.importc: "_O_WRONLY", header: "".}: int # O_RDONLY {.importc: "_O_RDONLY", header: "".}: int - proc CreatePipeHandles(Inhandle, OutHandle: ptr THandle) = + proc CreatePipeHandles(Inhandle, OutHandle: var THandle) = var piInheritablePipe: TSecurityAttributes piInheritablePipe.nlength = SizeOF(TSecurityAttributes) - piInheritablePipe.lpSecurityDescriptor = Nil + piInheritablePipe.lpSecurityDescriptor = nil piInheritablePipe.Binherithandle = 1 - if CreatePipe(Inhandle, Outhandle, addr(piInheritablePipe), 0) == 0'i32: + if CreatePipe(Inhandle, Outhandle, piInheritablePipe, 0) == 0'i32: OSError() proc startProcess*(command: string, @@ -201,15 +206,15 @@ when defined(Windows): hi, ho, he: THandle SI.cb = SizeOf(SI) SI.dwFlags = STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES - CreatePipeHandles(addr(SI.hStdInput), addr(HI)) - CreatePipeHandles(addr(HO), addr(Si.hStdOutput)) + CreatePipeHandles(SI.hStdInput, HI) + CreatePipeHandles(HO, Si.hStdOutput) #SI.hStdInput = GetStdHandle(STD_INPUT_HANDLE()) #SI.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE()) if poStdErrToStdOut in options: SI.hStdError = SI.hStdOutput HE = HO else: - CreatePipeHandles(addr(HE), addr(Si.hStdError)) + CreatePipeHandles(HE, Si.hStdError) #SI.hStdError = GetStdHandle(STD_ERROR_HANDLE()) #result.inputHandle = open_osfhandle(HI, O_WRONLY) #if result.inputHandle == -1'i32: OSError() @@ -224,16 +229,12 @@ when defined(Windows): var wd: cstring = nil if len(workingDir) > 0: wd = workingDir if env == nil: - success = Windows.CreateProcess(nil, - cmdl, nil, nil, 0, - NORMAL_PRIORITY_CLASS, nil, wd, - addr(SI), addr(ProcInfo)) + success = winlean.CreateProcess(nil, + cmdl, nil, nil, 0, NORMAL_PRIORITY_CLASS, nil, wd, SI, ProcInfo) else: var e = buildEnv(env) - success = Windows.CreateProcess(nil, - cmdl, nil, nil, 0, - NORMAL_PRIORITY_CLASS, e, wd, - addr(SI), addr(ProcInfo)) + success = winlean.CreateProcess(nil, + cmdl, nil, nil, 0, NORMAL_PRIORITY_CLASS, e, wd, SI, ProcInfo) dealloc(e) dealloc(cmdl) if success == 0: @@ -249,7 +250,7 @@ when defined(Windows): discard ResumeThread(p.FThreadHandle) proc running(p: PProcess): bool = - var x = waitForSingleObject(p.FThreadHandle, 50) + var x = waitForSingleObject(p.FProcessHandle, 50) return x == WAIT_TIMEOUT proc terminate(p: PProcess) = @@ -257,11 +258,11 @@ when defined(Windows): discard TerminateProcess(p.FProcessHandle, 0) proc waitForExit(p: PProcess): int = - discard WaitForSingleObject(p.FThreadHandle, Infinite) - var res: dword + discard CloseHandle(p.FThreadHandle) + discard WaitForSingleObject(p.FProcessHandle, Infinite) + var res: int32 discard GetExitCodeProcess(p.FProcessHandle, res) result = res - discard CloseHandle(p.FThreadHandle) discard CloseHandle(p.FProcessHandle) proc inputStream(p: PProcess): PStream = @@ -273,6 +274,29 @@ when defined(Windows): proc errorStream(p: PProcess): PStream = result = newFileHandleStream(p.errorHandle) + proc executeCommand(command: string): int = + var + SI: TStartupInfo + ProcInfo: TProcessInformation + process: THandle + L: int32 + SI.cb = SizeOf(SI) + SI.hStdError = GetStdHandle(STD_ERROR_HANDLE) + SI.hStdInput = GetStdHandle(STD_INPUT_HANDLE) + SI.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE) + if winlean.CreateProcess(nil, command, nil, nil, 0, + NORMAL_PRIORITY_CLASS, nil, nil, SI, ProcInfo) == 0: + OSError() + else: + Process = ProcInfo.hProcess + discard CloseHandle(ProcInfo.hThread) + if WaitForSingleObject(Process, INFINITE) != -1: + discard GetExitCodeProcess(Process, L) + result = int(L) + else: + result = -1 + discard CloseHandle(Process) + else: import posix @@ -321,15 +345,15 @@ else: if pid == 0: ## child process: discard close(p_stdin[writeIdx]) - discard dup2(p_stdin[readIdx], readIdx) + if dup2(p_stdin[readIdx], readIdx) < 0: OSError() discard close(p_stdout[readIdx]) - discard dup2(p_stdout[writeIdx], writeIdx) + if dup2(p_stdout[writeIdx], writeIdx) < 0: OSError() if poStdErrToStdOut in options: - discard dup2(p_stdout[writeIdx], 2) + if dup2(p_stdout[writeIdx], 2) < 0: OSError() else: if pipe(p_stderr) != 0'i32: OSError("failed to create a pipe") discard close(p_stderr[readIdx]) - discard dup2(p_stderr[writeIdx], 2) + if dup2(p_stderr[writeIdx], 2) < 0: OSError() if workingDir.len > 0: os.setCurrentDir(workingDir) @@ -347,8 +371,7 @@ else: else: discard execve("/bin/sh", a, ToCStringArray(env)) # too risky to raise an exception here: - echo("execve call failed: " & $strerror(errno)) - quit(1) + quit("execve call failed: " & $strerror(errno)) # Parent process. Copy process information. result.id = pid @@ -376,6 +399,7 @@ else: if running(p): discard kill(p.id, SIGKILL) proc waitForExit(p: PProcess): int = + result = 1 if waitPid(p.id, p.exitCode, 0) == int(p.id): result = p.exitCode @@ -393,3 +417,11 @@ else: var f: TFile if not openFile(f, p.errorHandle, fmRead): OSError() result = newFileStream(f) + + proc csystem(cmd: cstring): cint {.nodecl, importc: "system".} + + proc executeCommand(command: string): int = + result = csystem(command) + +when isMainModule: + echo executeCommand("gcc -v") diff --git a/lib/parsecsv.nim b/lib/parsecsv.nim new file mode 100644 index 000000000..7665c8287 --- /dev/null +++ b/lib/parsecsv.nim @@ -0,0 +1,176 @@ +# +# +# Nimrod's Runtime Library +# (c) Copyright 2009 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements a simple high performance `CSV`:idx: +## (`comma separated value`:idx:) parser. +## +## Example: How to use the parser +## ============================== +## +## .. code-block:: nimrod +## import os, parsecsv, streams +## var s = newFileStream(ParamStr(1), fmRead) +## if s == nil: quit("cannot open the file" & ParamStr(1)) +## var x: TCsvParser +## open(x, s, ParamStr(1)) +## while readRow(x): +## Echo "new row: " +## for val in items(x.row): +## Echo "##", val, "##" +## close(x) +## + +import + lexbase, streams + +type + TCsvRow* = seq[string] ## a row in a CSV file + TCsvParser* = object of TBaseLexer ## the parser object. + row*: TCsvRow ## the current row + filename: string + sep, quote, esc: char + skipWhite: bool + currRow: int + + EInvalidCsv* = object of EIO ## exception that is raised if + ## a parsing error occurs + +proc raiseEInvalidCsv(filename: string, line, col: int, + msg: string) {.noreturn.} = + var e: ref EInvalidCsv + new(e) + e.msg = filename & "(" & $line & ", " & $col & ") Error: " & msg + raise e + +proc error(my: TCsvParser, pos: int, msg: string) = + raiseEInvalidCsv(my.filename, my.LineNumber, getColNumber(my, pos), msg) + +proc open*(my: var TCsvParser, input: PStream, filename: string, + separator = ',', quote = '"', escape = '\0', + skipInitialSpace = false) = + ## initializes the parser with an input stream. `Filename` is only used + ## for nice error messages. The parser's behaviour can be controlled by + ## the diverse optional parameters: + ## - `separator`: character used to separate fields + ## - `quote`: Used to quote fields containing special characters like + ## `separator`, `quote` or new-line characters. '\0' disables the parsing + ## of quotes. + ## - `escape`: removes any special meaning from the following character; + ## '\0' disables escaping; if escaping is disabled and `quote` is not '\0', + ## two `quote` characters are parsed one literal `quote` character. + ## - `skipInitialSpace`: If true, whitespace immediately following the + ## `separator` is ignored. + lexbase.open(my, input) + my.filename = filename + my.sep = separator + my.quote = quote + my.esc = escape + my.skipWhite = skipInitialSpace + my.row = @[] + my.currRow = 0 + +proc parseField(my: var TCsvParser, a: var string) = + var pos = my.bufpos + var buf = my.buf + if my.skipWhite: + while buf[pos] in {' ', '\t'}: inc(pos) + setLen(a, 0) # reuse memory + if buf[pos] == my.quote and my.quote != '\0': + inc(pos) + while true: + var c = buf[pos] + if c == '\0': + my.bufpos = pos # can continue after exception? + error(my, pos, my.quote & " expected") + break + elif c == my.quote: + if my.esc == '\0' and buf[pos+1] == my.quote: + add(a, my.quote) + inc(pos, 2) + else: + inc(pos) + break + elif c == my.esc: + add(a, buf[pos+1]) + inc(pos, 2) + else: + case c + of '\c': + pos = handleCR(my, pos) + add(a, "\n") + of '\l': + pos = handleLF(my, pos) + add(a, "\n") + else: + add(a, c) + inc(pos) + else: + while true: + var c = buf[pos] + if c == my.sep: break + if c in {'\c', '\l', '\0'}: break + add(a, c) + inc(pos) + my.bufpos = pos + +proc processedRows*(my: var TCsvParser): int = + ## returns number of the processed rows + return my.currRow + +proc readRow*(my: var TCsvParser, columns = 0): bool = + ## reads the next row; if `columns` > 0, it expects the row to have + ## exactly this many columns. Returns false if the end of the file + ## has been encountered else true. + var col = 0 # current column + var oldpos = my.bufpos + while my.buf[my.bufpos] != '\0': + var oldlen = my.row.len + if oldlen < col+1: + setLen(my.row, col+1) + my.row[col] = "" + parseField(my, my.row[col]) + inc(col) + if my.buf[my.bufpos] == my.sep: + inc(my.bufpos) + else: + case my.buf[my.bufpos] + of '\c', '\l': + # skip empty lines: + while true: + case my.buf[my.bufpos] + of '\c': my.bufpos = handleCR(my, my.bufpos) + of '\l': my.bufpos = handleLF(my, my.bufpos) + else: break + of '\0': nil + else: error(my, my.bufpos, my.sep & " expected") + break + + setlen(my.row, col) + result = col > 0 + if result and col != columns and columns > 0: + error(my, oldpos+1, $columns & " columns expected, but found " & + $col & " columns") + inc(my.currRow) + +proc close*(my: var TCsvParser) {.inline.} = + ## closes the parser `my` and its associated input stream. + lexbase.close(my) + +when isMainModule: + import os + var s = newFileStream(ParamStr(1), fmRead) + if s == nil: quit("cannot open the file" & ParamStr(1)) + var x: TCsvParser + open(x, s, ParamStr(1)) + while readRow(x): + Echo "new row: " + for val in items(x.row): + Echo "##", val, "##" + close(x) + diff --git a/lib/parsexml.nim b/lib/parsexml.nim index 81b6da1de..78be404d1 100644 --- a/lib/parsexml.nim +++ b/lib/parsexml.nim @@ -22,7 +22,7 @@ ## * Thus the checks would have been very difficult to implement properly with ## little benefit, especially since they are simple to implement in the ## client. The client should use the `errorMsgExpected` proc to generate -## a nice error message that fits to the other error messages this library +## a nice error message that fits the other error messages this library ## creates. ## ## diff --git a/lib/ptrset.nim b/lib/ptrset.nim deleted file mode 100644 index 95f01b16f..000000000 --- a/lib/ptrset.nim +++ /dev/null @@ -1,205 +0,0 @@ -# This implements a new pointer set. Access time O(1). For 32 bit systems, we -# currently need 3 memory accesses. - -const - PageSize = 1024 * sizeof(int) - MemAlignment = 8 # minimal memory block that can be allocated - BitsPerUnit = sizeof(int)*8 - # a "unit" is a word, i.e. 4 bytes - # on a 32 bit system; I do not use the term "word" because under 32-bit - # Windows it is sometimes only 16 bits - - BitsPerPage = PageSize div MemAlignment - UnitsPerPage = BitsPerPage div BitsPerUnit - # how many units do we need to describe a page: - # on 32 bit systems this is only 16 (!) - -type - PPointer = ptr pointer - - TCollectorData = int - TCell {.final.} = object - refcount: TCollectorData # the refcount and bit flags - typ: PNimType - stackcount: int # stack counter for debugging - drefc: int # real reference counter for debugging - - PCell = ptr TCell - -proc cellToUsr(cell: PCell): pointer {.inline.} = - # convert object (=pointer to refcount) to pointer to userdata - result = cast[pointer](cast[TAddress](cell)+%TAddress(sizeof(TCell))) - -proc usrToCell(usr: pointer): PCell {.inline.} = - # convert pointer to userdata to object (=pointer to refcount) - result = cast[PCell](cast[TAddress](usr)-%TAddress(sizeof(TCell))) - -proc gcAlloc(size: int): pointer = - result = alloc0(size) - if result == nil: raiseOutOfMem() - -# ------------------ Zero count table (ZCT) and any table (AT) ------------- - -# this that has to equals zero, otherwise we have to round up UnitsPerPage: -when BitsPerPage mod BitsPerUnit != 0: - {.error: "(BitsPerPage mod BitsPerUnit) should be zero!".} - -# ------------------- cell set handling ------------------------------ -# A cellset consists of a hash table of page descriptors. A page -# descriptor has a bit for -# every Memalignment'th byte in the page. -# However, only bits corresponding to addresses that start memory blocks -# are set. -# Page descriptors are also linked to a list; the list -# is used for easy traversing of all page descriptors; this allows a -# fast iterator. -# We use a specialized hashing scheme; the formula is : -# hash = Page bitand max -# We use linear probing with the formular: (5*h)+1 -# Thus we likely get no collisions at all if the pages are given to us -# in a sequential manner by the operating system! -const - bitsPerNode = 10 # we use 10 bits per node; this means 3 memory accesses on - # 32 bit systems - -type - PPageDesc = ptr TPageDesc - - TBitIndex = range[0..UnitsPerPage-1] - - TPageDesc {.final.} = object - next: PPageDesc # all nodes are connected with this pointer - key: TAddress # start address at bit 0 - bits: array[TBitIndex, int] # a bit vector - - PPageDescArray = ptr array[0..1000_000, PPageDesc] - TCellSet {.final.} = object - counter, max: int - head: PPageDesc - data: PPageDescArray - - TSetNode {.final.} = object - n: array[0.. (1 shl bitsPerNode)-1, PSetNode] - PSetNode = ptr TSetNode - -const - InitCellSetSize = 1024 # must be a power of two! - -proc CellSetInit(s: var TCellSet) = - s.data = gcAlloc(InitCellSetSize * sizeof(PPageDesc)) - s.max = InitCellSetSize-1 - s.counter = 0 - s.head = nil - -proc CellSetDeinit(s: var TCellSet) = - var it = s.head - while it != nil: - var n = it.next - dealloc(it) - it = n - s.head = nil # play it safe here - dealloc(s.data) - s.data = nil - s.counter = 0 - -proc CellSetGet(t: TCellSet, key: TAddress): PPageDesc = - var h = cast[int](key) and t.max - while t.data[h] != nil: - if t.data[h].key == key: return t.data[h] - h = nextTry(h, t.max) - return nil - -proc CellSetRawInsert(t: TCellSet, data: PPageDescArray, - desc: PPageDesc) = - var h = cast[int](desc.key) and t.max - while data[h] != nil: - assert(data[h] != desc) - h = nextTry(h, t.max) - assert(data[h] == nil) - data[h] = desc - -proc CellSetEnlarge(t: var TCellSet) = - var - n: PPageDescArray - oldMax = t.max - t.max = ((t.max+1)*2)-1 - n = gcAlloc((t.max + 1) * sizeof(PPageDesc)) - for i in 0 .. oldmax: - if t.data[i] != nil: - CellSetRawInsert(t, n, t.data[i]) - dealloc(t.data) - t.data = n - -proc CellSetPut(t: var TCellSet, key: TAddress): PPageDesc = - var h = cast[int](key) and t.max - while true: - var x = t.data[h] - if x == nil: break - if x.key == key: return x - h = nextTry(h, t.max) - - if (t.max+1) * 2 < t.counter * 3: CellSetEnlarge(t) - inc(t.counter) - h = cast[int](key) and t.max - while t.data[h] != nil: h = nextTry(h, t.max) - assert(t.data[h] == nil) - # the new page descriptor goes into result - result = gcAlloc(sizeof(TPageDesc)) - result.next = t.head - result.key = key - t.head = result - t.data[h] = result - -# ---------- slightly higher level procs ---------------------------------- - -proc in_Operator(s: TCellSet, cell: PCell): bool = - var - u: TAddress - t: PPageDesc - u = cast[TAddress](cell) - t = CellSetGet(s, u /% PageSize) - if t != nil: - u = (u %% PageSize) /% MemAlignment - result = (t.bits[u /% BitsPerUnit] and (1 shl (u %% BitsPerUnit))) != 0 - else: - result = false - -proc incl(s: var TCellSet, cell: PCell) = - var - u: TAddress - t: PPageDesc - u = cast[TAddress](cell) - t = CellSetPut(s, u /% PageSize) - u = (u %% PageSize) /% MemAlignment - t.bits[u /% BitsPerUnit] = t.bits[u /% BitsPerUnit] or - (1 shl (u %% BitsPerUnit)) - -proc excl(s: var TCellSet, cell: PCell) = - var - u: TAddress - t: PPageDesc - u = cast[TAddress](cell) - t = CellSetGet(s, u /% PageSize) - if t != nil: - u = (u %% PageSize) /% MemAlignment - t.bits[u %% BitsPerUnit] = (t.bits[u /% BitsPerUnit] and - not (1 shl (u %% BitsPerUnit))) - -iterator elements(t: TCellSet): PCell {.inline.} = - # while traversing it is forbidden to add pointers to the tree! - var r = t.head - while r != nil: - var i = 0 - while i <= high(r.bits): - var w = r.bits[i] # taking a copy of r.bits[i] here is correct, because - # modifying operations are not allowed during traversation - var j = 0 - while w != 0: # test all remaining bits for zero - if (w and 1) != 0: # the bit is set! - yield cast[PCell]((r.key *% PageSize) +% - (i*%BitsPerUnit+%j) *% MemAlignment) - inc(j) - w = w shr 1 - inc(i) - r = r.next - diff --git a/lib/repr.nim b/lib/repr.nim index 35c5f9f42..765d66be0 100644 --- a/lib/repr.nim +++ b/lib/repr.nim @@ -104,7 +104,7 @@ proc reprSet(p: pointer, typ: PNimType): string {.compilerproc.} = type TReprClosure {.final.} = object # we cannot use a global variable here # as this wouldn't be thread-safe - marked: TCellSeq + marked: TCellSet recdepth: int # do not recurse endless indent: int # indentation @@ -171,14 +171,14 @@ proc reprRecord(result: var string, p: pointer, typ: PNimType, proc reprRef(result: var string, p: pointer, typ: PNimType, cl: var TReprClosure) = # we know that p is not nil here: - when defined(boehmGC): + when defined(boehmGC) or defined(nogc): var cell = cast[PCell](p) else: var cell = usrToCell(p) add result, "ref " & reprPointer(p) if cell notin cl.marked: # only the address is shown: - add(cl.marked, cell) + incl(cl.marked, cell) add result, " --> " reprAux(result, p, typ.base, cl) diff --git a/lib/strutils.nim b/lib/strutils.nim index e3a412053..075e6b252 100644 --- a/lib/strutils.nim +++ b/lib/strutils.nim @@ -865,6 +865,15 @@ proc validEmailAddress*(s: string): bool = "aero", "jobs", "museum": return true return false +proc validIdentifier*(s: string): bool = + ## returns true if `s` is a valid identifier. A valid identifier starts + ## with a character of the set `IdentStartChars` and is followed by any + ## number of characters of the set `IdentChars`. + if s[0] in IdentStartChars: + for i in 1..s.len-1: + if s[i] notin IdentChars: return false + return true + proc editDistance*(a, b: string): int = ## returns the edit distance between `a` and `b`. This uses the Levenshtein ## distance algorithm with only a linear memory overhead. This implementation diff --git a/lib/sysio.nim b/lib/sysio.nim index d79b5e287..bd52ef5ea 100644 --- a/lib/sysio.nim +++ b/lib/sysio.nim @@ -1,7 +1,7 @@ # # # Nimrod's Runtime Library -# (c) Copyright 2006 Andreas Rumpf +# (c) Copyright 2009 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -54,7 +54,12 @@ proc readLine(f: TFile): string = rawReadLine(f, result) proc write(f: TFile, s: string) = fputs(s, f) -proc write(f: TFile, i: int) = fprintf(f, "%ld", i) +proc write(f: TFile, i: int) = + when sizeof(int) == 8: + fprintf(f, "%lld", i) + else: + fprintf(f, "%ld", i) + proc write(f: TFile, b: bool) = if b: write(f, "true") else: write(f, "false") diff --git a/lib/sysstr.nim b/lib/sysstr.nim index ea46fa503..783bce6af 100644 --- a/lib/sysstr.nim +++ b/lib/sysstr.nim @@ -1,7 +1,7 @@ # # # Nimrod's Runtime Library -# (c) Copyright 2006 Andreas Rumpf +# (c) Copyright 2009 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -37,27 +37,20 @@ proc eqStrings(a, b: NimString): bool {.inline, compilerProc.} = proc rawNewString(space: int): NimString {.compilerProc.} = var s = space if s < 8: s = 7 - when defined(boehmGC): - result = cast[NimString](boehmAllocAtomic( - sizeof(TGenericSeq) + (s+1) * sizeof(char))) - result.len = 0 - result.data[0] = '\0' - else: - result = cast[NimString](newObj(addr(strDesc), sizeof(TGenericSeq) + - (s+1) * sizeof(char))) + result = cast[NimString](newObj(addr(strDesc), sizeof(TGenericSeq) + + (s+1) * sizeof(char))) result.space = s proc mnewString(len: int): NimString {.exportc.} = + #c_fprintf(c_stdout, "[NEWSTRING] len: %ld\n", len) result = rawNewString(len) result.len = len - when defined(boehmGC): - result.data[len] = '\0' proc toNimStr(str: CString, len: int): NimString {.compilerProc.} = result = rawNewString(len) result.len = len c_memcpy(result.data, str, (len+1) * sizeof(Char)) - result.data[len] = '\0' # IO.readline relies on this! + result.data[len] = '\0' # readline relies on this! proc cstrToNimstr(str: CString): NimString {.compilerProc.} = return toNimstr(str, c_strlen(str)) @@ -184,9 +177,9 @@ proc setLengthStr(s: NimString, newLen: int): NimString {.compilerProc.} = proc incrSeq(seq: PGenericSeq, elemSize: int): PGenericSeq {.compilerProc.} = # increments the length by one: - # this is needed for supporting the &= operator; + # this is needed for supporting ``add``; # - # add seq x generates: + # add(seq, x) generates: # seq = incrSeq(seq, sizeof(x)); # seq[seq->len-1] = x; when false: @@ -229,7 +222,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {. GenericSeqSize)) elif newLen < result.len: # we need to decref here, otherwise the GC leaks! - when not defined(boehmGC): + when not defined(boehmGC) and not defined(nogc): for i in newLen..result.len-1: forAllChildrenAux(cast[pointer](cast[TAddress](result) +% GenericSeqSize +% (i*%elemSize)), diff --git a/lib/system.nim b/lib/system.nim index 67a4221f1..23dbfc816 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1,7 +1,7 @@ # # # Nimrod's Runtime Library -# (c) Copyright 2008 Andreas Rumpf +# (c) Copyright 2009 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -415,11 +415,11 @@ proc `<=` *(x, y: int32): bool {.magic: "LeI", noSideEffect.} proc `<=` *(x, y: int64): bool {.magic: "LeI64", noSideEffect.} ## Returns true iff `x` is less than or equal to `y`. -proc `<` *(x, y: int): bool {.magic: "LtI", noSideEffect.} -proc `<` *(x, y: int8): bool {.magic: "LtI", noSideEffect.} -proc `<` *(x, y: int16): bool {.magic: "LtI", noSideEffect.} -proc `<` *(x, y: int32): bool {.magic: "LtI", noSideEffect.} -proc `<` *(x, y: int64): bool {.magic: "LtI64", noSideEffect.} +proc `<` *(x, y: int): bool {.magic: "LtI", noSideEffect.} +proc `<` *(x, y: int8): bool {.magic: "LtI", noSideEffect.} +proc `<` *(x, y: int16): bool {.magic: "LtI", noSideEffect.} +proc `<` *(x, y: int32): bool {.magic: "LtI", noSideEffect.} +proc `<` *(x, y: int64): bool {.magic: "LtI64", noSideEffect.} ## Returns true iff `x` is less than `y`. proc abs*(x: int): int {.magic: "AbsI", noSideEffect.} @@ -790,9 +790,10 @@ proc addQuitProc*(QuitProc: proc {.noconv.}) {.importc: "atexit", nodecl.} # In case of an unhandled exeption the exit handlers should # not be called explicitly! The user may decide to do this manually though. -proc copy*(s: string, first = 0): string {.importc: "copyStr", noSideEffect.} -proc copy*(s: string, first, last: int): string {.importc: "copyStrLast", - noSideEffect.} +proc copy*(s: string, first = 0): string {. + magic: "CopyStr", importc: "copyStr", noSideEffect.} +proc copy*(s: string, first, last: int): string {. + magic: "CopyStrLast", importc: "copyStrLast", noSideEffect.} ## copies a slice of `s` into a new string and returns this new ## string. The bounds `first` and `last` denote the indices of ## the first and last characters that shall be copied. If ``last`` @@ -803,7 +804,8 @@ proc setLen*(s: var string, newlen: int) {.magic: "SetLengthStr".} ## If the current length is greater than the new length, ## ``s`` will be truncated. -proc newString*(len: int): string {.importc: "mnewString", noSideEffect.} +proc newString*(len: int): string {. + magic: "NewString", importc: "mnewString", noSideEffect.} ## returns a new string of length ``len`` but with uninitialized ## content. One needs to fill the string character after character ## with the index operator ``s[i]``. This procedure exists only for @@ -835,30 +837,23 @@ proc equalMem*(a, b: Pointer, size: int): bool {. ## otherwise. Like any procedure dealing with raw memory this is ## *unsafe*. -const - mallocHeader = "" - -proc alloc*(size: int): pointer {. - importc: "malloc", header: mallocHeader, noconv.} +proc alloc*(size: int): pointer {.noconv.} ## allocates a new memory block with at least ``size`` bytes. The ## block has to be freed with ``realloc(block, 0)`` or ## ``dealloc(block)``. The block is not initialized, so reading ## from it before writing to it is undefined behaviour! -proc alloc0*(size: int): pointer {. - importc: "ALLOC_0", header: mallocHeader, noconv.} +proc alloc0*(size: int): pointer {.noconv.} ## allocates a new memory block with at least ``size`` bytes. The ## block has to be freed with ``realloc(block, 0)`` or ## ``dealloc(block)``. The block is initialized with all bytes ## containing zero, so it is somewhat safer than ``alloc``. -proc realloc*(p: Pointer, newsize: int): pointer {. - importc: "realloc", header: mallocHeader, noconv.} +proc realloc*(p: Pointer, newsize: int): pointer {.noconv.} ## grows or shrinks a given memory block. If p is **nil** then a new ## memory block is returned. In either way the block has at least ## ``newsize`` bytes. If ``newsize == 0`` and p is not **nil** ## ``realloc`` calls ``dealloc(p)``. In other cases the block has to ## be freed with ``dealloc``. -proc dealloc*(p: Pointer) {. - importc: "free", header: mallocHeader, noconv.} +proc dealloc*(p: Pointer) {.noconv.} ## frees the memory allocated with ``alloc``, ``alloc0`` or ## ``realloc``. This procedure is dangerous! If one forgets to ## free the memory a leak occurs; if one tries to access freed @@ -1436,66 +1431,7 @@ when not defined(EcmaScript) and not defined(NimrodVM): else: result = n.sons[n.len] - when defined(boehmgc): - const - boehmLib = "/opt/lib/libgc.so" - - proc boehmGC_disable {.importc: "GC_disable", dynlib: boehmLib.} - proc boehmGC_enable {.importc: "GC_enable", dynlib: boehmLib.} - proc boehmGCincremental {. - importc: "GC_enable_incremental", dynlib: boehmLib.} - proc boehmGCfullCollect {.importc: "GC_gcollect", dynlib: boehmLib.} - proc boehmAlloc(size: int): pointer {. - importc: "GC_malloc", dynlib: boehmLib.} - proc boehmAllocAtomic(size: int): pointer {. - importc: "GC_malloc_atomic", dynlib: boehmLib.} - proc boehmRealloc(p: pointer, size: int): pointer {. - importc: "GC_realloc", dynlib: boehmLib.} - proc boehmDealloc(p: pointer) {.importc: "GC_free", dynlib: boehmLib.} - - include cellsets - - when defined(boehmGC): - proc initGC() = nil - - #boehmGCincremental() - - proc GC_disable() = boehmGC_disable() - proc GC_enable() = boehmGC_enable() - proc GC_fullCollect() = boehmGCfullCollect() - proc GC_setStrategy(strategy: TGC_Strategy) = nil - proc GC_enableMarkAndSweep() = nil - proc GC_disableMarkAndSweep() = nil - proc GC_getStatistics(): string = return "" - - proc getOccupiedMem(): int = return -1 - proc getFreeMem(): int = return -1 - proc getTotalMem(): int = return -1 - - proc growObj(old: pointer, newsize: int): pointer {.inline.} = - result = boehmRealloc(old, newsize) - proc newObj(size: int): pointer {.compilerproc.} = - result = boehmAlloc(size) - proc newSeq(baseSize, len: int): pointer {.compilerproc.} = - # XXX: overflow checks! - result = newObj(len * baseSize + GenericSeqSize) - cast[PGenericSeq](result).len = len - cast[PGenericSeq](result).space = len - - proc setStackBottom(theStackBottom: pointer) {.compilerproc.} = nil - proc nimGCref(p: pointer) {.compilerproc, inline.} = nil - proc nimGCunref(p: pointer) {.compilerproc, inline.} = nil - - proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} = - dest^ = src - proc asgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} = - dest^ = src - proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerproc, inline.} = - dest^ = src - - elif not defined(nogc): - include gc - + include mm include sysstr include assign include repr diff --git a/lib/windows/windows.nim b/lib/windows/windows.nim index ea650e80a..1865f3369 100644 --- a/lib/windows/windows.nim +++ b/lib/windows/windows.nim @@ -3879,7 +3879,7 @@ const SW_SHOWNORMAL* = 1 WPF_RESTORETOMAXIMIZED* = 2 WPF_SETMINPOSITION* = 1 # Sleep - INFINITE* = 0xFFFFFFFF # SystemParametersInfo + INFINITE* = -1'i32 # SystemParametersInfo SPI_GETBEEP* = 1 SPI_SETBEEP* = 2 SPI_GETMOUSE* = 3 diff --git a/lib/winlean.nim b/lib/winlean.nim new file mode 100644 index 000000000..747ce7db5 --- /dev/null +++ b/lib/winlean.nim @@ -0,0 +1,108 @@ +# +# +# Nimrod's Runtime Library +# (c) Copyright 2009 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements a small wrapper for some needed Win API procedures, +## so that the Nimrod compiler does not depend on the huge Windows module. + +type + THandle* = int + WINBOOL* = int32 + + TSECURITY_ATTRIBUTES* {.final, pure.} = object + nLength*: int32 + lpSecurityDescriptor*: pointer + bInheritHandle*: WINBOOL + + TSTARTUPINFO* {.final, pure.} = object + cb*: int32 + lpReserved*: cstring + lpDesktop*: cstring + lpTitle*: cstring + dwX*: int32 + dwY*: int32 + dwXSize*: int32 + dwYSize*: int32 + dwXCountChars*: int32 + dwYCountChars*: int32 + dwFillAttribute*: int32 + dwFlags*: int32 + wShowWindow*: int16 + cbReserved2*: int16 + lpReserved2*: pointer + hStdInput*: THANDLE + hStdOutput*: THANDLE + hStdError*: THANDLE + + TPROCESS_INFORMATION* {.final, pure.} = object + hProcess*: THANDLE + hThread*: THANDLE + dwProcessId*: int32 + dwThreadId*: int32 + +const + STARTF_USESHOWWINDOW* = 1'i32 + STARTF_USESTDHANDLES* = 256'i32 + HIGH_PRIORITY_CLASS* = 128'i32 + IDLE_PRIORITY_CLASS* = 64'i32 + NORMAL_PRIORITY_CLASS* = 32'i32 + REALTIME_PRIORITY_CLASS* = 256'i32 + WAIT_TIMEOUT* = 0x00000102'i32 + INFINITE* = -1'i32 + + STD_INPUT_HANDLE* = -10'i32 + STD_OUTPUT_HANDLE* = -11'i32 + STD_ERROR_HANDLE* = -12'i32 + +proc CloseHandle*(hObject: THANDLE): WINBOOL {.stdcall, dynlib: "kernel32", + importc: "CloseHandle".} + +proc ReadFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToRead: int32, + lpNumberOfBytesRead: var int32, lpOverlapped: pointer): WINBOOL{. + stdcall, dynlib: "kernel32", importc: "ReadFile".} + +proc WriteFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToWrite: int32, + lpNumberOfBytesWritten: var int32, + lpOverlapped: pointer): WINBOOL{. + stdcall, dynlib: "kernel32", importc: "WriteFile".} + +proc CreatePipe*(hReadPipe, hWritePipe: var THandle, + lpPipeAttributes: var TSECURITY_ATTRIBUTES, + nSize: int32): WINBOOL{. + stdcall, dynlib: "kernel32", importc: "CreatePipe".} + +proc CreateProcess*(lpApplicationName, lpCommandLine: cstring, + lpProcessAttributes: ptr TSECURITY_ATTRIBUTES, + lpThreadAttributes: ptr TSECURITY_ATTRIBUTES, + bInheritHandles: WINBOOL, dwCreationFlags: int32, + lpEnvironment: pointer, lpCurrentDirectory: cstring, + lpStartupInfo: var TSTARTUPINFO, + lpProcessInformation: var TPROCESS_INFORMATION): WINBOOL{. + stdcall, dynlib: "kernel32", importc: "CreateProcessA".} + +proc SuspendThread*(hThread: THANDLE): int32 {.stdcall, dynlib: "kernel32", + importc: "SuspendThread".} +proc ResumeThread*(hThread: THANDLE): int32 {.stdcall, dynlib: "kernel32", + importc: "ResumeThread".} + +proc WaitForSingleObject*(hHandle: THANDLE, dwMilliseconds: int32): int32 {. + stdcall, dynlib: "kernel32", importc: "WaitForSingleObject".} + +proc TerminateProcess*(hProcess: THANDLE, uExitCode: int): WINBOOL {.stdcall, + dynlib: "kernel32", importc: "TerminateProcess".} + +proc GetExitCodeProcess*(hProcess: THANDLE, lpExitCode: var int32): WINBOOL {. + stdcall, dynlib: "kernel32", importc: "GetExitCodeProcess".} + +proc GetStdHandle*(nStdHandle: int32): THANDLE {.stdcall, dynlib: "kernel32", + importc: "GetStdHandle".} +proc SetStdHandle*(nStdHandle: int32, hHandle: THANDLE): WINBOOL {.stdcall, + dynlib: "kernel32", importc: "SetStdHandle".} +proc FlushFileBuffers*(hFile: THANDLE): WINBOOL {.stdcall, dynlib: "kernel32", + importc: "FlushFileBuffers".} + diff --git a/lib/wz_jsgraphics.js b/lib/wz_jsgraphics.js deleted file mode 100644 index f4ba47b53..000000000 --- a/lib/wz_jsgraphics.js +++ /dev/null @@ -1,1107 +0,0 @@ -/* This notice must be untouched at all times. - -wz_jsgraphics.js v. 3.03 -The latest version is available at -http://www.walterzorn.com -or http://www.devira.com -or http://www.walterzorn.de - -Copyright (c) 2002-2004 Walter Zorn. All rights reserved. -Created 3. 11. 2002 by Walter Zorn (Web: http://www.walterzorn.com ) -Last modified: 28. 1. 2008 - -Performance optimizations for Internet Explorer -by Thomas Frank and John Holdsworth. -fillPolygon method implemented by Matthieu Haller. - -High Performance JavaScript Graphics Library. -Provides methods -- to draw lines, rectangles, ellipses, polygons - with specifiable line thickness, -- to fill rectangles, polygons, ellipses and arcs -- to draw text. -NOTE: Operations, functions and branching have rather been optimized -to efficiency and speed than to shortness of source code. - -LICENSE: LGPL - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License (LGPL) as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA, -or see http://www.gnu.org/copyleft/lesser.html -*/ - - -var jg_ok, jg_ie, jg_fast, jg_dom, jg_moz; - - -function _chkDHTM(x, i) -{ - x = document.body || null; - jg_ie = x && typeof x.insertAdjacentHTML != "undefined" && document.createElement; - jg_dom = (x && !jg_ie && - typeof x.appendChild != "undefined" && - typeof document.createRange != "undefined" && - typeof (i = document.createRange()).setStartBefore != "undefined" && - typeof i.createContextualFragment != "undefined"); - jg_fast = jg_ie && document.all && !window.opera; - jg_moz = jg_dom && typeof x.style.MozOpacity != "undefined"; - jg_ok = !!(jg_ie || jg_dom); -} - -function _pntCnvDom() -{ - var x = this.wnd.document.createRange(); - x.setStartBefore(this.cnv); - x = x.createContextualFragment(jg_fast? this._htmRpc() : this.htm); - if(this.cnv) this.cnv.appendChild(x); - this.htm = ""; -} - -function _pntCnvIe() -{ - if(this.cnv) this.cnv.insertAdjacentHTML("BeforeEnd", jg_fast? this._htmRpc() : this.htm); - this.htm = ""; -} - -function _pntDoc() -{ - this.wnd.document.write(jg_fast? this._htmRpc() : this.htm); - this.htm = ''; -} - -function _pntN() -{ - ; -} - -function _mkDiv(x, y, w, h) -{ - this.htm += '
<\/div>'; -} - -function _mkDivIe(x, y, w, h) -{ - this.htm += '%%'+this.color+';'+x+';'+y+';'+w+';'+h+';'; -} - -function _mkDivPrt(x, y, w, h) -{ - this.htm += '
<\/div>'; -} - -var _regex = /%%([^;]+);([^;]+);([^;]+);([^;]+);([^;]+);/g; -function _htmRpc() -{ - return this.htm.replace( - _regex, - '
\n'); -} - -function _htmPrtRpc() -{ - return this.htm.replace( - _regex, - '
\n'); -} - -function _mkLin(x1, y1, x2, y2) -{ - if(x1 > x2) - { - var _x2 = x2; - var _y2 = y2; - x2 = x1; - y2 = y1; - x1 = _x2; - y1 = _y2; - } - var dx = x2-x1, dy = Math.abs(y2-y1), - x = x1, y = y1, - yIncr = (y1 > y2)? -1 : 1; - - if(dx >= dy) - { - var pr = dy<<1, - pru = pr - (dx<<1), - p = pr-dx, - ox = x; - while(dx > 0) - {--dx; - ++x; - if(p > 0) - { - this._mkDiv(ox, y, x-ox, 1); - y += yIncr; - p += pru; - ox = x; - } - else p += pr; - } - this._mkDiv(ox, y, x2-ox+1, 1); - } - - else - { - var pr = dx<<1, - pru = pr - (dy<<1), - p = pr-dy, - oy = y; - if(y2 <= y1) - { - while(dy > 0) - {--dy; - if(p > 0) - { - this._mkDiv(x++, y, 1, oy-y+1); - y += yIncr; - p += pru; - oy = y; - } - else - { - y += yIncr; - p += pr; - } - } - this._mkDiv(x2, y2, 1, oy-y2+1); - } - else - { - while(dy > 0) - {--dy; - y += yIncr; - if(p > 0) - { - this._mkDiv(x++, oy, 1, y-oy); - p += pru; - oy = y; - } - else p += pr; - } - this._mkDiv(x2, oy, 1, y2-oy+1); - } - } -} - -function _mkLin2D(x1, y1, x2, y2) -{ - if(x1 > x2) - { - var _x2 = x2; - var _y2 = y2; - x2 = x1; - y2 = y1; - x1 = _x2; - y1 = _y2; - } - var dx = x2-x1, dy = Math.abs(y2-y1), - x = x1, y = y1, - yIncr = (y1 > y2)? -1 : 1; - - var s = this.stroke; - if(dx >= dy) - { - if(dx > 0 && s-3 > 0) - { - var _s = (s*dx*Math.sqrt(1+dy*dy/(dx*dx))-dx-(s>>1)*dy) / dx; - _s = (!(s-4)? Math.ceil(_s) : Math.round(_s)) + 1; - } - else var _s = s; - var ad = Math.ceil(s/2); - - var pr = dy<<1, - pru = pr - (dx<<1), - p = pr-dx, - ox = x; - while(dx > 0) - {--dx; - ++x; - if(p > 0) - { - this._mkDiv(ox, y, x-ox+ad, _s); - y += yIncr; - p += pru; - ox = x; - } - else p += pr; - } - this._mkDiv(ox, y, x2-ox+ad+1, _s); - } - - else - { - if(s-3 > 0) - { - var _s = (s*dy*Math.sqrt(1+dx*dx/(dy*dy))-(s>>1)*dx-dy) / dy; - _s = (!(s-4)? Math.ceil(_s) : Math.round(_s)) + 1; - } - else var _s = s; - var ad = Math.round(s/2); - - var pr = dx<<1, - pru = pr - (dy<<1), - p = pr-dy, - oy = y; - if(y2 <= y1) - { - ++ad; - while(dy > 0) - {--dy; - if(p > 0) - { - this._mkDiv(x++, y, _s, oy-y+ad); - y += yIncr; - p += pru; - oy = y; - } - else - { - y += yIncr; - p += pr; - } - } - this._mkDiv(x2, y2, _s, oy-y2+ad); - } - else - { - while(dy > 0) - {--dy; - y += yIncr; - if(p > 0) - { - this._mkDiv(x++, oy, _s, y-oy+ad); - p += pru; - oy = y; - } - else p += pr; - } - this._mkDiv(x2, oy, _s, y2-oy+ad+1); - } - } -} - -function _mkLinDott(x1, y1, x2, y2) -{ - if(x1 > x2) - { - var _x2 = x2; - var _y2 = y2; - x2 = x1; - y2 = y1; - x1 = _x2; - y1 = _y2; - } - var dx = x2-x1, dy = Math.abs(y2-y1), - x = x1, y = y1, - yIncr = (y1 > y2)? -1 : 1, - drw = true; - if(dx >= dy) - { - var pr = dy<<1, - pru = pr - (dx<<1), - p = pr-dx; - while(dx > 0) - {--dx; - if(drw) this._mkDiv(x, y, 1, 1); - drw = !drw; - if(p > 0) - { - y += yIncr; - p += pru; - } - else p += pr; - ++x; - } - } - else - { - var pr = dx<<1, - pru = pr - (dy<<1), - p = pr-dy; - while(dy > 0) - {--dy; - if(drw) this._mkDiv(x, y, 1, 1); - drw = !drw; - y += yIncr; - if(p > 0) - { - ++x; - p += pru; - } - else p += pr; - } - } - if(drw) this._mkDiv(x, y, 1, 1); -} - -function _mkOv(left, top, width, height) -{ - var a = (++width)>>1, b = (++height)>>1, - wod = width&1, hod = height&1, - cx = left+a, cy = top+b, - x = 0, y = b, - ox = 0, oy = b, - aa2 = (a*a)<<1, aa4 = aa2<<1, bb2 = (b*b)<<1, bb4 = bb2<<1, - st = (aa2>>1)*(1-(b<<1)) + bb2, - tt = (bb2>>1) - aa2*((b<<1)-1), - w, h; - while(y > 0) - { - if(st < 0) - { - st += bb2*((x<<1)+3); - tt += bb4*(++x); - } - else if(tt < 0) - { - st += bb2*((x<<1)+3) - aa4*(y-1); - tt += bb4*(++x) - aa2*(((y--)<<1)-3); - w = x-ox; - h = oy-y; - if((w&2) && (h&2)) - { - this._mkOvQds(cx, cy, x-2, y+2, 1, 1, wod, hod); - this._mkOvQds(cx, cy, x-1, y+1, 1, 1, wod, hod); - } - else this._mkOvQds(cx, cy, x-1, oy, w, h, wod, hod); - ox = x; - oy = y; - } - else - { - tt -= aa2*((y<<1)-3); - st -= aa4*(--y); - } - } - w = a-ox+1; - h = (oy<<1)+hod; - y = cy-oy; - this._mkDiv(cx-a, y, w, h); - this._mkDiv(cx+ox+wod-1, y, w, h); -} - -function _mkOv2D(left, top, width, height) -{ - var s = this.stroke; - width += s+1; - height += s+1; - var a = width>>1, b = height>>1, - wod = width&1, hod = height&1, - cx = left+a, cy = top+b, - x = 0, y = b, - aa2 = (a*a)<<1, aa4 = aa2<<1, bb2 = (b*b)<<1, bb4 = bb2<<1, - st = (aa2>>1)*(1-(b<<1)) + bb2, - tt = (bb2>>1) - aa2*((b<<1)-1); - - if(s-4 < 0 && (!(s-2) || width-51 > 0 && height-51 > 0)) - { - var ox = 0, oy = b, - w, h, - pxw; - while(y > 0) - { - if(st < 0) - { - st += bb2*((x<<1)+3); - tt += bb4*(++x); - } - else if(tt < 0) - { - st += bb2*((x<<1)+3) - aa4*(y-1); - tt += bb4*(++x) - aa2*(((y--)<<1)-3); - w = x-ox; - h = oy-y; - - if(w-1) - { - pxw = w+1+(s&1); - h = s; - } - else if(h-1) - { - pxw = s; - h += 1+(s&1); - } - else pxw = h = s; - this._mkOvQds(cx, cy, x-1, oy, pxw, h, wod, hod); - ox = x; - oy = y; - } - else - { - tt -= aa2*((y<<1)-3); - st -= aa4*(--y); - } - } - this._mkDiv(cx-a, cy-oy, s, (oy<<1)+hod); - this._mkDiv(cx+a+wod-s, cy-oy, s, (oy<<1)+hod); - } - - else - { - var _a = (width-(s<<1))>>1, - _b = (height-(s<<1))>>1, - _x = 0, _y = _b, - _aa2 = (_a*_a)<<1, _aa4 = _aa2<<1, _bb2 = (_b*_b)<<1, _bb4 = _bb2<<1, - _st = (_aa2>>1)*(1-(_b<<1)) + _bb2, - _tt = (_bb2>>1) - _aa2*((_b<<1)-1), - - pxl = new Array(), - pxt = new Array(), - _pxb = new Array(); - pxl[0] = 0; - pxt[0] = b; - _pxb[0] = _b-1; - while(y > 0) - { - if(st < 0) - { - pxl[pxl.length] = x; - pxt[pxt.length] = y; - st += bb2*((x<<1)+3); - tt += bb4*(++x); - } - else if(tt < 0) - { - pxl[pxl.length] = x; - st += bb2*((x<<1)+3) - aa4*(y-1); - tt += bb4*(++x) - aa2*(((y--)<<1)-3); - pxt[pxt.length] = y; - } - else - { - tt -= aa2*((y<<1)-3); - st -= aa4*(--y); - } - - if(_y > 0) - { - if(_st < 0) - { - _st += _bb2*((_x<<1)+3); - _tt += _bb4*(++_x); - _pxb[_pxb.length] = _y-1; - } - else if(_tt < 0) - { - _st += _bb2*((_x<<1)+3) - _aa4*(_y-1); - _tt += _bb4*(++_x) - _aa2*(((_y--)<<1)-3); - _pxb[_pxb.length] = _y-1; - } - else - { - _tt -= _aa2*((_y<<1)-3); - _st -= _aa4*(--_y); - _pxb[_pxb.length-1]--; - } - } - } - - var ox = -wod, oy = b, - _oy = _pxb[0], - l = pxl.length, - w, h; - for(var i = 0; i < l; i++) - { - if(typeof _pxb[i] != "undefined") - { - if(_pxb[i] < _oy || pxt[i] < oy) - { - x = pxl[i]; - this._mkOvQds(cx, cy, x, oy, x-ox, oy-_oy, wod, hod); - ox = x; - oy = pxt[i]; - _oy = _pxb[i]; - } - } - else - { - x = pxl[i]; - this._mkDiv(cx-x, cy-oy, 1, (oy<<1)+hod); - this._mkDiv(cx+ox+wod, cy-oy, 1, (oy<<1)+hod); - ox = x; - oy = pxt[i]; - } - } - this._mkDiv(cx-a, cy-oy, 1, (oy<<1)+hod); - this._mkDiv(cx+ox+wod, cy-oy, 1, (oy<<1)+hod); - } -} - -function _mkOvDott(left, top, width, height) -{ - var a = (++width)>>1, b = (++height)>>1, - wod = width&1, hod = height&1, hodu = hod^1, - cx = left+a, cy = top+b, - x = 0, y = b, - aa2 = (a*a)<<1, aa4 = aa2<<1, bb2 = (b*b)<<1, bb4 = bb2<<1, - st = (aa2>>1)*(1-(b<<1)) + bb2, - tt = (bb2>>1) - aa2*((b<<1)-1), - drw = true; - while(y > 0) - { - if(st < 0) - { - st += bb2*((x<<1)+3); - tt += bb4*(++x); - } - else if(tt < 0) - { - st += bb2*((x<<1)+3) - aa4*(y-1); - tt += bb4*(++x) - aa2*(((y--)<<1)-3); - } - else - { - tt -= aa2*((y<<1)-3); - st -= aa4*(--y); - } - if(drw && y >= hodu) this._mkOvQds(cx, cy, x, y, 1, 1, wod, hod); - drw = !drw; - } -} - -function _mkRect(x, y, w, h) -{ - var s = this.stroke; - this._mkDiv(x, y, w, s); - this._mkDiv(x+w, y, s, h); - this._mkDiv(x, y+h, w+s, s); - this._mkDiv(x, y+s, s, h-s); -} - -function _mkRectDott(x, y, w, h) -{ - this.drawLine(x, y, x+w, y); - this.drawLine(x+w, y, x+w, y+h); - this.drawLine(x, y+h, x+w, y+h); - this.drawLine(x, y, x, y+h); -} - -function jsgFont() -{ - this.PLAIN = 'font-weight:normal;'; - this.BOLD = 'font-weight:bold;'; - this.ITALIC = 'font-style:italic;'; - this.ITALIC_BOLD = this.ITALIC + this.BOLD; - this.BOLD_ITALIC = this.ITALIC_BOLD; -} -var Font = new jsgFont(); - -function jsgStroke() -{ - this.DOTTED = -1; -} -var Stroke = new jsgStroke(); - -function jsGraphics(cnv, wnd) -{ - this.setColor = function(x) - { - this.color = x.toLowerCase(); - }; - - this.setStroke = function(x) - { - this.stroke = x; - if(!(x+1)) - { - this.drawLine = _mkLinDott; - this._mkOv = _mkOvDott; - this.drawRect = _mkRectDott; - } - else if(x-1 > 0) - { - this.drawLine = _mkLin2D; - this._mkOv = _mkOv2D; - this.drawRect = _mkRect; - } - else - { - this.drawLine = _mkLin; - this._mkOv = _mkOv; - this.drawRect = _mkRect; - } - }; - - this.setPrintable = function(arg) - { - this.printable = arg; - if(jg_fast) - { - this._mkDiv = _mkDivIe; - this._htmRpc = arg? _htmPrtRpc : _htmRpc; - } - else this._mkDiv = arg? _mkDivPrt : _mkDiv; - }; - - this.setFont = function(fam, sz, sty) - { - this.ftFam = fam; - this.ftSz = sz; - this.ftSty = sty || Font.PLAIN; - }; - - this.drawPolyline = this.drawPolyLine = function(x, y) - { - for (var i=x.length - 1; i;) - {--i; - this.drawLine(x[i], y[i], x[i+1], y[i+1]); - } - }; - - this.fillRect = function(x, y, w, h) - { - this._mkDiv(x, y, w, h); - }; - - this.drawPolygon = function(x, y) - { - this.drawPolyline(x, y); - this.drawLine(x[x.length-1], y[x.length-1], x[0], y[0]); - }; - - this.drawEllipse = this.drawOval = function(x, y, w, h) - { - this._mkOv(x, y, w, h); - }; - - this.fillEllipse = this.fillOval = function(left, top, w, h) - { - var a = w>>1, b = h>>1, - wod = w&1, hod = h&1, - cx = left+a, cy = top+b, - x = 0, y = b, oy = b, - aa2 = (a*a)<<1, aa4 = aa2<<1, bb2 = (b*b)<<1, bb4 = bb2<<1, - st = (aa2>>1)*(1-(b<<1)) + bb2, - tt = (bb2>>1) - aa2*((b<<1)-1), - xl, dw, dh; - if(w) while(y > 0) - { - if(st < 0) - { - st += bb2*((x<<1)+3); - tt += bb4*(++x); - } - else if(tt < 0) - { - st += bb2*((x<<1)+3) - aa4*(y-1); - xl = cx-x; - dw = (x<<1)+wod; - tt += bb4*(++x) - aa2*(((y--)<<1)-3); - dh = oy-y; - this._mkDiv(xl, cy-oy, dw, dh); - this._mkDiv(xl, cy+y+hod, dw, dh); - oy = y; - } - else - { - tt -= aa2*((y<<1)-3); - st -= aa4*(--y); - } - } - this._mkDiv(cx-a, cy-oy, w, (oy<<1)+hod); - }; - - this.fillArc = function(iL, iT, iW, iH, fAngA, fAngZ) - { - var a = iW>>1, b = iH>>1, - iOdds = (iW&1) | ((iH&1) << 16), - cx = iL+a, cy = iT+b, - x = 0, y = b, ox = x, oy = y, - aa2 = (a*a)<<1, aa4 = aa2<<1, bb2 = (b*b)<<1, bb4 = bb2<<1, - st = (aa2>>1)*(1-(b<<1)) + bb2, - tt = (bb2>>1) - aa2*((b<<1)-1), - // Vars for radial boundary lines - xEndA, yEndA, xEndZ, yEndZ, - iSects = (1 << (Math.floor((fAngA %= 360.0)/180.0) << 3)) - | (2 << (Math.floor((fAngZ %= 360.0)/180.0) << 3)) - | ((fAngA >= fAngZ) << 16), - aBndA = new Array(b+1), aBndZ = new Array(b+1); - - // Set up radial boundary lines - fAngA *= Math.PI/180.0; - fAngZ *= Math.PI/180.0; - xEndA = cx+Math.round(a*Math.cos(fAngA)); - yEndA = cy+Math.round(-b*Math.sin(fAngA)); - _mkLinVirt(aBndA, cx, cy, xEndA, yEndA); - xEndZ = cx+Math.round(a*Math.cos(fAngZ)); - yEndZ = cy+Math.round(-b*Math.sin(fAngZ)); - _mkLinVirt(aBndZ, cx, cy, xEndZ, yEndZ); - - while(y > 0) - { - if(st < 0) // Advance x - { - st += bb2*((x<<1)+3); - tt += bb4*(++x); - } - else if(tt < 0) // Advance x and y - { - st += bb2*((x<<1)+3) - aa4*(y-1); - ox = x; - tt += bb4*(++x) - aa2*(((y--)<<1)-3); - this._mkArcDiv(ox, y, oy, cx, cy, iOdds, aBndA, aBndZ, iSects); - oy = y; - } - else // Advance y - { - tt -= aa2*((y<<1)-3); - st -= aa4*(--y); - if(y && (aBndA[y] != aBndA[y-1] || aBndZ[y] != aBndZ[y-1])) - { - this._mkArcDiv(x, y, oy, cx, cy, iOdds, aBndA, aBndZ, iSects); - ox = x; - oy = y; - } - } - } - this._mkArcDiv(x, 0, oy, cx, cy, iOdds, aBndA, aBndZ, iSects); - if(iOdds >> 16) // Odd height - { - if(iSects >> 16) // Start-angle > end-angle - { - var xl = (yEndA <= cy || yEndZ > cy)? (cx - x) : cx; - this._mkDiv(xl, cy, x + cx - xl + (iOdds & 0xffff), 1); - } - else if((iSects & 0x01) && yEndZ > cy) - this._mkDiv(cx - x, cy, x, 1); - } - }; - -/* fillPolygon method, implemented by Matthieu Haller. -This javascript function is an adaptation of the gdImageFilledPolygon for Walter Zorn lib. -C source of GD 1.8.4 found at http://www.boutell.com/gd/ - -THANKS to Kirsten Schulz for the polygon fixes! - -The intersection finding technique of this code could be improved -by remembering the previous intertersection, and by using the slope. -That could help to adjust intersections to produce a nice -interior_extrema. */ - this.fillPolygon = function(array_x, array_y) - { - var i; - var y; - var miny, maxy; - var x1, y1; - var x2, y2; - var ind1, ind2; - var ints; - - var n = array_x.length; - if(!n) return; - - miny = array_y[0]; - maxy = array_y[0]; - for(i = 1; i < n; i++) - { - if(array_y[i] < miny) - miny = array_y[i]; - - if(array_y[i] > maxy) - maxy = array_y[i]; - } - for(y = miny; y <= maxy; y++) - { - var polyInts = new Array(); - ints = 0; - for(i = 0; i < n; i++) - { - if(!i) - { - ind1 = n-1; - ind2 = 0; - } - else - { - ind1 = i-1; - ind2 = i; - } - y1 = array_y[ind1]; - y2 = array_y[ind2]; - if(y1 < y2) - { - x1 = array_x[ind1]; - x2 = array_x[ind2]; - } - else if(y1 > y2) - { - y2 = array_y[ind1]; - y1 = array_y[ind2]; - x2 = array_x[ind1]; - x1 = array_x[ind2]; - } - else continue; - - // Modified 11. 2. 2004 Walter Zorn - if((y >= y1) && (y < y2)) - polyInts[ints++] = Math.round((y-y1) * (x2-x1) / (y2-y1) + x1); - - else if((y == maxy) && (y > y1) && (y <= y2)) - polyInts[ints++] = Math.round((y-y1) * (x2-x1) / (y2-y1) + x1); - } - polyInts.sort(_CompInt); - for(i = 0; i < ints; i+=2) - this._mkDiv(polyInts[i], y, polyInts[i+1]-polyInts[i]+1, 1); - } - }; - - this.drawString = function(txt, x, y) - { - this.htm += '
'+ - txt + - '<\/div>'; - }; - -/* drawStringRect() added by Rick Blommers. -Allows to specify the size of the text rectangle and to align the -text both horizontally (e.g. right) and vertically within that rectangle */ - this.drawStringRect = function(txt, x, y, width, halign) - { - this.htm += '
'+ - txt + - '<\/div>'; - }; - - this.drawImage = function(imgSrc, x, y, w, h, a) - { - this.htm += '
'+ - ''+ - '<\/div>'; - }; - - this.clear = function() - { - this.htm = ""; - if(this.cnv) this.cnv.innerHTML = ""; - }; - - this._mkOvQds = function(cx, cy, x, y, w, h, wod, hod) - { - var xl = cx - x, xr = cx + x + wod - w, yt = cy - y, yb = cy + y + hod - h; - if(xr > xl+w) - { - this._mkDiv(xr, yt, w, h); - this._mkDiv(xr, yb, w, h); - } - else - w = xr - xl + w; - this._mkDiv(xl, yt, w, h); - this._mkDiv(xl, yb, w, h); - }; - - this._mkArcDiv = function(x, y, oy, cx, cy, iOdds, aBndA, aBndZ, iSects) - { - var xrDef = cx + x + (iOdds & 0xffff), y2, h = oy - y, xl, xr, w; - - if(!h) h = 1; - x = cx - x; - - if(iSects & 0xff0000) // Start-angle > end-angle - { - y2 = cy - y - h; - if(iSects & 0x00ff) - { - if(iSects & 0x02) - { - xl = Math.max(x, aBndZ[y]); - w = xrDef - xl; - if(w > 0) this._mkDiv(xl, y2, w, h); - } - if(iSects & 0x01) - { - xr = Math.min(xrDef, aBndA[y]); - w = xr - x; - if(w > 0) this._mkDiv(x, y2, w, h); - } - } - else - this._mkDiv(x, y2, xrDef - x, h); - y2 = cy + y + (iOdds >> 16); - if(iSects & 0xff00) - { - if(iSects & 0x0100) - { - xl = Math.max(x, aBndA[y]); - w = xrDef - xl; - if(w > 0) this._mkDiv(xl, y2, w, h); - } - if(iSects & 0x0200) - { - xr = Math.min(xrDef, aBndZ[y]); - w = xr - x; - if(w > 0) this._mkDiv(x, y2, w, h); - } - } - else - this._mkDiv(x, y2, xrDef - x, h); - } - else - { - if(iSects & 0x00ff) - { - if(iSects & 0x02) - xl = Math.max(x, aBndZ[y]); - else - xl = x; - if(iSects & 0x01) - xr = Math.min(xrDef, aBndA[y]); - else - xr = xrDef; - y2 = cy - y - h; - w = xr - xl; - if(w > 0) this._mkDiv(xl, y2, w, h); - } - if(iSects & 0xff00) - { - if(iSects & 0x0100) - xl = Math.max(x, aBndA[y]); - else - xl = x; - if(iSects & 0x0200) - xr = Math.min(xrDef, aBndZ[y]); - else - xr = xrDef; - y2 = cy + y + (iOdds >> 16); - w = xr - xl; - if(w > 0) this._mkDiv(xl, y2, w, h); - } - } - }; - - this.setStroke(1); - this.setFont("verdana,geneva,helvetica,sans-serif", "12px", Font.PLAIN); - this.color = "#000000"; - this.htm = ""; - this.wnd = wnd || window; - - if(!jg_ok) _chkDHTM(); - if(jg_ok) - { - if(cnv) - { - if(typeof(cnv) == "string") - this.cont = document.all? (this.wnd.document.all[cnv] || null) - : document.getElementById? (this.wnd.document.getElementById(cnv) || null) - : null; - else if(cnv == window.document) - this.cont = document.getElementsByTagName("body")[0]; - // If cnv is a direct reference to a canvas DOM node - // (option suggested by Andreas Luleich) - else this.cont = cnv; - // Create new canvas inside container DIV. Thus the drawing and clearing - // methods won't interfere with the container's inner html. - // Solution suggested by Vladimir. - this.cnv = this.wnd.document.createElement("div"); - this.cnv.style.fontSize=0; - this.cont.appendChild(this.cnv); - this.paint = jg_dom? _pntCnvDom : _pntCnvIe; - } - else - this.paint = _pntDoc; - } - else - this.paint = _pntN; - - this.setPrintable(false); -} - -function _mkLinVirt(aLin, x1, y1, x2, y2) -{ - var dx = Math.abs(x2-x1), dy = Math.abs(y2-y1), - x = x1, y = y1, - xIncr = (x1 > x2)? -1 : 1, - yIncr = (y1 > y2)? -1 : 1, - p, - i = 0; - if(dx >= dy) - { - var pr = dy<<1, - pru = pr - (dx<<1); - p = pr-dx; - while(dx > 0) - {--dx; - if(p > 0) // Increment y - { - aLin[i++] = x; - y += yIncr; - p += pru; - } - else p += pr; - x += xIncr; - } - } - else - { - var pr = dx<<1, - pru = pr - (dy<<1); - p = pr-dy; - while(dy > 0) - {--dy; - y += yIncr; - aLin[i++] = x; - if(p > 0) // Increment x - { - x += xIncr; - p += pru; - } - else p += pr; - } - } - for(var len = aLin.length, i = len-i; i;) - aLin[len-(i--)] = x; -}; - -function _CompInt(x, y) -{ - return(x - y); -} - diff --git a/lib/xmlgen.nim b/lib/xmlgen.nim new file mode 100644 index 000000000..79a782252 --- /dev/null +++ b/lib/xmlgen.nim @@ -0,0 +1,406 @@ +# +# +# Nimrod's Runtime Library +# (c) Copyright 2009 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements a simple `XML`:idx: and `HTML`:idx: code +## generator. Each commonly used HTML tag has a corresponding macro +## that generates a string with its HTML representation. +## +## Example: +## +## .. code-block:: nimrod +## var nim = "Nimrod" +## echo h1(a(href="http://force7.de/nimrod", nim)) +## +## Writes the string:: +## +##

Nimrod

+## + +import + macros, strutils + +const + coreAttr* = " id class title style " + eventAttr* = " onclick ondblclick onmousedown onmouseup " & + "onmouseover onmousemove onmouseout onkeypress onkeydown onkeyup " + commonAttr* = coreAttr & eventAttr + +proc getIdent(e: PNimrodNode): string {.compileTime.} = + case e.kind + of nnkIdent: result = normalize($e.ident) + of nnkAccQuoted: result = getIdent(e[0]) + else: error("cannot extract identifier from node: " & toStrLit(e).strVal) + +proc delete[T](s: var seq[T], attr: T): bool = + var idx = find(s, attr) + if idx >= 0: + var L = s.len + s[idx] = s[L-1] + setLen(s, L-1) + result = true + +proc xmlCheckedTag*(e: PNimrodNode, tag: string, + optAttr = "", reqAttr = "", + isLeaf = false): PNimrodNode {.compileTime.} = + ## use this procedure to define a new XML tag + + # copy the attributes; when iterating over them these lists + # will be modified, so that each attribute is only given one value + var req = splitSeq(reqAttr) + var opt = splitSeq(optAttr) + result = newNimNode(nnkBracket, e) + result.add(newStrLitNode("<")) + result.add(newStrLitNode(tag)) + # first pass over attributes: + for i in 1..e.len-1: + if e[i].kind == nnkExprEqExpr: + var name = getIdent(e[i][0]) + if delete(req, name) or delete(opt, name): + result.add(newStrLitNode(" ")) + result.add(newStrLitNode(name)) + result.add(newStrLitNode("=\"")) + result.add(e[i][1]) + result.add(newStrLitNode("\"")) + else: + error("invalid attribute for '" & tag & "' element: " & name) + # check each required attribute exists: + if req.len > 0: + error(req[0] & " attribute for '" & tag & "' element expected") + if isLeaf: + for i in 1..e.len-1: + if e[i].kind != nnkExprEqExpr: + error("element " & tag & " cannot be nested") + result.add(newStrLitNode(" />")) + else: + result.add(newStrLitNode(">")) + # second pass over elements: + for i in 1..e.len-1: + if e[i].kind != nnkExprEqExpr: result.add(e[i]) + result.add(newStrLitNode("")) + result = NestList(!"&", result) + + +macro a*(e: expr): expr = + ## generates the HTML ``a`` element. + result = xmlCheckedTag(e, "a", "href charset type hreflang rel rev " & + "accesskey tabindex" & commonAttr) + +macro acronym*(e: expr): expr = + ## generates the HTML ``acronym`` element. + result = xmlCheckedTag(e, "acronym", commonAttr) + +macro address*(e: expr): expr = + ## generates the HTML ``address`` element. + result = xmlCheckedTag(e, "address", commonAttr) + +macro area*(e: expr): expr = + ## generates the HTML ``area`` element. + result = xmlCheckedTag(e, "area", "shape coords href nohref" & + " accesskey tabindex" & commonAttr, "alt", true) + +macro b*(e: expr): expr = + ## generates the HTML ``b`` element. + result = xmlCheckedTag(e, "b", commonAttr) + +macro base*(e: expr): expr = + ## generates the HTML ``base`` element. + result = xmlCheckedTag(e, "base", "", "href", true) + +macro big*(e: expr): expr = + ## generates the HTML ``big`` element. + result = xmlCheckedTag(e, "big", commonAttr) + +macro blockquote*(e: expr): expr = + ## generates the HTML ``blockquote`` element. + result = xmlCheckedTag(e, "blockquote", " cite" & commonAttr) + +macro body*(e: expr): expr = + ## generates the HTML ``body`` element. + result = xmlCheckedTag(e, "body", commonAttr) + +macro br*(e: expr): expr = + ## generates the HTML ``br`` element. + result = xmlCheckedTag(e, "br", "", "", true) + +macro button*(e: expr): expr = + ## generates the HTML ``button`` element. + result = xmlCheckedTag(e, "button", "accesskey tabindex " & + "disabled name type value" & commonAttr) + +macro caption*(e: expr): expr = + ## generates the HTML ``caption`` element. + result = xmlCheckedTag(e, "caption", commonAttr) + +macro cite*(e: expr): expr = + ## generates the HTML ``cite`` element. + result = xmlCheckedTag(e, "cite", commonAttr) + +macro code*(e: expr): expr = + ## generates the HTML ``code`` element. + result = xmlCheckedTag(e, "code", commonAttr) + +macro col*(e: expr): expr = + ## generates the HTML ``col`` element. + result = xmlCheckedTag(e, "col", "span align valign" & commonAttr, "", true) + +macro colgroup*(e: expr): expr = + ## generates the HTML ``colgroup`` element. + result = xmlCheckedTag(e, "colgroup", "span align valign" & commonAttr) + +macro dd*(e: expr): expr = + ## generates the HTML ``dd`` element. + result = xmlCheckedTag(e, "dd", commonAttr) + +macro del*(e: expr): expr = + ## generates the HTML ``del`` element. + result = xmlCheckedTag(e, "del", "cite datetime" & commonAttr) + +macro dfn*(e: expr): expr = + ## generates the HTML ``dfn`` element. + result = xmlCheckedTag(e, "dfn", commonAttr) + +macro `div`*(e: expr): expr = + ## generates the HTML ``div`` element. + result = xmlCheckedTag(e, "div", commonAttr) + +macro dl*(e: expr): expr = + ## generates the HTML ``dl`` element. + result = xmlCheckedTag(e, "dl", commonAttr) + +macro dt*(e: expr): expr = + ## generates the HTML ``dt`` element. + result = xmlCheckedTag(e, "dt", commonAttr) + +macro em*(e: expr): expr = + ## generates the HTML ``em`` element. + result = xmlCheckedTag(e, "em", commonAttr) + +macro fieldset*(e: expr): expr = + ## generates the HTML ``fieldset`` element. + result = xmlCheckedTag(e, "fieldset", commonAttr) + +macro form*(e: expr): expr = + ## generates the HTML ``form`` element. + result = xmlCheckedTag(e, "form", "method encype accept accept-charset" & + commonAttr, "action") + +macro h1*(e: expr): expr = + ## generates the HTML ``h1`` element. + result = xmlCheckedTag(e, "h1", commonAttr) + +macro h2*(e: expr): expr = + ## generates the HTML ``h2`` element. + result = xmlCheckedTag(e, "h2", commonAttr) + +macro h3*(e: expr): expr = + ## generates the HTML ``h3`` element. + result = xmlCheckedTag(e, "h3", commonAttr) + +macro h4*(e: expr): expr = + ## generates the HTML ``h4`` element. + result = xmlCheckedTag(e, "h4", commonAttr) + +macro h5*(e: expr): expr = + ## generates the HTML ``h5`` element. + result = xmlCheckedTag(e, "h5", commonAttr) + +macro h6*(e: expr): expr = + ## generates the HTML ``h6`` element. + result = xmlCheckedTag(e, "h6", commonAttr) + +macro head*(e: expr): expr = + ## generates the HTML ``head`` element. + result = xmlCheckedTag(e, "head", "profile") + +macro html*(e: expr): expr = + ## generates the HTML ``html`` element. + result = xmlCheckedTag(e, "html", "", "xmlns") + +macro hr*(e: expr): expr = + ## generates the HTML ``hr`` element. + result = xmlCheckedTag(e, "hr", commonAttr, "", true) + +macro i*(e: expr): expr = + ## generates the HTML ``i`` element. + result = xmlCheckedTag(e, "i", commonAttr) + +macro img*(e: expr): expr = + ## generates the HTML ``img`` element. + result = xmlCheckedTag(e, "img", "longdesc height width", "src alt", true) + +macro input*(e: expr): expr = + ## generates the HTML ``input`` element. + result = xmlCheckedTag(e, "input", "name type value checked maxlength src" & + " alt accept disabled readonly accesskey tabindex" & commonAttr, "", true) + +macro ins*(e: expr): expr = + ## generates the HTML ``ins`` element. + result = xmlCheckedTag(e, "ins", "cite datetime" & commonAttr) + +macro kbd*(e: expr): expr = + ## generates the HTML ``kbd`` element. + result = xmlCheckedTag(e, "kbd", commonAttr) + +macro label*(e: expr): expr = + ## generates the HTML ``label`` element. + result = xmlCheckedTag(e, "label", "for accesskey" & commonAttr) + +macro legend*(e: expr): expr = + ## generates the HTML ``legend`` element. + result = xmlCheckedTag(e, "legend", "accesskey" & commonAttr) + +macro li*(e: expr): expr = + ## generates the HTML ``li`` element. + result = xmlCheckedTag(e, "li", commonAttr) + +macro link*(e: expr): expr = + ## generates the HTML ``link`` element. + result = xmlCheckedTag(e, "link", "href charset hreflang type rel rev media" & + commonAttr, "", true) + +macro map*(e: expr): expr = + ## generates the HTML ``map`` element. + result = xmlCheckedTag(e, "map", "class title" & eventAttr, "id", false) + +macro meta*(e: expr): expr = + ## generates the HTML ``meta`` element. + result = xmlCheckedTag(e, "meta", "name http-equiv scheme", "content", true) + +macro noscript*(e: expr): expr = + ## generates the HTML ``noscript`` element. + result = xmlCheckedTag(e, "noscript", commonAttr) + +macro `object`*(e: expr): expr = + ## generates the HTML ``object`` element. + result = xmlCheckedTag(e, "object", "classid data codebase declare type " & + "codetype archive standby width height name tabindex" & commonAttr) + +macro ol*(e: expr): expr = + ## generates the HTML ``ol`` element. + result = xmlCheckedTag(e, "ol", commonAttr) + +macro optgroup*(e: expr): expr = + ## generates the HTML ``optgroup`` element. + result = xmlCheckedTag(e, "optgroup", "disabled" & commonAttr, "label", false) + +macro option*(e: expr): expr = + ## generates the HTML ``option`` element. + result = xmlCheckedTag(e, "option", "selected value" & commonAttr) + +macro p*(e: expr): expr = + ## generates the HTML ``p`` element. + result = xmlCheckedTag(e, "p", commonAttr) + +macro param*(e: expr): expr = + ## generates the HTML ``param`` element. + result = xmlCheckedTag(e, "param", "value id type valuetype", "name", true) + +macro pre*(e: expr): expr = + ## generates the HTML ``pre`` element. + result = xmlCheckedTag(e, "pre", commonAttr) + +macro q*(e: expr): expr = + ## generates the HTML ``q`` element. + result = xmlCheckedTag(e, "q", "cite" & commonAttr) + +macro samp*(e: expr): expr = + ## generates the HTML ``samp`` element. + result = xmlCheckedTag(e, "samp", commonAttr) + +macro script*(e: expr): expr = + ## generates the HTML ``script`` element. + result = xmlCheckedTag(e, "script", "src charset defer", "type", false) + +macro select*(e: expr): expr = + ## generates the HTML ``select`` element. + result = xmlCheckedTag(e, "select", "name size multiple disabled tabindex" & + commonAttr) + +macro small*(e: expr): expr = + ## generates the HTML ``small`` element. + result = xmlCheckedTag(e, "small", commonAttr) + +macro span*(e: expr): expr = + ## generates the HTML ``span`` element. + result = xmlCheckedTag(e, "span", commonAttr) + +macro strong*(e: expr): expr = + ## generates the HTML ``strong`` element. + result = xmlCheckedTag(e, "strong", commonAttr) + +macro style*(e: expr): expr = + ## generates the HTML ``style`` element. + result = xmlCheckedTag(e, "style", "media title", "type") + +macro sub*(e: expr): expr = + ## generates the HTML ``sub`` element. + result = xmlCheckedTag(e, "sub", commonAttr) + +macro sup*(e: expr): expr = + ## generates the HTML ``sup`` element. + result = xmlCheckedTag(e, "sup", commonAttr) + +macro table*(e: expr): expr = + ## generates the HTML ``table`` element. + result = xmlCheckedTag(e, "table", "summary border cellpadding cellspacing" & + " frame rules width" & commonAttr) + +macro tbody*(e: expr): expr = + ## generates the HTML ``tbody`` element. + result = xmlCheckedTag(e, "tbody", "align valign" & commonAttr) + +macro td*(e: expr): expr = + ## generates the HTML ``td`` element. + result = xmlCheckedTag(e, "td", "colspan rowspan abbr axis headers scope" & + " align valign" & commonAttr) + +macro textarea*(e: expr): expr = + ## generates the HTML ``textarea`` element. + result = xmlCheckedTag(e, "textarea", " name disabled readonly accesskey" & + " tabindex" & commonAttr, "rows cols", false) + +macro tfoot*(e: expr): expr = + ## generates the HTML ``tfoot`` element. + result = xmlCheckedTag(e, "tfoot", "align valign" & commonAttr) + +macro th*(e: expr): expr = + ## generates the HTML ``th`` element. + result = xmlCheckedTag(e, "th", "colspan rowspan abbr axis headers scope" & + " align valign" & commonAttr) + +macro thead*(e: expr): expr = + ## generates the HTML ``thead`` element. + result = xmlCheckedTag(e, "thead", "align valign" & commonAttr) + +macro title*(e: expr): expr = + ## generates the HTML ``title`` element. + result = xmlCheckedTag(e, "title") + +macro tr*(e: expr): expr = + ## generates the HTML ``tr`` element. + result = xmlCheckedTag(e, "tr", "align valign" & commonAttr) + +macro tt*(e: expr): expr = + ## generates the HTML ``tt`` element. + result = xmlCheckedTag(e, "tt", commonAttr) + +macro ul*(e: expr): expr = + ## generates the HTML ``ul`` element. + result = xmlCheckedTag(e, "ul", commonAttr) + +macro `var`*(e: expr): expr = + ## generates the HTML ``var`` element. + result = xmlCheckedTag(e, "var", commonAttr) + +when isMainModule: + var nim = "Nimrod" + echo h1(a(href="http://force7.de/nimrod", nim)) + diff --git a/nim/ast.pas b/nim/ast.pas index a57632468..0c3137b2b 100644 --- a/nim/ast.pas +++ b/nim/ast.pas @@ -15,7 +15,7 @@ interface {$include 'config.inc'} uses - nsystem, charsets, msgs, hashes, + nsystem, charsets, msgs, nhashes, nversion, options, strutils, crc, ropes, idents, lists; const @@ -245,18 +245,18 @@ type mSymDiffSet, mConStrStr, mConArrArr, mConArrT, mConTArr, mConTT, mSlice, mAppendStrCh, mAppendStrStr, mAppendSeqElem, mAppendSeqSeq, mInRange, mInSet, mAsgn, mRepr, mExit, mSetLengthStr, mSetLengthSeq, - mAssert, mSwap, mIsNil, mArrToSeq, mArray, mOpenArray, - mRange, mSet, mSeq, mInt, mInt8, mInt16, - mInt32, mInt64, mFloat, mFloat32, mFloat64, mBool, - mChar, mString, mCstring, mPointer, mAnyEnum, mEmptySet, - mIntSetBaseType, mNil, mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion, - mNimrodMajor, mNimrodMinor, mNimrodPatch, mCpuEndian, mHostOS, mHostCPU, - mNaN, mInf, mNegInf, mNLen, mNChild, mNSetChild, - mNAdd, mNAddMultiple, mNDel, mNKind, mNIntVal, mNFloatVal, - mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal, mNSetFloatVal, - mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNNewNimNode, mNCopyNimNode, - mNCopyNimTree, mStrToIdent, mIdentToStr, mEqIdent, mNHint, mNWarning, - mNError + mAssert, mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast, + mNewString, mArray, mOpenArray, mRange, mSet, mSeq, + mInt, mInt8, mInt16, mInt32, mInt64, mFloat, + mFloat32, mFloat64, mBool, mChar, mString, mCstring, + mPointer, mAnyEnum, mEmptySet, mIntSetBaseType, mNil, mIsMainModule, + mCompileDate, mCompileTime, mNimrodVersion, mNimrodMajor, mNimrodMinor, mNimrodPatch, + mCpuEndian, mHostOS, mHostCPU, mNaN, mInf, mNegInf, + mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, + mNKind, mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, + mNStrVal, mNSetIntVal, mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, + mNSetStrVal, mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr, + mEqIdent, mNHint, mNWarning, mNError //[[[end]]] ); @@ -327,7 +327,7 @@ type ); TLocFlag = ( - lfIndirect, // backend introduced a pointer + lfIndirect, // backend introduced a pointer lfParamCopy, // backend introduced a parameter copy (LLVM) lfNoDeepCopy, // no need for a deep copy lfNoDecl, // do not declare it in C @@ -504,18 +504,18 @@ const // "MagicToStr" array: 'SymDiffSet', 'ConStrStr', 'ConArrArr', 'ConArrT', 'ConTArr', 'ConTT', 'Slice', 'AppendStrCh', 'AppendStrStr', 'AppendSeqElem', 'AppendSeqSeq', 'InRange', 'InSet', 'Asgn', 'Repr', 'Exit', 'SetLengthStr', 'SetLengthSeq', - 'Assert', 'Swap', 'IsNil', 'ArrToSeq', 'Array', 'OpenArray', - 'Range', 'Set', 'Seq', 'Int', 'Int8', 'Int16', - 'Int32', 'Int64', 'Float', 'Float32', 'Float64', 'Bool', - 'Char', 'String', 'Cstring', 'Pointer', 'AnyEnum', 'EmptySet', - 'IntSetBaseType', 'Nil', 'IsMainModule', 'CompileDate', 'CompileTime', 'NimrodVersion', - 'NimrodMajor', 'NimrodMinor', 'NimrodPatch', 'CpuEndian', 'HostOS', 'HostCPU', - 'NaN', 'Inf', 'NegInf', 'NLen', 'NChild', 'NSetChild', - 'NAdd', 'NAddMultiple', 'NDel', 'NKind', 'NIntVal', 'NFloatVal', - 'NSymbol', 'NIdent', 'NGetType', 'NStrVal', 'NSetIntVal', 'NSetFloatVal', - 'NSetSymbol', 'NSetIdent', 'NSetType', 'NSetStrVal', 'NNewNimNode', 'NCopyNimNode', - 'NCopyNimTree', 'StrToIdent', 'IdentToStr', 'EqIdent', 'NHint', 'NWarning', - 'NError' + 'Assert', 'Swap', 'IsNil', 'ArrToSeq', 'CopyStr', 'CopyStrLast', + 'NewString', 'Array', 'OpenArray', 'Range', 'Set', 'Seq', + 'Int', 'Int8', 'Int16', 'Int32', 'Int64', 'Float', + 'Float32', 'Float64', 'Bool', 'Char', 'String', 'Cstring', + 'Pointer', 'AnyEnum', 'EmptySet', 'IntSetBaseType', 'Nil', 'IsMainModule', + 'CompileDate', 'CompileTime', 'NimrodVersion', 'NimrodMajor', 'NimrodMinor', 'NimrodPatch', + 'CpuEndian', 'HostOS', 'HostCPU', 'NaN', 'Inf', 'NegInf', + 'NLen', 'NChild', 'NSetChild', 'NAdd', 'NAddMultiple', 'NDel', + 'NKind', 'NIntVal', 'NFloatVal', 'NSymbol', 'NIdent', 'NGetType', + 'NStrVal', 'NSetIntVal', 'NSetFloatVal', 'NSetSymbol', 'NSetIdent', 'NSetType', + 'NSetStrVal', 'NNewNimNode', 'NCopyNimNode', 'NCopyNimTree', 'StrToIdent', 'IdentToStr', + 'EqIdent', 'NHint', 'NWarning', 'NError' //[[[end]]] ); diff --git a/nim/astalgo.pas b/nim/astalgo.pas index f7b6f651d..e5475ddd1 100644 --- a/nim/astalgo.pas +++ b/nim/astalgo.pas @@ -17,7 +17,7 @@ interface {$include 'config.inc'} uses - nsystem, ast, hashes, charsets, strutils, options, msgs, ropes, idents; + nsystem, ast, nhashes, charsets, strutils, options, msgs, ropes, idents; function hashNode(p: PObject): THash; diff --git a/nim/ccgexprs.pas b/nim/ccgexprs.pas index 03de5c4de..bd0c520d2 100644 --- a/nim/ccgexprs.pas +++ b/nim/ccgexprs.pas @@ -1254,15 +1254,9 @@ begin refType := skipVarGenericRange(e.sons[1].typ); InitLocExpr(p, e.sons[1], a); initLoc(b, locExpr, a.t, OnHeap); - - if optBoehmGC in gGlobalOptions then - b.r := ropef('($1) newObj(sizeof($2))', - [getTypeDesc(p.module, reftype), - getTypeDesc(p.module, skipGenericRange(reftype.sons[0]))]) - else - b.r := ropef('($1) newObj($2, sizeof($3))', - [getTypeDesc(p.module, reftype), genTypeInfo(p.module, refType), - getTypeDesc(p.module, skipGenericRange(reftype.sons[0]))]); + b.r := ropef('($1) newObj($2, sizeof($3))', + [getTypeDesc(p.module, reftype), genTypeInfo(p.module, refType), + getTypeDesc(p.module, skipGenericRange(reftype.sons[0]))]); genAssignment(p, a, b, {@set}[]); // set the object type: bt := skipGenericRange(refType.sons[0]); @@ -1279,16 +1273,10 @@ begin InitLocExpr(p, e.sons[1], a); InitLocExpr(p, e.sons[2], b); initLoc(c, locExpr, a.t, OnHeap); - if optBoehmGC in gGlobalOptions then - c.r := ropef('($1) newSeq(sizeof($2), $3)', - [getTypeDesc(p.module, seqtype), - getTypeDesc(p.module, skipGenericRange(seqtype.sons[0])), - rdLoc(b)]) - else - c.r := ropef('($1) newSeq($2, $3)', - [getTypeDesc(p.module, seqtype), - genTypeInfo(p.module, seqType), - rdLoc(b)]); + c.r := ropef('($1) newSeq($2, $3)', + [getTypeDesc(p.module, seqtype), + genTypeInfo(p.module, seqType), + rdLoc(b)]); genAssignment(p, a, c, {@set}[]); end; @@ -1945,6 +1933,7 @@ begin mSetLengthSeq: genSetLengthSeq(p, e, d); mIncl, mExcl, mCard, mLtSet, mLeSet, mEqSet, mMulSet, mPlusSet, mMinusSet, mInSet: genSetOp(p, e, d, op); + mNewString, mCopyStr, mCopyStrLast: genCall(p, e, d); mExit: genCall(p, e, d); mArrToSeq: genArrToSeq(p, e, d); mNLen..mNError: diff --git a/nim/ccgstmts.pas b/nim/ccgstmts.pas index 7588f7e15..f3fcdf518 100644 --- a/nim/ccgstmts.pas +++ b/nim/ccgstmts.pas @@ -878,7 +878,7 @@ var i: int; prc: PSym; begin - assert(t <> nil); + //assert(t <> nil); if inCheckpoint(t.info) then MessageOut(renderTree(t)); case t.kind of @@ -913,7 +913,7 @@ begin nkRaiseStmt: genRaiseStmt(p, t); nkTypeSection: begin // we have to emit the type information for object types here to support - // seperate compilation: + // separate compilation: genTypeSection(p.module, t); end; nkCommentStmt, nkNilLit, nkIteratorDef, nkIncludeStmt, nkImportStmt, diff --git a/nim/ccgutils.pas b/nim/ccgutils.pas index 56eff6c9e..49c1a8cee 100644 --- a/nim/ccgutils.pas +++ b/nim/ccgutils.pas @@ -16,7 +16,7 @@ interface uses charsets, nsystem, - ast, astalgo, ropes, lists, hashes, strutils, types, msgs; + ast, astalgo, ropes, lists, nhashes, strutils, types, msgs; function toCChar(c: Char): string; function makeCString(const s: string): PRope; diff --git a/nim/cgen.pas b/nim/cgen.pas index 5dcb7f50b..df8431a30 100644 --- a/nim/cgen.pas +++ b/nim/cgen.pas @@ -16,7 +16,7 @@ interface {$include 'config.inc'} uses - nsystem, ast, astalgo, strutils, hashes, trees, platform, magicsys, + 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; diff --git a/nim/commands.pas b/nim/commands.pas index 8a4435eb0..fde2d26c7 100644 --- a/nim/commands.pas +++ b/nim/commands.pas @@ -1,61 +1,61 @@ -// -// -// The Nimrod Compiler -// (c) Copyright 2008 Andreas Rumpf -// -// See the file "copying.txt", included in this -// distribution, for details about the copyright. -// - -unit commands; - -// This module handles the parsing of command line arguments. - -interface - -{$include 'config.inc'} - -uses - nsystem, charsets, nos, msgs, options, nversion, condsyms, strutils, extccomp, - platform, lists, wordrecg; - -procedure writeCommandLineUsage; - -type - TCmdLinePass = ( - passCmd1, // first pass over the command line - passCmd2, // second pass over the command line - passPP // preprocessor called ProcessCommand() - ); - -procedure ProcessCommand(const switch: string; pass: TCmdLinePass); -procedure processSwitch(const switch, arg: string; pass: TCmdlinePass; - const info: TLineInfo); - -implementation - -{@ignore} -const -{$ifdef fpc} - compileDate = {$I %date%}; -{$else} - compileDate = '2009-0-0'; -{$endif} -{@emit} - -const - HelpMessage = 'Nimrod Compiler Version $1 (' +{&} - compileDate +{&} ') [$2: $3]' +{&} nl +{&} - 'Copyright (c) 2004-2009 by Andreas Rumpf' +{&} nl; - -const - Usage = '' -//[[[cog -//from string import replace -//def f(x): return "+{&} '" + replace(x, "'", "''")[:-1] + "' +{&} nl" -//for line in open("data/basicopt.txt").readlines(): -// cog.outl(f(line)) -//]]] +// +// +// The Nimrod Compiler +// (c) Copyright 2008 Andreas Rumpf +// +// See the file "copying.txt", included in this +// distribution, for details about the copyright. +// + +unit commands; + +// This module handles the parsing of command line arguments. + +interface + +{$include 'config.inc'} + +uses + nsystem, charsets, nos, msgs, options, nversion, condsyms, strutils, extccomp, + platform, lists, wordrecg; + +procedure writeCommandLineUsage; + +type + TCmdLinePass = ( + passCmd1, // first pass over the command line + passCmd2, // second pass over the command line + passPP // preprocessor called ProcessCommand() + ); + +procedure ProcessCommand(const switch: string; pass: TCmdLinePass); +procedure processSwitch(const switch, arg: string; pass: TCmdlinePass; + const info: TLineInfo); + +implementation + +{@ignore} +const +{$ifdef fpc} + compileDate = {$I %date%}; +{$else} + compileDate = '2009-0-0'; +{$endif} +{@emit} + +const + HelpMessage = 'Nimrod Compiler Version $1 (' +{&} + compileDate +{&} ') [$2: $3]' +{&} nl +{&} + 'Copyright (c) 2004-2009 by Andreas Rumpf' +{&} nl; + +const + Usage = '' +//[[[cog +//from string import replace +//def f(x): return "+{&} '" + replace(x, "'", "''")[:-1] + "' +{&} nl" +//for line in open("data/basicopt.txt").readlines(): +// cog.outl(f(line)) +//]]] +{&} 'Usage::' +{&} nl +{&} ' nimrod command [options] inputfile [arguments]' +{&} nl +{&} 'Command::' +{&} nl @@ -88,14 +88,14 @@ const +{&} ' -r, --run run the compiled program with given arguments' +{&} nl +{&} ' --advanced show advanced command line switches' +{&} nl +{&} ' -h, --help show this help' +{&} nl -//[[[end]]] - ; - - AdvancedUsage = '' -//[[[cog -//for line in open("data/advopt.txt").readlines(): -// cog.outl(f(line)) -//]]] +//[[[end]]] + ; + + AdvancedUsage = '' +//[[[cog +//for line in open("data/advopt.txt").readlines(): +// cog.outl(f(line)) +//]]] +{&} 'Advanced commands::' +{&} nl +{&} ' pas convert a Pascal file to Nimrod syntax' +{&} nl +{&} ' pretty pretty print the inputfile' +{&} nl @@ -125,401 +125,454 @@ const +{&} ' --checkpoints:on|off turn on|off checkpoints; for debugging Nimrod' +{&} nl +{&} ' --skip_cfg do not read the general configuration file' +{&} nl +{&} ' --skip_proj_cfg do not read the project''s configuration file' +{&} nl ++{&} ' --gc:refc|boehm use Nimrod''s native GC|Boehm GC' +{&} nl +{&} ' --index:FILE use FILE to generate a documenation index file' +{&} nl +{&} ' --putenv:key=value set an environment variable' +{&} nl +{&} ' --list_cmd list the commands used to execute external programs' +{&} nl +{&} ' --verbosity:0|1|2|3 set Nimrod''s verbosity level (0 is default)' +{&} nl +{&} ' -v, --version show detailed version information' +{&} nl -//[[[end]]] - ; - -function getCommandLineDesc: string; -begin - result := format(HelpMessage, [VersionAsString, - platform.os[platform.hostOS].name, cpu[platform.hostCPU].name]) +{&} Usage -end; - -var - helpWritten: boolean; // BUGFIX 19 - versionWritten: boolean; - advHelpWritten: boolean; - -procedure HelpOnError(pass: TCmdLinePass); -begin - if (pass = passCmd1) and not helpWritten then begin - // BUGFIX 19 - MessageOut(getCommandLineDesc()); - helpWritten := true - end -end; - -procedure writeAdvancedUsage(pass: TCmdLinePass); -begin - if (pass = passCmd1) and not advHelpWritten then begin - // BUGFIX 19 - MessageOut(format(HelpMessage, [VersionAsString, - platform.os[platform.hostOS].name, - cpu[platform.hostCPU].name]) +{&} - AdvancedUsage); - advHelpWritten := true; - helpWritten := true; - halt(0); - end -end; - -procedure writeVersionInfo(pass: TCmdLinePass); -begin - if (pass = passCmd1) and not versionWritten then begin - versionWritten := true; - helpWritten := true; - messageOut(format(HelpMessage, [VersionAsString, - platform.os[platform.hostOS].name, - cpu[platform.hostCPU].name])) - end -end; - -procedure writeCommandLineUsage; -begin - if not helpWritten then begin - messageOut(getCommandLineDesc()); - helpWritten := true - end -end; - -procedure InvalidCmdLineOption(pass: TCmdLinePass; const switch: string; - const info: TLineInfo); -begin - liMessage(info, errInvalidCmdLineOption, switch) -end; - -procedure splitSwitch(const switch: string; out cmd, arg: string; - pass: TCmdLinePass; const info: TLineInfo); -var - i: int; -begin - cmd := ''; - i := strStart; - if (i < length(switch)+strStart) and (switch[i] = '-') then inc(i); - if (i < length(switch)+strStart) and (switch[i] = '-') then inc(i); - while i < length(switch) + strStart do begin - case switch[i] of - 'a'..'z', 'A'..'Z', '0'..'9', '_', '.': - addChar(cmd, switch[i]); - else break; - end; - inc(i); - end; - if i >= length(switch) + strStart then - arg := '' - else if switch[i] in [':', '=', '['] then - arg := ncopy(switch, i + 1) - else - InvalidCmdLineOption(pass, switch, info) -end; - -procedure ProcessOnOffSwitch(const op: TOptions; const arg: string; - pass: TCmdlinePass; const info: TLineInfo); -begin - case whichKeyword(arg) of - wOn: gOptions := gOptions + op; - wOff: gOptions := gOptions - op; - else liMessage(info, errOnOrOffExpectedButXFound, arg) - end -end; - -procedure ProcessOnOffSwitchG(const op: TGlobalOptions; const arg: string; - pass: TCmdlinePass; const info: TLineInfo); -begin - case whichKeyword(arg) of - wOn: gGlobalOptions := gGlobalOptions + op; - wOff: gGlobalOptions := gGlobalOptions - op; - else liMessage(info, errOnOrOffExpectedButXFound, arg) - end -end; - -procedure ExpectArg(const switch, arg: string; pass: TCmdLinePass; - const info: TLineInfo); -begin - if (arg = '') then - liMessage(info, errCmdLineArgExpected, switch) -end; - -procedure ProcessSpecificNote(const arg: string; state: TSpecialWord; - pass: TCmdlinePass; const info: TLineInfo); -var - i, x: int; - n: TNoteKind; - id: string; -begin - id := ''; - // arg = "X]:on|off" - i := strStart; - n := hintMin; - while (i < length(arg)+strStart) and (arg[i] <> ']') do begin - addChar(id, arg[i]); - inc(i) - end; - if (i < length(arg)+strStart) and (arg[i] = ']') then - inc(i) - else - InvalidCmdLineOption(pass, arg, info); - if (i < length(arg)+strStart) and (arg[i] in [':', '=']) then - inc(i) - else - InvalidCmdLineOption(pass, arg, info); - if state = wHint then begin - x := findStr(msgs.HintsToStr, id); - if x >= 0 then - n := TNoteKind(x + ord(hintMin)) - else - InvalidCmdLineOption(pass, arg, info) - end - else begin - x := findStr(msgs.WarningsToStr, id); - if x >= 0 then - n := TNoteKind(x + ord(warnMin)) - else - InvalidCmdLineOption(pass, arg, info) - end; - case whichKeyword(ncopy(arg, i)) of - wOn: include(gNotes, n); - wOff: exclude(gNotes, n); - else liMessage(info, errOnOrOffExpectedButXFound, arg) - end -end; - -function processPath(const path: string): string; -begin - result := UnixToNativePath(format(path, - ['nimrod', getPrefixDir(), 'lib', libpath])) -end; - -procedure processCompile(const filename: string); -var - found, trunc, ext: string; -begin - found := findFile(filename); - if found = '' then found := filename; - splitFilename(found, trunc, ext); - extccomp.addExternalFileToCompile(trunc); - extccomp.addFileToLink(completeCFilePath(trunc, false)); -end; - -procedure processSwitch(const switch, arg: string; pass: TCmdlinePass; - const info: TLineInfo); -var - theOS: TSystemOS; - cpu: TSystemCPU; - key, val, path: string; -begin - case whichKeyword(switch) of - wPath, wP: begin - expectArg(switch, arg, pass, info); - path := processPath(arg); - {@discard} lists.IncludeStr(options.searchPaths, path) - end; - wOut, wO: begin - expectArg(switch, arg, pass, info); - options.outFile := arg; - end; - wDefine, wD: begin - expectArg(switch, arg, pass, info); - DefineSymbol(arg) - end; - wUndef, wU: begin - expectArg(switch, arg, pass, info); - UndefSymbol(arg) - end; - wCompile: begin - expectArg(switch, arg, pass, info); - if pass in {@set}[passCmd2, passPP] then - processCompile(arg); - end; - wLink: begin - expectArg(switch, arg, pass, info); - if pass in {@set}[passCmd2, passPP] then - addFileToLink(arg); - end; - wDebuginfo: include(gGlobalOptions, optCDebug); - wCompileOnly, wC: include(gGlobalOptions, optCompileOnly); - wNoLinking: include(gGlobalOptions, optNoLinking); - wForceBuild, wF: include(gGlobalOptions, optForceFullMake); - wGC: begin - case whichKeyword(arg) of - wBoehm: begin - include(gGlobalOptions, optBoehmGC); - exclude(gGlobalOptions, optRefcGC); - DefineSymbol('boehmgc'); - end; - wRefc: begin - exclude(gGlobalOptions, optBoehmGC); - include(gGlobalOptions, optRefcGC) - end; - wNone: begin - exclude(gGlobalOptions, optRefcGC); - exclude(gGlobalOptions, optBoehmGC); - defineSymbol('nogc'); - end - else - liMessage(info, errNoneBoehmRefcExpectedButXFound, arg) - end - end; - wWarnings, wW: ProcessOnOffSwitch({@set}[optWarns], arg, pass, info); - wWarning: ProcessSpecificNote(arg, wWarning, pass, info); - wHint: ProcessSpecificNote(arg, wHint, pass, info); - wHints: ProcessOnOffSwitch({@set}[optHints], arg, pass, info); - wCheckpoints: ProcessOnOffSwitch({@set}[optCheckpoints], arg, pass, info); - wStackTrace: ProcessOnOffSwitch({@set}[optStackTrace], arg, pass, info); - wLineTrace: ProcessOnOffSwitch({@set}[optLineTrace], arg, pass, info); - wDebugger: begin - ProcessOnOffSwitch({@set}[optEndb], arg, pass, info); - if optEndb in gOptions then - DefineSymbol('endb') - else - UndefSymbol('endb') - end; - wProfiler: begin - ProcessOnOffSwitch({@set}[optProfiler], arg, pass, info); - if optProfiler in gOptions then DefineSymbol('profiler') - else UndefSymbol('profiler') - end; - wChecks, wX: ProcessOnOffSwitch(checksOptions, arg, pass, info); - wObjChecks: ProcessOnOffSwitch({@set}[optObjCheck], arg, pass, info); - wFieldChecks: ProcessOnOffSwitch({@set}[optFieldCheck], arg, pass, info); - wRangeChecks: ProcessOnOffSwitch({@set}[optRangeCheck], arg, pass, info); - wBoundChecks: ProcessOnOffSwitch({@set}[optBoundsCheck], arg, pass, info); - wOverflowChecks: ProcessOnOffSwitch({@set}[optOverflowCheck], arg, pass, info); - wLineDir: ProcessOnOffSwitch({@set}[optLineDir], arg, pass, info); - wAssertions, wA: ProcessOnOffSwitch({@set}[optAssert], arg, pass, info); - wDeadCodeElim: ProcessOnOffSwitchG({@set}[optDeadCodeElim], arg, pass, info); - wOpt: begin - case whichKeyword(arg) of - wSpeed: begin - include(gOptions, optOptimizeSpeed); - exclude(gOptions, optOptimizeSize) - end; - wSize: begin - exclude(gOptions, optOptimizeSpeed); - include(gOptions, optOptimizeSize) - end; - wNone: begin - exclude(gOptions, optOptimizeSpeed); - exclude(gOptions, optOptimizeSize) - end - else - liMessage(info, errNoneSpeedOrSizeExpectedButXFound, arg) - end - end; - wApp: begin - case whichKeyword(arg) of - wGui: begin - include(gGlobalOptions, optGenGuiApp); - defineSymbol('guiapp') - end; - wConsole: - exclude(gGlobalOptions, optGenGuiApp); - wLib: begin - include(gGlobalOptions, optGenDynLib); - exclude(gGlobalOptions, optGenGuiApp); - defineSymbol('library') - end; - else - liMessage(info, errGuiConsoleOrLibExpectedButXFound, arg) - end - end; - wListDef: begin - if pass in {@set}[passCmd2, passPP] then - condsyms.listSymbols(); - end; - wPassC, wT: begin - expectArg(switch, arg, pass, info); - if pass in {@set}[passCmd2, passPP] then - extccomp.addCompileOption(arg) - end; - wPassL, wL: begin - expectArg(switch, arg, pass, info); - if pass in {@set}[passCmd2, passPP] then - extccomp.addLinkOption(arg) - end; - wIndex: begin - expectArg(switch, arg, pass, info); - if pass in {@set}[passCmd2, passPP] then - gIndexFile := arg - end; - wImport: begin - expectArg(switch, arg, pass, info); - options.addImplicitMod(arg); - end; - wListCmd: include(gGlobalOptions, optListCmd); - wGenMapping: include(gGlobalOptions, optGenMapping); - wOS: begin - if (pass = passCmd1) then begin - theOS := platform.NameToOS(arg); - if theOS = osNone then - liMessage(info, errUnknownOS, arg); - if theOS <> platform.hostOS then begin - setTarget(theOS, targetCPU); - include(gGlobalOptions, optCompileOnly); - condsyms.InitDefines() - end - end - end; - wCPU: begin - if (pass = passCmd1) then begin - cpu := platform.NameToCPU(arg); - if cpu = cpuNone then - liMessage(info, errUnknownCPU, arg); - if cpu <> platform.hostCPU then begin - setTarget(targetOS, cpu); - include(gGlobalOptions, optCompileOnly); - condsyms.InitDefines() - end - end - end; - wRun, wR: include(gGlobalOptions, optRun); - wVerbosity: begin - expectArg(switch, arg, pass, info); - gVerbosity := parseInt(arg); - end; - wVersion, wV: writeVersionInfo(pass); - wAdvanced: writeAdvancedUsage(pass); - wHelp, wH: helpOnError(pass); - wSymbolFiles: ProcessOnOffSwitchG({@set}[optSymbolFiles], arg, pass, info); - wSkipCfg: include(gGlobalOptions, optSkipConfigFile); - wSkipProjCfg: include(gGlobalOptions, optSkipProjConfigFile); - wGenScript: include(gGlobalOptions, optGenScript); - wLib: begin - expectArg(switch, arg, pass, info); - libpath := processPath(arg) - end; - wPutEnv: begin - expectArg(switch, arg, pass, info); - splitSwitch(arg, key, val, pass, info); - nos.putEnv(key, val); - end; - wCC: begin - expectArg(switch, arg, pass, info); - setCC(arg) - end; - wMaxErr: begin - expectArg(switch, arg, pass, info); - gErrorMax := parseInt(arg); - end; - else if strutils.find(switch, '.') >= strStart then - options.setConfigVar(switch, arg) - else - InvalidCmdLineOption(pass, switch, info) - end -end; - -procedure ProcessCommand(const switch: string; pass: TCmdLinePass); -var - cmd, arg: string; - info: TLineInfo; -begin - info := newLineInfo('command line', 1, 1); - splitSwitch(switch, cmd, arg, pass, info); - ProcessSwitch(cmd, arg, pass, info) -end; - -end. +//[[[end]]] + ; + +function getCommandLineDesc: string; +begin + result := format(HelpMessage, [VersionAsString, + platform.os[platform.hostOS].name, cpu[platform.hostCPU].name]) +{&} Usage +end; + +var + helpWritten: boolean; // BUGFIX 19 + versionWritten: boolean; + advHelpWritten: boolean; + +procedure HelpOnError(pass: TCmdLinePass); +begin + if (pass = passCmd1) and not helpWritten then begin + // BUGFIX 19 + MessageOut(getCommandLineDesc()); + helpWritten := true + end +end; + +procedure writeAdvancedUsage(pass: TCmdLinePass); +begin + if (pass = passCmd1) and not advHelpWritten then begin + // BUGFIX 19 + MessageOut(format(HelpMessage, [VersionAsString, + platform.os[platform.hostOS].name, + cpu[platform.hostCPU].name]) +{&} + AdvancedUsage); + advHelpWritten := true; + helpWritten := true; + halt(0); + end +end; + +procedure writeVersionInfo(pass: TCmdLinePass); +begin + if (pass = passCmd1) and not versionWritten then begin + versionWritten := true; + helpWritten := true; + messageOut(format(HelpMessage, [VersionAsString, + platform.os[platform.hostOS].name, + cpu[platform.hostCPU].name])) + end +end; + +procedure writeCommandLineUsage; +begin + if not helpWritten then begin + messageOut(getCommandLineDesc()); + helpWritten := true + end +end; + +procedure InvalidCmdLineOption(pass: TCmdLinePass; const switch: string; + const info: TLineInfo); +begin + liMessage(info, errInvalidCmdLineOption, switch) +end; + +procedure splitSwitch(const switch: string; out cmd, arg: string; + pass: TCmdLinePass; const info: TLineInfo); +var + i: int; +begin + cmd := ''; + i := strStart; + if (i < length(switch)+strStart) and (switch[i] = '-') then inc(i); + if (i < length(switch)+strStart) and (switch[i] = '-') then inc(i); + while i < length(switch) + strStart do begin + case switch[i] of + 'a'..'z', 'A'..'Z', '0'..'9', '_', '.': + addChar(cmd, switch[i]); + else break; + end; + inc(i); + end; + if i >= length(switch) + strStart then + arg := '' + else if switch[i] in [':', '=', '['] then + arg := ncopy(switch, i + 1) + else + InvalidCmdLineOption(pass, switch, info) +end; + +procedure ProcessOnOffSwitch(const op: TOptions; const arg: string; + pass: TCmdlinePass; const info: TLineInfo); +begin + case whichKeyword(arg) of + wOn: gOptions := gOptions + op; + wOff: gOptions := gOptions - op; + else liMessage(info, errOnOrOffExpectedButXFound, arg) + end +end; + +procedure ProcessOnOffSwitchG(const op: TGlobalOptions; const arg: string; + pass: TCmdlinePass; const info: TLineInfo); +begin + case whichKeyword(arg) of + wOn: gGlobalOptions := gGlobalOptions + op; + wOff: gGlobalOptions := gGlobalOptions - op; + else liMessage(info, errOnOrOffExpectedButXFound, arg) + end +end; + +procedure ExpectArg(const switch, arg: string; pass: TCmdLinePass; + const info: TLineInfo); +begin + if (arg = '') then + liMessage(info, errCmdLineArgExpected, switch) +end; + +procedure ExpectNoArg(const switch, arg: string; pass: TCmdLinePass; + const info: TLineInfo); +begin + if (arg <> '') then + liMessage(info, errCmdLineNoArgExpected, switch) +end; + +procedure ProcessSpecificNote(const arg: string; state: TSpecialWord; + pass: TCmdlinePass; const info: TLineInfo); +var + i, x: int; + n: TNoteKind; + id: string; +begin + id := ''; + // arg = "X]:on|off" + i := strStart; + n := hintMin; + while (i < length(arg)+strStart) and (arg[i] <> ']') do begin + addChar(id, arg[i]); + inc(i) + end; + if (i < length(arg)+strStart) and (arg[i] = ']') then + inc(i) + else + InvalidCmdLineOption(pass, arg, info); + if (i < length(arg)+strStart) and (arg[i] in [':', '=']) then + inc(i) + else + InvalidCmdLineOption(pass, arg, info); + if state = wHint then begin + x := findStr(msgs.HintsToStr, id); + if x >= 0 then + n := TNoteKind(x + ord(hintMin)) + else + InvalidCmdLineOption(pass, arg, info) + end + else begin + x := findStr(msgs.WarningsToStr, id); + if x >= 0 then + n := TNoteKind(x + ord(warnMin)) + else + InvalidCmdLineOption(pass, arg, info) + end; + case whichKeyword(ncopy(arg, i)) of + wOn: include(gNotes, n); + wOff: exclude(gNotes, n); + else liMessage(info, errOnOrOffExpectedButXFound, arg) + end +end; + +function processPath(const path: string): string; +begin + result := UnixToNativePath(format(path, + ['nimrod', getPrefixDir(), 'lib', libpath])) +end; + +procedure processCompile(const filename: string); +var + found, trunc, ext: string; +begin + found := findFile(filename); + if found = '' then found := filename; + splitFilename(found, trunc, ext); + extccomp.addExternalFileToCompile(trunc); + extccomp.addFileToLink(completeCFilePath(trunc, false)); +end; + +procedure processSwitch(const switch, arg: string; pass: TCmdlinePass; + const info: TLineInfo); +var + theOS: TSystemOS; + cpu: TSystemCPU; + key, val, path: string; +begin + case whichKeyword(switch) of + wPath, wP: begin + expectArg(switch, arg, pass, info); + path := processPath(arg); + {@discard} lists.IncludeStr(options.searchPaths, path) + end; + wOut, wO: begin + expectArg(switch, arg, pass, info); + options.outFile := arg; + end; + wDefine, wD: begin + expectArg(switch, arg, pass, info); + DefineSymbol(arg) + end; + wUndef, wU: begin + expectArg(switch, arg, pass, info); + UndefSymbol(arg) + end; + wCompile: begin + expectArg(switch, arg, pass, info); + if pass in {@set}[passCmd2, passPP] then + processCompile(arg); + end; + wLink: begin + expectArg(switch, arg, pass, info); + if pass in {@set}[passCmd2, passPP] then + addFileToLink(arg); + end; + wDebuginfo: begin + expectNoArg(switch, arg, pass, info); + include(gGlobalOptions, optCDebug); + end; + wCompileOnly, wC: begin + expectNoArg(switch, arg, pass, info); + include(gGlobalOptions, optCompileOnly); + end; + wNoLinking: begin + expectNoArg(switch, arg, pass, info); + include(gGlobalOptions, optNoLinking); + end; + wForceBuild, wF: begin + expectNoArg(switch, arg, pass, info); + include(gGlobalOptions, optForceFullMake); + end; + wGC: begin + expectArg(switch, arg, pass, info); + case whichKeyword(arg) of + wBoehm: begin + include(gGlobalOptions, optBoehmGC); + exclude(gGlobalOptions, optRefcGC); + DefineSymbol('boehmgc'); + end; + wRefc: begin + exclude(gGlobalOptions, optBoehmGC); + include(gGlobalOptions, optRefcGC) + end; + wNone: begin + exclude(gGlobalOptions, optRefcGC); + exclude(gGlobalOptions, optBoehmGC); + defineSymbol('nogc'); + end + else + liMessage(info, errNoneBoehmRefcExpectedButXFound, arg) + end + end; + wWarnings, wW: ProcessOnOffSwitch({@set}[optWarns], arg, pass, info); + wWarning: ProcessSpecificNote(arg, wWarning, pass, info); + wHint: ProcessSpecificNote(arg, wHint, pass, info); + wHints: ProcessOnOffSwitch({@set}[optHints], arg, pass, info); + wCheckpoints: ProcessOnOffSwitch({@set}[optCheckpoints], arg, pass, info); + wStackTrace: ProcessOnOffSwitch({@set}[optStackTrace], arg, pass, info); + wLineTrace: ProcessOnOffSwitch({@set}[optLineTrace], arg, pass, info); + wDebugger: begin + ProcessOnOffSwitch({@set}[optEndb], arg, pass, info); + if optEndb in gOptions then + DefineSymbol('endb') + else + UndefSymbol('endb') + end; + wProfiler: begin + ProcessOnOffSwitch({@set}[optProfiler], arg, pass, info); + if optProfiler in gOptions then DefineSymbol('profiler') + else UndefSymbol('profiler') + end; + wChecks, wX: ProcessOnOffSwitch(checksOptions, arg, pass, info); + wObjChecks: ProcessOnOffSwitch({@set}[optObjCheck], arg, pass, info); + wFieldChecks: ProcessOnOffSwitch({@set}[optFieldCheck], arg, pass, info); + wRangeChecks: ProcessOnOffSwitch({@set}[optRangeCheck], arg, pass, info); + wBoundChecks: ProcessOnOffSwitch({@set}[optBoundsCheck], arg, pass, info); + wOverflowChecks: ProcessOnOffSwitch({@set}[optOverflowCheck], arg, pass, info); + wLineDir: ProcessOnOffSwitch({@set}[optLineDir], arg, pass, info); + wAssertions, wA: ProcessOnOffSwitch({@set}[optAssert], arg, pass, info); + wDeadCodeElim: ProcessOnOffSwitchG({@set}[optDeadCodeElim], arg, pass, info); + wOpt: begin + expectArg(switch, arg, pass, info); + case whichKeyword(arg) of + wSpeed: begin + include(gOptions, optOptimizeSpeed); + exclude(gOptions, optOptimizeSize) + end; + wSize: begin + exclude(gOptions, optOptimizeSpeed); + include(gOptions, optOptimizeSize) + end; + wNone: begin + exclude(gOptions, optOptimizeSpeed); + exclude(gOptions, optOptimizeSize) + end + else + liMessage(info, errNoneSpeedOrSizeExpectedButXFound, arg) + end + end; + wApp: begin + expectArg(switch, arg, pass, info); + case whichKeyword(arg) of + wGui: begin + include(gGlobalOptions, optGenGuiApp); + defineSymbol('guiapp') + end; + wConsole: + exclude(gGlobalOptions, optGenGuiApp); + wLib: begin + include(gGlobalOptions, optGenDynLib); + exclude(gGlobalOptions, optGenGuiApp); + defineSymbol('library') + end; + else + liMessage(info, errGuiConsoleOrLibExpectedButXFound, arg) + end + end; + wListDef: begin + expectNoArg(switch, arg, pass, info); + if pass in {@set}[passCmd2, passPP] then + condsyms.listSymbols(); + end; + wPassC, wT: begin + expectArg(switch, arg, pass, info); + if pass in {@set}[passCmd2, passPP] then + extccomp.addCompileOption(arg) + end; + wPassL, wL: begin + expectArg(switch, arg, pass, info); + if pass in {@set}[passCmd2, passPP] then + extccomp.addLinkOption(arg) + end; + wIndex: begin + expectArg(switch, arg, pass, info); + if pass in {@set}[passCmd2, passPP] then + gIndexFile := arg + end; + wImport: begin + expectArg(switch, arg, pass, info); + options.addImplicitMod(arg); + end; + wListCmd: begin + expectNoArg(switch, arg, pass, info); + include(gGlobalOptions, optListCmd); + end; + wGenMapping: begin + expectNoArg(switch, arg, pass, info); + include(gGlobalOptions, optGenMapping); + end; + wOS: begin + expectArg(switch, arg, pass, info); + if (pass = passCmd1) then begin + theOS := platform.NameToOS(arg); + if theOS = osNone then + liMessage(info, errUnknownOS, arg); + if theOS <> platform.hostOS then begin + setTarget(theOS, targetCPU); + include(gGlobalOptions, optCompileOnly); + condsyms.InitDefines() + end + end + end; + wCPU: begin + expectArg(switch, arg, pass, info); + if (pass = passCmd1) then begin + cpu := platform.NameToCPU(arg); + if cpu = cpuNone then + liMessage(info, errUnknownCPU, arg); + if cpu <> platform.hostCPU then begin + setTarget(targetOS, cpu); + include(gGlobalOptions, optCompileOnly); + condsyms.InitDefines() + end + end + end; + wRun, wR: begin + expectNoArg(switch, arg, pass, info); + include(gGlobalOptions, optRun); + end; + wVerbosity: begin + expectArg(switch, arg, pass, info); + gVerbosity := parseInt(arg); + end; + wVersion, wV: begin + expectNoArg(switch, arg, pass, info); + writeVersionInfo(pass); + end; + wAdvanced: begin + expectNoArg(switch, arg, pass, info); + writeAdvancedUsage(pass); + end; + wHelp, wH: begin + expectNoArg(switch, arg, pass, info); + helpOnError(pass); + end; + wSymbolFiles: ProcessOnOffSwitchG({@set}[optSymbolFiles], arg, pass, info); + wSkipCfg: begin + expectNoArg(switch, arg, pass, info); + include(gGlobalOptions, optSkipConfigFile); + end; + wSkipProjCfg: begin + expectNoArg(switch, arg, pass, info); + include(gGlobalOptions, optSkipProjConfigFile); + end; + wGenScript: begin + expectNoArg(switch, arg, pass, info); + include(gGlobalOptions, optGenScript); + end; + wLib: begin + expectArg(switch, arg, pass, info); + libpath := processPath(arg) + end; + wPutEnv: begin + expectArg(switch, arg, pass, info); + splitSwitch(arg, key, val, pass, info); + nos.putEnv(key, val); + end; + wCC: begin + expectArg(switch, arg, pass, info); + setCC(arg) + end; + wMaxErr: begin + expectArg(switch, arg, pass, info); + gErrorMax := parseInt(arg); + end; + else if strutils.find(switch, '.') >= strStart then + options.setConfigVar(switch, arg) + else + InvalidCmdLineOption(pass, switch, info) + end +end; + +procedure ProcessCommand(const switch: string; pass: TCmdLinePass); +var + cmd, arg: string; + info: TLineInfo; +begin + info := newLineInfo('command line', 1, 1); + splitSwitch(switch, cmd, arg, pass, info); + ProcessSwitch(cmd, arg, pass, info) +end; + +end. diff --git a/nim/condsyms.pas b/nim/condsyms.pas index 9c5d64d4b..1df513bbc 100644 --- a/nim/condsyms.pas +++ b/nim/condsyms.pas @@ -15,7 +15,7 @@ unit condsyms; interface uses - nsystem, ast, astalgo, msgs, hashes, platform, strutils, idents; + nsystem, ast, astalgo, msgs, nhashes, platform, strutils, idents; var gSymbols: TStrTable; diff --git a/nim/docgen.pas b/nim/docgen.pas index 15969f51d..784ab6c6c 100644 --- a/nim/docgen.pas +++ b/nim/docgen.pas @@ -18,7 +18,7 @@ interface {$include 'config.inc'} uses - nsystem, charsets, ast, astalgo, strutils, hashes, options, nversion, msgs, + nsystem, charsets, ast, astalgo, strutils, nhashes, options, nversion, msgs, nos, ropes, idents, wordrecg, nmath, pnimsyn, rnimsyn, scanner, rst, ntime, highlite; @@ -722,6 +722,16 @@ begin end end; +function renderContainer(d: PDoc; n: PRstNode): PRope; +var + arg: PRope; +begin + result := renderRstToHtml(d, n.sons[2]); + arg := toRope(strip(getArgument(n))); + if arg = nil then result := ropef('
$1
', [result]) + else result := ropef('
$2
', [arg, result]) +end; + function renderRstToHtml(d: PDoc; n: PRstNode): PRope; var outer, inner: string; @@ -811,6 +821,10 @@ begin result := renderCodeBlock(d, n); exit end; + rnContainer: begin + result := renderContainer(d, n); + exit + end; rnSubstitutionReferences, rnSubstitutionDef: outer := '|$1|'; rnDirective: outer := ''; diff --git a/nim/ecmasgen.pas b/nim/ecmasgen.pas index c9dfcfe25..2eecfba71 100644 --- a/nim/ecmasgen.pas +++ b/nim/ecmasgen.pas @@ -17,7 +17,7 @@ interface {$include 'config.inc'} uses - nsystem, ast, astalgo, strutils, hashes, trees, platform, magicsys, + nsystem, ast, astalgo, strutils, nhashes, trees, platform, magicsys, extccomp, options, nversion, nimsets, msgs, crc, bitsets, idents, lists, types, nos, ntime, ropes, nmath, passes, ccgutils, wordrecg, rnimsyn, rodread; diff --git a/nim/evals.pas b/nim/evals.pas index f9ca85c8f..218046c7e 100644 --- a/nim/evals.pas +++ b/nim/evals.pas @@ -1,7 +1,7 @@ // // // The Nimrod Compiler -// (c) Copyright 2008 Andreas Rumpf +// (c) Copyright 2009 Andreas Rumpf // // See the file "copying.txt", included in this // distribution, for details about the copyright. @@ -157,7 +157,7 @@ begin end; var - gWhileCounter: int; // Use a counter to prevend endless loops! + gWhileCounter: int; // Use a counter to prevent endless loops! // We make this counter global, because otherwise // nested loops could make the compiler extremely slow. gNestedEvals: int; // count the recursive calls to ``evalAux`` to prevent @@ -390,7 +390,7 @@ begin stackTrace(c, n, errIndexOutOfBounds); end; else - stackTrace(c, n, errIndexNoIntType); + stackTrace(c, n, errNilAccess); end end; @@ -506,7 +506,8 @@ begin result := emptyNode end end; - if result = nil then InternalError(n.info, 'evalSym: ' + n.sym.name.s); + if result = nil then + stackTrace(c, n, errCannotInterpretNodeX, n.sym.name.s); end; function evalIncDec(c: PEvalContext; n: PNode; sign: biggestInt): PNode; @@ -563,8 +564,12 @@ function evalDeref(c: PEvalContext; n: PNode): PNode; begin result := evalAux(c, n.sons[0]); if result.kind = nkExceptBranch then exit; - if result.kind <> nkRefTy then InternalError(n.info, 'evalDeref'); - result := result.sons[0]; + case result.kind of + nkExceptBranch: exit; + nkNilLit: stackTrace(c, n, errNilAccess); + nkRefTy: result := result.sons[0]; + else InternalError(n.info, 'evalDeref ' + nodeKindToStr[result.kind]); + end; end; function evalAddr(c: PEvalContext; n: PNode): PNode; @@ -574,7 +579,6 @@ var begin result := evalAux(c, n.sons[0]); if result.kind = nkExceptBranch then exit; - if result.kind <> nkRefTy then InternalError(n.info, 'evalDeref'); a := result; t := newType(tyPtr, c.module); addSon(t, a.typ); @@ -732,6 +736,7 @@ end; function evalSetLengthSeq(c: PEvalContext; n: PNode): PNode; var a, b: PNode; + newLen, oldLen, i: int; begin result := evalAux(c, n.sons[1]); if result.kind = nkExceptBranch then exit; @@ -739,8 +744,12 @@ begin result := evalAux(c, n.sons[2]); if result.kind = nkExceptBranch then exit; b := result; - if a.kind = nkBracket then setLength(a.sons, int(getOrdValue(b))) - else InternalError(n.info, 'evalSetLengthSeq'); + if a.kind <> nkBracket then InternalError(n.info, 'evalSetLengthSeq'); + newLen := int(getOrdValue(b)); + oldLen := sonsLen(a); + setLength(a.sons, newLen); + for i := oldLen to newLen-1 do + a.sons[i] := getNullValue(skipVarGeneric(n.sons[1].typ), n.info); result := emptyNode end; @@ -758,10 +767,13 @@ begin b := result; t := skipVarGeneric(n.sons[1].typ); - result := newNodeIT(nkBracket, n.info, t); + if a.kind = nkEmpty then InternalError(n.info, 'first parameter is empty'); + a.kind := nkBracket; + a.info := n.info; + a.typ := t; for i := 0 to int(getOrdValue(b))-1 do - addSon(result, getNullValue(t.sons[0], n.info)); - // XXX: assign to `a`? result := emptyNode + addSon(a, getNullValue(t.sons[0], n.info)); + result := emptyNode end; function evalAssert(c: PEvalContext; n: PNode): PNode; @@ -907,7 +919,7 @@ end; function evalMagicOrCall(c: PEvalContext; n: PNode): PNode; var m: TMagic; - a, b: PNode; + a, b, cc: PNode; k: biggestInt; i: int; begin @@ -1179,22 +1191,35 @@ begin mNError: begin result := evalAux(c, n.sons[1]); if result.kind = nkExceptBranch then exit; - liMessage(n.info, errUser, getStrValue(result)); + stackTrace(c, n, errUser, getStrValue(result)); result := emptyNode end; mConStrStr: result := evalConStrStr(c, n); mRepr: result := evalRepr(c, n); + mNewString: begin + result := evalAux(c, n.sons[1]); + if result.kind = nkExceptBranch then exit; + a := result; + result := newNodeIT(nkStrLit, n.info, n.typ); + result.strVal := newString(int(getOrdValue(a))); + end; else begin result := evalAux(c, n.sons[1]); if result.kind = nkExceptBranch then exit; a := result; + b := nil; + cc := nil; if sonsLen(n) > 2 then begin result := evalAux(c, n.sons[2]); if result.kind = nkExceptBranch then exit; - end - else - result := nil; - result := evalOp(m, n, a, result); + b := result; + if sonsLen(n) > 3 then begin + result := evalAux(c, n.sons[3]); + if result.kind = nkExceptBranch then exit; + cc := result; + end + end; + result := evalOp(m, n, a, b, cc); end end end; @@ -1213,7 +1238,7 @@ begin nkNilLit: result := n; // end of atoms nkCall, nkHiddenCallConv, nkMacroStmt: result := evalMagicOrCall(c, n); - nkCurly, nkBracket: begin + nkCurly, nkBracket, nkRange: begin result := copyNode(n); for i := 0 to sonsLen(n)-1 do addSon(result, evalAux(c, n.sons[i])); end; diff --git a/nim/extccomp.pas b/nim/extccomp.pas index f51e5f690..a53ad1c10 100644 --- a/nim/extccomp.pas +++ b/nim/extccomp.pas @@ -15,8 +15,8 @@ interface {$include 'config.inc'} uses - nsystem, charsets, lists, ropes, nos, strutils, platform, condsyms, options, - msgs; + nsystem, charsets, lists, ropes, nos, strutils, osproc, platform, condsyms, + options, msgs; // some things are read in from the configuration file @@ -387,7 +387,7 @@ procedure execExternalProgram(const cmd: string); begin if (optListCmd in gGlobalOptions) or (gVerbosity > 0) then MessageOut('Executing: ' +{&} nl +{&} cmd); - if executeShellCommand(cmd) <> 0 then + if executeCommand(cmd) <> 0 then rawMessage(errExecutionOfProgramFailed); end; diff --git a/nim/hashtest.pas b/nim/hashtest.pas index ba7a62372..7e93ca5bf 100644 --- a/nim/hashtest.pas +++ b/nim/hashtest.pas @@ -3,7 +3,7 @@ program hashtest; {$include 'config.inc'} uses - hashes; + nhashes; begin writeln(output, getNormalizedHash(ParamStr(1))); diff --git a/nim/highlite.pas b/nim/highlite.pas index 5ef4acc12..ad7a6f724 100644 --- a/nim/highlite.pas +++ b/nim/highlite.pas @@ -17,7 +17,7 @@ interface {$include 'config.inc'} uses - charsets, nsystem, sysutils, hashes, options, msgs, strutils, platform, + charsets, nsystem, sysutils, nhashes, options, msgs, strutils, platform, idents, lexbase, wordrecg, scanner; type diff --git a/nim/idents.pas b/nim/idents.pas index c0e4c994f..c1c1755e9 100644 --- a/nim/idents.pas +++ b/nim/idents.pas @@ -17,7 +17,7 @@ unit idents; interface uses - hashes, nsystem, strutils; + nhashes, nsystem, strutils; type TIdObj = object(NObject) diff --git a/nim/interact.pas b/nim/interact.pas index ac238107f..aab3c7fc2 100644 --- a/nim/interact.pas +++ b/nim/interact.pas @@ -15,7 +15,7 @@ interface {$include 'config.inc'} uses - nsystem, llstream, strutils, charsets, ropes, strtabs, msgs; + nsystem, llstream, strutils, charsets, ropes, nstrtabs, msgs; implementation diff --git a/nim/magicsys.pas b/nim/magicsys.pas index 7a717e61d..462912995 100644 --- a/nim/magicsys.pas +++ b/nim/magicsys.pas @@ -16,7 +16,7 @@ interface uses nsystem, - ast, astalgo, hashes, msgs, platform, nversion, ntime, idents, rodread; + ast, astalgo, nhashes, msgs, platform, nversion, ntime, idents, rodread; var // magic symbols in the system module: SystemModule: PSym; diff --git a/nim/main.pas b/nim/main.pas index c888e5c3c..b1c58c2b9 100644 --- a/nim/main.pas +++ b/nim/main.pas @@ -152,7 +152,7 @@ begin semanticPasses(); registerPass(cgen.cgenPass()); registerPass(rodwrite.rodwritePass()); - registerPass(cleanupPass()); + //registerPass(cleanupPass()); compileProject(filename); //for i := low(TTypeKind) to high(TTypeKind) do // MessageOut('kind: ' +{&} typeKindToStr[i] +{&} ' = ' +{&} toString(sameTypeA[i])); diff --git a/nim/msgs.pas b/nim/msgs.pas index 0eb1651d9..53e1b3388 100644 --- a/nim/msgs.pas +++ b/nim/msgs.pas @@ -96,10 +96,10 @@ type errAttemptToRedefine, errStmtInvalidAfterReturn, errStmtExpected, - errYieldOnlyInInterators, errInvalidLabel, errInvalidCmdLineOption, errCmdLineArgExpected, + errCmdLineNoArgExpected, errInvalidVarSubstitution, errUnknownVar, errUnknownCcompiler, @@ -138,7 +138,7 @@ type errStaticAssertCannotBeEval, errDotRequiresRecordOrObjectType, errUndeclaredFieldX, - errIndexNoIntType, + errNilAccess, errIndexOutOfBounds, errIndexTypesDoNotMatch, errBracketsInvalidForType, @@ -348,17 +348,17 @@ const 'exception expected', 'exception already handled', '''return'' only allowed in routine', - '''yield'' only allowed in iterator', + '''yield'' only allowed in a loop of an iterator', 'invalid number of ''yield'' expresions', '''return'' not allowed in iterator', 'current routine cannot return an expression', 'attempt to redefine ''$1''', 'statement not allowed after ''return'', ''break'' or ''raise''', 'statement expected', - '''yield'' statement is only allowed in iterators', '''$1'' is no label', 'invalid command line option: ''$1''', 'argument for command line option expected: ''$1''', + 'invalid argument for command line option: ''$1''', 'invalid variable substitution in ''$1''', 'unknown variable: ''$1''', 'unknown C compiler: ''$1''', @@ -397,7 +397,7 @@ const 'argument to ''staticAssert'' cannot be evaluated at compile time', '''.'' requires a record or object type', 'undeclared field: ''$1''', - 'index has to be an integer type', + 'attempt to access a nil address', 'index out of bounds', 'index types do not match', '''[]'' operator invalid for this type', diff --git a/nim/hashes.pas b/nim/nhashes.pas similarity index 99% rename from nim/hashes.pas rename to nim/nhashes.pas index 0d7eb205d..0564f6f47 100644 --- a/nim/hashes.pas +++ b/nim/nhashes.pas @@ -6,7 +6,7 @@ // See the file "copying.txt", included in this // distribution, for details about the copyright. // -unit hashes; +unit nhashes; {$include 'config.inc'} diff --git a/nim/strtabs.pas b/nim/nstrtabs.pas similarity index 96% rename from nim/strtabs.pas rename to nim/nstrtabs.pas index 4fcf32891..bcb10f2ed 100644 --- a/nim/strtabs.pas +++ b/nim/nstrtabs.pas @@ -6,7 +6,7 @@ // See the file "copying.txt", included in this // distribution, for details about the copyright. // -unit strtabs; +unit nstrtabs; // String tables. @@ -15,7 +15,7 @@ interface {$include 'config.inc'} uses - nsystem, nos, hashes, strutils; + nsystem, nos, nhashes, strutils; type TStringTableMode = ( @@ -93,9 +93,9 @@ end; function myhash(t: PStringTable; const key: string): THash; begin case t.mode of - modeCaseSensitive: result := hashes.GetHashStr(key); - modeCaseInsensitive: result := hashes.GetHashStrCI(key); - modeStyleInsensitive: result := hashes.getNormalizedHash(key); + modeCaseSensitive: result := nhashes.GetHashStr(key); + modeCaseInsensitive: result := nhashes.GetHashStrCI(key); + modeStyleInsensitive: result := nhashes.getNormalizedHash(key); end end; diff --git a/nim/nversion.pas b/nim/nversion.pas index de0ad2b79..ae6392db9 100644 --- a/nim/nversion.pas +++ b/nim/nversion.pas @@ -1,42 +1,42 @@ -// -// -// The Nimrod Compiler -// (c) Copyright 2008 Andreas Rumpf -// -// See the file "copying.txt", included in this -// distribution, for details about the copyright. -// - -unit nversion; - -// this unit implements the version handling - -interface - -{$include 'config.inc'} - -uses - strutils; - -const - MaxSetElements = 1 shl 16; // (2^16) to support unicode character sets? - defaultAsmMarkerSymbol = '!'; - - //[[[cog - //from koch import NIMROD_VERSION - //from string import split - //cog.outl("VersionAsString = '%s';" % NIMROD_VERSION) - //ver = split(NIMROD_VERSION, '.') - //cog.outl('VersionMajor = %s;' % ver[0]) - //cog.outl('VersionMinor = %s;' % ver[1]) - //cog.outl('VersionPatch = %s;' % ver[2]) - //]]] - VersionAsString = '0.7.6'; +// +// +// The Nimrod Compiler +// (c) Copyright 2008 Andreas Rumpf +// +// See the file "copying.txt", included in this +// distribution, for details about the copyright. +// + +unit nversion; + +// this unit implements the version handling + +interface + +{$include 'config.inc'} + +uses + strutils; + +const + MaxSetElements = 1 shl 16; // (2^16) to support unicode character sets? + defaultAsmMarkerSymbol = '!'; + + //[[[cog + //from koch import NIMROD_VERSION + //from string import split + //cog.outl("VersionAsString = '%s';" % NIMROD_VERSION) + //ver = split(NIMROD_VERSION, '.') + //cog.outl('VersionMajor = %s;' % ver[0]) + //cog.outl('VersionMinor = %s;' % ver[1]) + //cog.outl('VersionPatch = %s;' % ver[2]) + //]]] + VersionAsString = '0.7.8'; VersionMajor = 0; VersionMinor = 7; - VersionPatch = 6; - //[[[[end]]]] - -implementation - -end. + VersionPatch = 8; + //[[[[end]]]] + +implementation + +end. diff --git a/nim/options.pas b/nim/options.pas index d6f6d14da..f84d8458c 100644 --- a/nim/options.pas +++ b/nim/options.pas @@ -13,7 +13,7 @@ interface {$include 'config.inc'} uses - nsystem, nos, lists, strutils, strtabs; + nsystem, nos, lists, strutils, nstrtabs; type // please make sure we have under 32 options @@ -150,12 +150,12 @@ end; function getConfigVar(const key: string): string; begin - result := strtabs.get(gConfigVars, key); + result := nstrtabs.get(gConfigVars, key); end; procedure setConfigVar(const key, val: string); begin - strtabs.put(gConfigVars, key, val); + nstrtabs.put(gConfigVars, key, val); end; function getOutFile(const filename, ext: string): string; diff --git a/nim/osproc.pas b/nim/osproc.pas new file mode 100644 index 000000000..dd6bd10f0 --- /dev/null +++ b/nim/osproc.pas @@ -0,0 +1,30 @@ +// +// +// The Nimrod Compiler +// (c) Copyright 2009 Andreas Rumpf +// +// See the file "copying.txt", included in this +// distribution, for details about the copyright. +// +unit osproc; + +// This module provides Nimrod's osproc module in Pascal +// Note: Only implement what is really needed here! + +interface + +{$include 'config.inc'} + +uses + nsystem, nos; + +function executeCommand(const cmd: string): int; + +implementation + +function executeCommand(const cmd: string): int; +begin + result := executeShellCommand(cmd); +end; + +end. diff --git a/nim/parsecfg.pas b/nim/parsecfg.pas index 3c10cc8fc..620335aa6 100644 --- a/nim/parsecfg.pas +++ b/nim/parsecfg.pas @@ -17,7 +17,7 @@ interface {$include 'config.inc'} uses - nsystem, charsets, llstream, sysutils, hashes, strutils, lexbase; + nsystem, charsets, llstream, sysutils, nhashes, strutils, lexbase; type TCfgEventKind = ( diff --git a/nim/paslex.pas b/nim/paslex.pas index c0136e4d8..da9283163 100644 --- a/nim/paslex.pas +++ b/nim/paslex.pas @@ -17,7 +17,7 @@ interface uses charsets, nsystem, sysutils, - hashes, options, msgs, strutils, platform, idents, + nhashes, options, msgs, strutils, platform, idents, lexbase, wordrecg, scanner; const diff --git a/nim/pragmas.pas b/nim/pragmas.pas index 9a60e6bd3..df48f27c9 100644 --- a/nim/pragmas.pas +++ b/nim/pragmas.pas @@ -1,7 +1,7 @@ // // // The Nimrod Compiler -// (c) Copyright 2008 Andreas Rumpf +// (c) Copyright 2009 Andreas Rumpf // // See the file "copying.txt", included in this // distribution, for details about the copyright. @@ -143,7 +143,7 @@ begin else v := expectStrLit(c, n); Include(s.flags, sfImportc); // magics don't need an implementation, so we // treat them as imported, instead of modifing a lot of working code - Include(s.loc.Flags, lfNoDecl); // magics don't need to be declared! + // BUGFIX: magic does not imply ``lfNoDecl`` anymore! for m := low(TMagic) to high(TMagic) do if magicToStr[m] = v then begin s.magic := m; exit diff --git a/nim/ropes.pas b/nim/ropes.pas index 864afd5b8..6b6540c24 100644 --- a/nim/ropes.pas +++ b/nim/ropes.pas @@ -64,7 +64,7 @@ interface {$include 'config.inc'} uses - nsystem, msgs, strutils, platform, hashes, crc; + nsystem, msgs, strutils, platform, nhashes, crc; const CacheLeafs = true; diff --git a/nim/rst.pas b/nim/rst.pas index 0c5377646..6d0d476c9 100644 --- a/nim/rst.pas +++ b/nim/rst.pas @@ -16,7 +16,7 @@ interface {$include 'config.inc'} uses - nsystem, nos, msgs, strutils, platform, hashes, ropes, charsets, options; + nsystem, nos, msgs, strutils, platform, nhashes, ropes, charsets, options; type TRstNodeKind = ( @@ -79,6 +79,7 @@ type rnImage, rnFigure, rnCodeBlock, + rnContainer, // ``container`` directive rnIndex, // index directve: // .. index:: // key @@ -111,9 +112,9 @@ const 'TableRow', 'TableHeaderCell', 'TableDataCell', 'Label', 'Footnote', 'Citation', 'StandaloneHyperlink', 'Hyperlink', 'Ref', 'Directive', 'DirArg', 'Raw', 'Title', 'Contents', 'Image', 'Figure', 'CodeBlock', - 'Index', 'SubstitutionDef', 'GeneralRole', 'Sub', 'Sup', 'Idx', - 'Emphasis', 'StrongEmphasis', 'InterpretedText', 'InlineLiteral', - 'SubstitutionReferences', 'Leaf' + 'Container', 'Index', 'SubstitutionDef', 'GeneralRole', + 'Sub', 'Sup', 'Idx', 'Emphasis', 'StrongEmphasis', 'InterpretedText', + 'InlineLiteral', 'SubstitutionReferences', 'Leaf' ); type @@ -1178,12 +1179,12 @@ end; type TDirKind = ( // must be ordered alphabetically! - dkNone, dkAuthor, dkAuthors, dkCodeBlock, + dkNone, dkAuthor, dkAuthors, dkCodeBlock, dkContainer, dkContents, dkFigure, dkImage, dkInclude, dkIndex, dkRaw, dkTitle ); const - DirIds: array [0..10] of string = ( - '', 'author', 'authors', 'code-block', + DirIds: array [0..11] of string = ( + '', 'author', 'authors', 'code-block', 'container', 'contents', 'figure', 'image', 'include', 'index', 'raw', 'title' ); @@ -1993,6 +1994,14 @@ begin result.kind := rnCodeBlock end; +function dirContainer(var p: TRstParser): PRstNode; +begin + result := parseDirective(p, {@set}[hasArg], parseSectionWrapper); + assert(result.kind = rnDirective); + assert(rsonsLen(result) = 3); + result.kind := rnContainer; +end; + function dirImage(var p: TRstParser): PRstNode; begin result := parseDirective(p, {@set}[hasOptions, hasArg, argIsFile], nil); @@ -2071,6 +2080,7 @@ begin dkImage: result := dirImage(p); dkFigure: result := dirFigure(p); dkTitle: result := dirTitle(p); + dkContainer: result := dirContainer(p); dkContents: result := dirContents(p); dkRaw: result := dirRaw(p); dkCodeblock: result := dirCodeBlock(p); diff --git a/nim/scanner.pas b/nim/scanner.pas index d035b973b..51532c801 100644 --- a/nim/scanner.pas +++ b/nim/scanner.pas @@ -21,7 +21,7 @@ interface {$include 'config.inc'} uses - charsets, nsystem, sysutils, hashes, options, msgs, strutils, platform, + charsets, nsystem, sysutils, nhashes, options, msgs, strutils, platform, idents, lexbase, llstream, wordrecg; const diff --git a/nim/sem.pas b/nim/sem.pas index 3494754fd..09f9bf49b 100644 --- a/nim/sem.pas +++ b/nim/sem.pas @@ -112,6 +112,23 @@ begin end end; +function semAfterMacroCall(c: PContext; n, p: PNode): PNode; +begin + result := n; + if (p = nil) or (p.kind <> nkIdent) then + liMessage(n.info, errInvalidParamKindX, renderTree(p)) + else begin + case p.ident.id of + ord(wExpr): result := semExprWithType(c, result); + ord(wStmt): result := semStmt(c, result); + ord(wTypeDesc): + result.typ := semTypeNode(c, result, nil); + else + liMessage(p.info, errInvalidParamKindX, p.ident.s) + end + end +end; + function semMacroExpr(c: PContext; n: PNode; sym: PSym): PNode; var p: PEvalContext; @@ -128,7 +145,7 @@ begin result := s.params[0]; popStackFrame(p); if cyclicTree(result) then liMessage(n.info, errCyclicTree); - result := semStmt(c, result); + result := semAfterMacroCall(c, result, sym.ast.sons[paramsPos].sons[0]); // now, that was easy ... // and we get more flexibility than in any other programming language end; @@ -137,14 +154,12 @@ end; {$include 'seminst.pas'} {$include 'sigmatch.pas'} - procedure CheckBool(t: PNode); begin if (t.Typ = nil) or (skipVarGeneric(t.Typ).kind <> tyBool) then liMessage(t.Info, errExprMustBeBool); end; - procedure typeMismatch(n: PNode; formal, actual: PType); begin liMessage(n.Info, errGenerated, @@ -167,13 +182,17 @@ var prc: PSym; it: PNode; begin - for i := 0 to sonsLen(c.generics)-1 do begin + for i := c.lastGenericIdx to sonsLen(c.generics)-1 do begin it := c.generics.sons[i].sons[1]; if it.kind <> nkSym then InternalError('addCodeForGenerics'); prc := it.sym; - if (prc.kind in [skProc, skConverter]) and (prc.magic = mNone) then + if (prc.kind in [skProc, skConverter]) and (prc.magic = mNone) then begin + if (prc.ast = nil) or (prc.ast.sons[codePos] = nil) then + InternalError(prc.info, 'no code for ' + prc.name.s); addSon(n, prc.ast); + end end; + c.lastGenericIdx := sonsLen(c.generics); end; function myOpen(module: PSym; const filename: string): PPassContext; @@ -212,10 +231,21 @@ end; function myProcess(context: PPassContext; n: PNode): PNode; var c: PContext; + a: PNode; begin result := nil; c := PContext(context); result := semStmt(c, n); + // BUGFIX: process newly generated generics here, not at the end! + if sonsLen(c.generics) > 0 then begin + a := newNodeI(nkStmtList, n.info); + addCodeForGenerics(c, a); + if sonsLen(a) > 0 then begin + // a generic has been added to `a`: + addSonIfNotNil(a, result); + result := a + end + end end; function myClose(context: PPassContext; n: PNode): PNode; @@ -226,7 +256,8 @@ begin closeScope(c.tab); // close module's scope rawCloseScope(c.tab); // imported symbols; don't check for unused ones! if n = nil then result := newNode(nkStmtList) - else result := n; + else InternalError(n.info, 'n is not nil'); + //result := n; addCodeForGenerics(c, result); popOwner(); c.p := nil; diff --git a/nim/semdata.pas b/nim/semdata.pas index 3393ed4b3..acca48376 100644 --- a/nim/semdata.pas +++ b/nim/semdata.pas @@ -55,6 +55,7 @@ type libs: TLinkedList; // all libs used by this module p: PProcCon; // procedure context fromCache: bool; // is the module read from a cache? + lastGenericIdx: int; // used for the generics stack semConstExpr: function (c: PContext; n: PNode): PNode; // for the pragmas module end; diff --git a/nim/semfold.pas b/nim/semfold.pas index 781c3b97d..fdbad9f4c 100644 --- a/nim/semfold.pas +++ b/nim/semfold.pas @@ -24,7 +24,7 @@ function getConstExpr(module: PSym; n: PNode): PNode; // evaluates the constant expression or returns nil if it is no constant // expression -function evalOp(m: TMagic; n, a, b: PNode): PNode; +function evalOp(m: TMagic; n, a, b, c: PNode): PNode; function leValueConv(a, b: PNode): Boolean; function newIntNodeT(const intVal: BiggestInt; n: PNode): PNode; @@ -113,8 +113,8 @@ begin InternalError(a.info, 'no symbol for ordinal value: ' + toString(x)); end; -function evalOp(m: TMagic; n, a, b: PNode): PNode; -// if this is an unary operation, b is nil +function evalOp(m: TMagic; n, a, b, c: PNode): PNode; +// b and c may be nil begin result := nil; case m of @@ -127,8 +127,9 @@ begin mBitnotI, mBitnotI64: result := newIntNodeT(not getInt(a), n); mLengthStr: result := newIntNodeT(length(getStr(a)), n); - mLengthSeq, mLengthArray, - mLengthOpenArray: result := newIntNodeT(lengthOrd(a.typ), n); + mLengthArray: result := newIntNodeT(lengthOrd(a.typ), n); + mLengthSeq, mLengthOpenArray: + result := newIntNodeT(sonsLen(a), n); // BUGFIX mUnaryPlusI, mUnaryPlusI64, mUnaryPlusF64: result := a; // throw `+` away mToFloat, mToBiggestFloat: @@ -273,6 +274,11 @@ begin else result := newStrNodeT('true', n) end; + mCopyStr: + result := newStrNodeT(ncopy(getStr(a), int(getOrdValue(b))+strStart), n); + mCopyStrLast: + result := newStrNodeT(ncopy(getStr(a), int(getOrdValue(b))+strStart, + int(getOrdValue(c))+strStart), n); mFloatToStr: result := newStrNodeT(toStringF(getFloat(a)), n); mCStrToStr, mCharToStr: result := newStrNodeT(getStrOrChar(a), n); mStrToStr: result := a; @@ -281,7 +287,7 @@ begin result := copyTree(a); result.typ := n.typ; end; - mExit, mInc, ast.mDec, mAssert, mSwap, + mNewString, mExit, mInc, ast.mDec, mAssert, mSwap, mAppendStrCh, mAppendStrStr, mAppendSeqElem, mAppendSeqSeq, mSetLengthStr, mSetLengthSeq, mNLen..mNError: begin end; else InternalError(a.info, 'evalOp(' +{&} magicToStr[m] +{&} ')'); @@ -376,7 +382,7 @@ end; function getConstExpr(module: PSym; n: PNode): PNode; var s: PSym; - a, b: PNode; + a, b, c: PNode; i: int; begin result := nil; @@ -443,10 +449,14 @@ begin if a = nil then exit; if sonsLen(n) > 2 then begin b := getConstExpr(module, n.sons[2]); - if b = nil then exit + if b = nil then exit; + if sonsLen(n) > 3 then begin + c := getConstExpr(module, n.sons[3]); + if c = nil then exit; + end end else b := nil; - result := evalOp(s.magic, n, a, b); + result := evalOp(s.magic, n, a, b, c); end end except diff --git a/nim/semstmts.pas b/nim/semstmts.pas index ebf14693c..a5242b526 100644 --- a/nim/semstmts.pas +++ b/nim/semstmts.pas @@ -354,7 +354,8 @@ var begin result := n; checkSonsLen(n, 1); - if (c.p.owner = nil) or (c.p.owner.kind <> skIterator) then + if (c.p.owner = nil) or (c.p.owner.kind <> skIterator) + or (c.p.nestedLoopCounter <= 0) then liMessage(n.info, errYieldNotAllowedHere); if (n.sons[0] <> nil) then begin n.sons[0] := SemExprWithType(c, n.sons[0]); diff --git a/nim/tigen.pas b/nim/tigen.pas index 937883e5e..687b70920 100644 --- a/nim/tigen.pas +++ b/nim/tigen.pas @@ -17,7 +17,7 @@ interface {$include 'config.inc'} uses - nsystem, ast, astalgo, strutils, hashes, trees, treetab, platform, magicsys, + nsystem, ast, astalgo, strutils, nhashes, trees, treetab, platform, magicsys, options, msgs, crc, idents, lists, types, rnimsyn; function gcWalker(t: PType): PNode; diff --git a/nim/transf.pas b/nim/transf.pas index 5d9f44143..c4ed5740c 100644 --- a/nim/transf.pas +++ b/nim/transf.pas @@ -801,7 +801,7 @@ begin inc(j); if isConstExpr(a) then while (j < sonsLen(m)) and isConstExpr(m.sons[j]) do begin - a := evalOp(op.magic, m, a, m.sons[j]); + a := evalOp(op.magic, m, a, m.sons[j], nil); inc(j) end; addSon(result, a); diff --git a/nim/treetab.pas b/nim/treetab.pas index dbd7b5276..31d7aa0cf 100644 --- a/nim/treetab.pas +++ b/nim/treetab.pas @@ -15,7 +15,7 @@ interface {$include 'config.inc'} uses - nsystem, hashes, ast, astalgo, types; + nsystem, nhashes, ast, astalgo, types; function NodeTableGet(const t: TNodeTable; key: PNode): int; procedure NodeTablePut(var t: TNodeTable; key: PNode; val: int); diff --git a/nim/wordrecg.pas b/nim/wordrecg.pas index dd2df0047..7957d354b 100644 --- a/nim/wordrecg.pas +++ b/nim/wordrecg.pas @@ -19,7 +19,7 @@ interface {$include 'config.inc'} uses - nsystem, hashes, strutils, idents; + nsystem, nhashes, strutils, idents; type TSpecialWord = (wInvalid, diff --git a/objdata.txt b/objdata.txt deleted file mode 100644 index 653ae5931..000000000 --- a/objdata.txt +++ /dev/null @@ -1,8 +0,0 @@ -nodes: 2224942 -syms: 39562 -Types: 28189 - -nodes: 2224942 -syms: 39562 -Types: 29054 -Ropes: 1245961 diff --git a/rod/nimrod.ini b/rod/nimrod.ini index 755c1dd17..a32c78e57 100644 --- a/rod/nimrod.ini +++ b/rod/nimrod.ini @@ -81,6 +81,7 @@ Files: "lib/base/lua/*.nim" [Windows] Files: "bin/nimrod.exe" +Files: "bin/nimrodd.exe" Files: "dist/mingw" BinPath: r"bin;dist\mingw\bin" diff --git a/tests/csvtest.csv b/tests/csvtest.csv new file mode 100644 index 000000000..6e7e14103 --- /dev/null +++ b/tests/csvtest.csv @@ -0,0 +1,8 @@ +headerField1,headerField2,headerField3 +12,12132,"hallo "" + du" +1,, +,2, +,,3 +1,2,3 + diff --git a/tests/data.csv b/tests/data.csv new file mode 100644 index 000000000..ea73f7387 --- /dev/null +++ b/tests/data.csv @@ -0,0 +1,6 @@ +Algo_A; Algo_B; Algo_C +12; 12; 16 +2; 5; 9 +63; 65.3; 90 +0; 1.2; 3 + diff --git a/tests/gctest.nim b/tests/gctest.nim index 2f8b97b38..f58dc3217 100644 --- a/tests/gctest.nim +++ b/tests/gctest.nim @@ -28,6 +28,16 @@ type of nkList: sons: seq[PCaseNode] else: unused: seq[string] + TIdObj* = object of TObject + id*: int # unique id; use this for comparisons and not the pointers + + PIdObj* = ref TIdObj + PIdent* = ref TIdent + TIdent*{.acyclic.} = object of TIdObj + s*: string + next*: PIdent # for hash-table chaining + h*: int # hash value of s + var flip: int @@ -134,7 +144,17 @@ proc buildBTree(father: var TBNode) = father.t.data = @["ha", "lets", "stress", "it"] setSons(father) +proc getIdent(identifier: cstring, length: int, h: int): PIdent = + new(result) + result.h = h + result.s = newString(length) + proc main() = + discard getIdent("addr", 4, 0) + discard getIdent("hall", 4, 0) + discard getIdent("echo", 4, 0) + discard getIdent("huch", 4, 0) + var father: TBNode for i in 1..1_00: @@ -156,9 +176,6 @@ proc main() = writeln(stdout, s[89]) write(stdout, "done!\n") -#main() - -#GC_disable() var father: TBNode s: string @@ -177,4 +194,4 @@ main() write(stdout, "finished\n") GC_fullCollect() GC_fullCollect() -write(stdout, GC_getStatistics()) +writeln(stdout, GC_getStatistics()) diff --git a/tests/toop1.nim b/tests/toop1.nim index bf3d2021d..8bae002e7 100644 --- a/tests/toop1.nim +++ b/tests/toop1.nim @@ -31,7 +31,7 @@ proc init(my: var TRectangle) = my.height = 10 my.draw = drawRectangle -macro `!` (n: expr): expr = +macro `!` (n: expr): stmt = result = newNimNode(nnkCall, n) var dot = newNimNode(nnkDotExpr, n) dot.add(n[1]) # obj diff --git a/todo.txt b/todo.txt index 3e80ba6f1..66c4762f6 100644 --- a/todo.txt +++ b/todo.txt @@ -4,27 +4,17 @@ TO IMPLEMENT Plan ---- -* implement new memory manager --> hopefully faster turnaround times * implement LLVM backend --> faster turnaround times - - -RST ---- -- footnotes; prefix :i: whitespace before :i:, _reference, `reference`__ - __ anonymous: www.nimrod.org +* implement ``p(.int, int.): string`` notation for resolution of overloaded + procs Bugs ---- -- BUG: check if "break" is valid is not complete: "break" within "for" - may be incorrect, if the called iterator is not in a loop - --> check that "yield" is inside a loop! - BUG: returning an array does not work --> see md5.nim module - BUG: if not nodeOfDegree(g, 1) >= 0: inc(counter) -- BUG: addr/deref may not work when interpreting - BUG: the parser allows empty object case branches - BUG: when optmizing cgen.c with Visual C++, GCC, LLVM (O3), it breaks. -- BUG: ``-cc:bcc`` command line option does not error - BUG: symbol files still do not work - BUG: tlastmod returns wrong results on BSD (Linux, MacOS X: works) @@ -32,6 +22,12 @@ Bugs High priority ------------- +- new $$ string interpolation operator? + $$"The value is $var &var" -- too hard to implement + +- find a way to reindroduce the cleanup() pass for C code generation: this + is hard because of partial evaluation --> symbol files will fix this as + a side effect - typeAllowed() for parameters... - implicit conversions from ``ptr/ref T`` to ``var T`` and from ``ptr/ref T`` to ``T``? Yes. @@ -44,15 +40,40 @@ High priority implement - language change: inheritance should only work with reference types, so that the ``type`` field is not needed for objects! --> zero overhead aggregation +- resizing of strings/sequences could take into account the memory that + is allocated + + +Library +------- + +- socket, http, ftp, email, fastcgi: implement from scratch +- osproc for Windows +- bignums + +- gui module +- finish json module: hard + +- YAML module +- ncurses bindings +- python +- TCL +- automate module: expect-like module for Nimrod + +- for system: + proc `@` [T](a: openArray[T]): seq[T] = + newSeq(result, a.len) + for i in 0..a.len-1: result[i] = a[i] + + --> ensure @[] calls the array version! + For the next versions ===================== - multi-processor support - IDE -- better support for GDB? - support for generation of dynamic libraries -- better code generator: skip ropes datastructure, it uses too much memory - make set optimizations part of the transformation (--> all backends profit from it), but this really needs a more abstract code generator @@ -60,11 +81,8 @@ For the next versions Further ideas/nice to have ========================== -- queues additional to streams: have to positions (read/write) instead of one +- queues additional to streams: have two positions (read/write) instead of one - introduce: refany type??? -- CLR code generator; better use XYZ? --> Version 1.2? -- provide an interactive shell: if the user wants his commands - to be executed, the command should end with # - implement packed arrays (bit arrays)/ packed records - implement tables (implement as library? - no! Builtin because of constructor syntax is nice to have) @@ -119,23 +137,6 @@ Version 2 -Library -------- - -- gui module -- finish json module: hard -- socket, http, ftp, email, fastcgi: implement from scratch -- ncurses bindings -- osproc for Windows -- bignums -- python -- TCL -- automate module: expect-like module for Nimrod -- parsecsv module - -- YAML module - - Low priority ------------ @@ -176,23 +177,25 @@ Low priority o.x = 13 # ambigious -- implement stack walking via assembler for horribly advanced optimizers -- use `` notation for identifier concatenation? +- use `` notation for identifier concatenation - Visual C++: emit ``default: __assume(0);`` for optimization - macros: ``typecheck`` pragma; this is really a good idea! This allows transformations based on types! - make callconv a set - partial generic instantation is missing -- get code generation for C++ exception handling right! - find a way for easy constructors and destructors; though constructors are flawed... destructors are not, however! - multiple dispatch: no, but provide a proc ``typeId`` to allow the user to implement it efficiently -- replace ropes with strings in the C code generator: This may yield a HUGE - speedup of the compiler! (10%) - code generated for type information is wasteful +RST +--- +- footnotes; prefix :i: whitespace before :i:, _reference, `reference`__ + __ anonymous: www.nimrod.org + + Changelog ========= @@ -542,4 +545,39 @@ Changelog - BUGFIX: iterators using open arrays - BUGFIX: [$anyEnum] +0.7.6: release +0.7.7: +- implemented the "parsecsv" module +- added ``math.TRunningStat`` object and its methods +- added ``strutils.validIdentifier`` +- reStructuredText parser: implemented ``.. container ::`` directive +- updated the website +- ``cgi.stackTraceNewLine`` functionality +- added ``cgi.decodeData`` +- BUGFIX: evaluation for ``mLengthSeq``, ``mLengthOpenArray``, + ``evalSetLengthSeq``, ``evalNewSeq`` +- ``copy`` and ``newString`` are magics now; thus several more things + can be evaluated +- ``evalAddr`` fixed +- BUGFIX: generics are now processed earlier in the pipeline; thus + generics can be used within macros +- new module ``xmlgen`` +- ``macros.error`` now prints a stack trace +- changed bootstrapping in ``koch.py`` and ``boot.nim`` to fix bug + #369607. +- implemented the new memory management; the GC does not take advantage of + it yet +- BUGFIX: magics don't imply ``lfNoDecl`` any longer +- BUGFIX: ``newString`` is not evaluated at compile-time anymore, unless + evaluation is requested +- the GC now relies on the new memory manager +- BUGFIX: check that "yield" is inside a loop! +- BUGFIX: ``isAllocatedPtr`` still had a small bug +- overflow checking for ``newSeq`` now works +- BUGFIX: ``commands.processSwitch`` no errors if an argument is given to a + switch that does not receive one + +0.7.8: release + + diff --git a/tools/niminst b/tools/niminst index a21ff14869fe05d3cfcfed5933326be44e5ea531..628e7632ad9393216e53da2337492c0011643b6b 100644 GIT binary patch literal 295608 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

GJituoa%oMi|@;~KMRZ_dY&c9l8;f6 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

PQZ$fF< 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

*|2o*THvzA8<{;`Tw2W;4`m9`y1GQ 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 z zx@wA57B0rC3K)f9iA!mgm?D)m7+>{8tySPzNI0geC!pVLF#C^KVPUw?qZDYf30G08 LyS~&YEbspZ@>zz} diff --git a/tools/nimweb.nim b/tools/nimweb.nim index 135be9570..63f13ea25 100644 --- a/tools/nimweb.nim +++ b/tools/nimweb.nim @@ -1,7 +1,7 @@ # # # The Nimrod Website Generator -# (c) Copyright 2008 Andreas Rumpf +# (c) Copyright 2009 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -15,7 +15,7 @@ type TConfigData = object of TObject tabs, links: seq[TKeyValPair] doc, srcdoc, webdoc: seq[string] - authors, projectName, projectTitle, infile, outdir, ticker: string + authors, projectName, projectTitle, logo, infile, outdir, ticker: string vars: PStringTable nimrodArgs: string @@ -29,6 +29,9 @@ proc initConfigData(c: var TConfigData) = c.outdir = "" c.nimrodArgs = "" c.authors = "" + c.projectTitle = "" + c.projectName = "" + c.logo = "" c.ticker = "" c.vars = newStringTable(modeStyleInsensitive) @@ -37,7 +40,7 @@ include "sunset.tmpl" # ------------------------- configuration file ------------------------------- const - Version = "0.5" + Version = "0.6" Usage = "nimweb - Nimrod Installation Generator Version " & version & """ (c) 2008 Andreas Rumpf @@ -119,6 +122,7 @@ proc parseIniFile(c: var TConfigData) = case normalize(k.key) of "name": c.projectName = v of "title": c.projectTitle = v + of "logo": c.logo = v of "authors": c.authors = v else: quit(errorStr(p, "unknown variable: " & k.key)) of "var": nil diff --git a/tools/sunset.tmpl b/tools/sunset.tmpl index e10f58eff..44f7ac486 100644 --- a/tools/sunset.tmpl +++ b/tools/sunset.tmpl @@ -14,7 +14,9 @@

- +