explicit types for generic routines

This commit is contained in:
Andreas Rumpf 2010-05-28 23:32:46 +02:00
commit 6c20509121
25 changed files with 411 additions and 343 deletions

View file

@ -114,6 +114,71 @@ Thus we need to serialize this graph as RTTI for C code generation.
Look at the file ``lib/system/hti.nim`` for more information. Look at the file ``lib/system/hti.nim`` for more information.
The compiler's architecture
===========================
Nimrod uses the classic compiler architecture: A scanner feds tokens to a
parser. The parser builds a syntax tree that is used by the code generator.
This syntax tree is the interface between the parser and the code generator.
It is essential to understand most of the compiler's code.
In order to compile Nimrod correctly, type-checking has to be seperated from
parsing. Otherwise generics cannot work.
.. include:: filelist.txt
The syntax tree
---------------
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. The `macros <macros.html>`_ module contains many
examples how the AST represents each syntactic structure.
How the RTL is compiled
=======================
The ``system`` module contains the part of the RTL which needs support by
compiler magic (and the stuff that needs to be in it because the spec
says so). The C code generator generates the C code for it just like any other
module. However, calls to some procedures like ``addInt`` are inserted by
the CCG. Therefore the module ``magicsys`` contains a table (``compilerprocs``)
with all symbols that are marked as ``compilerproc``. ``compilerprocs`` are
needed by the code generator. A ``magic`` proc is not the same as a
``compilerproc``: A ``magic`` is a proc that needs compiler magic for its
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
====================================
Generation of dynamic link libraries or shared libraries is not difficult; the
underlying C compiler already does all the hard work for us. The problem is the
common runtime library, especially the memory manager. Note that Borland's
Delphi had exactly the same problem. The workaround is to not link the GC with
the Dll and provide an extra runtime dll that needs to be initialized.
The Garbage Collector The Garbage Collector
===================== =====================
@ -216,71 +281,6 @@ the check whether the ref is on the stack is very cheap (only two
comparisons). comparisons).
The compiler's architecture
===========================
Nimrod uses the classic compiler architecture: A scanner feds tokens to a
parser. The parser builds a syntax tree that is used by the code generator.
This syntax tree is the interface between the parser and the code generator.
It is essential to understand most of the compiler's code.
In order to compile Nimrod correctly, type-checking has to be seperated from
parsing. Otherwise generics would not work.
.. include:: filelist.txt
The syntax tree
---------------
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. The `macros <macros.html>`_ module contains many
examples how the AST represents each syntactic structure.
How the RTL is compiled
=======================
The ``system`` module contains the part of the RTL which needs support by
compiler magic (and the stuff that needs to be in it because the spec
says so). The C code generator generates the C code for it just like any other
module. However, calls to some procedures like ``addInt`` are inserted by
the CCG. Therefore the module ``magicsys`` contains a table (``compilerprocs``)
with all symbols that are marked as ``compilerproc``. ``compilerprocs`` are
needed by the code generator. A ``magic`` proc is not the same as a
``compilerproc``: A ``magic`` is a proc that needs compiler magic for its
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
====================================
Generation of dynamic link libraries or shared libraries is not difficult; the
underlying C compiler already does all the hard work for us. The problem is the
common runtime library, especially the memory manager. Note that Borland's
Delphi had exactly the same problem. The workaround is to not link the GC with
the Dll and provide an extra runtime dll that needs to be initialized.
Code generation for closures Code generation for closures
============================ ============================

View file

@ -238,7 +238,7 @@ Database support
for other databases too. for other databases too.
* `db_sqlite <db_sqlite.html>`_ * `db_sqlite <db_sqlite.html>`_
A higher level mySQL database wrapper. The same interface is implemented A higher level SQLite database wrapper. The same interface is implemented
for other databases too. for other databases too.

View file

@ -276,10 +276,10 @@ Index
`ropes.html#115 <ropes.html#115>`_ `ropes.html#115 <ropes.html#115>`_
`[]`:idx: `[]`:idx:
`xmltree.html#114 <xmltree.html#114>`_ `graphics.html#111 <graphics.html#111>`_
`[]`:idx: `[]`:idx:
`graphics.html#111 <graphics.html#111>`_ `xmltree.html#114 <xmltree.html#114>`_
`[]=`:idx: `[]=`:idx:
`strtabs.html#106 <strtabs.html#106>`_ `strtabs.html#106 <strtabs.html#106>`_
@ -731,12 +731,6 @@ Index
`clonglong`:idx: `clonglong`:idx:
`system.html#388 <system.html#388>`_ `system.html#388 <system.html#388>`_
`Close`:idx:
* `system.html#512 <system.html#512>`_
* `db_postgres.html#117 <db_postgres.html#117>`_
* `db_mysql.html#117 <db_mysql.html#117>`_
* `db_sqlite.html#117 <db_sqlite.html#117>`_
`close`:idx: `close`:idx:
* `sockets.html#121 <sockets.html#121>`_ * `sockets.html#121 <sockets.html#121>`_
* `lexbase.html#105 <lexbase.html#105>`_ * `lexbase.html#105 <lexbase.html#105>`_
@ -746,8 +740,14 @@ Index
* `zipfiles.html#103 <zipfiles.html#103>`_ * `zipfiles.html#103 <zipfiles.html#103>`_
* `httpserver.html#106 <httpserver.html#106>`_ * `httpserver.html#106 <httpserver.html#106>`_
`Close`:idx:
* `system.html#513 <system.html#513>`_
* `db_postgres.html#117 <db_postgres.html#117>`_
* `db_mysql.html#117 <db_mysql.html#117>`_
* `db_sqlite.html#117 <db_sqlite.html#117>`_
`CloseFile`:idx: `CloseFile`:idx:
`system.html#511 <system.html#511>`_ `system.html#512 <system.html#512>`_
`closure`:idx: `closure`:idx:
`manual.html#177 <manual.html#177>`_ `manual.html#177 <manual.html#177>`_
@ -1350,8 +1350,8 @@ Index
`system.html#392 <system.html#392>`_ `system.html#392 <system.html#392>`_
`cstringArrayToSeq`:idx: `cstringArrayToSeq`:idx:
* `system.html#539 <system.html#539>`_
* `system.html#540 <system.html#540>`_ * `system.html#540 <system.html#540>`_
* `system.html#541 <system.html#541>`_
`CSV`:idx: `CSV`:idx:
`parsecsv.html#101 <parsecsv.html#101>`_ `parsecsv.html#101 <parsecsv.html#101>`_
@ -1777,8 +1777,7 @@ Index
* `strutils.html#157 <strutils.html#157>`_ * `strutils.html#157 <strutils.html#157>`_
`deleteStr`:idx: `deleteStr`:idx:
* `strutils.html#124 <strutils.html#124>`_ `strutils.html#124 <strutils.html#124>`_
* `strutils.html#158 <strutils.html#158>`_
`dfn`:idx: `dfn`:idx:
`xmlgen.html#125 <xmlgen.html#125>`_ `xmlgen.html#125 <xmlgen.html#125>`_
@ -1894,7 +1893,7 @@ Index
* `db_sqlite.html#104 <db_sqlite.html#104>`_ * `db_sqlite.html#104 <db_sqlite.html#104>`_
`editDistance`:idx: `editDistance`:idx:
`strutils.html#166 <strutils.html#166>`_ `strutils.html#165 <strutils.html#165>`_
`EDivByZero`:idx: `EDivByZero`:idx:
`system.html#147 <system.html#147>`_ `system.html#147 <system.html#147>`_
@ -2020,7 +2019,7 @@ Index
`endb.html#102 <endb.html#102>`_ `endb.html#102 <endb.html#102>`_
`EndOfFile`:idx: `EndOfFile`:idx:
* `system.html#513 <system.html#513>`_ * `system.html#514 <system.html#514>`_
* `lexbase.html#101 <lexbase.html#101>`_ * `lexbase.html#101 <lexbase.html#101>`_
`endsWith`:idx: `endsWith`:idx:
@ -2132,7 +2131,7 @@ Index
`escape`:idx: `escape`:idx:
* `manual.html#133 <manual.html#133>`_ * `manual.html#133 <manual.html#133>`_
* `strutils.html#163 <strutils.html#163>`_ * `strutils.html#162 <strutils.html#162>`_
* `xmltree.html#122 <xmltree.html#122>`_ * `xmltree.html#122 <xmltree.html#122>`_
`escape sequences`:idx: `escape sequences`:idx:
@ -2373,7 +2372,7 @@ Index
`mysql.html#218 <mysql.html#218>`_ `mysql.html#218 <mysql.html#218>`_
`fileHandle`:idx: `fileHandle`:idx:
`system.html#538 <system.html#538>`_ `system.html#539 <system.html#539>`_
`fileNewer`:idx: `fileNewer`:idx:
`os.html#119 <os.html#119>`_ `os.html#119 <os.html#119>`_
@ -2433,7 +2432,7 @@ Index
`macros.html#130 <macros.html#130>`_ `macros.html#130 <macros.html#130>`_
`FlushFile`:idx: `FlushFile`:idx:
`system.html#515 <system.html#515>`_ `system.html#516 <system.html#516>`_
`for`:idx: `for`:idx:
* `manual.html#214 <manual.html#214>`_ * `manual.html#214 <manual.html#214>`_
@ -2594,10 +2593,10 @@ Index
`os.html#162 <os.html#162>`_ `os.html#162 <os.html#162>`_
`getFilePos`:idx: `getFilePos`:idx:
`system.html#535 <system.html#535>`_ `system.html#536 <system.html#536>`_
`getFileSize`:idx: `getFileSize`:idx:
* `system.html#527 <system.html#527>`_ * `system.html#528 <system.html#528>`_
* `os.html#171 <os.html#171>`_ * `os.html#171 <os.html#171>`_
`getFreeMem`:idx: `getFreeMem`:idx:
@ -2866,13 +2865,13 @@ Index
`hr`:idx: `hr`:idx:
`xmlgen.html#140 <xmlgen.html#140>`_ `xmlgen.html#140 <xmlgen.html#140>`_
`html`:idx:
`xmlgen.html#139 <xmlgen.html#139>`_
`HTML`:idx: `HTML`:idx:
* `parsexml.html#102 <parsexml.html#102>`_ * `parsexml.html#102 <parsexml.html#102>`_
* `xmlgen.html#102 <xmlgen.html#102>`_ * `xmlgen.html#102 <xmlgen.html#102>`_
`html`:idx:
`xmlgen.html#139 <xmlgen.html#139>`_
`htmlTag`:idx: `htmlTag`:idx:
* `htmlparser.html#105 <htmlparser.html#105>`_ * `htmlparser.html#105 <htmlparser.html#105>`_
* `htmlparser.html#106 <htmlparser.html#106>`_ * `htmlparser.html#106 <htmlparser.html#106>`_
@ -2914,24 +2913,24 @@ Index
`ident=`:idx: `ident=`:idx:
`macros.html#132 <macros.html#132>`_ `macros.html#132 <macros.html#132>`_
`IdentChars`:idx:
`strutils.html#105 <strutils.html#105>`_
`identChars`:idx: `identChars`:idx:
`pegs.html#132 <pegs.html#132>`_ `pegs.html#132 <pegs.html#132>`_
`IdentChars`:idx:
`strutils.html#105 <strutils.html#105>`_
`identifier`:idx: `identifier`:idx:
`manual.html#105 <manual.html#105>`_ `manual.html#105 <manual.html#105>`_
`Identifiers`:idx: `Identifiers`:idx:
`manual.html#116 <manual.html#116>`_ `manual.html#116 <manual.html#116>`_
`IdentStartChars`:idx:
`strutils.html#106 <strutils.html#106>`_
`identStartChars`:idx: `identStartChars`:idx:
`pegs.html#133 <pegs.html#133>`_ `pegs.html#133 <pegs.html#133>`_
`IdentStartChars`:idx:
`strutils.html#106 <strutils.html#106>`_
`if`:idx: `if`:idx:
`manual.html#189 <manual.html#189>`_ `manual.html#189 <manual.html#189>`_
@ -3018,7 +3017,7 @@ Index
* `db_sqlite.html#115 <db_sqlite.html#115>`_ * `db_sqlite.html#115 <db_sqlite.html#115>`_
`insertSep`:idx: `insertSep`:idx:
`strutils.html#162 <strutils.html#162>`_ `strutils.html#161 <strutils.html#161>`_
`int`:idx: `int`:idx:
`system.html#101 <system.html#101>`_ `system.html#101 <system.html#101>`_
@ -3208,8 +3207,8 @@ Index
`nimrodc.html#103 <nimrodc.html#103>`_ `nimrodc.html#103 <nimrodc.html#103>`_
`lines`:idx: `lines`:idx:
* `system.html#536 <system.html#536>`_
* `system.html#537 <system.html#537>`_ * `system.html#537 <system.html#537>`_
* `system.html#538 <system.html#538>`_
`lineTrace`:idx: `lineTrace`:idx:
`nimrodc.html#105 <nimrodc.html#105>`_ `nimrodc.html#105 <nimrodc.html#105>`_
@ -3233,13 +3232,13 @@ Index
`LoadLib`:idx: `LoadLib`:idx:
`dynlib.html#102 <dynlib.html#102>`_ `dynlib.html#102 <dynlib.html#102>`_
`loadXML`:idx:
`xmldomparser.html#104 <xmldomparser.html#104>`_
`loadXml`:idx: `loadXml`:idx:
* `xmlparser.html#104 <xmlparser.html#104>`_ * `xmlparser.html#104 <xmlparser.html#104>`_
* `xmlparser.html#105 <xmlparser.html#105>`_ * `xmlparser.html#105 <xmlparser.html#105>`_
`loadXML`:idx:
`xmldomparser.html#104 <xmldomparser.html#104>`_
`loadXMLFile`:idx: `loadXMLFile`:idx:
`xmldomparser.html#105 <xmldomparser.html#105>`_ `xmldomparser.html#105 <xmldomparser.html#105>`_
@ -3965,12 +3964,12 @@ Index
`nan`:idx: `nan`:idx:
`system.html#441 <system.html#441>`_ `system.html#441 <system.html#441>`_
`natural`:idx:
`pegs.html#135 <pegs.html#135>`_
`Natural`:idx: `Natural`:idx:
`system.html#134 <system.html#134>`_ `system.html#134 <system.html#134>`_
`natural`:idx:
`pegs.html#135 <pegs.html#135>`_
`neginf`:idx: `neginf`:idx:
`system.html#440 <system.html#440>`_ `system.html#440 <system.html#440>`_
@ -4056,13 +4055,13 @@ Index
`newIntLitNode`:idx: `newIntLitNode`:idx:
`macros.html#142 <macros.html#142>`_ `macros.html#142 <macros.html#142>`_
`newLine`:idx:
`pegs.html#122 <pegs.html#122>`_
`newline`:idx: `newline`:idx:
* `manual.html#121 <manual.html#121>`_ * `manual.html#121 <manual.html#121>`_
* `pegs.html#121 <pegs.html#121>`_ * `pegs.html#121 <pegs.html#121>`_
`newLine`:idx:
`pegs.html#122 <pegs.html#122>`_
`NewLines`:idx: `NewLines`:idx:
`lexbase.html#102 <lexbase.html#102>`_ `lexbase.html#102 <lexbase.html#102>`_
@ -4246,12 +4245,12 @@ Index
`ord`:idx: `ord`:idx:
`system.html#182 <system.html#182>`_ `system.html#182 <system.html#182>`_
`ordinal`:idx:
`tut1.html#114 <tut1.html#114>`_
`Ordinal`:idx: `Ordinal`:idx:
`system.html#114 <system.html#114>`_ `system.html#114 <system.html#114>`_
`ordinal`:idx:
`tut1.html#114 <tut1.html#114>`_
`Ordinal types`:idx: `Ordinal types`:idx:
`manual.html#142 <manual.html#142>`_ `manual.html#142 <manual.html#142>`_
@ -4313,12 +4312,12 @@ Index
`parseColor`:idx: `parseColor`:idx:
`colors.html#249 <colors.html#249>`_ `colors.html#249 <colors.html#249>`_
`parseFloat`:idx:
`parseutils.html#111 <parseutils.html#111>`_
`ParseFloat`:idx: `ParseFloat`:idx:
`strutils.html#144 <strutils.html#144>`_ `strutils.html#144 <strutils.html#144>`_
`parseFloat`:idx:
`parseutils.html#111 <parseutils.html#111>`_
`parseHex`:idx: `parseHex`:idx:
`parseutils.html#101 <parseutils.html#101>`_ `parseutils.html#101 <parseutils.html#101>`_
@ -4332,17 +4331,17 @@ Index
`parseIdent`:idx: `parseIdent`:idx:
`parseutils.html#103 <parseutils.html#103>`_ `parseutils.html#103 <parseutils.html#103>`_
`ParseInt`:idx:
`strutils.html#142 <strutils.html#142>`_
`parseInt`:idx: `parseInt`:idx:
`parseutils.html#109 <parseutils.html#109>`_ `parseutils.html#109 <parseutils.html#109>`_
`ParseInt`:idx:
`strutils.html#142 <strutils.html#142>`_
`parseOct`:idx: `parseOct`:idx:
`parseutils.html#102 <parseutils.html#102>`_ `parseutils.html#102 <parseutils.html#102>`_
`ParseOctInt`:idx: `ParseOctInt`:idx:
`strutils.html#159 <strutils.html#159>`_ `strutils.html#158 <strutils.html#158>`_
`parsePeg`:idx: `parsePeg`:idx:
`pegs.html#154 <pegs.html#154>`_ `pegs.html#154 <pegs.html#154>`_
@ -4644,8 +4643,7 @@ Index
`httpclient.html#109 <httpclient.html#109>`_ `httpclient.html#109 <httpclient.html#109>`_
`PostgreSQL`:idx: `PostgreSQL`:idx:
* `db_postgres.html#101 <db_postgres.html#101>`_ `db_postgres.html#101 <db_postgres.html#101>`_
* `db_sqlite.html#101 <db_sqlite.html#101>`_
`pow`:idx: `pow`:idx:
`math.html#132 <math.html#132>`_ `math.html#132 <math.html#132>`_
@ -4878,23 +4876,23 @@ Index
`streams.html#106 <streams.html#106>`_ `streams.html#106 <streams.html#106>`_
`readBuffer`:idx: `readBuffer`:idx:
`system.html#530 <system.html#530>`_ `system.html#531 <system.html#531>`_
`ReadBytes`:idx: `ReadBytes`:idx:
`system.html#528 <system.html#528>`_ `system.html#529 <system.html#529>`_
`readChar`:idx: `readChar`:idx:
* `system.html#514 <system.html#514>`_ * `system.html#515 <system.html#515>`_
* `streams.html#105 <streams.html#105>`_ * `streams.html#105 <streams.html#105>`_
`ReadChars`:idx: `ReadChars`:idx:
`system.html#529 <system.html#529>`_ `system.html#530 <system.html#530>`_
`readData`:idx: `readData`:idx:
`cgi.html#109 <cgi.html#109>`_ `cgi.html#109 <cgi.html#109>`_
`readFile`:idx: `readFile`:idx:
`system.html#516 <system.html#516>`_ `system.html#517 <system.html#517>`_
`readFloat32`:idx: `readFloat32`:idx:
`streams.html#111 <streams.html#111>`_ `streams.html#111 <streams.html#111>`_
@ -4915,7 +4913,7 @@ Index
`streams.html#107 <streams.html#107>`_ `streams.html#107 <streams.html#107>`_
`readLine`:idx: `readLine`:idx:
* `system.html#524 <system.html#524>`_ * `system.html#525 <system.html#525>`_
* `streams.html#114 <streams.html#114>`_ * `streams.html#114 <streams.html#114>`_
`readRow`:idx: `readRow`:idx:
@ -5041,6 +5039,9 @@ Index
* `regexprs.html#117 <regexprs.html#117>`_ * `regexprs.html#117 <regexprs.html#117>`_
* `re.html#131 <re.html#131>`_ * `re.html#131 <re.html#131>`_
`reopen`:idx:
`system.html#511 <system.html#511>`_
`repeatChar`:idx: `repeatChar`:idx:
`strutils.html#147 <strutils.html#147>`_ `strutils.html#147 <strutils.html#147>`_
@ -5256,7 +5257,7 @@ Index
`os.html#163 <os.html#163>`_ `os.html#163 <os.html#163>`_
`setFilePos`:idx: `setFilePos`:idx:
`system.html#534 <system.html#534>`_ `system.html#535 <system.html#535>`_
`SET_FLAG`:idx: `SET_FLAG`:idx:
`mysql.html#135 <mysql.html#135>`_ `mysql.html#135 <mysql.html#135>`_
@ -5378,6 +5379,9 @@ Index
* `db_postgres.html#106 <db_postgres.html#106>`_ * `db_postgres.html#106 <db_postgres.html#106>`_
* `db_sqlite.html#106 <db_sqlite.html#106>`_ * `db_sqlite.html#106 <db_sqlite.html#106>`_
`SQLite`:idx:
`db_sqlite.html#101 <db_sqlite.html#101>`_
`sqlite3_aggregate_context`:idx: `sqlite3_aggregate_context`:idx:
`sqlite3.html#261 <sqlite3.html#261>`_ `sqlite3.html#261 <sqlite3.html#261>`_
@ -6401,7 +6405,7 @@ Index
`system.html#411 <system.html#411>`_ `system.html#411 <system.html#411>`_
`toBin`:idx: `toBin`:idx:
`strutils.html#161 <strutils.html#161>`_ `strutils.html#160 <strutils.html#160>`_
`TObject`:idx: `TObject`:idx:
`system.html#136 <system.html#136>`_ `system.html#136 <system.html#136>`_
@ -6421,7 +6425,7 @@ Index
* `unicode.html#111 <unicode.html#111>`_ * `unicode.html#111 <unicode.html#111>`_
`toOct`:idx: `toOct`:idx:
`strutils.html#160 <strutils.html#160>`_ `strutils.html#159 <strutils.html#159>`_
`toOctal`:idx: `toOctal`:idx:
`strutils.html#125 <strutils.html#125>`_ `strutils.html#125 <strutils.html#125>`_
@ -6722,10 +6726,10 @@ Index
`cgi.html#110 <cgi.html#110>`_ `cgi.html#110 <cgi.html#110>`_
`validEmailAddress`:idx: `validEmailAddress`:idx:
`strutils.html#164 <strutils.html#164>`_ `strutils.html#163 <strutils.html#163>`_
`validIdentifier`:idx: `validIdentifier`:idx:
`strutils.html#165 <strutils.html#165>`_ `strutils.html#164 <strutils.html#164>`_
`Var`:idx: `Var`:idx:
`manual.html#187 <manual.html#187>`_ `manual.html#187 <manual.html#187>`_
@ -6788,32 +6792,32 @@ Index
`times.html#118 <times.html#118>`_ `times.html#118 <times.html#118>`_
`write`:idx: `write`:idx:
* `system.html#517 <system.html#517>`_
* `system.html#518 <system.html#518>`_ * `system.html#518 <system.html#518>`_
* `system.html#519 <system.html#519>`_ * `system.html#519 <system.html#519>`_
* `system.html#520 <system.html#520>`_ * `system.html#520 <system.html#520>`_
* `system.html#521 <system.html#521>`_ * `system.html#521 <system.html#521>`_
* `system.html#522 <system.html#522>`_ * `system.html#522 <system.html#522>`_
* `system.html#523 <system.html#523>`_ * `system.html#523 <system.html#523>`_
* `system.html#524 <system.html#524>`_
* `streams.html#103 <streams.html#103>`_ * `streams.html#103 <streams.html#103>`_
* `streams.html#104 <streams.html#104>`_ * `streams.html#104 <streams.html#104>`_
* `ropes.html#118 <ropes.html#118>`_ * `ropes.html#118 <ropes.html#118>`_
`writeBuffer`:idx: `writeBuffer`:idx:
`system.html#533 <system.html#533>`_ `system.html#534 <system.html#534>`_
`writeBytes`:idx: `writeBytes`:idx:
`system.html#531 <system.html#531>`_ `system.html#532 <system.html#532>`_
`writeChars`:idx: `writeChars`:idx:
`system.html#532 <system.html#532>`_ `system.html#533 <system.html#533>`_
`writeContentType`:idx: `writeContentType`:idx:
`cgi.html#144 <cgi.html#144>`_ `cgi.html#144 <cgi.html#144>`_
`writeln`:idx: `writeln`:idx:
* `system.html#525 <system.html#525>`_
* `system.html#526 <system.html#526>`_ * `system.html#526 <system.html#526>`_
* `system.html#527 <system.html#527>`_
`WriteStyled`:idx: `WriteStyled`:idx:
`terminal.html#112 <terminal.html#112>`_ `terminal.html#112 <terminal.html#112>`_

View file

@ -3,7 +3,7 @@ import re
for x in lines("myfile.txt"): for x in lines("myfile.txt"):
if x =~ re"(\w+)=(.*)": if x =~ re"(\w+)=(.*)":
echo "Key: ", matches[1], echo "Key: ", matches[0],
" Value: ", matches[2] " Value: ", matches[1]

View file

@ -9,8 +9,7 @@
## This module implements portable dialogs for Nimrod; the implementation ## This module implements portable dialogs for Nimrod; the implementation
## builds on the GTK interface. On Windows, native dialogs are shown if ## builds on the GTK interface. On Windows, native dialogs are shown instead.
## appropriate.
import import
glib2, gtk2 glib2, gtk2
@ -174,7 +173,7 @@ proc ChooseFileToSave*(window: PWindow, root: string = ""): string =
var chooser = file_chooser_dialog_new("Save File", window, var chooser = file_chooser_dialog_new("Save File", window,
FILE_CHOOSER_ACTION_SAVE, FILE_CHOOSER_ACTION_SAVE,
STOCK_CANCEL, RESPONSE_CANCEL, STOCK_CANCEL, RESPONSE_CANCEL,
STOCK_OPEN, RESPONSE_OK, nil) STOCK_SAVE, RESPONSE_OK, nil)
if root.len > 0: if root.len > 0:
discard set_current_folder(chooser, root) discard set_current_folder(chooser, root)
set_do_overwrite_confirmation(chooser, true) set_do_overwrite_confirmation(chooser, true)

View file

@ -24,6 +24,13 @@ __TINYC__
#if !defined(__TINYC__) #if !defined(__TINYC__)
# include <math.h> # include <math.h>
#else
/*# define __GNUC__ 3
# define GCC_MAJOR 4
# define __GNUC_MINOR__ 4
# define __GNUC_PATCHLEVEL__ 5 */
# define __DECLSPEC_SUPPORTED 1
#endif #endif
/* calling convention mess ----------------------------------------------- */ /* calling convention mess ----------------------------------------------- */

View file

@ -953,8 +953,8 @@ proc parseCmdLine*(c: string): seq[string] =
## causing a literal double quotation mark (") to be placed in argv. ## causing a literal double quotation mark (") to be placed in argv.
## ##
## On Posix systems, it uses the following parsing rules: ## On Posix systems, it uses the following parsing rules:
## components are separated by ## Components are separated by whitespace unless the whitespace
## whitespace unless the whitespace occurs within ``"`` or ``'`` quotes. ## occurs within ``"`` or ``'`` quotes.
result = @[] result = @[]
var i = 0 var i = 0
var a = "" var a = ""
@ -963,6 +963,7 @@ proc parseCmdLine*(c: string): seq[string] =
while c[i] == ' ' or c[i] == '\t': inc(i) while c[i] == ' ' or c[i] == '\t': inc(i)
when defined(windows): when defined(windows):
# parse a single argument according to the above rules: # parse a single argument according to the above rules:
if c[i] == '\0': break
var inQuote = false var inQuote = false
while true: while true:
case c[i] case c[i]
@ -971,7 +972,7 @@ proc parseCmdLine*(c: string): seq[string] =
var j = i var j = i
while c[j] == '\\': inc(j) while c[j] == '\\': inc(j)
if c[j] == '"': if c[j] == '"':
for k in 0..(j-i) div 2: a.add('\\') for k in 1..(j-i) div 2: a.add('\\')
if (j-i) mod 2 == 0: if (j-i) mod 2 == 0:
i = j i = j
else: else:

View file

@ -26,6 +26,19 @@ type
when defined(posix): when defined(posix):
type type
TTime* = distinct int ## distinct type that represents a time TTime* = distinct int ## distinct type that represents a time
Ttimeval {.importc: "struct timeval", header: "<sys/select.h>",
final, pure.} = object ## struct timeval
tv_sec: int ## Seconds.
tv_usec: int ## Microseconds.
# we cannot import posix.nim here, because posix.nim depends on times.nim.
# Ok, we could, but I don't want circular dependencies.
# And gettimeofday() is not defined in the posix module anyway. Sigh.
proc posix_gettimeofday(tp: var Ttimeval, unused: pointer = nil) {.
importc: "gettimeofday", header: "<sys/time.h>".}
elif defined(windows): elif defined(windows):
when defined(vcc): when defined(vcc):
# newest version of Visual C++ defines time_t to be of 64 bits # newest version of Visual C++ defines time_t to be of 64 bits
@ -147,7 +160,7 @@ when not defined(ECMAScript):
PTimeInfo = ptr structTM PTimeInfo = ptr structTM
PTime = ptr TTime PTime = ptr TTime
TClock {.importc: "clock_t".} = range[low(int)..high(int)] TClock {.importc: "clock_t".} = distinct int #range[low(int)..high(int)]
proc localtime(timer: PTime): PTimeInfo {. proc localtime(timer: PTime): PTimeInfo {.
importc: "localtime", header: "<time.h>".} importc: "localtime", header: "<time.h>".}
@ -197,9 +210,17 @@ when not defined(ECMAScript):
return toBiggestInt(difftime(a, b)) return toBiggestInt(difftime(a, b))
proc getStartMilsecs(): int = proc getStartMilsecs(): int =
#echo "clocks per sec: ", clocksPerSec #echo "clocks per sec: ", clocksPerSec, "clock: ", int(clock())
#return clock() div (clocksPerSec div 1000) #return clock() div (clocksPerSec div 1000)
result = toInt(toFloat(clock()) / (toFloat(clocksPerSec) / 1000.0)) when defined(posix):
var a: Ttimeval
posix_gettimeofday(a)
result = a.tv_sec * 1000 + a.tv_usec
else:
result = int(clock()) div (clocksPerSec div 1000)
when false:
when defined(macosx):
result = toInt(toFloat(clock()) / (toFloat(clocksPerSec) / 1000.0))
proc getTime(): TTime = return timec(nil) proc getTime(): TTime = return timec(nil)
proc getLocalTime(t: TTime): TTimeInfo = proc getLocalTime(t: TTime): TTimeInfo =

View file

@ -1176,3 +1176,5 @@ proc cmpRunesIgnoreCase*(a, b: string): int =
if result != 0: return if result != 0: return
result = a.len - b.len result = a.len - b.len
proc substringAt*(s, sub: string, start: int): int =

View file

@ -981,6 +981,9 @@ when not defined(NimrodVM):
proc getCurrentExceptionMsg*(): string {.exportc.} proc getCurrentExceptionMsg*(): string {.exportc.}
## retrieves the error message that was attached to the current ## retrieves the error message that was attached to the current
## exception; if there is none, "" is returned. ## exception; if there is none, "" is returned.
proc getCurrentException*(): ref E_Base
## retrieves the current exception; if there is none, nil is returned.
# new constants: # new constants:
const const
@ -1390,6 +1393,13 @@ when not defined(EcmaScript) and not defined(NimrodVM):
## ##
## Default mode is readonly. Returns true iff the file could be opened. ## Default mode is readonly. Returns true iff the file could be opened.
proc reopen*(f: TFile, filename: string, mode: TFileMode = fmRead): bool
## reopens the file `f` with given `filename` and `mode`. This
## is often used to redirect the `stdin`, `stdout` or `stderr`
## file variables.
##
## Default mode is readonly. Returns true iff the file could be reopened.
proc CloseFile*(f: TFile) {.importc: "fclose", nodecl, deprecated.} proc CloseFile*(f: TFile) {.importc: "fclose", nodecl, deprecated.}
## Closes the file. ## Closes the file.
## **Deprecated since version 0.8.0**: Use `close` instead. ## **Deprecated since version 0.8.0**: Use `close` instead.
@ -1554,6 +1564,7 @@ when not defined(EcmaScript) and not defined(NimrodVM):
else: else:
result = n.sons[n.len] result = n.sons[n.len]
include "system/systhread"
include "system/mm" include "system/mm"
include "system/sysstr" include "system/sysstr"
include "system/assign" include "system/assign"
@ -1564,6 +1575,10 @@ when not defined(EcmaScript) and not defined(NimrodVM):
if excHandler == nil: return "" if excHandler == nil: return ""
return $excHandler.exc.msg return $excHandler.exc.msg
proc getCurrentException(): ref E_Base =
if excHandler != nil:
result = excHandler.exc
{.push stack_trace: off.} {.push stack_trace: off.}
when defined(endb): when defined(endb):
include "system/debugger" include "system/debugger"

View file

@ -376,10 +376,10 @@ proc freeBigChunk(a: var TAllocator, c: PBigChunk) =
proc splitChunk(a: var TAllocator, c: PBigChunk, size: int) = proc splitChunk(a: var TAllocator, c: PBigChunk, size: int) =
var rest = cast[PBigChunk](cast[TAddress](c) +% size) var rest = cast[PBigChunk](cast[TAddress](c) +% size)
if rest in a.freeChunksList: assert(rest notin a.freeChunksList)
c_fprintf(c_stdout, "to add: %p\n", rest) # c_fprintf(c_stdout, "to add: %p\n", rest)
writeFreeList(allocator) # writeFreeList(allocator)
assert false # assert false
rest.size = c.size - size rest.size = c.size - size
rest.used = false rest.used = false
rest.next = nil rest.next = nil

View file

@ -1,7 +1,7 @@
# #
# #
# Nimrod's Runtime Library # Nimrod's Runtime Library
# (c) Copyright 2009 Andreas Rumpf # (c) Copyright 2010 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -478,6 +478,10 @@ proc gcMark(p: pointer) {.inline.} =
cell.refcount = cell.refcount +% rcIncrement cell.refcount = cell.refcount +% rcIncrement
add(gch.decStack, cell) add(gch.decStack, cell)
proc markThreadStacks(gch: var TGcHeap) =
when isMultiThreaded:
nil
# ----------------- stack management -------------------------------------- # ----------------- stack management --------------------------------------
# inspired from Smart Eiffel # inspired from Smart Eiffel
@ -613,6 +617,7 @@ proc collectCT(gch: var TGcHeap) =
gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize()) gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize())
assert(gch.decStack.len == 0) assert(gch.decStack.len == 0)
markStackAndRegisters(gch) markStackAndRegisters(gch)
markThreadStacks(gch)
gch.stat.maxStackCells = max(gch.stat.maxStackCells, gch.decStack.len) gch.stat.maxStackCells = max(gch.stat.maxStackCells, gch.decStack.len)
inc(gch.stat.stackScans) inc(gch.stat.stackScans)
collectZCT(gch) collectZCT(gch)

View file

@ -27,6 +27,9 @@ proc strlen(c: cstring): int {.importc: "strlen", nodecl.}
proc setvbuf(stream: TFile, buf: pointer, typ, size: cint): cint {. proc setvbuf(stream: TFile, buf: pointer, typ, size: cint): cint {.
importc, nodecl.} importc, nodecl.}
proc freopen(path, mode: cstring, stream: TFile): TFile {.importc: "freopen",
nodecl.}
proc write(f: TFile, c: cstring) = fputs(c, f) proc write(f: TFile, c: cstring) = fputs(c, f)
var var
@ -112,9 +115,7 @@ const
proc Open(f: var TFile, filename: string, proc Open(f: var TFile, filename: string,
mode: TFileMode = fmRead, mode: TFileMode = fmRead,
bufSize: int = -1): Bool = bufSize: int = -1): Bool =
var var p: pointer = fopen(filename, FormatOpen[mode])
p: pointer
p = fopen(filename, FormatOpen[mode])
result = (p != nil) result = (p != nil)
f = cast[TFile](p) f = cast[TFile](p)
if bufSize > 0: if bufSize > 0:
@ -123,6 +124,10 @@ proc Open(f: var TFile, filename: string,
elif bufSize == 0: elif bufSize == 0:
discard setvbuf(f, nil, IONBF, 0) discard setvbuf(f, nil, IONBF, 0)
proc reopen(f: TFile, filename: string, mode: TFileMode = fmRead): bool =
var p: pointer = freopen(filename, FormatOpen[mode], f)
result = p != nil
proc fdopen(filehandle: TFileHandle, mode: cstring): TFile {. proc fdopen(filehandle: TFileHandle, mode: cstring): TFile {.
importc: pccHack & "fdopen", header: "<stdio.h>".} importc: pccHack & "fdopen", header: "<stdio.h>".}

View file

@ -278,7 +278,7 @@ elif defined(macosx):
LibName = "libSDL-1.2.0.dylib" LibName = "libSDL-1.2.0.dylib"
else: else:
const const
LibName = "libSDL.so" LibName = "libSDL.so(|.1|.0)"
const const
MAJOR_VERSION* = 1'i8 MAJOR_VERSION* = 1'i8
MINOR_VERSION* = 2'i8 MINOR_VERSION* = 2'i8

View file

@ -163,7 +163,7 @@ elif defined(macosx):
ttfLibName = "libSDL_ttf-2.0.0.dylib" ttfLibName = "libSDL_ttf-2.0.0.dylib"
else: else:
const const
ttfLibName = "libSDL_ttf.so" ttfLibName = "libSDL_ttf.so(|.1|.0)"
const const
MAJOR_VERSION* = 2'i8 MAJOR_VERSION* = 2'i8
MINOR_VERSION* = 0'i8 MINOR_VERSION* = 0'i8

View file

@ -417,23 +417,20 @@ proc renderRstToRst(d: PDoc, n: PRstNode): PRope =
# debugging, but most code is already debugged... # debugging, but most code is already debugged...
const const
lvlToChar: array[0..8, char] = ['!', '=', '-', '~', '`', '<', '*', '|', '+'] lvlToChar: array[0..8, char] = ['!', '=', '-', '~', '`', '<', '*', '|', '+']
var
L: int
ind: PRope
result = nil result = nil
if n == nil: return if n == nil: return
ind = toRope(repeatChar(d.indent)) var ind = toRope(repeatChar(d.indent))
case n.kind case n.kind
of rnInner: of rnInner:
result = renderRstSons(d, n) result = renderRstSons(d, n)
of rnHeadline: of rnHeadline:
result = renderRstSons(d, n) result = renderRstSons(d, n)
L = ropeLen(result) var L = ropeLen(result)
result = ropef("$n$1$2$n$1$3", result = ropef("$n$1$2$n$1$3",
[ind, result, toRope(repeatChar(L, lvlToChar[n.level]))]) [ind, result, toRope(repeatChar(L, lvlToChar[n.level]))])
of rnOverline: of rnOverline:
result = renderRstSons(d, n) result = renderRstSons(d, n)
L = ropeLen(result) var L = ropeLen(result)
result = ropef("$n$1$3$n$1$2$n$1$3", result = ropef("$n$1$3$n$1$2$n$1$3",
[ind, result, toRope(repeatChar(L, lvlToChar[n.level]))]) [ind, result, toRope(repeatChar(L, lvlToChar[n.level]))])
of rnTransition: of rnTransition:
@ -464,7 +461,7 @@ proc renderRstToRst(d: PDoc, n: PRstNode): PRope =
dec(d.indent, 2) dec(d.indent, 2)
of rnField: of rnField:
result = renderRstToRst(d, n.sons[0]) result = renderRstToRst(d, n.sons[0])
L = max(ropeLen(result) + 3, 30) var L = max(ropeLen(result) + 3, 30)
inc(d.indent, L) inc(d.indent, L)
result = ropef("$n$1:$2:$3$4", [ind, result, toRope( result = ropef("$n$1:$2:$3$4", [ind, result, toRope(
repeatChar(L - ropeLen(result) - 2)), renderRstToRst(d, n.sons[1])]) repeatChar(L - ropeLen(result) - 2)), renderRstToRst(d, n.sons[1])])

View file

@ -714,8 +714,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
var a = result var a = result
result = newNodeIT(nkIntLit, n.info, n.typ) result = newNodeIT(nkIntLit, n.info, n.typ)
case a.kind case a.kind
of nkEmpty..nkNilLit: of nkEmpty..nkNilLit: nil
nil
else: result.intVal = sonsLen(a) else: result.intVal = sonsLen(a)
of mNChild: of mNChild:
result = evalAux(c, n.sons[1], {efLValue}) result = evalAux(c, n.sons[1], {efLValue})

View file

@ -1022,8 +1022,6 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
var s = qualifiedLookup(c, n.sons[0], false) var s = qualifiedLookup(c, n.sons[0], false)
if s != nil and s.kind in {skProc, skMethod, skConverter, skIterator}: if s != nil and s.kind in {skProc, skMethod, skConverter, skIterator}:
# type parameters: partial generic specialization # type parameters: partial generic specialization
# XXX: too implement!
internalError(n.info, "explicit generic instantation not implemented")
result = partialSpecialization(c, n, s) result = partialSpecialization(c, n, s)
else: else:
result = semArrayAccess(c, n, flags) result = semArrayAccess(c, n, flags)

View file

@ -1,29 +1,28 @@
# #
# #
# The Nimrod Compiler # The Nimrod Compiler
# (c) Copyright 2009 Andreas Rumpf # (c) Copyright 2010 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
# This module does the instantiation of generic procs and types. # This module does the instantiation of generic procs and types.
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, info: TLineInfo): PSym proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
info: TLineInfo): PSym
# generates an instantiated proc # generates an instantiated proc
proc searchInstTypes(tab: TIdTable, key: PType): PType = proc searchInstTypes(tab: TIdTable, key: PType): PType =
var
t: PType
match: bool
# returns nil if we need to declare this type # returns nil if we need to declare this type
result = PType(IdTableGet(tab, key)) result = PType(IdTableGet(tab, key))
if (result == nil) and (tab.counter > 0): if (result == nil) and (tab.counter > 0):
# we have to do a slow linear search because types may need # we have to do a slow linear search because types may need
# to be compared by their structure: # to be compared by their structure:
for h in countup(0, high(tab.data)): for h in countup(0, high(tab.data)):
t = PType(tab.data[h].key) var t = PType(tab.data[h].key)
if t != nil: if t != nil:
if key.containerId == t.containerID: if key.containerId == t.containerID:
match = true var match = true
for j in countup(0, sonsLen(t) - 1): for j in countup(0, sonsLen(t) - 1):
# XXX sameType is not really correct for nested generics? # XXX sameType is not really correct for nested generics?
if not sameType(t.sons[j], key.sons[j]): if not sameType(t.sons[j], key.sons[j]):
@ -39,20 +38,16 @@ proc containsGenericType(t: PType): bool =
result = iterOverType(t, containsGenericTypeIter, nil) result = iterOverType(t, containsGenericTypeIter, nil)
proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable) = proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable) =
var
s, q: PSym
t: PType
a: PNode
if (n.kind != nkGenericParams): if (n.kind != nkGenericParams):
InternalError(n.info, "instantiateGenericParamList; no generic params") InternalError(n.info, "instantiateGenericParamList; no generic params")
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
a = n.sons[i] var a = n.sons[i]
if a.kind != nkSym: if a.kind != nkSym:
InternalError(a.info, "instantiateGenericParamList; no symbol") InternalError(a.info, "instantiateGenericParamList; no symbol")
q = a.sym var q = a.sym
if not (q.typ.kind in {tyTypeDesc, tyGenericParam}): continue if not (q.typ.kind in {tyTypeDesc, tyGenericParam}): continue
s = newSym(skType, q.name, getCurrOwner()) var s = newSym(skType, q.name, getCurrOwner())
t = PType(IdTableGet(pt, q.typ)) var t = PType(IdTableGet(pt, q.typ))
if t == nil: liMessage(a.info, errCannotInstantiateX, s.name.s) if t == nil: liMessage(a.info, errCannotInstantiateX, s.name.s)
if (t.kind == tyGenericParam): if (t.kind == tyGenericParam):
InternalError(a.info, "instantiateGenericParamList: " & q.name.s) InternalError(a.info, "instantiateGenericParamList: " & q.name.s)
@ -60,27 +55,26 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable) =
addDecl(c, s) addDecl(c, s)
proc GenericCacheGet(c: PContext, genericSym, instSym: PSym): PSym = proc GenericCacheGet(c: PContext, genericSym, instSym: PSym): PSym =
var a, b: PSym
result = nil result = nil
for i in countup(0, sonsLen(c.generics) - 1): for i in countup(0, sonsLen(c.generics) - 1):
if c.generics.sons[i].kind != nkExprEqExpr: if c.generics.sons[i].kind != nkExprEqExpr:
InternalError(genericSym.info, "GenericCacheGet") InternalError(genericSym.info, "GenericCacheGet")
a = c.generics.sons[i].sons[0].sym var a = c.generics.sons[i].sons[0].sym
if genericSym.id == a.id: if genericSym.id == a.id:
b = c.generics.sons[i].sons[1].sym var b = c.generics.sons[i].sons[1].sym
if equalParams(b.typ.n, instSym.typ.n) == paramsEqual: if equalParams(b.typ.n, instSym.typ.n) == paramsEqual:
#if gVerbosity > 0 then #if gVerbosity > 0 then
# MessageOut('found in cache: ' + getProcHeader(instSym)); # MessageOut('found in cache: ' + getProcHeader(instSym));
return b return b
proc GenericCacheAdd(c: PContext, genericSym, instSym: PSym) = proc GenericCacheAdd(c: PContext, genericSym, instSym: PSym) =
var n: PNode var n = newNode(nkExprEqExpr)
n = newNode(nkExprEqExpr)
addSon(n, newSymNode(genericSym)) addSon(n, newSymNode(genericSym))
addSon(n, newSymNode(instSym)) addSon(n, newSymNode(instSym))
addSon(c.generics, n) addSon(c.generics, n)
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, info: TLineInfo): PSym = proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
info: TLineInfo): PSym =
# generates an instantiated proc # generates an instantiated proc
var var
oldPrc, oldMod: PSym oldPrc, oldMod: PSym
@ -89,8 +83,8 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, info: TLineInfo): PSy
if c.InstCounter > 1000: InternalError(fn.ast.info, "nesting too deep") if c.InstCounter > 1000: InternalError(fn.ast.info, "nesting too deep")
inc(c.InstCounter) inc(c.InstCounter)
oldP = c.p # restore later oldP = c.p # restore later
# NOTE: for access of private fields within generics from a different module # NOTE: for access of private fields within generics from a different module
# and other identifiers we fake the current module temporarily! # and other identifiers we fake the current module temporarily!
oldMod = c.module oldMod = c.module
c.module = getModule(fn) c.module = getModule(fn)
result = copySym(fn, false) result = copySym(fn, false)
@ -151,8 +145,6 @@ type
proc ReplaceTypeVarsT(cl: var TReplTypeVars, t: PType): PType proc ReplaceTypeVarsT(cl: var TReplTypeVars, t: PType): PType
proc ReplaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym proc ReplaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
proc ReplaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode = proc ReplaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
var length: int
result = nil
if n != nil: if n != nil:
result = copyNode(n) result = copyNode(n)
result.typ = ReplaceTypeVarsT(cl, n.typ) result.typ = ReplaceTypeVarsT(cl, n.typ)
@ -162,7 +154,7 @@ proc ReplaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
of nkSym: of nkSym:
result.sym = ReplaceTypeVarsS(cl, n.sym) result.sym = ReplaceTypeVarsS(cl, n.sym)
else: else:
length = sonsLen(n) var length = sonsLen(n)
if length > 0: if length > 0:
newSons(result, length) newSons(result, length)
for i in countup(0, length - 1): for i in countup(0, length - 1):
@ -172,7 +164,7 @@ proc ReplaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
if s == nil: if s == nil:
return nil return nil
result = PSym(idTableGet(cl.symMap, s)) result = PSym(idTableGet(cl.symMap, s))
if (result == nil): if result == nil:
result = copySym(s, false) result = copySym(s, false)
incl(result.flags, sfFromGeneric) incl(result.flags, sfFromGeneric)
idTablePut(cl.symMap, s, result) idTablePut(cl.symMap, s, result)
@ -229,8 +221,9 @@ proc ReplaceTypeVarsT(cl: var TReplTypeVars, t: PType): PType =
result.sons[i] = ReplaceTypeVarsT(cl, result.sons[i]) result.sons[i] = ReplaceTypeVarsT(cl, result.sons[i])
result.n = ReplaceTypeVarsN(cl, result.n) result.n = ReplaceTypeVarsN(cl, result.n)
if result.Kind in GenericTypes: if result.Kind in GenericTypes:
liMessage(cl.info, errCannotInstantiateX, TypeToString(t, preferName)) #writeln(output, ropeToStr(Typetoyaml(result))); liMessage(cl.info, errCannotInstantiateX, TypeToString(t, preferName))
#checkConstructedType(cl.info, result); #writeln(output, ropeToStr(Typetoyaml(result)))
#checkConstructedType(cl.info, result)
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType = proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
var cl: TReplTypeVars var cl: TReplTypeVars
@ -240,7 +233,8 @@ proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
cl.c = c cl.c = c
result = ReplaceTypeVarsT(cl, header) result = ReplaceTypeVarsT(cl, header)
proc generateTypeInstance(p: PContext, pt: TIdTable, arg: PNode, t: PType): PType = proc generateTypeInstance(p: PContext, pt: TIdTable, arg: PNode,
t: PType): PType =
var cl: TReplTypeVars var cl: TReplTypeVars
InitIdTable(cl.symMap) InitIdTable(cl.symMap)
copyIdTable(cl.typeMap, pt) copyIdTable(cl.typeMap, pt)
@ -251,4 +245,9 @@ proc generateTypeInstance(p: PContext, pt: TIdTable, arg: PNode, t: PType): PTyp
popInfoContext() popInfoContext()
proc partialSpecialization(c: PContext, n: PNode, s: PSym): PNode = proc partialSpecialization(c: PContext, n: PNode, s: PSym): PNode =
for i in 1..sonsLen(n)-1:
n.sons[i].typ = semTypeNode(c, n.sons[i], nil)
# we cannot check for the proper number of type parameters because in
# `f[a,b](x, y)` `f` is not resolved yet properly.
# XXX: BUG this should be checked somehow!
result = n result = n

View file

@ -6,6 +6,7 @@
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
# this module does the semantic checking of statements # this module does the semantic checking of statements
proc semExprNoType(c: PContext, n: PNode): PNode = proc semExprNoType(c: PContext, n: PNode): PNode =
@ -267,14 +268,13 @@ proc SemReturn(c: PContext, n: PNode): PNode =
liMessage(n.info, errCannotReturnExpr) liMessage(n.info, errCannotReturnExpr)
proc SemYield(c: PContext, n: PNode): PNode = proc SemYield(c: PContext, n: PNode): PNode =
var restype: PType
result = n result = n
checkSonsLen(n, 1) checkSonsLen(n, 1)
if (c.p.owner == nil) or (c.p.owner.kind != skIterator): if (c.p.owner == nil) or (c.p.owner.kind != skIterator):
liMessage(n.info, errYieldNotAllowedHere) liMessage(n.info, errYieldNotAllowedHere)
if (n.sons[0] != nil): if (n.sons[0] != nil):
n.sons[0] = SemExprWithType(c, n.sons[0]) # check for type compatibility: n.sons[0] = SemExprWithType(c, n.sons[0]) # check for type compatibility:
restype = c.p.owner.typ.sons[0] var restype = c.p.owner.typ.sons[0]
if (restype != nil): if (restype != nil):
n.sons[0] = fitNode(c, restype, n.sons[0]) n.sons[0] = fitNode(c, restype, n.sons[0])
if (n.sons[0].typ == nil): InternalError(n.info, "semYield") if (n.sons[0].typ == nil): InternalError(n.info, "semYield")
@ -477,6 +477,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
s = newSymS(skType, a.sons[j], c) s = newSymS(skType, a.sons[j], c)
s.typ = newTypeS(tyGenericParam, c) s.typ = newTypeS(tyGenericParam, c)
else: else:
# not a type param, but an expression
s = newSymS(skGenericParam, a.sons[j], c) s = newSymS(skGenericParam, a.sons[j], c)
s.typ = typ s.typ = typ
s.ast = def s.ast = def

View file

@ -6,6 +6,7 @@
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
# this module does the semantic checking of type declarations # this module does the semantic checking of type declarations
proc fitNode(c: PContext, formal: PType, arg: PNode): PNode = proc fitNode(c: PContext, formal: PType, arg: PNode): PNode =
@ -63,10 +64,9 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
inc(counter) inc(counter)
proc semSet(c: PContext, n: PNode, prev: PType): PType = proc semSet(c: PContext, n: PNode, prev: PType): PType =
var base: PType
result = newOrPrevType(tySet, prev, c) result = newOrPrevType(tySet, prev, c)
if sonsLen(n) == 2: if sonsLen(n) == 2:
base = semTypeNode(c, n.sons[1], nil) var base = semTypeNode(c, n.sons[1], nil)
addSon(result, base) addSon(result, base)
if base.kind == tyGenericInst: base = lastSon(base) if base.kind == tyGenericInst: base = lastSon(base)
if base.kind != tyGenericParam: if base.kind != tyGenericParam:
@ -77,29 +77,26 @@ proc semSet(c: PContext, n: PNode, prev: PType): PType =
proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string, proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string,
prev: PType): PType = prev: PType): PType =
var base: PType
result = newOrPrevType(kind, prev, c) result = newOrPrevType(kind, prev, c)
if sonsLen(n) == 2: if sonsLen(n) == 2:
base = semTypeNode(c, n.sons[1], nil) var base = semTypeNode(c, n.sons[1], nil)
addSon(result, base) addSon(result, base)
else: else:
liMessage(n.info, errXExpectsOneTypeParam, kindStr) liMessage(n.info, errXExpectsOneTypeParam, kindStr)
proc semAnyRef(c: PContext, n: PNode, kind: TTypeKind, kindStr: string, proc semAnyRef(c: PContext, n: PNode, kind: TTypeKind, kindStr: string,
prev: PType): PType = prev: PType): PType =
var base: PType
result = newOrPrevType(kind, prev, c) result = newOrPrevType(kind, prev, c)
if sonsLen(n) == 1: if sonsLen(n) == 1:
base = semTypeNode(c, n.sons[0], nil) var base = semTypeNode(c, n.sons[0], nil)
addSon(result, base) addSon(result, base)
else: else:
liMessage(n.info, errXExpectsOneTypeParam, kindStr) liMessage(n.info, errXExpectsOneTypeParam, kindStr)
proc semVarType(c: PContext, n: PNode, prev: PType): PType = proc semVarType(c: PContext, n: PNode, prev: PType): PType =
var base: PType
result = newOrPrevType(tyVar, prev, c) result = newOrPrevType(tyVar, prev, c)
if sonsLen(n) == 1: if sonsLen(n) == 1:
base = semTypeNode(c, n.sons[0], nil) var base = semTypeNode(c, n.sons[0], nil)
if base.kind == tyVar: liMessage(n.info, errVarVarTypeNotAllowed) if base.kind == tyVar: liMessage(n.info, errVarVarTypeNotAllowed)
addSon(result, base) addSon(result, base)
else: else:
@ -111,15 +108,14 @@ proc semDistinct(c: PContext, n: PNode, prev: PType): PType =
else: liMessage(n.info, errXExpectsOneTypeParam, "distinct") else: liMessage(n.info, errXExpectsOneTypeParam, "distinct")
proc semRangeAux(c: PContext, n: PNode, prev: PType): PType = proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
var a, b: PNode
if (n.kind != nkRange): InternalError(n.info, "semRangeAux") if (n.kind != nkRange): InternalError(n.info, "semRangeAux")
checkSonsLen(n, 2) checkSonsLen(n, 2)
result = newOrPrevType(tyRange, prev, c) result = newOrPrevType(tyRange, prev, c)
result.n = newNodeI(nkRange, n.info) result.n = newNodeI(nkRange, n.info)
if (n.sons[0] == nil) or (n.sons[1] == nil): if (n.sons[0] == nil) or (n.sons[1] == nil):
liMessage(n.Info, errRangeIsEmpty) liMessage(n.Info, errRangeIsEmpty)
a = semConstExpr(c, n.sons[0]) var a = semConstExpr(c, n.sons[0])
b = semConstExpr(c, n.sons[1]) var b = semConstExpr(c, n.sons[1])
if not sameType(a.typ, b.typ): liMessage(n.info, errPureTypeMismatch) if not sameType(a.typ, b.typ): liMessage(n.info, errPureTypeMismatch)
if not (a.typ.kind in if not (a.typ.kind in
{tyInt..tyInt64, tyEnum, tyBool, tyChar, tyFloat..tyFloat128}): {tyInt..tyInt64, tyEnum, tyBool, tyChar, tyFloat..tyFloat128}):
@ -159,10 +155,9 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
liMessage(n.info, errArrayExpectsTwoTypeParams) liMessage(n.info, errArrayExpectsTwoTypeParams)
proc semOrdinal(c: PContext, n: PNode, prev: PType): PType = proc semOrdinal(c: PContext, n: PNode, prev: PType): PType =
var base: PType
result = newOrPrevType(tyOrdinal, prev, c) result = newOrPrevType(tyOrdinal, prev, c)
if sonsLen(n) == 2: if sonsLen(n) == 2:
base = semTypeNode(c, n.sons[1], nil) var base = semTypeNode(c, n.sons[1], nil)
if base.kind != tyGenericParam: if base.kind != tyGenericParam:
if not isOrdinalType(base): if not isOrdinalType(base):
liMessage(n.sons[1].info, errOrdinalTypeExpected) liMessage(n.sons[1].info, errOrdinalTypeExpected)
@ -231,7 +226,7 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags): PSym = allowed: TSymFlags): PSym =
# identifier with visibility # identifier with visibility
if n.kind == nkPostfix: if n.kind == nkPostfix:
if (sonsLen(n) == 2) and (n.sons[0].kind == nkIdent): if sonsLen(n) == 2 and n.sons[0].kind == nkIdent:
result = newSymS(kind, n.sons[1], c) result = newSymS(kind, n.sons[1], c)
var v = n.sons[0].ident var v = n.sons[0].ident
if (sfStar in allowed) and (v.id == ord(wStar)): if (sfStar in allowed) and (v.id == ord(wStar)):
@ -426,7 +421,7 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
base: PType base: PType
pos: int pos: int
IntSetInit(check) IntSetInit(check)
pos = 0 # n.sons[0] contains the pragmas (if any). We process these later... pos = 0 # n.sons[0] contains the pragmas (if any). We process these later...
checkSonsLen(n, 3) checkSonsLen(n, 3)
if n.sons[1] != nil: if n.sons[1] != nil:
base = semTypeNode(c, n.sons[1].sons[0], nil) base = semTypeNode(c, n.sons[1].sons[0], nil)
@ -444,28 +439,30 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
proc addTypeVarsOfGenericBody(c: PContext, t: PType, genericParams: PNode, proc addTypeVarsOfGenericBody(c: PContext, t: PType, genericParams: PNode,
cl: var TIntSet): PType = cl: var TIntSet): PType =
var
L: int
s: PSym
result = t result = t
if (t == nil): return if t == nil: return
if IntSetContainsOrIncl(cl, t.id): return if IntSetContainsOrIncl(cl, t.id): return
case t.kind case t.kind
of tyGenericBody: of tyGenericBody:
#debug(t)
result = newTypeS(tyGenericInvokation, c) result = newTypeS(tyGenericInvokation, c)
addSon(result, t) addSon(result, t)
for i in countup(0, sonsLen(t) - 2): for i in countup(0, sonsLen(t) - 2):
if t.sons[i].kind != tyGenericParam: if t.sons[i].kind != tyGenericParam:
InternalError("addTypeVarsOfGenericBody") InternalError("addTypeVarsOfGenericBody")
s = copySym(t.sons[i].sym) # do not declare ``TKey`` twice:
#if not IntSetContainsOrIncl(cl, t.sons[i].sym.ident.id):
var s = copySym(t.sons[i].sym)
s.position = sonsLen(genericParams) s.position = sonsLen(genericParams)
addDecl(c, s) addDecl(c, s)
addSon(genericParams, newSymNode(s)) addSon(genericParams, newSymNode(s))
addSon(result, t.sons[i]) addSon(result, t.sons[i])
of tyGenericInst: of tyGenericInst:
L = sonsLen(t) - 1 #debug(t)
var L = sonsLen(t) - 1
t.sons[L] = addTypeVarsOfGenericBody(c, t.sons[L], genericParams, cl) t.sons[L] = addTypeVarsOfGenericBody(c, t.sons[L], genericParams, cl)
of tyGenericInvokation: of tyGenericInvokation:
#debug(t)
for i in countup(1, sonsLen(t) - 1): for i in countup(1, sonsLen(t) - 1):
t.sons[i] = addTypeVarsOfGenericBody(c, t.sons[i], genericParams, cl) t.sons[i] = addTypeVarsOfGenericBody(c, t.sons[i], genericParams, cl)
else: else:
@ -476,13 +473,12 @@ proc paramType(c: PContext, n, genericParams: PNode, cl: var TIntSet): PType =
result = semTypeNode(c, n, nil) result = semTypeNode(c, n, nil)
if (genericParams != nil) and (sonsLen(genericParams) == 0): if (genericParams != nil) and (sonsLen(genericParams) == 0):
result = addTypeVarsOfGenericBody(c, result, genericParams, cl) result = addTypeVarsOfGenericBody(c, result, genericParams, cl)
#if result.kind == tyGenericInvokation: debug(result)
proc semProcTypeNode(c: PContext, n, genericParams: PNode, prev: PType): PType = proc semProcTypeNode(c: PContext, n, genericParams: PNode, prev: PType): PType =
var var
length, counter: int def, res: PNode
a, def, res: PNode
typ: PType typ: PType
arg: PSym
check, cl: TIntSet check, cl: TIntSet
checkMinSonsLen(n, 1) checkMinSonsLen(n, 1)
result = newOrPrevType(tyProc, prev, c) result = newOrPrevType(tyProc, prev, c)
@ -491,27 +487,29 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, prev: PType): PType =
if (genericParams != nil) and (sonsLen(genericParams) == 0): IntSetInit(cl) if (genericParams != nil) and (sonsLen(genericParams) == 0): IntSetInit(cl)
if n.sons[0] == nil: if n.sons[0] == nil:
addSon(result, nil) # return type addSon(result, nil) # return type
addSon(result.n, newNodeI(nkType, n.info)) # BUGFIX: nkType must exist! addSon(result.n, newNodeI(nkType, n.info))
# XXX but it does not, if n.sons[paramsPos] == nil? # BUGFIX: nkType must exist!
# XXX but it does not, if n.sons[paramsPos] == nil?
else: else:
addSon(result, nil) addSon(result, nil)
res = newNodeI(nkType, n.info) res = newNodeI(nkType, n.info)
addSon(result.n, res) addSon(result.n, res)
IntSetInit(check) IntSetInit(check)
counter = 0 var counter = 0
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
a = n.sons[i] var a = n.sons[i]
if (a.kind != nkIdentDefs): IllFormedAst(a) if a.kind != nkIdentDefs: IllFormedAst(a)
checkMinSonsLen(a, 3) checkMinSonsLen(a, 3)
length = sonsLen(a) var length = sonsLen(a)
if a.sons[length - 2] != nil: if a.sons[length - 2] != nil:
typ = paramType(c, a.sons[length - 2], genericParams, cl) typ = paramType(c, a.sons[length - 2], genericParams, cl)
else: else:
typ = nil typ = nil
if a.sons[length - 1] != nil: if a.sons[length - 1] != nil:
def = semExprWithType(c, a.sons[length - 1]) # check type compability between def.typ and typ: def = semExprWithType(c, a.sons[length - 1])
if (typ != nil): # check type compability between def.typ and typ:
if (cmpTypes(typ, def.typ) < isConvertible): if typ != nil:
if cmpTypes(typ, def.typ) < isConvertible:
typeMismatch(a.sons[length - 1], typ, def.typ) typeMismatch(a.sons[length - 1], typ, def.typ)
def = fitNode(c, typ, def) def = fitNode(c, typ, def)
else: else:
@ -519,7 +517,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, prev: PType): PType =
else: else:
def = nil def = nil
for j in countup(0, length - 3): for j in countup(0, length - 3):
arg = newSymS(skParam, a.sons[j], c) var arg = newSymS(skParam, a.sons[j], c)
arg.typ = typ arg.typ = typ
arg.position = counter arg.position = counter
inc(counter) inc(counter)
@ -600,21 +598,16 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
markUsed(n, n.sym) markUsed(n, n.sym)
else: else:
liMessage(n.info, errTypeExpected) liMessage(n.info, errTypeExpected)
of nkObjectTy: of nkObjectTy: result = semObjectNode(c, n, prev)
result = semObjectNode(c, n, prev) of nkTupleTy: result = semTuple(c, n, prev)
of nkTupleTy: of nkRefTy: result = semAnyRef(c, n, tyRef, "ref", prev)
result = semTuple(c, n, prev) of nkPtrTy: result = semAnyRef(c, n, tyPtr, "ptr", prev)
of nkRefTy: of nkVarTy: result = semVarType(c, n, prev)
result = semAnyRef(c, n, tyRef, "ref", prev) of nkDistinctTy: result = semDistinct(c, n, prev)
of nkPtrTy:
result = semAnyRef(c, n, tyPtr, "ptr", prev)
of nkVarTy:
result = semVarType(c, n, prev)
of nkDistinctTy:
result = semDistinct(c, n, prev)
of nkProcTy: of nkProcTy:
checkSonsLen(n, 2) checkSonsLen(n, 2)
result = semProcTypeNode(c, n.sons[0], nil, prev) # dummy symbol for `pragma`: result = semProcTypeNode(c, n.sons[0], nil, prev)
# dummy symbol for `pragma`:
s = newSymS(skProc, newIdentNode(getIdent("dummy"), n.info), c) s = newSymS(skProc, newIdentNode(getIdent("dummy"), n.info), c)
s.typ = result s.typ = result
pragma(c, s, n.sons[1], procTypePragmas) pragma(c, s, n.sons[1], procTypePragmas)
@ -636,49 +629,33 @@ proc setMagicType(m: PSym, kind: TTypeKind, size: int) =
proc processMagicType(c: PContext, m: PSym) = proc processMagicType(c: PContext, m: PSym) =
case m.magic #registerSysType(m.typ); case m.magic #registerSysType(m.typ);
of mInt: of mInt: setMagicType(m, tyInt, intSize)
setMagicType(m, tyInt, intSize) of mInt8: setMagicType(m, tyInt8, 1)
of mInt8: of mInt16: setMagicType(m, tyInt16, 2)
setMagicType(m, tyInt8, 1) of mInt32: setMagicType(m, tyInt32, 4)
of mInt16: of mInt64: setMagicType(m, tyInt64, 8)
setMagicType(m, tyInt16, 2) of mFloat: setMagicType(m, tyFloat, floatSize)
of mInt32: of mFloat32: setMagicType(m, tyFloat32, 4)
setMagicType(m, tyInt32, 4) of mFloat64: setMagicType(m, tyFloat64, 8)
of mInt64: of mBool: setMagicType(m, tyBool, 1)
setMagicType(m, tyInt64, 8) of mChar: setMagicType(m, tyChar, 1)
of mFloat:
setMagicType(m, tyFloat, floatSize)
of mFloat32:
setMagicType(m, tyFloat32, 4)
of mFloat64:
setMagicType(m, tyFloat64, 8)
of mBool:
setMagicType(m, tyBool, 1)
of mChar:
setMagicType(m, tyChar, 1)
of mString: of mString:
setMagicType(m, tyString, ptrSize) setMagicType(m, tyString, ptrSize)
addSon(m.typ, getSysType(tyChar)) addSon(m.typ, getSysType(tyChar))
of mCstring: of mCstring:
setMagicType(m, tyCString, ptrSize) setMagicType(m, tyCString, ptrSize)
addSon(m.typ, getSysType(tyChar)) addSon(m.typ, getSysType(tyChar))
of mPointer: of mPointer: setMagicType(m, tyPointer, ptrSize)
setMagicType(m, tyPointer, ptrSize)
of mEmptySet: of mEmptySet:
setMagicType(m, tySet, 1) setMagicType(m, tySet, 1)
addSon(m.typ, newTypeS(tyEmpty, c)) addSon(m.typ, newTypeS(tyEmpty, c))
of mIntSetBaseType: of mIntSetBaseType:
setMagicType(m, tyRange, intSize) #intSetBaseType := m.typ; setMagicType(m, tyRange, intSize) #intSetBaseType := m.typ;
return return
of mNil: of mNil: setMagicType(m, tyNil, ptrSize)
setMagicType(m, tyNil, ptrSize) of mExpr: setMagicType(m, tyExpr, 0)
of mExpr: of mStmt: setMagicType(m, tyStmt, 0)
setMagicType(m, tyExpr, 0) of mTypeDesc: setMagicType(m, tyTypeDesc, 0)
of mStmt: of mArray, mOpenArray, mRange, mSet, mSeq, mOrdinal: return
setMagicType(m, tyStmt, 0)
of mTypeDesc:
setMagicType(m, tyTypeDesc, 0)
of mArray, mOpenArray, mRange, mSet, mSeq, mOrdinal:
return
else: liMessage(m.info, errTypeExpected) else: liMessage(m.info, errTypeExpected)

View file

@ -30,7 +30,7 @@ type
TTypeRelation = enum # order is important! TTypeRelation = enum # order is important!
isNone, isConvertible, isIntConv, isSubtype, isGeneric, isEqual isNone, isConvertible, isIntConv, isSubtype, isGeneric, isEqual
proc initCandidate(c: var TCandidate, callee: PType) = proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} =
c.exactMatches = 0 c.exactMatches = 0
c.subtypeMatches = 0 c.subtypeMatches = 0
c.convMatches = 0 c.convMatches = 0
@ -38,11 +38,25 @@ proc initCandidate(c: var TCandidate, callee: PType) =
c.genericMatches = 0 c.genericMatches = 0
c.state = csEmpty c.state = csEmpty
c.callee = callee c.callee = callee
c.calleeSym = nil
c.call = nil c.call = nil
c.baseTypeMatch = false c.baseTypeMatch = false
initIdTable(c.bindings) #assert(c.callee <> nil);
proc initCandidate(c: var TCandidate, callee: PType) =
initCandidateAux(c, callee)
c.calleeSym = nil
initIdTable(c.bindings)
proc initCandidate(c: var TCandidate, callee: PSym, binding: PNode) =
initCandidateAux(c, callee.typ)
c.calleeSym = callee
initIdTable(c.bindings)
if binding != nil:
var typeParams = callee.ast[genericParamsPos]
for i in 1..min(sonsLen(typeParams), sonsLen(binding)-1):
var formalTypeParam = typeParams.sons[i-1].typ
#debug(formalTypeParam)
IdTablePut(c.bindings, formalTypeParam, binding[i].typ)
proc copyCandidate(a: var TCandidate, b: TCandidate) = proc copyCandidate(a: var TCandidate, b: TCandidate) =
a.exactMatches = b.exactMatches a.exactMatches = b.exactMatches
a.subtypeMatches = b.subtypeMatches a.subtypeMatches = b.subtypeMatches
@ -326,7 +340,7 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
case a.kind case a.kind
of tyPointer: result = isEqual of tyPointer: result = isEqual
of tyNil: result = isSubtype of tyNil: result = isSubtype
of tyRef, tyPtr, tyProc, tyCString: result = isConvertible of tyPtr, tyProc, tyCString: result = isConvertible
else: nil else: nil
of tyString: of tyString:
case a.kind case a.kind
@ -664,21 +678,20 @@ proc sameMethodDispatcher(a, b: PSym): bool =
if aa.kind == nkSym and bb.kind == nkSym and aa.sym == bb.sym: if aa.kind == nkSym and bb.kind == nkSym and aa.sym == bb.sym:
result = true result = true
proc semDirectCall(c: PContext, n: PNode, filter: TSymKinds): PNode = proc semDirectCallWithBinding(c: PContext, n, f: PNode, filter: TSymKinds,
var initialBinding: PNode): PNode =
var
o: TOverloadIter o: TOverloadIter
x, y, z: TCandidate x, y, z: TCandidate
#liMessage(n.info, warnUser, renderTree(n)); #liMessage(n.info, warnUser, renderTree(n));
var sym = initOverloadIter(o, c, n.sons[0]) var sym = initOverloadIter(o, c, f)
result = nil result = nil
if sym == nil: return if sym == nil: return
initCandidate(x, sym.typ) initCandidate(x, sym, initialBinding)
x.calleeSym = sym initCandidate(y, sym, initialBinding)
initCandidate(y, sym.typ)
y.calleeSym = sym
while sym != nil: while sym != nil:
if sym.kind in filter: if sym.kind in filter:
initCandidate(z, sym.typ) initCandidate(z, sym, initialBinding)
z.calleeSym = sym z.calleeSym = sym
matches(c, n, z) matches(c, n, z)
if z.state == csMatch: if z.state == csMatch:
@ -689,7 +702,7 @@ proc semDirectCall(c: PContext, n: PNode, filter: TSymKinds): PNode =
if cmp < 0: x = z # z is better than x if cmp < 0: x = z # z is better than x
elif cmp == 0: y = z # z is as good as x elif cmp == 0: y = z # z is as good as x
else: nil else: nil
sym = nextOverloadIter(o, c, n.sons[0]) sym = nextOverloadIter(o, c, f)
if x.state == csEmpty: if x.state == csEmpty:
# no overloaded proc found # no overloaded proc found
# do not generate an error yet; the semantic checking will check for # do not generate an error yet; the semantic checking will check for
@ -714,3 +727,16 @@ proc semDirectCall(c: PContext, n: PNode, filter: TSymKinds): PNode =
result = x.call result = x.call
result.sons[0] = newSymNode(x.calleeSym) result.sons[0] = newSymNode(x.calleeSym)
result.typ = x.callee.sons[0] result.typ = x.callee.sons[0]
proc semDirectCall(c: PContext, n: PNode, filter: TSymKinds): PNode =
# process the bindings once:
var initialBinding: PNode
var f = n.sons[0]
if f.kind == nkBracketExpr:
# fill in the bindings:
initialBinding = f
f = f.sons[0]
else:
initialBinding = nil
result = semDirectCallWithBinding(c, n, f, filter, initialBinding)

View file

@ -63,55 +63,55 @@ proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PSym =
incl(result.flags, sfFromGeneric) incl(result.flags, sfFromGeneric)
proc transform(c: PTransf, n: PNode): PNode proc transform(c: PTransf, n: PNode): PNode
#
# # Transforming iterators into non-inlined versions is pretty hard, but
#Transforming iterators into non-inlined versions is pretty hard, but # unavoidable for not bloating the code too much. If we had direct access to
#unavoidable for not bloating the code too much. If we had direct access to # the program counter, things'd be much easier.
#the program counter, things'd be much easier. # ::
#:: #
# # iterator items(a: string): char =
# iterator items(a: string): char = # var i = 0
# var i = 0 # while i < length(a):
# while i < length(a): # yield a[i]
# yield a[i] # inc(i)
# inc(i) #
# # for ch in items("hello world"): # `ch` is an iteration variable
# for ch in items("hello world"): # `ch` is an iteration variable # echo(ch)
# echo(ch) #
# # Should be transformed into::
#Should be transformed into:: #
# # type
# type # TItemsClosure = record
# TItemsClosure = record # i: int
# i: int # state: int
# state: int # proc items(a: string, c: var TItemsClosure): char =
# proc items(a: string, c: var TItemsClosure): char = # case c.state
# case c.state # of 0: goto L0 # very difficult without goto!
# of 0: goto L0 # very difficult without goto! # of 1: goto L1 # can be implemented by GCC's computed gotos
# of 1: goto L1 # can be implemented by GCC's computed gotos #
# # block L0:
# block L0: # c.i = 0
# c.i = 0 # while c.i < length(a):
# while c.i < length(a): # c.state = 1
# c.state = 1 # return a[i]
# return a[i] # block L1: inc(c.i)
# block L1: inc(c.i) #
# # More efficient, but not implementable::
#More efficient, but not implementable:: #
# # type
# type # TItemsClosure = record
# TItemsClosure = record # i: int
# i: int # pc: pointer
# pc: pointer #
# # proc items(a: string, c: var TItemsClosure): char =
# proc items(a: string, c: var TItemsClosure): char = # goto c.pc
# goto c.pc # c.i = 0
# c.i = 0 # while c.i < length(a):
# while c.i < length(a): # c.pc = label1
# c.pc = label1 # return a[i]
# return a[i] # label1: inc(c.i)
# label1: inc(c.i) #
#
proc newAsgnStmt(c: PTransf, le, ri: PNode): PNode = proc newAsgnStmt(c: PTransf, le, ri: PNode): PNode =
result = newNodeI(nkFastAsgn, ri.info) result = newNodeI(nkFastAsgn, ri.info)
addSon(result, le) addSon(result, le)
@ -290,8 +290,8 @@ proc transformConv(c: PTransf, n: PNode): PNode =
if not isOrdinalType(source): if not isOrdinalType(source):
# XXX int64 -> float conversion? # XXX int64 -> float conversion?
result = n result = n
elif (firstOrd(dest) <= firstOrd(source)) and elif firstOrd(dest) <= firstOrd(source) and
(lastOrd(source) <= lastOrd(dest)): lastOrd(source) <= lastOrd(dest):
# BUGFIX: simply leave n as it is; we need a nkConv node, # BUGFIX: simply leave n as it is; we need a nkConv node,
# but no range check: # but no range check:
result = n result = n
@ -540,8 +540,8 @@ proc getMergeOp(n: PNode): PSym =
proc flattenTreeAux(d, a: PNode, op: PSym) = proc flattenTreeAux(d, a: PNode, op: PSym) =
var op2 = getMergeOp(a) var op2 = getMergeOp(a)
if (op2 != nil) and if op2 != nil and
((op2.id == op.id) or (op.magic != mNone) and (op2.magic == op.magic)): (op2.id == op.id or op.magic != mNone and op2.magic == op.magic):
for i in countup(1, sonsLen(a) - 1): flattenTreeAux(d, a.sons[i], op) for i in countup(1, sonsLen(a) - 1): flattenTreeAux(d, a.sons[i], op)
else: else:
addSon(d, copyTree(a)) addSon(d, copyTree(a))

View file

@ -17,6 +17,7 @@ tcnstseq.nim;AngelikaAnneAnnaAnkaAnja
tconstr2.nim;69 tconstr2.nim;69
tcopy.nim;TEMP=C:\Programs\xyz\bin tcopy.nim;TEMP=C:\Programs\xyz\bin
tcurrncy.nim;25 tcurrncy.nim;25
texplicitgeneric1.nim;Key: 12 value: 12Key: 13 value: 13 Key: A value: 12 Key: B value: 13
tfinally.nim;came here tfinally.nim;came here
tfloat1.nim;Error: unhandled exception: FPU operation caused an overflow [EFloatOverflow] tfloat1.nim;Error: unhandled exception: FPU operation caused an overflow [EFloatOverflow]
tfloat2.nim;Error: unhandled exception: FPU operation caused a NaN result [EFloatInvalidOp] tfloat2.nim;Error: unhandled exception: FPU operation caused a NaN result [EFloatInvalidOp]

1 tack.nim 125
17 tconstr2.nim 69
18 tcopy.nim TEMP=C:\Programs\xyz\bin
19 tcurrncy.nim 25
20 texplicitgeneric1.nim Key: 12 value: 12Key: 13 value: 13 Key: A value: 12 Key: B value: 13
21 tfinally.nim came here
22 tfloat1.nim Error: unhandled exception: FPU operation caused an overflow [EFloatOverflow]
23 tfloat2.nim Error: unhandled exception: FPU operation caused a NaN result [EFloatInvalidOp]

View file

@ -10,6 +10,13 @@ Bugfixes
- Bugfix: Command line parsing on Windows and ``os.parseCmdLine`` now adheres - Bugfix: Command line parsing on Windows and ``os.parseCmdLine`` now adheres
to the same parsing rules as Microsoft's C/C++ startup code. to the same parsing rules as Microsoft's C/C++ startup code.
- Bugfix: Passing a ``ref`` pointer to the untyped ``pointer`` type is invalid.
- Bugfix: Updated ``keyval`` example.
- Bugfix: ``system.splitChunk`` still contained code for debug output.
- Bugfix: ``times.getStartMilsecs`` uses ``gettimeofday`` for Posix times. It
used to use ``clock`` which has the wrong semantics.
- Bugfix: ``dialogs.ChooseFileToSave`` uses ``STOCK_SAVE`` instead of
``STOCK_OPEN`` for the GTK backend.
Changes affecting backwards compatibility Changes affecting backwards compatibility
@ -24,6 +31,10 @@ Additions
- The ``{.compile: "file.c".}`` pragma uses a CRC check to see if the file - The ``{.compile: "file.c".}`` pragma uses a CRC check to see if the file
needs to be recompiled. needs to be recompiled.
- Added ``system.reopen``.
- Added ``system.getCurrentException``.
- Implemented explicit type arguments for generics.
- Implemented implicit type arguments for generics.
2010-03-14 Version 0.8.8 released 2010-03-14 Version 0.8.8 released