Compare commits

...

1416 Commits

Author SHA1 Message Date
Araq
687a1b7de4 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-04-21 10:10:28 +02:00
Araq
7a557013ae version 0.9.4 2014-04-21 09:46:36 +02:00
Araq
80e377b668 manual.txt updates 2014-04-21 09:45:21 +02:00
Araq
d22506c645 fixes #847 2014-04-21 09:18:47 +02:00
Andreas Rumpf
41f82fb45f Merge pull request #1113 from flaviut/del_dead
Delete dead files
2014-04-21 03:57:59 +02:00
Araq
5e839d50b4 fixes DLL generation 2014-04-21 03:44:48 +02:00
Araq
b15f323f03 updated news.txt 2014-04-21 03:44:19 +02:00
Araq
667b7d8508 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-04-21 02:46:05 +02:00
Araq
a868575436 doc2 likes future.nim now 2014-04-21 02:45:57 +02:00
Araq
042ffed6c4 some progress for #1082 2014-04-21 01:34:54 +02:00
Dominik Picheta
e80930247f Tester now ignores deprecation warnings. 2014-04-21 00:17:00 +01:00
Araq
2c97242739 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-04-21 00:07:40 +02:00
Araq
e3fab47508 attempt to make some tests green 2014-04-21 00:07:31 +02:00
Araq
472190bedc fixes #1085 2014-04-21 00:04:36 +02:00
Dominik Picheta
5cf8c05a22 Fixes #1119. 2014-04-20 22:56:30 +01:00
Andreas Rumpf
23621857bb Merge pull request #1099 from Varriount/os/getFileInfo
Added os.getFileInfo procedure.
2014-04-20 23:40:29 +02:00
Andreas Rumpf
726c709f97 Merge pull request #1097 from gradha/pr_avoid_idetools_crash
Avoid idetools crash on nil parameters.
2014-04-20 23:39:45 +02:00
Andreas Rumpf
1205f9107e Merge pull request #1107 from ReneSac/devel
Additions and clarifications to tutorial 1.
2014-04-20 23:39:25 +02:00
Andreas Rumpf
e34c3e7c3b Merge pull request #1123 from flaviut/bug1110
Document vmgen.nim a bit
2014-04-20 23:35:22 +02:00
Andreas Rumpf
38892bbf6a Merge pull request #1124 from EXetoC/spawn-arg-check
Spawn argument checking.
2014-04-20 23:34:21 +02:00
Dominik Picheta
ca2b73f64a Revert 4b09baa0a and 33fcd1123. 2014-04-20 22:35:17 +01:00
Dominik Picheta
443fdd6d69 Fixed docs in future module. 2014-04-20 22:17:56 +01:00
flaviut
29261a0eae Document vmgen.nim a bit 2014-04-20 17:10:15 -04:00
EXetoC
d29cf2d0e2 Add test for bad spawn argument. 2014-04-20 23:09:29 +02:00
Dominik Picheta
dad99376a5 Param name and type combos now work in type sig. sugar. 2014-04-20 22:08:03 +01:00
EXetoC
171f4a21e8 Fix spawn ICE on invalid argument. 2014-04-20 23:03:31 +02:00
Dominik Picheta
57cc8237f7 Fixes #1093. 2014-04-20 21:55:45 +01:00
Araq
36fc1d9d72 spawn has a chance of working on posix 2014-04-20 22:42:51 +02:00
Araq
4075159933 reintroduce thread analysis but disable it for backwards compatibility 2014-04-20 22:15:25 +02:00
Araq
da7d6c8446 fixes bootstrapping 2014-04-20 21:34:17 +02:00
Araq
1bb0bdec24 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-04-20 20:01:36 +02:00
Araq
e6d17e6273 made large parts of the stdlib gcsafe 2014-04-20 20:01:24 +02:00
Dominik Picheta
013289480d Merge pull request #1076 from runvnc/redis_pipeline
Redis: optional pipelining and better tested transactions
2014-04-20 16:59:38 +01:00
Dominik Picheta
ed935dfef1 Remove echo from => macro and fix tclosuremacro test. 2014-04-20 14:38:10 +01:00
Dominik Picheta
232d252885 Added new future module with a closure macro. 2014-04-20 14:33:44 +01:00
Dominik Picheta
cf3b54fdcb Removes tthreadanalysis3 from threadTests spec. 2014-04-20 13:29:08 +01:00
Araq
be6474af63 removed flawed thread analysis pass 2014-04-20 14:00:04 +02:00
Araq
39e4e3f205 fixes OR for int8|int16 etc 2014-04-20 13:59:38 +02:00
Jason Livesay
d7caba8b65 Use enum 2014-04-20 04:29:24 -07:00
Araq
c80d563afb actors compile again 2014-04-20 12:10:23 +02:00
Araq
13b941d8ee attempt to fix bootstrapping 2014-04-20 02:53:38 +02:00
Araq
05e89ffceb Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-04-20 01:19:10 +02:00
Araq
9a2704056a marked markAndSweep GC thread safe 2014-04-20 01:17:46 +02:00
flaviut
d0f0076c59 parsecfg is never used and is also part of the stdlib 2014-04-19 17:43:17 -04:00
flaviut
fb91efd47e charsets is never used 2014-04-19 17:42:42 -04:00
flaviut
e74868f4c6 Delete dead file 2014-04-19 17:19:22 -04:00
Simon Hafner
1f9f34b9a7 Merge pull request #1111 from gradha/pr_mentions_jsondoc_command
Mentions jsondoc in compiler advanced help.
2014-04-19 16:05:06 -05:00
Araq
3b69a8d27a New concurrency model: next steps 2014-04-19 22:24:43 +02:00
ReneSac
56a6928635 Referential data types may need to be declared.
And other small fixes.
2014-04-19 13:31:55 -03:00
Grzegorz Adam Hankiewicz
6ee1717238 Mentions jsondoc in compiler advanced help. 2014-04-19 11:46:28 +02:00
Simon Hafner
23e9ed81a2 added continue to errStmtInvalidAfterReturn 2014-04-18 21:19:39 -05:00
Dominik Picheta
1465355c54 Disabled tgtk test. 2014-04-19 00:17:35 +01:00
Dominik Picheta
20e3ab70b2 Improves tobjasgn test. 2014-04-18 23:31:45 +01:00
Dominik Picheta
00dc93b65b Fixes collections/ttables. 2014-04-18 21:50:51 +01:00
ReneSac
e2fe9dd9ab Additions and clarifications to tutorial 1. 2014-04-17 21:28:08 -03:00
Varriount
63d384d0cd Merge pull request #1100 from gradha/pr_excludes_nimcache_from_backups
Adds option to exclude nimcache dirs from time machine backups.
2014-04-17 13:37:06 -04:00
Jason Livesay
7584d867e1 delete extra statement from debugging 2014-04-17 03:52:33 -07:00
Jason Livesay
1068022dfb Allow QUEUED reply only if pipelined; don't return status replies from flushPipeline; Rewrite someTests 2014-04-17 03:47:44 -07:00
Simon Hafner
5859e80364 added an sqlite constant 2014-04-16 23:34:50 -05:00
Simon Hafner
6886a47305 Merge pull request #1102 from gradha/pr_improves_startProcess_docstring
Improves startProcess docstring for poEvalCommand usage.
2014-04-16 18:44:26 -05:00
Simon Hafner
208ef29706 Merge pull request #1101 from gradha/pr_adds_missing_import
Adds missing import.
2014-04-16 18:43:54 -05:00
Grzegorz Adam Hankiewicz
de04c97696 Improves startProcess docstring for poEvalCommand usage. 2014-04-16 23:14:13 +02:00
Grzegorz Adam Hankiewicz
84c1aa9990 Adds missing import. 2014-04-16 22:54:52 +02:00
Grzegorz Adam Hankiewicz
1c89c45ae9 Adds option to exclude nimcache dirs from time machine backups. 2014-04-16 22:46:16 +02:00
Dominik Picheta
2fb5d62927 Tester now appreciates the test target. Modified 'cmd' in specs. 2014-04-16 21:28:19 +01:00
Dominik Picheta
6692d95ee2 Fixes incorrect nodejs detection in tester. 2014-04-16 21:02:34 +01:00
Dominik Picheta
c93c014bc6 Modified tester output. Fixed JS tests. 2014-04-16 12:26:02 +01:00
Clay Sweetser
9ce0ac38e5 Added tests for getFileInfo proc. 2014-04-16 03:35:09 -04:00
Clay Sweetser
733b289209 Fixed _get_osfhandle declaration. 2014-04-16 03:35:09 -04:00
Clay Sweetser
73570cbe38 Allowed getFileInfo to accept TFile objects. 2014-04-16 03:35:08 -04:00
Clay Sweetser
79f0c66b4d Completed Linux/Posix implementation of getFileInfo
Moved parts of getFileInfo into a helper template.
2014-04-16 03:35:08 -04:00
Clay Sweetser
8af083c847 Added Posix implementation of getFileInfo, organized code. 2014-04-16 03:35:07 -04:00
Clay Sweetser
37ac424e9a Added Windows implementation of getFileInfo procedures 2014-04-16 03:35:07 -04:00
Araq
8e08ff559f first version of 'spawn' 2014-04-16 08:44:57 +02:00
Dominik Picheta
941cc937d3 Fixes docgen. 2014-04-15 22:09:12 +01:00
Simon Hafner
3670fe2385 Merge pull request #1098 from gradha/pr_fixes_debugger_typo
Fixes typo to be able to use debugger.
2014-04-15 14:48:29 -05:00
Grzegorz Adam Hankiewicz
6baedfe946 Fixes typo to be able to use debugger. 2014-04-15 21:23:52 +02:00
Grzegorz Adam Hankiewicz
c163c06a65 Avoids idetools crash on nil parameters. 2014-04-15 21:13:10 +02:00
Dominik Picheta
9e7c0fd2b0 Fixes #1005 2014-04-15 13:53:02 +01:00
Dominik Picheta
21d0cc8cdf Add checks for invalid socket when creating sockets. 2014-04-15 13:51:25 +01:00
Araq
b961e47bfe new concurrency model: first steps; shared is not a keyword anymore 2014-04-14 08:45:43 +02:00
Araq
817337af30 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-04-13 22:32:01 +02:00
Araq
d96f25619a implemented 'R ptr T' syntax 2014-04-13 22:31:49 +02:00
Simon Hafner
bb94abd88a Merge pull request #1084 from gradha/pr_adds_sequtils_split
Adds generic split proc to sequtils.
2014-04-13 15:08:25 -05:00
Dominik Picheta
3612aca5fe Implemented buffering for asynchronous sockets. 2014-04-13 14:18:47 +01:00
Grzegorz Adam Hankiewicz
c3cb03c640 Renames split to distribute. Refs #1084. 2014-04-13 10:50:27 +02:00
Andreas Rumpf
ed0736d73d Merge pull request #1079 from flaviut/kochcleanfix
Fix Koch deleting the .gitignore while cleaning
2014-04-13 08:41:08 +02:00
Andreas Rumpf
2e9950afe8 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-04-13 00:40:17 +02:00
Andreas Rumpf
fe387888bd fixes for asynchttpserver 2014-04-13 00:39:15 +02:00
Andreas Rumpf
455c3c19ca added mget for TSet 2014-04-13 00:33:06 +02:00
Andreas Rumpf
f862e80be9 added 'hash' for set[T]' 2014-04-13 00:32:10 +02:00
Andreas Rumpf
3ee25170c3 fixes '==' for TTTable 2014-04-13 00:22:07 +02:00
Andreas Rumpf
587f0bd086 fixes '==' for TTTable 2014-04-13 00:20:25 +02:00
Andreas Rumpf
6b1543a6a8 -d:useFFI is obsolete 2014-04-13 00:12:21 +02:00
Andreas Rumpf
90a6f4ba98 fixed a typo 2014-04-13 00:00:06 +02:00
Dominik Picheta
e333b8bc1e Rewrote sentence about Babel in lib.txt. 2014-04-12 01:42:09 +01:00
Dominik Picheta
58e583e39b Implemented babel package list in lib.html. 2014-04-12 00:09:03 +01:00
Dominik Picheta
7cddb39969 Adds split proc for strings with a string separator. 2014-04-11 21:42:44 +01:00
Dominik Picheta
96c97d4103 JS: Fixes math and streams module and implements json. 2014-04-11 21:41:45 +01:00
Dominik Picheta
b0a16fb619 Fixes problems with JS code gen.
--out for JS backend now works. setLen now works, this also fixes the base64
module. getCurrentExceptionMsg now also works with exceptions thrown by
JS. log() supports a variable number of args now. Fixed some case
sensitivity issues with arrayConstr and other functions.
2014-04-11 21:36:02 +01:00
Grzegorz Adam Hankiewicz
fac9947ebe Adds generic split proc to sequtils. 2014-04-11 22:24:49 +02:00
Jason Livesay
ebe174c868 delete echo statements used for debugging 2014-04-10 22:27:09 -07:00
Jason Livesay
be02aaec72 factor per comments 2014-04-10 22:23:33 -07:00
flaviut
3f3014f626 Koch deletes the .gitignore while cleaning 2014-04-10 21:59:43 -04:00
Jason Livesay
9a728b15a2 Don't need ref string; use PPipeline instead of ref TPipeline 2014-04-10 16:46:26 -07:00
Jason Livesay
5da463e1f7 Redis: optional pipelining and better tested transactions 2014-04-09 20:43:45 -07:00
Andreas Rumpf
dcfc7a8896 resolved conflict 2014-04-10 01:47:20 +02:00
Simon Hafner
a86c774932 deleted & purged dlls 2014-04-09 18:17:54 -05:00
Simon Hafner
8b82004359 deleted & purged dlls 2014-04-09 18:17:42 -05:00
Andreas Rumpf
a690e7b267 Merge pull request #1075 from flaviut/inlinedocs
Add some documentations and code examples in system
2014-04-09 22:56:18 +02:00
Araq
d0f013477b refined and documented regionized pointers 2014-04-09 08:37:08 +02:00
Araq
54935e2e70 fixes bootstrapping 2014-04-09 01:11:52 +02:00
Araq
0c64849aab Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-04-09 00:48:27 +02:00
flaviut
a157985e01 Fix typos in system.nim 2014-04-08 18:36:03 -04:00
Araq
4196757de7 implemented region pointers 2014-04-09 00:33:51 +02:00
flaviut
0dffbd66bb Concatenates was misspelled 2014-04-08 18:29:02 -04:00
Andreas Rumpf
36869b3aed Merge pull request #901 from reactormonk/seq_toString
Added `$` for seq
2014-04-09 00:06:38 +02:00
Andreas Rumpf
bb8b9da391 Merge pull request #902 from reactormonk/float_toString
use `.f` instead of `.16e` for floats
2014-04-09 00:06:18 +02:00
Andreas Rumpf
e2d02d5943 Merge pull request #691 from rbehrends/fix-shallow-pragma
Fixes shallow pragma for objects and tuples.
2014-04-09 00:05:59 +02:00
flaviut
fde53bffd7 Code example for clamp 2014-04-08 18:00:44 -04:00
flaviut
2a470c4217 Document inplace string appending 2014-04-08 17:56:11 -04:00
flaviut
6e70d8afb4 Code examples for string concatination 2014-04-08 17:51:21 -04:00
flaviut
fb547ef76b Code docs for contains, in, is, and of 2014-04-08 17:44:53 -04:00
flaviut
af4c0851c1 Inline docs for sequence appending 2014-04-08 17:05:32 -04:00
Araq
3e25d5f247 merged better html links #850 2014-04-08 01:19:15 +02:00
Araq
831a8c8db4 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-04-08 00:34:35 +02:00
Andreas Rumpf
230af70be4 Merge pull request #1069 from flaviut/devel
Add renderRstToJson in docutils
2014-04-08 00:09:37 +02:00
Araq
42a8ab34f1 preparations for easier debugging 2014-04-07 23:28:29 +02:00
Dominik Picheta
369d8c57ae Disable async macro code output. Added some WSA error codes to winlean. 2014-04-07 20:46:47 +01:00
Dominik Picheta
12e247acc6 Merge branch 'devel' of github.com:Araq/Nimrod into devel 2014-04-07 20:31:59 +01:00
Araq
3197ec8e72 make tests green again 2014-04-07 15:46:02 +02:00
Araq
abb7010820 fixes #1063 2014-04-07 14:21:33 +02:00
Araq
1b97fcd448 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-04-07 02:02:06 +02:00
Araq
d20e4e0df4 updated news.txt 2014-04-07 01:59:17 +02:00
Dominik Picheta
152fcc8ec4 Change the expected path in tfailedassert.
This will cause this test to fail on Linux. The behaviour on Windows is
however correct, the filename returned by instantiationInfo is the
projPath defined as being "relative to the project's root".
2014-04-06 23:57:20 +01:00
Dominik Picheta
61c9c429d4 Fixes selectors module on Mac OS X. 2014-04-06 23:20:55 +01:00
Dominik Picheta
d2593e1d62 setLen now used on asyncdispatch.recv's return value on Linux.
This fixes issues with the async httpclient.
2014-04-06 22:06:25 +01:00
Dominik Picheta
d98b0d9f79 Selectors module now uses select on operating systems other than Linux. 2014-04-06 21:43:51 +01:00
Araq
9840a6912d Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-04-06 22:05:59 +02:00
Araq
7c065bfadf fixes #798 2014-04-06 22:05:42 +02:00
Dominik Picheta
b2fd562983 Updates docs and news. 2014-04-06 20:46:31 +01:00
Dominik Picheta
5eaec84785 Select implementation in selectors module compiles again. 2014-04-06 19:27:47 +01:00
Dominik Picheta
439569cfa3 Documentation for async httpclient. Notes for url modules. 2014-04-06 19:27:16 +01:00
Dominik Picheta
b23dce03a1 Get rid of incorrect assert in asyncdispatch. 2014-04-06 19:26:21 +01:00
Dominik Picheta
291aa2eb30 Fixes docgen. 2014-04-06 19:25:46 +01:00
Andreas Rumpf
b988f75a35 Merge pull request #1071 from ReneSac/devel
Zero is not a power of two. Fixes #1047
2014-04-06 20:12:46 +02:00
ReneSac
8095fbf982 Removed trailing ';'. 2014-04-06 15:07:20 -03:00
Araq
5d6053173a fixes #297 2014-04-06 19:53:24 +02:00
Araq
a4ccd7b865 doc generation for asyncdispatch works 2014-04-06 19:36:29 +02:00
ReneSac
83661492e7 Fix typo in previous commit. 2014-04-06 14:20:51 -03:00
ReneSac
a4559ab17e Zero is not a power of two. Fix #1047
Also, fixed some docstrings and added {.noSideEffect.} pragma to nextPowerOfTwo().
2014-04-06 14:18:16 -03:00
Araq
5def38ad69 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-04-06 17:31:49 +02:00
Araq
cf7e83ecc5 fixes #913 2014-04-06 17:26:20 +02:00
Araq
034af8354d fixes #866 2014-04-06 17:18:43 +02:00
Zahary Karadjov
f6f5c9e9e6 propagate semExpr flags in macro/template expansion 2014-04-06 16:55:28 +03:00
flaviut
99ebcaec3a Modify renderRstToJson to use the json library 2014-04-05 23:53:19 -04:00
Dominik Picheta
4d2f1396cb Revent pruneSocketSet to efficient version. 2014-04-05 23:30:16 +01:00
Dominik Picheta
51c203bab0 Modified behaviour of checkBuffer to match new select behaviour. Refs #822. 2014-04-05 23:10:51 +01:00
flaviut
335de0c49a Add renderRstToJson in docutils 2014-04-05 15:58:16 -04:00
Dominik Picheta
cd70bba332 Added asynchttpserver module. 2014-04-05 20:30:32 +01:00
Dominik Picheta
d0478a5637 Asyncdispatch fixes.
``return`` is now transformed into a ``return nil`` in the async iterator
to work around the no-yield in ``try .. except ..`` closure iterator
limitation.
2014-04-05 20:27:42 +01:00
Dominik Picheta
694fc87b1d Merge branch 'devel' of github.com:Araq/Nimrod into devel 2014-04-05 20:26:54 +01:00
Araq
fc814b87dc Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-04-05 21:05:20 +02:00
Araq
4835199125 new VM: proper shield against endless recursions 2014-04-05 21:05:07 +02:00
Dominik Picheta
d02af5cc4c Merge pull request #1066 from ithkuil/devel
Transaction support for redis
2014-04-05 14:08:39 +01:00
Jason Livesay
e6d2490b9c Support transactions 2014-04-04 23:29:50 -07:00
Jason Livesay
8d1c4a23de Allow multi/exec replies so transactions work. 2014-04-04 16:11:43 -07:00
Araq
033f2bbbf2 new VM: fixes for exception handling 2014-04-04 09:06:29 +02:00
Araq
6a055990f9 minor VM bugfix 2014-04-04 08:19:02 +02:00
Araq
160933f9de Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-04-03 22:40:34 +02:00
Araq
325dd44e81 gensym'ed symbols work with lambda-lifting; closures produce objects instead of tuples for easier debugging 2014-04-03 22:35:10 +02:00
Dominik Picheta
5a4afbef84 Proper handling of disconnections during reading in httpclient. 2014-04-03 20:06:59 +01:00
Dominik Picheta
4399895d2e Async httpclient should now work. Changed recv behaviour.
asyncdispatch.recv no longer guarantees that it will read ALL the data
requested. The underlying WinAPI function doesn't guarantee this and it
already wasn't guaranteed anyway since the socket could disconnect
mid-transmission.
2014-04-03 20:02:42 +01:00
Araq
62a10df765 fixes yet another option type 2014-04-03 07:54:58 +02:00
Dominik Picheta
e4e87f1cb2 Refactored createCb in asyncdispatch. 2014-04-02 21:28:45 +01:00
Araq
5dc28cc9a7 added tmissingnilcheck test 2014-04-02 22:18:53 +02:00
Araq
29fdc7a5be Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-04-02 22:05:05 +02:00
Araq
3e9ebd24f2 todo.txt updated 2014-04-02 21:49:58 +02:00
Andreas Rumpf
e810c760fd Merge pull request #1060 from EXetoC/vm-arithmetic-overflow
Arithmetic underflow/overflow checking for the VM
2014-04-02 19:59:26 +02:00
Andreas Rumpf
207874aa2d Merge pull request #1061 from EXetoC/fix-tests
Fix some tests.
2014-04-02 19:57:37 +02:00
Andreas Rumpf
843693d676 Merge pull request #1048 from gradha/pr_adds_convenience_uncompress_to_zlib
Adds convenience uncompress and inflate procs to zlib.
2014-04-02 19:57:05 +02:00
Andreas Rumpf
cc9230824a Merge pull request #1052 from rleisti/devel
Remove exception from TEventEmitter.emit
2014-04-02 19:55:31 +02:00
Araq
ac02aecb04 make tstaticprintseq green 2014-04-01 20:40:01 +02:00
Araq
b579ca44eb Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-04-01 19:41:51 +02:00
Araq
befdce51b4 fixed another vm bug 2014-04-01 16:35:50 +02:00
Araq
dc2b21e9b2 tsymchoicefield compiles 2014-04-01 08:21:08 +02:00
Araq
6a94ca3187 fixes #880 2014-04-01 08:17:23 +02:00
Simon Hafner
71b69a627f added $ for arrays 2014-03-31 15:58:52 -05:00
Simon Hafner
ffb36db5a6 Merge branch 'devel' of github.com:Araq/Nimrod into seq_toString 2014-03-31 15:49:04 -05:00
EXetoC
e69899fb49 Fix some tests. 2014-03-31 21:38:35 +02:00
EXetoC
c75b247a90 Remove executable. 2014-03-31 14:52:16 +02:00
EXetoC
52c6956d1a Add underflow/overflow tests. 2014-03-31 14:50:44 +02:00
EXetoC
b919ab790b Implement overflow/underflow checking for the VM. 2014-03-31 14:11:21 +02:00
Araq
44ee8aecfd disable extern name checking as it breaks building of nimrtl.dll 2014-03-30 22:40:09 +02:00
Ron Leisti
f3d7c452d2 events.TEventEmitter.emit no longer throws an exception if the named event does not exist 2014-03-29 19:51:56 -04:00
Dominik Picheta
aae774a279 Fix docgen. 2014-03-29 22:01:20 +00:00
Dominik Picheta
227c54c786 Replaced idents with genSym in asyncdispatch. 2014-03-29 21:28:01 +00:00
Araq
3afb42496b Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-03-29 14:47:43 +01:00
Araq
f50575d147 fixes #932 2014-03-29 14:47:01 +01:00
Araq
b6d5f18c93 iterators check seqs/strings are not resized during iteration 2014-03-29 13:50:07 +01:00
Grzegorz Adam Hankiewicz
20e55fc5d4 Uses finally as statement to release zlib memory. Refs #1048. 2014-03-29 12:29:17 +01:00
Grzegorz Adam Hankiewicz
a6f8bae69f Uses swap() to avoid variable copies. Refs #1048. 2014-03-29 12:27:18 +01:00
Grzegorz Adam Hankiewicz
d41988d8b2 Modifies inflate() to return a discardable bool. Refs #1048. 2014-03-29 12:24:54 +01:00
Grzegorz Adam Hankiewicz
cc718435b3 Adds convenience uncompress and inflate procs to zlib.
The new uncompress() version doesn't require you to know the size of the
inflated destination buffer. The inflate() proc wraps it for convenience
on a var string type.
2014-03-29 01:14:33 +01:00
Andreas Rumpf
05421cf84b Merge pull request #1045 from barcharcraz/lowerBound
fixed doc comment
2014-03-28 23:13:41 +01:00
Araq
2958adc47f tester outputs full test path 2014-03-28 18:15:51 +01:00
Araq
12e3c11eb6 fixes #911 2014-03-28 08:40:15 +01:00
Dominik Picheta
23d581d377 Added test for issue #911. 2014-03-27 21:52:28 +00:00
Araq
5a51a25fd0 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-03-27 21:24:53 +01:00
Araq
31cfed0aa8 fixes a typo 2014-03-27 21:24:41 +01:00
Charlie Barto
76dfa611ed fixed doc comment 2014-03-27 15:13:10 -04:00
Varriount
f40625f5c4 Merge pull request #1032 from barcharcraz/lowerBound
Added lowerBound function to the stdlib
2014-03-27 15:08:19 -04:00
Araq
de5d18188f ENDB: got rid of deprecated 'nil' stmt 2014-03-27 19:59:31 +01:00
Araq
76ef752957 made some tests green 2014-03-27 19:43:17 +01:00
Araq
3365b42bbe fixes #1009 2014-03-27 19:20:59 +01:00
zah
74af96dbf6 Merge pull request #1042 from ithkuil/devel
Calling randomize() again within 1 second will now provide a different seed
2014-03-27 14:01:59 +02:00
Charlie Barto
491291ae24 added usage example for lower bound 2014-03-27 00:21:19 -04:00
Jason Livesay
cabc5c80d3 Calling randomize() again within 1 second will now provide a different seed 2014-03-26 18:54:34 -07:00
Araq
dc956c485a fixes tmemit regression 2014-03-26 22:56:56 +01:00
Araq
a1e97ad4a4 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-03-26 20:31:29 +01:00
Araq
78cc4de9a1 fixes #1025; don't know what this breaks 2014-03-26 20:31:18 +01:00
Dominik Picheta
783087fd57 Implemented async for httpclient. 2014-03-26 16:43:32 +00:00
Araq
9fdb131686 fixes #992 2014-03-26 16:22:34 +01:00
Dominik Picheta
4ed1ac0078 Move asyncdispatch tests to asyncnet. 2014-03-26 10:31:16 +00:00
zah
6d0451ccce Merge pull request #1036 from jlhouchin/devel
fixed parens around getSysType arguments
2014-03-26 11:39:59 +02:00
Araq
7874c0efcb borrow dots for distinct types documented 2014-03-26 08:42:27 +01:00
Araq
cdb4d83ead implemented 'borrow dot' feature for distinct types 2014-03-26 01:27:22 +01:00
Araq
d15788d00a added #903 to the test suite 2014-03-26 01:00:34 +01:00
Jimmie Houchin
c58ec376b6 fixed parens around getSysType arguments 2014-03-25 17:48:27 -05:00
Araq
9e66d988e7 mongodb wrapper properly removed from core 2014-03-25 01:26:32 +01:00
Araq
8755792077 mongodb wrapper properly removed from core 2014-03-25 01:25:17 +01:00
Araq
bf2f6397c8 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-03-24 18:42:31 +01:00
Araq
907e1b80b2 VM: attempt to get integer ops right 2014-03-24 17:29:31 +01:00
Zahary Karadjov
e8c50640d7 failing test case preventing the use of --gc:v2: tsymchoicefield 2014-03-24 12:17:22 +02:00
Araq
ee1192679e VM: endless loop prevention 2014-03-24 08:43:57 +01:00
Charlie Barto
976fb18a8f made the default comparator for lowerBound unqualified, so the user can customize via two phase lookup 2014-03-23 18:30:54 -04:00
Charlie Barto
baa304f370 added lowerBound function to algorithm library 2014-03-23 18:28:05 -04:00
Dominik Picheta
d310b01db1 Moved the global dispatcher to asyncdispatch. 2014-03-23 18:24:11 +00:00
Araq
e855f6c073 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-03-23 17:48:32 +01:00
Araq
5920edf6e4 fixes #404 2014-03-23 17:48:10 +01:00
Dominik Picheta
10f205bb52 Fixes tasyncawait and the net module on Linux. 2014-03-23 11:39:24 +00:00
Araq
3a34a8880c Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-03-23 00:00:07 +01:00
Araq
7a311f93f7 fixes #994 2014-03-22 23:48:33 +01:00
Dominik Picheta
192e11e7b7 Many renames. Created high level asyncnet module. 2014-03-22 22:33:53 +00:00
Dominik Picheta
2ce9f1c77f Copied most blocking socket operations to the net module. 2014-03-22 22:33:53 +00:00
Dominik Picheta
5bf45d9285 Clean up IP address code in net module. 2014-03-22 22:33:52 +00:00
Dominik Picheta
ca6b4bf0f9 Asyncio2 doc improvements. Changed recvLine's behaviour.
recvLine had an edge case where it would return a partial line if the
socket were to be disconnected in the middle of a line being read. The
behaviour now is that the data is simply lost as it likely will be
unparsable by the protocol anyway.
2014-03-22 22:33:51 +00:00
Araq
a4f30c3682 fixes wrong commit 2014-03-22 23:02:01 +01:00
Araq
b76d2eac7f fixes #1006 2014-03-22 22:59:23 +01:00
Araq
5f64d7a353 fixes #1023 2014-03-22 21:18:56 +01:00
Araq
5f478e5aa1 fixes #1010 2014-03-22 11:50:42 +01:00
Araq
5aac789e0e Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-03-22 02:52:33 +01:00
Araq
e53fc91282 fixed tuples in a static context; preparations for correct compile time evaluation of integral ops 2014-03-22 02:52:06 +01:00
Araq
fb5ece805f added mapMem/unmapMem to memfiles; untested 2014-03-22 02:51:03 +01:00
Araq
a431207e52 bugfix: reprEnum for enums with negative values 2014-03-22 02:49:51 +01:00
Araq
28e375c4f6 improved docs about strongSpaces 2014-03-22 02:45:35 +01:00
Araq
02e97422ed c2nim knows about arrray[N, T] 2014-03-22 02:43:37 +01:00
Andreas Rumpf
13d26dc53d Merge pull request #1021 from skyfex/devel
Added documentation for packed pragma
2014-03-21 23:52:30 +01:00
Audun Wilhelmsen
2a182f55ae Fixed typo in docs 2014-03-21 18:10:27 +01:00
Audun Wilhelmsen
1b423139e6 Fixed typo and line breaks in docs 2014-03-20 23:47:50 +01:00
Zahary Karadjov
4f91dd40ed msg -> errmsg 2014-03-21 00:27:28 +02:00
Audun Wilhelmsen
b59fba5845 Added documentation for packed pragma 2014-03-20 23:11:33 +01:00
Zahary Karadjov
09bda74e7d fix #1015 2014-03-20 23:45:31 +02:00
Zahary Karadjov
8ba062d952 fix #1016 2014-03-20 23:24:25 +02:00
Zahary Karadjov
f49f2f38f0 fix the handling of "msg" tests 2014-03-20 23:12:24 +02:00
Zahary Karadjov
b2aa70c6ef fix #1018
Previously, generic types originating from the same body symbol were compared
structurally. The bug illustrates a case, where such a comparison is not correct.
The new approach follows the established method used in typeRel.
2014-03-20 22:27:49 +02:00
Zahary Karadjov
8a0509b3b2 implements `distinct with/without X, Y`
This still doesn't work quite right, because some common operations like array
indexing lay completely outside the scope/symbol lookup system - they are not
even magics.
2014-03-20 01:16:50 +02:00
Zahary Karadjov
d508384d39 fix #1013 2014-03-20 01:16:50 +02:00
Zahary Karadjov
4b7655fd10 reference implementation of a vector swizzle library
This also provides the initial steps towards support for type class "filtered" type inference
fixes an "ordinal type expected" ICE, related to the use of static params
2014-03-20 01:16:50 +02:00
Andreas Rumpf
a66d059acc Merge pull request #1014 from skyfex/devel
Packed pragma and tests for packed and union pragma
2014-03-19 22:29:37 +01:00
Audun Wilhelmsen
ca228e46b5 Fix compilation error when using packed pragma with vcc. 2014-03-18 21:23:35 +01:00
Audun Wilhelmsen
1e45bb79ab Added support for {.packed.} pragma on objects
Added tests for packed and union pragmas
2014-03-18 21:11:57 +01:00
Andreas Rumpf
261a6ca017 Merge pull request #999 from zielmicha/zlib_abi_version
Provide zlib version explicitly on Linux.
2014-03-16 22:09:49 +01:00
Andreas Rumpf
c27fb4116e Merge pull request #1000 from gradha/pr_adds_likely_example_983
Adds example to likely/unlikely docstring. Refs #983.
2014-03-16 22:09:28 +01:00
Andreas Rumpf
9d4b77a65a Merge pull request #1003 from flaviut/devel
Add token position to `nimrod scan`
2014-03-16 22:08:43 +01:00
Zahary Karadjov
b3da0ab888 fix #1007 2014-03-16 21:44:21 +02:00
Zahary Karadjov
26890b6525 make some tests red :) (i.e. print failure details while running the tester) 2014-03-16 21:05:20 +02:00
Zahary Karadjov
49b0440c47 make some tests green 2014-03-16 20:42:49 +02:00
Zahary Karadjov
f0953db3ba handle arbitrary expressions dependent on static input params in proc signatures 2014-03-16 20:42:06 +02:00
Zahary Karadjov
da5d88f04e use g++ and clang++ automatically when compiling to C++ 2014-03-16 20:42:06 +02:00
Zahary Karadjov
ac271e76b1 more robust handling of proc signatures containing inter-param type references 2014-03-16 20:42:06 +02:00
Zahary Karadjov
7dcf6ff50b fix #997 2014-03-16 20:42:06 +02:00
Zahary Karadjov
27c2c1e75c fix #996 2014-03-16 20:42:06 +02:00
Zahary Karadjov
37b199d34a first phase of tyGenericParam reforms needed for static params 2014-03-16 20:42:06 +02:00
Zahary Karadjov
4d2c948281 fix #1001 2014-03-16 20:42:06 +02:00
Zahary Karadjov
cf8fe16a48 fix #715 again
the regression was caused by the introduction of "generic" lambdas
2014-03-16 20:42:06 +02:00
Zahary Karadjov
7080d02af4 allow multi-line expressions using the dot operator
this enables parsing of expressions like:

``` Nimrod
s.items
  .map(proc (x): auto = x * 2)
  .filter do (x) -> auto:
    return x % 2 == 0
  .group_by((x) => x.length)
```
2014-03-16 20:42:06 +02:00
Zahary Karadjov
63d93ad1ab grammar fix: allow free-standing expressions such as type(foo) is bar 2014-03-16 20:42:06 +02:00
Dominik Picheta
de64e8ec22 PFuture[void] now works.
Return types can also be completely ommitted. PFuture[void] will then be
implicitly deduced.
2014-03-15 00:11:01 +00:00
Dominik Picheta
0519afba1d Merge pull request #972 from Matthias247/ipaddress
Added a IpAddress structure to the net module
2014-03-14 21:27:00 +00:00
Matthias Einwag
95e4ab99e7 Make the IP address exceptions more detailed 2014-03-14 22:17:44 +01:00
Dominik Picheta
afb7dbf81a Fixes compilation of asyncio2 on Windows.
Added a close(PDispatcher, TSocketHandle) implementation which unregisters
the handle.
2014-03-14 20:18:51 +00:00
Dominik Picheta
1a75b17cd0 File descriptors are now removed from fds list explicitly in close().
Fixes tasyncawait on linux.
2014-03-14 18:46:08 +00:00
flaviut
5e47c18e3f Add token position to nimrod scan
A block of the format "linenum:col\t' is added to the start of each token that is printed.
2014-03-14 14:18:38 -04:00
Araq
3e056afb1c fixes #993 2014-03-13 22:29:48 +01:00
Grzegorz Adam Hankiewicz
dd18c0ddd5 Adds example to likely/unlikely docstring. Refs #983. 2014-03-13 19:56:11 +01:00
Michał Zieliński
a9bc8220fd Provide zlib version explicit on Linux.
- workaround for Gentoo (#987),
- also, it's a good practice to provide ABI version in calls to dlopen,
so if zlib ever changes ABI, wrappers won't break siliently.
2014-03-13 12:04:27 +01:00
Araq
1c35fb3c89 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-03-13 02:52:51 +01:00
Araq
2fc84325c7 should fix the nkExprColonExpr bug in the vm 2014-03-13 02:52:40 +01:00
Dominik Picheta
d2f130c3fc Fix compilation on linux. 2014-03-12 23:19:40 +00:00
Dominik Picheta
d97a397139 Fixed tasyncawait on Windows.
Implicit registration of an fd now only occurs when a new socket is
created (in socket() or accept()). This makes the implementation much
simpler, changes to the linux version will follow.
2014-03-12 20:42:36 +00:00
Dominik Picheta
15919b7c98 EOS exception now contains the error code. 2014-03-11 23:06:22 +00:00
Dominik Picheta
2ce07042fd tasyncawait now works on Linux.
Reworked detection of a file descriptor being closed with epoll (in the
case of sockets it is when the remote host disconnects). Ensured that
events are only updated when they change.
2014-03-11 21:53:35 +00:00
Zahary Karadjov
9b5357da5a Merge branch 'devel' of github.com:Araq/Nimrod into devel 2014-03-11 00:59:35 +02:00
Zahary Karadjov
71695ab791 fix tsemistatic 2014-03-11 00:58:27 +02:00
Araq
3270676e77 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-03-10 22:23:38 +01:00
Araq
121553d1a6 osproc compiles again for haiku 2014-03-10 17:32:50 +01:00
Zahary Karadjov
1546d210c5 fix #971 2014-03-10 18:13:48 +02:00
Zahary Karadjov
85fe5e1940 fix #988
trivial crash caused due to unchecked iteration over an empty reclist
2014-03-10 13:04:22 +02:00
Araq
d4714ed14e minor additions to the manual 2014-03-10 08:46:41 +01:00
Zahary Karadjov
d5798b43de fix #986 2014-03-10 01:57:08 +02:00
Zahary Karadjov
9fb0755572 further improvements for static generic params; activate the hardest test cases 2014-03-10 00:36:19 +02:00
Zahary Karadjov
45a345e93d fix #866; generic static params 2014-03-09 23:38:17 +02:00
Zahary Karadjov
3dcf735482 fix #909 2014-03-09 22:15:11 +02:00
Zahary Karadjov
29b7104a53 fix #829; (macros.quote)
the fix is a little bit peculiar:

the inserted call to getAst was getting a false-positive for being a lambda proc,
because lambdalifting.isInnerProc takes into account who is the owner of a given
symbol: (a nested proc is a callable symbol owned by the enclosing proc)
2014-03-09 21:04:12 +02:00
Zahary Karadjov
752352a683 fix #949 2014-03-09 20:47:05 +02:00
Zahary Karadjov
eebe0035b5 teach opcLdObj about nkExprColonExpr 2014-03-09 17:06:29 +02:00
Zahary Karadjov
1793a0b5ce Merge branch 'devel' of github.com:Araq/Nimrod into devel 2014-03-09 16:05:29 +02:00
Zahary Karadjov
5aa486cf11 few more fixes for static params in macros; new failing test cases for static evaluation 2014-03-09 16:04:58 +02:00
Dominik Picheta
a097526956 Fixes to asyncio2 on Linux. 2014-03-09 13:49:38 +00:00
Zahary Karadjov
5820093e58 Merge branch 'devel' of github.com:Araq/Nimrod into devel 2014-03-09 14:02:16 +02:00
Zahary Karadjov
4b09a89758 fix #966
test for ``map`` defined as inline iterator
2014-03-09 14:02:01 +02:00
Matthias Einwag
7b055388b7 raise exceptions through newException 2014-03-09 11:47:22 +01:00
Zahary Karadjov
518b794491 implicit auto return type for inline iterators 2014-03-08 23:27:33 +02:00
Zahary Karadjov
085b339b8b implements higher-order inline iterators and return type inference for iterators 2014-03-08 22:57:06 +02:00
Andreas Rumpf
7704cdc90e Merge pull request #981 from Varriount/tester/enhanced-json-output
Tester now outputs all the test results of the current test run to json.
2014-03-08 21:51:55 +01:00
Clay Sweetser
5f19af9e01 Removed debug code 2014-03-08 14:30:05 -05:00
Andreas Rumpf
edfcbab86f Merge pull request #899 from Leu-Gim/master
Fixes passing non-default host and port to db_mysql.Open.
2014-03-08 10:46:39 +01:00
Andreas Rumpf
aaa13c0011 Merge pull request #979 from EXetoC/alloc-overloads
More updates to the allocation interface
2014-03-08 10:33:13 +01:00
Clay Sweetser
71de5ea909 Tester now outputs all the test results of the current test run to json. 2014-03-07 17:50:57 -05:00
Araq
dd216755ff Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-03-07 22:28:48 +01:00
Araq
91d842e1ec implements strongSpaces parsing mode 2014-03-07 22:25:05 +01:00
EXetoC
3147f7f6c2 Use 'Natural' or 'Positive' instead of 'int' where applicable. 2014-03-07 01:32:07 +01:00
EXetoC
c7b83d2c44 Update unit test. 2014-03-07 01:09:16 +01:00
EXetoC
5b7e44f0aa create -> createU, create0 -> create. 2014-03-07 01:00:18 +01:00
EXetoC
61e5435081 Update unit test. 2014-03-07 00:36:58 +01:00
EXetoC
5e78baa061 Use separate names for type-based allocation procs rather than overloading. 2014-03-07 00:34:44 +01:00
EXetoC
90e326504b Update test with new names. 2014-03-07 00:09:43 +01:00
EXetoC
3ae21ea48e Better names. 2014-03-07 00:09:23 +01:00
Zahary Karadjov
2cbe46daff Merge branch 'devel' of github.com:Araq/Nimrod into devel 2014-03-06 23:25:45 +02:00
Zahary Karadjov
ee1b0d8c67 fix #587 2014-03-06 23:25:04 +02:00
Andreas Rumpf
7500a5ea0b Merge pull request #978 from ReneSac/devel
Added comment explaining 'assert_numbits' error.
2014-03-06 22:24:52 +01:00
ReneSac
a88a635847 Added comment explaining 'assert_numbits' error. 2014-03-06 18:18:25 -03:00
Zahary Karadjov
249dd70273 test cases for the new handling of iterators by the is operator 2014-03-06 23:03:02 +02:00
Andreas Rumpf
9e989676d8 Merge pull request #975 from zielmicha/zmq-fix
zmq: remove unnecessary 'var' decls from high-level procs
2014-03-06 21:07:02 +01:00
Zahary Karadjov
862c0ef83d split the inline and closure iterators into different symbol kinds for easier discrimination between them 2014-03-06 21:57:35 +02:00
zah
d786974a45 Merge pull request #977 from EXetoC/alloc-overloads
Allocation overloads
2014-03-06 15:30:19 +02:00
EXetoC
d1bc6cf098 Merge branch 'devel' into alloc-overloads 2014-03-06 02:46:31 +01:00
EXetoC
853bdbf494 Add allocation unit tests. 2014-03-06 02:45:55 +01:00
EXetoC
bbd245b47b Add missing cast. 2014-03-06 02:43:05 +01:00
EXetoC
6a83a5e468 Add type-specific allocation procs. 2014-03-06 01:12:18 +01:00
Araq
7904446c47 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-03-05 21:30:13 +01:00
Araq
c5db5875f7 system.nim makes use of the 'unchecked' pragma 2014-03-05 21:30:02 +01:00
Araq
5506e8491d implemented 'union' and 'unchecked' pragmas 2014-03-05 20:19:04 +01:00
Araq
a066e4e5c5 c2nim knows about the 'union' pragma 2014-03-05 20:05:05 +01:00
Michał Zieliński
6e42513acd zmq: remove unnecessary 'var' decls from high-level procs 2014-03-05 18:31:22 +01:00
Simon Hafner
d944e09eb9 Merge pull request #974 from ninjin/devel
No execute bit for csources build.sh, fixing doc
2014-03-05 09:55:13 -06:00
Pontus Stenetorp
b0625d2aa3 No execute bit for c-sources build.sh, fixing doc 2014-03-05 18:36:59 +09:00
Araq
3dfb4891c7 bugfix: unreported 'compiles' bug 2014-03-05 08:47:27 +01:00
Araq
4f946cb44e fixes #942 2014-03-05 08:30:05 +01:00
Araq
94e444c90f Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-03-05 02:15:08 +01:00
Araq
aa92669d92 fixes #937 2014-03-05 02:14:53 +01:00
Zahary Karadjov
5324c9ebba iterators now return tyIter(T);
tyIter(T) represents an "iteration yielding values of type T"

I'm planning to use that in the context of the `is` operator
supporting predicates such as `C.items is iterator` and also
in the upcoming support for higher-order inline iterators.
2014-03-05 02:23:53 +02:00
Matthias Einwag
74d51a7700 $ for TIpAddress now prints in the recommended format 2014-03-04 23:02:23 +01:00
Matthias Einwag
0f88ee7d0c Use character ranges from strutils. 2014-03-04 22:41:53 +01:00
Zahary Karadjov
016492375f failing test case for static evaluation 2014-03-04 22:38:43 +02:00
Araq
1ce30b9e10 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-03-04 16:41:37 +01:00
Varriount
ab0fea9199 Changed behavior when babel cannot be found/run
Failure to find and run babel when using the tester now produces a warning message instead of causing the tester to quit.
2014-03-04 10:10:00 -05:00
Araq
ed5bbfe36d fixes #968 2014-03-04 08:31:11 +01:00
Araq
7918c30b90 removed dead code 2014-03-04 08:30:11 +01:00
Araq
f54556518e don't produce nested indents for nested stmt lists 2014-03-04 08:29:41 +01:00
Matthias Einwag
e328d015f1 Added a IpAddress structure to the net module 2014-03-04 00:49:08 +01:00
Varriount
af31f19ebb Fix categories.nim 2014-03-03 18:43:41 -05:00
Andreas Rumpf
5009ea56c0 Merge pull request #970 from Varriount/testament/babel-integration
Integrated 'babel' with testament
2014-03-04 00:24:40 +01:00
Clay Sweetser
9620893d72 Allowed specification of what babel packages to install via new categories - 'babel-core', 'babel-extra', and 'babel-all' 2014-03-03 17:53:47 -05:00
Clay Sweetser
269bf8e334 Removed babel package tests from those run when 'all' is specified. 2014-03-03 06:26:22 -05:00
Araq
74549c327e added a warning for htmlgen 2014-03-03 08:17:51 +01:00
Andreas Rumpf
835926e174 Merge pull request #927 from gradha/pr_adds_posix_timegm
Adds posix.timegm(), brother of posix.mktime().
2014-03-03 01:00:44 +01:00
Andreas Rumpf
bc8ec5b6b4 Merge pull request #969 from gradha/pr_avoids_crash_on_unknown_rst_directive
Avoids crash parsing unknown rst raw directive. Fixes #761.
2014-03-03 00:30:35 +01:00
Araq
dfeb0e8432 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-03-02 23:46:32 +01:00
Araq
614557994e the compiler is now aware of packages 2014-03-02 23:46:20 +01:00
Clay Sweetser
3249f16d85 Integrated 'babel' with testament 2014-03-02 17:21:42 -05:00
Grzegorz Adam Hankiewicz
d8793dcf56 Avoids crash parsing unknown rst raw directive. Fixes #761. 2014-03-02 23:15:30 +01:00
Araq
c55f5b34ee better handling of packages, still incomplete 2014-03-02 15:41:53 +01:00
Araq
d4263b1012 bugfix: walkFiles on windows shouldn't yield directories 2014-03-02 11:15:31 +01:00
Dominik Picheta
0d263f155b Fixes sockets2 on Windows. 2014-02-28 19:31:12 +00:00
Andreas Rumpf
25f6e0c681 Merge pull request #963 from zielmicha/wait-for-exit-doc
osproc: add warning about using waitForExit without poParentStreams
2014-02-27 23:39:16 +01:00
Andreas Rumpf
393706498e Merge pull request #962 from barcharcraz/vstweaks
added another version of initGeneralTokenizer
2014-02-27 23:38:53 +01:00
Araq
c4f9c3b53e tstmtexprs.nim works again 2014-02-27 23:28:15 +01:00
Araq
f0a70c7aae xmltree.<> macro works again 2014-02-27 20:47:44 +01:00
Araq
d828b0b96e some progress on the new name mangler 2014-02-27 20:43:10 +01:00
Araq
2f692dcc3a make C backend more robust against compiler bugs 2014-02-27 20:39:34 +01:00
Araq
e1600f209f nil -> discard 2014-02-27 20:29:02 +01:00
Araq
8a4138da55 fixed typo in error message 2014-02-27 20:28:41 +01:00
Michał Zieliński
f4371bfef8 osproc: add warning about using waitForExit without poParentStreams 2014-02-27 19:52:04 +01:00
Charlie Barto
a79579da6f added an overload for highlight.initGeneralTokenizer that accepts a cstring.
I use this when calling the highlighter from C#.
2014-02-26 22:25:02 -05:00
Araq
2b271e7b17 renamed TRegister to TFullReg so that older versions can compile it 2014-02-26 06:29:22 +01:00
Araq
384a018906 htmlgen works again 2014-02-25 21:30:18 +01:00
Araq
ad79b125e7 bootstrapping should work again 2014-02-25 18:08:40 +01:00
Araq
b7bb56bdca made some tests green; htmlgen still broken 2014-02-25 08:41:29 +01:00
Araq
3a2e1ce538 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-02-25 01:29:12 +01:00
Araq
20131c32af Merge branch 'vm2_2' into devel 2014-02-25 01:21:00 +01:00
Zahary Karadjov
b677110bd6 rename compilerProcs to match the recently changed jssys.nim 2014-02-25 02:16:57 +02:00
Araq
10768904eb Merge branch 'devel' of https://github.com/Araq/Nimrod into devel
Conflicts:
	lib/system/jssys.nim
2014-02-25 01:06:35 +01:00
Araq
263cabd1c2 added canonizer 2014-02-25 01:02:10 +01:00
Araq
4c26c3a428 bugfix: typo 2014-02-25 00:40:21 +01:00
Zahary Karadjov
e6b0b7ecc9 some fixes for static params usage in macros 2014-02-25 01:36:08 +02:00
Andreas Rumpf
1024e7a3db Merge pull request #957 from zielmicha/macosx-fix
osproc: MacOSX workaround for lack of execvpe
2014-02-24 20:28:57 +01:00
Michał Zieliński
7314f11adc osproc: MacOSX fix - if -> when 2014-02-24 17:45:45 +01:00
Michał Zieliński
30a3098095 osproc: MacOSX workaround for lack of execvpe 2014-02-24 17:01:00 +01:00
Araq
b320e02903 keine_schweine test is not platform dependent 2014-02-24 16:41:26 +01:00
Araq
0c31686fec new VM is getting stable 2014-02-24 01:30:40 +01:00
Andreas Rumpf
00b69192f2 Merge pull request #953 from zielmicha/vfork
osproc: increase stack size from 8k to 64k and disable useClone default
2014-02-23 21:43:00 +01:00
Michał Zieliński
6712aa6e38 osproc: use fork by default on Linux, clone if requested by useClone flag 2014-02-23 21:06:40 +01:00
Michał Zieliński
95eb2b88e6 osproc: increase stack size from 8k to 64k 2014-02-23 21:01:03 +01:00
Andreas Rumpf
46967f921a Merge pull request #917 from zielmicha/vfork
osproc: Raise exception if execv fails in child process
2014-02-23 19:49:19 +01:00
Andreas Rumpf
6b945139e0 Merge pull request #951 from skyfex/devel
Tests and fixes for return in except and finally statements
2014-02-23 11:34:08 +01:00
Andreas Rumpf
587f94f85b Merge pull request #946 from gradha/pr_documents_readall
Documents system.readAll() limitations. Refs #298.
2014-02-23 11:29:46 +01:00
Audun Wilhelmsen
1250db5075 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-02-23 00:26:46 +01:00
Audun Wilhelmsen
739b4f214b Fixed #688 : return in except statments. Also fixed return in finally statements. 2014-02-23 00:23:06 +01:00
Audun Wilhelmsen
ef379d0a10 Added test cases for return in except statements. 2014-02-23 00:20:16 +01:00
Audun Wilhelmsen
66675d174b Added tougher test case for return within finally statement. 2014-02-23 00:19:18 +01:00
Dominik Picheta
3b5825e9bc Implemented selector support for asyncio2. 2014-02-22 17:22:19 +00:00
Andreas Rumpf
ed4f2f5e4d Merge pull request #947 from gradha/pr_checks_bad_exported_symbols_800
Checks that exported symbols are valid C identifiers. Refs #800.
2014-02-22 10:50:22 +01:00
Andreas Rumpf
b89c8df35e Merge pull request #948 from h3rald/patch-1
pegs.findAll iterator fix
2014-02-22 10:45:25 +01:00
Grzegorz Adam Hankiewicz
3aa7f65240 Addresses issues raised on #947. Refs #800.
* Uses errGenerated instead of deprecated extending of enums.
* Reduces bloat and usefulness of end user error messages.
* Limits checks to C, Cpp and Objc targets.
2014-02-22 10:21:24 +01:00
Fabio Cevasco
067c3816ba Rewrote the changes to findAll using if/else 2014-02-22 10:07:37 +01:00
Araq
efc21baeb9 simple macros work again 2014-02-22 01:37:34 +01:00
Araq
ee74706c3b fixed opcConv 2014-02-22 01:09:43 +01:00
Araq
6e584c42c2 vm2: new representation of registers 2014-02-21 17:23:37 +01:00
Fabio Cevasco
6621454dec pegs.findAll iterator fix
Modified the findAll iterator so that it continues looking for a match within the input string (bug?).
2014-02-21 14:14:43 +01:00
Grzegorz Adam Hankiewicz
adb390af4b Checks that exported symbols are valid C identifiers. Refs #800. 2014-02-21 00:32:28 +01:00
Grzegorz Adam Hankiewicz
12c95f31dc Documents system.readAll() limitations. Refs #298. 2014-02-20 23:32:03 +01:00
Zahary Karadjov
1a6d05515f fix #945 2014-02-20 23:33:58 +02:00
Michał Zieliński
1f376d8594 osproc: use push stacktrace:off instead of nostackframe 2014-02-18 20:22:40 +01:00
Zahary Karadjov
0bbf6081d0 fix #931 and few more tests 2014-02-18 20:04:58 +02:00
Araq
ab72377ce6 renamed noStackFrame to asmNoStackFrame 2014-02-18 09:57:59 +01:00
Zahary Karadjov
f13a836972 Merge branch 'devel' of gh:/Araq/Nimrod into devel 2014-02-18 02:46:49 +02:00
Zahary Karadjov
cda92048ba fix some trivial errors in the test suite and some more regressions caused by tyTypeDesc[tyNone] 2014-02-18 02:46:14 +02:00
Dominik Picheta
15953dfed9 Make ticker title consistent. 2014-02-18 00:27:40 +00:00
Dominik Picheta
4ef62584da Merge branch 'devel' of github.com:Araq/Nimrod into devel 2014-02-18 00:19:01 +00:00
Dominik Picheta
866205cba4 Added google analytics to website. 2014-02-18 00:18:34 +00:00
Dominik Picheta
1ac7f36952 Fix line-height for h1 in website. 2014-02-18 00:08:31 +00:00
Dominik Picheta
4cd558bdad Improved community page and fixed ticker links. 2014-02-18 00:04:09 +00:00
Andreas Rumpf
c41687237d Merge pull request #897 from micklat/devel
dynlib: optionally pass RTLD_GLOBAL to dlopen
2014-02-18 01:00:37 +01:00
Araq
5036852938 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-02-18 00:39:37 +01:00
Zahary Karadjov
4d3846e26b fix tbindtypedesc and tactiontable2 2014-02-18 01:37:00 +02:00
Dominik Picheta
b01945a061 Modified website news titles and made ticker titles consistent. 2014-02-17 23:22:29 +00:00
Zahary Karadjov
765c682c92 fix #204; 2014-02-18 01:19:31 +02:00
Andreas Rumpf
c484bf6ee4 Merge pull request #934 from vocalbit/devel
Add two news items to website.
2014-02-18 00:04:24 +01:00
Araq
9b63fccf16 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-02-17 23:59:48 +01:00
Araq
420d4197f1 todo.txt changes 2014-02-17 23:59:32 +01:00
Zahary Karadjov
eaab22089d fix #807 2014-02-17 20:44:11 +02:00
vocalbit
6c908fbaf1 Make ticker puntuation consistent. 2014-02-17 00:48:21 -08:00
vocalbit
a6c825709c Fix website news formatting and grammar to be consistent. 2014-02-17 00:47:05 -08:00
vocalbit
eb3958f1b9 Add two news items to website. 2014-02-17 00:35:35 -08:00
Araq
14bdedb0f7 got rid of debugging code 2014-02-17 08:27:16 +01:00
Araq
3ec2973875 fixes #926 2014-02-17 08:26:44 +01:00
Araq
350a49cc26 fixes #923 2014-02-17 07:52:41 +01:00
Zahary Karadjov
9dd753f218 quite messy implementation of generic lambdas, needs reworking; fixes #715 2014-02-17 03:03:17 +02:00
Zahary Karadjov
9a41db7d7a Merge branch 'devel' of gh:/Araq/Nimrod into devel 2014-02-17 00:48:10 +02:00
Zahary Karadjov
b80503814d fix #188 2014-02-17 00:47:45 +02:00
Dominik Picheta
5cd9b035b4 Merge branch 'newasync' into devel 2014-02-16 20:03:58 +00:00
Dominik Picheta
17ef758cc3 Fix processing of 'await' with a nnkCall.
Specifically, ``discard readMessages(disp, await disp.accept(server))``
works now, i.e. using 'await' as one of the params to a proc call.
2014-02-16 19:56:17 +00:00
Araq
3ef92a34ee fixes #922 2014-02-16 19:17:12 +01:00
Dominik Picheta
cac39b27cf Added await test. 2014-02-16 13:55:38 +00:00
Dominik Picheta
7d2ed73a62 Fixes issues with 'discard' in async macro. 2014-02-16 13:55:06 +00:00
Andreas Rumpf
6f9b0fe712 Merge pull request #921 from gradha/pr_improves_times_format
Improves times.format parsing, fixes #740
2014-02-16 11:56:51 +01:00
Andreas Rumpf
f5c0d07a76 Merge pull request #929 from skyfex/devel
Fixed issue 391 (nested break in except-stmts)
2014-02-16 11:36:08 +01:00
Andreas Rumpf
18c47b9e13 Merge pull request #928 from Varriount/testement/nil-to-discard
Changed tests and tools to use 'discard' statements
2014-02-16 11:31:03 +01:00
Audun Wilhelmsen
8cccaebc2e Fixed issue 391 (nested break in except-stmts) 2014-02-16 02:08:36 +01:00
Zahary Karadjov
74f4901430 fix argument_parser 2014-02-16 02:23:06 +02:00
Clay Sweetser
ce5a494927 Changed tests and tools to use 'discard' statements instead of 'nil' for empty blocks. 2014-02-15 18:57:03 -05:00
Araq
228d5173ff nil->discard 2014-02-15 23:40:29 +01:00
Dominik Picheta
fb7598d25a Async readLine now works. Fixes recv issues.
When using MSG_PEEK and data is retrieved ``lpNumberOfBytesRecvd`` will
not be set to the number of bytes read by WSARecv. The buffer must
therefore be checked to ensure it's empty when determining whether
``recv`` shall return "" to signal disconnection as we want to read as
much data as has been received by the system.
2014-02-15 21:13:23 +00:00
Zahary Karadjov
f701ee086a Merge branch 'devel' of gh:/Araq/Nimrod into devel 2014-02-15 20:46:54 +02:00
Zahary Karadjov
c1f1f84194 fix some regressions caused by tyTypeDesc[tyNone] 2014-02-15 20:44:01 +02:00
Zahary Karadjov
c1c6b6e50e handle nested case objects in destructor generation 2014-02-15 19:05:58 +02:00
Grzegorz Adam Hankiewicz
c2b50c0e38 Adds posix.timegm(), brother of posix.mktime(). 2014-02-15 17:50:40 +01:00
Zahary Karadjov
492fa86638 the delegator pragma becomes a set of dot operators 2014-02-15 17:41:35 +02:00
Dominik Picheta
de8d473301 Fixed problems with IOCP procs finishing immediately, added await macro. 2014-02-15 14:15:18 +00:00
Michał Zieliński
4c09fc110f osproc: make failed execv an exception (when using fork or clone)
startProcessAuxFork creates a pipe, which is used by a child to pass
an error code if execv fails.
2014-02-15 15:09:06 +01:00
Grzegorz Adam Hankiewicz
293f356420 Supports parsing format times without separators. Refs #740. 2014-02-15 11:20:00 +01:00
Grzegorz Adam Hankiewicz
bd9e9acdaa Splits token parsing case into separate proc. Refs #740. 2014-02-15 11:02:13 +01:00
Araq
d142824d65 made 'koch web' work when current dir has a space in it 2014-02-15 02:27:49 +01:00
Araq
8637e47219 actors.nim compiles again 2014-02-15 02:27:09 +01:00
Dominik Picheta
66b0582a0b Merge branch 'devel' into newasync 2014-02-14 23:57:10 +00:00
Araq
2b9311e9f1 fixes #584 2014-02-14 23:47:06 +01:00
Araq
cf544f6a85 fixes #811 2014-02-14 22:37:36 +01:00
Araq
f95a8df243 fixes #811 2014-02-14 22:19:40 +01:00
Michał Zieliński
cd2bd7fa7b osproc: use clone with CLONE_VM on Linux for faster process spawning 2014-02-14 15:50:28 +01:00
Araq
49fa421ba7 fixes #914 2014-02-14 15:49:44 +01:00
Araq
09c8a51348 bugfix: 'system' on windows is sane 2014-02-14 15:46:30 +01:00
Araq
e210b049e9 fixes #712 2014-02-14 02:29:19 +01:00
Araq
f2216b8e32 fixes #833 2014-02-14 02:12:07 +01:00
Araq
896c96134f fixes #892 2014-02-14 02:02:01 +01:00
Araq
a5efe84921 nil->discard 2014-02-14 01:53:47 +01:00
Araq
5cc8213950 koch install should work now as documented 2014-02-14 00:16:52 +01:00
Araq
5d4c048705 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-02-13 21:30:11 +01:00
Araq
f637c36a7a the tester now produces a diff in the JSON 2014-02-13 21:29:50 +01:00
Araq
4dae4fafe9 edited compiler's config 2014-02-13 21:21:17 +01:00
Simon Hafner
7a3106d659 moved tsets test to collections/ 2014-02-12 16:15:34 -06:00
Dominik Picheta
2fa22078b8 Merge branch 'devel' into newasync 2014-02-12 21:29:56 +00:00
Dominik Picheta
6a65d1c515 newProc can now be used to construct iterator defs. 2014-02-12 21:28:17 +00:00
Dominik Picheta
7e7f5a6927 Rename PFutureVoid to PFutureBase. 2014-02-12 21:27:00 +00:00
Dominik Picheta
b3a0906619 Merge branch 'devel' into newasync 2014-02-11 23:50:58 +00:00
Dominik Picheta
02cf019ab6 Fixes macros.len crashing on nodes which lack the sons field. 2014-02-11 23:50:09 +00:00
Simon Hafner
33fcd11236 add a trailing zero to $float 2014-02-11 17:46:34 -06:00
Simon Hafner
4b09baa0a0 use .f instead of .16e for floats
It doesn't write a trailing zero, but it's better than floats being all
over your screen.
2014-02-11 15:06:24 -06:00
Simon Hafner
565031f0cd removed $ for openarray, was commented out 2014-02-11 14:21:20 -06:00
Simon Hafner
b6e4a5229d explicit firstElement for $ in collections 2014-02-11 14:20:55 -06:00
Simon Hafner
f6e8da4332 Added $ for seq 2014-02-11 14:16:12 -06:00
Araq
232af9de6c fixes #612 2014-02-11 16:32:02 +01:00
Zahary Karadjov
a158053ae9 fixes #797; generic procs can be used in places expecting matching concrete proc types 2014-02-11 01:14:57 +02:00
Simon Hafner
e8c87d070a fixed a bug in map for sets 2014-02-10 13:02:47 -06:00
Simon Hafner
56c41ae140 added tests for set 2014-02-10 12:45:00 -06:00
Simon Hafner
0b5c14962e added map to sets 2014-02-10 12:44:44 -06:00
Araq
007d17ce3f more things case consistent 2014-02-10 17:12:25 +01:00
Miguel
51d2384e1a Fix for db_mysql.Open. 'Connection' argument in 'Open' was not used, so MySQL host and port were always default ones. Now 'Connection' is treated as 'host:port'. 2014-02-10 18:41:39 +04:00
Michał Zieliński
87abc22cc3 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-02-10 14:40:18 +01:00
Micky Latowicki
9ce775f468 dynlib: optionally pass RTLD_GLOBAL to dlopen 2014-02-10 09:30:21 +02:00
Miguel
a6186fa486 Merge branch 'devel' of git://github.com/Araq/Nimrod 2014-02-10 05:16:39 +04:00
Araq
5d93957048 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-02-10 00:52:12 +01:00
Araq
5b6e42c94f fixes #889 2014-02-10 00:52:01 +01:00
Andreas Rumpf
c1707e920e Merge pull request #867 from reactormonk/no_explicit_return
removed explicit return in the documentation
2014-02-10 00:22:50 +01:00
Andreas Rumpf
c8df0e312a Merge pull request #896 from reactormonk/set_fix
Set fix. fixes #887
2014-02-10 00:21:46 +01:00
Araq
b9c0a4addc nofoward doesn't exist yet; fixes #890 2014-02-10 00:16:29 +01:00
Simon Hafner
93f2af1cb3 fixes #887 2014-02-09 17:06:23 -06:00
Simon Hafner
0779d96a83 moved the tests for TSet to the correct place 2014-02-09 17:04:00 -06:00
Miguel
eb9964fbbb Merge branch 'devel' of git://github.com/Araq/Nimrod 2014-02-10 01:20:42 +04:00
Dominik Picheta
728be67afb Resolved conflict. 2014-02-09 21:05:02 +00:00
Dominik Picheta
f0b4be275f Merge branch 'devel' into newasync 2014-02-09 21:00:05 +00:00
Araq
e478374e0d capturing of an iterator works better 2014-02-09 21:47:46 +01:00
Michał Zieliński
820fdd6348 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-02-09 15:34:18 +01:00
Araq
f51a4ece6a Merge branch 'newasync' of https://github.com/Araq/Nimrod into devel 2014-02-09 09:37:24 +01:00
Dominik Picheta
3dec6483e7 Merge branch 'devel' of github.com:Araq/Nimrod into newasync 2014-02-09 02:44:59 +00:00
Araq
e6a50307bb fixes #885 2014-02-09 02:37:49 +01:00
Araq
ac3bce79d1 compiles on sparc again 2014-02-09 01:34:17 +01:00
Araq
783095a100 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-02-09 00:58:30 +01:00
Araq
0965351792 fixes #882; fixes #853 2014-02-09 00:58:18 +01:00
Araq
dbc8aa60e3 fixes 'newSeq[T]' instantiation bug 2014-02-09 00:41:53 +01:00
Dominik Picheta
76e8efe36e Added a generic-lacking version of PFuture. 2014-02-08 22:59:40 +00:00
Dominik Picheta
eedf51e9d1 Added new sockets modules: asyncio2, net, and sockets2. 2014-02-08 16:08:03 +00:00
Dominik Picheta
a3f3efa1ba Merge branch 'devel' into newasync 2014-02-08 15:59:42 +00:00
Andreas Rumpf
a70235daaa Merge pull request #877 from EXetoC/times-symbol-export
Export procs that are useful elsewhere.
2014-02-07 19:10:29 +01:00
Araq
c3adc19f47 tester compiles again 2014-02-07 18:49:41 +01:00
Araq
d07d83d8fc Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-02-07 18:21:25 +01:00
Araq
a087f6057e bugfix: codegen issue that caused getGMTime() to leak memory 2014-02-07 17:06:20 +01:00
Simon Hafner
5498415f3b indexBy, which indexes a collection into a hashtable 2014-02-06 16:11:55 -06:00
Simon Hafner
75f232eb6e removed unittest from talgorithm 2014-02-06 14:55:05 -06:00
EXetoC
38e4dfc164 Export procs that are useful elsewhere. 2014-02-06 14:18:44 +01:00
Andreas Rumpf
afb7bc0e63 Merge pull request #875 from EXetoC/mongo
A first attempt at fixing the MongoDB modules.
2014-02-06 02:46:19 +01:00
Andreas Rumpf
902a40ffcc Merge pull request #876 from superfunc/devel
Fixed typo's in tutorial 2
2014-02-06 02:45:16 +01:00
Araq
3be07d842a fixes regression: constant fac4 didn't work 2014-02-06 02:41:53 +01:00
superfunc
f05acd9612 Fixed typo's in tutorial 2 2014-02-05 16:56:43 -08:00
Araq
cc0a32ae87 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-02-06 00:27:10 +01:00
Araq
550b5d9aea stdlib compiles mostly without warnings again 2014-02-06 00:27:01 +01:00
Araq
8215a32edd case consistency for -d:useWinAnsi 2014-02-05 23:46:55 +01:00
Araq
d912d18379 tyTypeDesc and tyRange always have 1 child; this might be tyNone but it is required for skipTypes 2014-02-05 23:43:13 +01:00
Simon Hafner
fb85d6062a tracked down a few more returns 2014-02-05 13:14:08 -06:00
Araq
c097acedd3 bugfix: immediate templates are preferred consistently (danger: breaks code) 2014-02-04 17:29:34 +01:00
zah
672681dd4b Merge pull request #870 from barcharcraz/templaterr
Added better error messages for ill-formed generics
2014-02-04 01:17:15 -08:00
Charlie Barto
7cfec91057 deleted assert that would never fire because it turned into an error message 2014-02-04 00:07:17 -05:00
Charlie Barto
51076a0be6 added good error for stuff like string[int] or int[int] 2014-02-03 23:54:01 -05:00
Simon Hafner
a90f0f50cf removed explicit return in the documentation 2014-02-03 12:40:51 -06:00
Araq
96e616198d Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-02-03 19:03:40 +01:00
Andreas Rumpf
866cfb9bb8 Merge pull request #865 from ReneSac/devel
Additions to the language manual and tests of new procedure call syntax.
2014-02-03 10:03:07 -08:00
Araq
a2fce822dc Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-02-03 19:00:17 +01:00
Araq
c69d167fa9 updated todo.txt 2014-02-03 19:00:05 +01:00
Araq
99352c1e4c macro tests almost green 2014-02-03 17:35:03 +01:00
ReneSac
5bd3ec0bfb Remove spurious import added in the last commit. 2014-02-03 01:12:27 -02:00
ReneSac
300c0376b5 Fix optarg() and added two more tests.
One for 'do notation' in a single function in an expression, another the trick of using the method call syntax to pass two parameters.
2014-02-03 01:06:19 -02:00
ReneSac
db031e2b47 Expandeded part about different proc call syntaxes. 2014-02-03 01:00:01 -02:00
Andreas Rumpf
7b3f95d810 Merge pull request #864 from gradha/pr_adds_posix_utimes
Adds utimes() importc to posix module.
2014-02-02 16:18:20 -08:00
Andreas Rumpf
e75814da67 Merge pull request #862 from gradha/pr_mentions_exportc_limits
Mentions {.exportc.} limits. Refs #826.
2014-02-02 16:17:03 -08:00
Grzegorz Adam Hankiewicz
52d4e07146 Adds utimes() importc to posix module. 2014-02-02 23:28:17 +01:00
Grzegorz Adam Hankiewicz
92e3f667bd Mentions {.exportc.} limits. Refs #826. 2014-02-02 17:59:17 +01:00
Grzegorz Adam Hankiewicz
ea42682dbc Merge pull request #846 from gradha/pr_adds_mapit_templates
Adds convenience mapIt templates to sequtils.
2014-02-02 08:47:42 -08:00
Grzegorz Adam Hankiewicz
700f32e814 Adds convenience mapIt templates. 2014-02-02 17:37:06 +01:00
Araq
c30f6cfcf1 cleaned up command expressions 2014-02-02 14:34:37 +01:00
Araq
7196c7637e bootstraps again 2014-02-02 10:07:29 +01:00
Araq
48888b9034 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-02-02 10:00:22 +01:00
Araq
47e4f9698c fixes #844 2014-02-02 10:00:10 +01:00
Andreas Rumpf
20cf73669d Merge pull request #861 from Varriount/os/add-linkprocs-prettyplease
Added symlink procs
2014-02-01 18:06:06 -08:00
Araq
4b94aba6de fixes #735 2014-02-02 03:03:38 +01:00
Clay Sweetser
7cd5e79464 Added symlink procs 2014-02-01 20:56:34 -05:00
EXetoC
798295a9b6 A first attempt at fixing the MongoDB modules. 2014-02-02 02:22:42 +01:00
Dominik Picheta
69bc077937 Fixes docgen for logging module. 2014-02-02 01:01:12 +00:00
Araq
ef44d90c8d Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-02-02 01:58:17 +01:00
Araq
eeae68f9e4 added the parts of #541 that I like 2014-02-02 01:57:56 +01:00
Andreas Rumpf
925d19a8fb Merge pull request #859 from reactormonk/sets_equivalence
sets equivalence
2014-02-01 16:46:45 -08:00
Simon Hafner
6fda10aed0 added test specs for the tester 2014-02-01 18:39:39 -06:00
Araq
561f6c2d2f Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-02-02 01:38:40 +01:00
Araq
435610e0af merged #823 against devel 2014-02-02 01:38:19 +01:00
Araq
38db937193 merged #811 against devel 2014-02-02 01:22:31 +01:00
Andreas Rumpf
087448d167 Merge pull request #830 from zielmicha/osproc
osproc: introduce poEvalCommand, poUsePath, fix remaining quoting issues.
2014-02-01 16:11:09 -08:00
Andreas Rumpf
8fa4401b20 Merge pull request #834 from gradha/pr_adds_strutils_const
Adds AllChars constant to strutils.
2014-02-01 16:08:58 -08:00
Araq
200102580b Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-02-02 01:07:44 +01:00
Araq
b96aa59aef merge issue #707 by hand 2014-02-02 01:07:02 +01:00
Andreas Rumpf
602723f894 Merge pull request #855 from gradha/pr_fixes_try_insert_id
Avoids raising exceptions in tryInsertID.
2014-02-01 15:56:19 -08:00
Andreas Rumpf
fccb0170d4 Merge pull request #843 from gradha/pr_gc_docs
Adds note about manual memory handling to GC doc.
2014-02-01 15:55:55 -08:00
Araq
efcbaa965e remove the old tester 2014-02-02 00:45:47 +01:00
Araq
d29aa4c5ac new tester produces json output 2014-02-02 00:41:04 +01:00
Araq
38697234f6 mark and sweep GC compiles with --cs:partial 2014-02-02 00:35:26 +01:00
Araq
a5098f1fda fixed cases 2014-02-02 00:03:57 +01:00
Araq
3b5c0b27ce case consistency for excpt.nim 2014-02-02 00:03:30 +01:00
Araq
4b47bee654 deactivated debug output 2014-02-02 00:02:57 +01:00
Araq
43d1181c04 year 2014 2014-02-02 00:02:39 +01:00
Araq
7fe340e7bc year 2014 2014-02-02 00:02:08 +01:00
Araq
e647428539 case consistency for dynlib.nim 2014-02-02 00:01:33 +01:00
Araq
70eff919cd only 1 argument allowed for command expressions 2014-02-02 00:00:56 +01:00
Araq
bd9f6505c1 'discard' instead of 'nil' for system.nim 2014-02-02 00:00:17 +01:00
Araq
0b8f68def0 tstringinterp almost working 2014-02-01 23:58:20 +01:00
Araq
31f3034c3a case consistency for evalffi 2014-02-01 23:57:09 +01:00
Araq
68d8cd1301 case consistency for evalffi 2014-02-01 23:56:32 +01:00
Simon Hafner
9f29bb8d9e corrected docs and tests 2014-02-01 16:07:44 -06:00
Dominik Picheta
f9c2ec8d92 Fixes wrong slurp path in tester. 2014-02-01 14:57:52 +00:00
Araq
6d62503e5d documented new symbol binding rules for templates 2014-02-01 13:39:40 +01:00
Araq
d8d93218fa bugfix: object constructor doesn't allow 'distinct' types 2014-02-01 11:56:21 +01:00
Simon Hafner
2c5a2d07fb sets equivalence 2014-01-31 18:22:27 -06:00
Simon Hafner
e01fb17d02 product more robust against empty input 2014-01-30 23:55:43 -06:00
Simon Hafner
f070edb8b9 forgot to export product 2014-01-30 02:09:37 -06:00
Simon Hafner
ac0f15379c added Cartesian product 2014-01-30 02:07:55 -06:00
Grzegorz Adam Hankiewicz
d07f86b159 Avoids raising exceptions in tryInsertID. 2014-01-29 23:25:21 +01:00
Simon Hafner
47e2999fec Merge pull request #851 from EXetoC/highlite-typo
Punctation -> punctuation.
2014-01-29 09:10:23 -08:00
EXetoC
b549ca4517 Punctation -> Punctuation; fix remaining typos. 2014-01-29 17:35:11 +01:00
EXetoC
446ffb5481 Punctation -> punctuation. 2014-01-29 02:29:25 +01:00
Dominik Picheta
9344e9fbf7 Finished logging module. 2014-01-27 18:20:08 +00:00
Dominik Picheta
92f7c479b9 Fixes #848. 2014-01-27 17:48:39 +00:00
Michał Zieliński
11053afff8 osproc: fix naming inconsistiences 2014-01-26 22:30:20 +01:00
Michał Zieliński
e0e0b409e4 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel
Conflicts:
	lib/pure/osproc.nim
2014-01-26 17:06:21 +01:00
Grzegorz Adam Hankiewicz
7956737ef1 Adds note about manual memory handling to GC doc. 2014-01-26 16:39:20 +01:00
Miguel
a8b4e3c764 Merge branch 'devel' of git://github.com/Araq/Nimrod 2014-01-26 05:37:18 +04:00
Zahary Karadjov
5d712e0d3f Merge branch 'devel' of https://www.github.com/Araq/Nimrod into devel 2014-01-26 01:38:45 +02:00
Zahary Karadjov
5a6030a16b the is operator now uses exactly the same algorithm as proc signature matching 2014-01-26 00:45:50 +02:00
Araq
ad74332a92 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-01-25 23:04:03 +01:00
Araq
8a7f50889c fixes #838 2014-01-25 23:03:43 +01:00
Grzegorz Adam Hankiewicz
6ee21aa365 Merge pull request #841 from gradha/pr_oniondocs_devel
Added docgen documentation to devel branch
2014-01-25 07:27:16 -08:00
Grzegorz Adam Hankiewicz
7f9fb3a024 Merge branch 'pr_oniondocs' into pr_oniondocs_devel 2014-01-25 16:24:39 +01:00
Araq
f16881ad16 disable internalError so that nimbuild compiles again 2014-01-25 14:24:33 +01:00
Araq
9d4c4592fa more efficient calls for closure iterators 2014-01-25 14:22:38 +01:00
Araq
9af1ab5f43 fixes a minor parser bug 2014-01-25 14:22:05 +01:00
Araq
c4cb795081 updated asyncio and ftpclient modules 2014-01-25 14:21:27 +01:00
Araq
869e7d93e0 nativeStackTrace might work again 2014-01-25 14:20:40 +01:00
Zahary Karadjov
3f71b7f1f6 implements #766;
expressions such as Type.field are now recognised by the compiler.
This also fixes a bug, preventing the user-defined to check for the presence of
regular fields in addition to procs
2014-01-24 23:52:52 +02:00
Simon Hafner
35efec457c Merge pull request #839 from ReneSac/master
Optimized the size of PNG images. 172KB > 143KB
2014-01-24 12:58:19 -08:00
René
03138cb73a Optimized the size of PNG images. 172KB > 143KB
Used optpng + pngout + deflopt.
2014-01-24 16:59:29 -02:00
Zahary Karadjov
a6a18be089 support for parametric user-defined type classes 2014-01-24 14:13:32 +02:00
Araq
de538deb7a should compile on netbsd 2014-01-23 20:43:56 +01:00
Araq
f332ac1d37 renderer knows about nkStaticTy and nkTypeClassTy 2014-01-23 19:23:41 +01:00
Araq
3e5cb6644f typeClasses now documented in grammar.txt 2014-01-23 17:19:12 +01:00
Araq
2ecff76aac master compiler compiles with devel 2014-01-23 16:45:17 +01:00
Araq
556efb5158 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-01-23 12:22:49 +01:00
Araq
1465a7b080 small code cleanups 2014-01-23 12:22:34 +01:00
Araq
d01ff8994b closure iterators work 2014-01-23 08:47:22 +01:00
Araq
3f87326247 closure iterators almost work 2014-01-23 01:41:26 +01:00
Zahary Karadjov
3c840102bc fix the error "only proc headers can feature pragmas" when compiling in JS mode 2014-01-23 00:02:57 +02:00
Grzegorz Adam Hankiewicz
d63eca96e5 Adds AllChars constant to strutils. 2014-01-22 23:01:50 +01:00
Zahary Karadjov
9dec669b94 nest PreMain inside NimMain for easier consumption of static libraries developed in Nimrod
fixes many uses of $N instead of $n for new lines that don't affect #line directives
2014-01-23 00:01:15 +02:00
Araq
37229df7fc next steps for closure iterators 2014-01-22 17:32:38 +01:00
Araq
85a5bfe605 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-01-20 20:07:55 +01:00
Araq
4a0aadef4d parser support anon iterators 2014-01-20 20:07:44 +01:00
Zahary Karadjov
a09ddfa099 fix the segfault in #827 2014-01-20 15:22:44 +02:00
Michał Zieliński
ad1a0c51e2 Merge branch 'osproc' into devel
Conflicts:
	lib/posix/posix.nim
	lib/pure/osproc.nim
2014-01-20 13:32:20 +01:00
Araq
d18f40b4e2 updated grammar.txt 2014-01-20 08:35:09 +01:00
Araq
79f59d18f1 command syntax is allowed in expressions 2014-01-20 08:29:02 +01:00
Araq
6fd008f23e Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-01-19 20:25:03 +01:00
Araq
15859d94ec compiler warns when you use GC'ed memory and '--gc:none' 2014-01-19 20:24:44 +01:00
Andreas Rumpf
d23c2b5dcc Merge pull request #822 from onionhammer/devel
Corrected prunesocketset and pruneprocessset
2014-01-19 09:02:09 -08:00
onionhammer
34f7eca8f7 Added ret != 0 back 2014-01-19 10:55:33 -06:00
Erik O'Leary
5d8d1ed8bc Corrected prunesocketset and pruneprocessset
fd sets passed to select() were pruning ready FDs rather than pruning
UN-ready FDs.
2014-01-19 10:51:21 -06:00
Araq
73c6efdf66 'nil' as a statement is deprecated, use an empty 'discard' instead 2014-01-19 16:54:59 +01:00
Araq
cde9e5d644 merge master into devel 2014-01-19 01:31:45 +01:00
Araq
a59939d295 it's the year 2014 2014-01-19 01:25:48 +01:00
Araq
6df259f15b 'inject' for the new symbol binding rules in templates 2014-01-19 01:25:23 +01:00
Araq
d986a5adb5 make encodings.nim case consistent 2014-01-19 01:23:38 +01:00
Andreas Rumpf
f4b81ba92b Merge pull request #775 from fowlmouth/patch-3
Update endians.nim
2014-01-18 15:05:57 -08:00
Andreas Rumpf
899d286d2b Merge pull request #812 from girvo/koch-fix
Koch now uses $PATH/nimrod correctly
2014-01-18 15:03:06 -08:00
Araq
36afdca87f resolved conflicts with master 2014-01-18 01:16:45 +01:00
Araq
5073914b86 unittest module works again 2014-01-18 00:58:59 +01:00
Araq
383fbca27e better tester 2014-01-17 08:47:51 +01:00
Araq
12247b3f56 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-01-17 01:19:18 +01:00
Araq
fc452787e7 better html generator for the tester; fixes some VM bugs 2014-01-17 01:18:57 +01:00
Simon Hafner
b1c44561bb Merge pull request #818 from hiteshjasani/pr_devel_doc_import_constraints
Add docs for constraining and qualifying imports.
2014-01-16 12:16:48 -08:00
Hitesh Jasani
74af6351b2 Add docs for constraining and qualifying imports. 2014-01-16 14:42:12 -05:00
Simon Hafner
8f499db4c3 Merge pull request #817 from gradha/pr_improves_docs2
Improves docs2
2014-01-16 07:34:37 -08:00
Grzegorz Adam Hankiewicz
42f152569d References TRune, links unicode modules where mentioned.
Amends 0f3941b0013ea5d390586719f930fcf02b929f4d.
2014-01-15 22:23:24 +01:00
Grzegorz Adam Hankiewicz
2c2174f2d0 Clarifies system.lines() docstring.
Amends c087f905134b249cf20cbabc4066fbfa62dd668a.
2014-01-15 22:23:24 +01:00
Grzegorz Adam Hankiewicz
63ab238f5d Adds note about conflicts with using as a statement. 2014-01-15 22:23:23 +01:00
Grzegorz Adam Hankiewicz
7aa263bebf Duplicates string literal table for character literals.
Hopefully the index spamming will lead more people here.
2014-01-15 22:23:22 +01:00
Grzegorz Adam Hankiewicz
077b8327ec Documents rstgen index related procs. 2014-01-15 22:23:22 +01:00
Grzegorz Adam Hankiewicz
f3273757ed Removes links to modules recently removed from stdlib. 2014-01-15 22:23:21 +01:00
Grzegorz Adam Hankiewicz
457497980c Moves mongodb module to lower level wrapper group. 2014-01-15 22:23:20 +01:00
Grzegorz Adam Hankiewicz
74f94482cc Adds parseopt2 module to documentation index. 2014-01-15 22:23:20 +01:00
Grzegorz Adam Hankiewicz
3cf46c2def Documents wrapping named arguments in curly braces. 2014-01-15 22:23:19 +01:00
Grzegorz Adam Hankiewicz
0029832ba1 Adds note about iterators having same signature as procs. 2014-01-15 22:23:17 +01:00
Grzegorz Adam Hankiewicz
9602349f30 Adds note about procs and multiple variable assignment. 2014-01-15 22:23:17 +01:00
Grzegorz Adam Hankiewicz
338a93f119 Adds docstrings to lines() iterators. 2014-01-15 22:23:16 +01:00
Grzegorz Adam Hankiewicz
db7d0e6a66 Adds using statement to the one and only true index. 2014-01-15 22:23:15 +01:00
Andreas Rumpf
0132f350af Merge pull request #814 from discoloda/devel
Many small improvements to c2nim
2014-01-14 13:42:20 -08:00
Vincent Burns
aec9195c95 Applied Araq's suggestions for c2nim 2014-01-14 16:35:00 -05:00
Vincent Burns
5395347582 removed hack for return statement 2014-01-14 12:05:14 -05:00
Vincent Burns
d35dedf041 Slightly better type parsing for parameters and cast expressions 2014-01-14 11:22:59 -05:00
Araq
a1713bc2f9 tester: htmlgen almost works 2014-01-14 01:28:52 +01:00
Araq
c648a5774a tester support html generation 2014-01-14 01:12:56 +01:00
Andreas Rumpf
3f8bfb1e98 Merge pull request #777 from fowlmouth/patch-4
Update os.nim
2014-01-13 14:39:40 -08:00
Andreas Rumpf
90721375e2 Merge pull request #779 from brihat/master
Define $ operator for TRune
2014-01-13 14:34:24 -08:00
Vincent Burns
d9a61c13dd Fix for expression parsing, 'new' is a valid C symbol 2014-01-13 02:01:10 -05:00
Vincent Burns
5f905865be Fix for some comments during if statements
added test files
2014-01-13 01:51:36 -05:00
Vincent Burns
58855c2fc7 Support more proper do..while statements 2014-01-13 01:42:26 -05:00
Vincent Burns
97eaeb3aec for statements support comma expressions 2014-01-13 01:16:24 -05:00
Araq
20b5f31c03 new tester; all tests categorized 2014-01-13 02:10:03 +01:00
Araq
51ee524109 Merge branch 'devel' of https://github.com/Araq/Nimrod into devel 2014-01-13 01:22:03 +01:00
Araq
4045d7829b fixes db_sqlite 2014-01-13 01:21:46 +01:00
Araq
1e4c4d62e4 bugfix: doc generation for actors.nim works again 2014-01-13 01:08:57 +01:00
Araq
9ab1a3c724 added test cases from strange loop event 2014-01-13 01:05:09 +01:00
Vincent Burns
570f8b21e1 New expression parser
tests pass
2014-01-12 17:13:23 -05:00
Dominik Picheta
429d337ef6 Rename C sources dir to c_code. 2014-01-12 21:48:57 +00:00
Araq
616434c492 bugfix: renderer supports 'ptr' etc. as type constraint 2014-01-12 21:41:52 +01:00
Araq
137e971547 new vm: bugfix 2014-01-12 21:40:24 +01:00
Dominik Picheta
e27e873b7b Add info about twitter and bootstrapping from github to website. 2014-01-12 20:13:26 +00:00
Vincent Burns
c5bd98b7db Properly lex floating constants
digit-sequence? '.' digit-sequence exponent-part?
digit-sequence '.' exponent-part?
exponent-part: [eE] [+-]? digit-sequence
2014-01-12 13:23:52 -05:00
Vincent Burns
2dc91cb4d5 Lex '\xHH' character constants 2014-01-12 12:53:25 -05:00
Vincent Burns
0a0fec4a5c Added spliceHeader option to c2nim
parse a header file first, then the source. completing a c 'module'
2014-01-12 12:48:06 -05:00
Josh Girvin
fb4a96ff78 Koch now uses PATH/nimrod correctly 2014-01-13 02:45:35 +10:00
Araq
346443d1b5 case consistency improvements 2014-01-11 21:56:05 +01:00
Grzegorz Adam Hankiewicz
2ed7849921 Transforms docgen sample to be generated from source. 2014-01-06 14:55:03 +01:00
Grzegorz Adam Hankiewicz
91ae5a3585 Adds some cross references to docgen manual. 2014-01-06 13:40:11 +01:00
Grzegorz Adam Hankiewicz
5844697aa6 Adds docgen to list of documentation to build. 2014-01-06 13:31:21 +01:00
Grzegorz Adam Hankiewicz
fd6bb131b8 Reformats text to fit width of 80 columns. 2014-01-06 13:22:44 +01:00
Grzegorz Adam Hankiewicz
0b6c9d7d75 Fixes two minor typos. 2014-01-06 13:18:27 +01:00
Zahary Karadjov
1280c56f38 fix bootstrapping on windows 2014-01-06 00:16:16 +02:00
Zahary Karadjov
1ffae7cbaf progress towards fixing tgenericshardcases 2014-01-06 00:15:55 +02:00
Zahary Karadjov
789ba107cf introduce tyFromExpr; fixes #618 2014-01-04 13:10:52 +02:00
Zahary Karadjov
02533c260b fixed #597 2014-01-02 17:55:18 +02:00
Erik O'Leary
e0fc07df89 Added docgen documentation 2013-12-31 19:37:20 -06:00
Zahary Karadjov
8e0941576f clean-up some obsolete code; close #602 2013-12-31 12:39:43 +02:00
Zahary Karadjov
ed3ab6539d close #517 2013-12-31 04:13:51 +02:00
Zahary Karadjov
8f3d5a25a6 Templates will pick the candidate in the nearest scope when symbols are mixed-in 2013-12-31 04:04:59 +02:00
Zahary Karadjov
754e2ef1db migrate the static param handling to ReplaceTypeVars; fix tgenericvariant 2013-12-30 19:15:41 +02:00
Dominik Picheta
fba0f33f1b Merge pull request #788 from zielmicha/httpclient-fix
httpclient: strip trailing whitespace from headers.
2013-12-30 09:13:18 -08:00
Grzegorz Adam Hankiewicz
1a4ba705f3 Merge pull request #791 from gradha/pr_removes_generated_file
Removes generated .dot file uploaded by mistake.
2013-12-30 08:59:21 -08:00
Grzegorz Adam Hankiewicz
fc68a7d880 Removes generated .dot file uploaded by mistake. 2013-12-30 17:58:05 +01:00
Zahary Karadjov
af7c3251cd properly remove intLiterals from proc signatures; fixes trettypeinference 2013-12-30 17:07:49 +02:00
Zahary Karadjov
7e24cf26de handle recursive types during the instantiation of meta types; propagate tfHasMeta more carefully 2013-12-30 16:06:32 +02:00
Zahary Karadjov
88873f7965 add incl/excl for sets accepting accepting other sets 2013-12-30 14:25:05 +02:00
Grzegorz Adam Hankiewicz
987ac2439a Merge pull request #776 from gradha/pr_docs
Docstrings
2013-12-30 03:06:22 -08:00
Zahary Karadjov
046d829e5d Introduce a PreMain proc in the C codegen
The rationale here is that it has become too hard to step into a program
when #line directives are enabled. You have to skip over many lines of init
code that doesn't have corresponding lines in the nimrod program.
Now, you can just step-out of PreMain and go straight to the useful code
in NimMain.
2013-12-30 11:02:48 +02:00
Zahary Karadjov
e3f53409f6 proc redefinition search based on the type system instead of on sloppy AST matching
This will work the same for procs/templates/macros/etc, having arbitrary mix of implicit
and explicit generics (as long as the symbols are equivalent for the purposes of overload
resolution, they will be detected as redefinitions)

fixes tgeneric
2013-12-30 10:57:12 +02:00
Zahary Karadjov
fa3bb8d66b restore return type inference 2013-12-30 00:03:57 +02:00
Zahary Karadjov
723efe7cfb fix the filtering of void params in procs' signatures 2013-12-29 19:26:52 +02:00
Zahary Karadjov
afddae5aaf Merge branch 'upstream' into devel
Conflicts:
	compiler/ccgutils.nim
	compiler/msgs.nim
	compiler/sem.nim
	compiler/semexprs.nim
	compiler/seminst.nim
	compiler/semmagic.nim
	compiler/semstmts.nim
	compiler/semtypes.nim
	compiler/semtypinst.nim
	compiler/sigmatch.nim
	compiler/types.nim
	compiler/vmgen.nim
	lib/core/macros.nim
	lib/system.nim
	tests/reject/tenummix.nim
	web/news.txt
2013-12-29 17:21:00 +02:00
Zahary Karadjov
72291875bf integrate the logic of fixupProcType into ReplaceTypeVars 2013-12-29 16:08:33 +02:00
Araq
437cfa73ab todo.txt updated 2013-12-29 03:45:10 +01:00
Araq
4ed8cec7ca case consistency: niminst 2013-12-29 03:42:20 +01:00
Araq
286f166304 case consistency for linux 2013-12-29 03:32:46 +01:00
Araq
b731e6ef1c case consistency: cs:partial bootstraps on windows 2013-12-29 03:19:10 +01:00
Araq
438703f59e case consistency: next steps 2013-12-29 01:13:51 +01:00
Araq
1101a40f91 improvements for 'pretty' 2013-12-28 23:30:53 +01:00
Zahary Karadjov
66a2556525 make more tests green 2013-12-29 00:00:37 +02:00
Zahary Karadjov
eb1d23c0c7 fixes #787 2013-12-28 23:53:48 +02:00
Michał Zieliński
0420c8c363 httpclient: strip trailing whitespace from headers.
- we can do that according to the RFC.
- fixes #783
2013-12-28 17:26:08 +01:00
Zahary Karadjov
5d75ce2f2e fix tclosure4 2013-12-28 15:07:30 +02:00
Dominik Picheta
f622504b5b Fixes #594
This was already partially fixed, ``expandTilde`` was the missing piece
from perfection.
2013-12-28 12:25:01 +00:00
Zahary Karadjov
f34ca1a7d7 fix illegal recursion checks 2013-12-28 14:17:36 +02:00
Zahary Karadjov
a59f13b00d lift generic parameters from concrete composite type classes 2013-12-28 12:50:45 +02:00
Araq
f2b9905b4e case consistency part 9 2013-12-28 01:57:19 +01:00
Araq
e2648fa3fb case consistency part 8 2013-12-28 01:47:40 +01:00
Araq
7e0da3e8f7 case consistency part 7 2013-12-28 01:36:35 +01:00
Araq
bf205fa85d case consistency part 6 2013-12-28 01:17:02 +01:00
Araq
9c3751a37c case consistency part 5 2013-12-28 00:37:45 +01:00
Araq
92b8fac94a case consistency part 4 2013-12-27 23:10:36 +01:00
Araq
706266d8b7 case consistency part 3 2013-12-27 21:46:43 +01:00
Zahary Karadjov
a27eb51535 towards support for composite type classes such as seq[Number] and SquareMatrix[T] 2013-12-27 18:34:28 +02:00
Araq
a427648c48 case consistency part 2 2013-12-27 16:35:21 +01:00
Araq
2df9b442c6 case consistency part 1 2013-12-27 15:48:53 +01:00
Zahary Karadjov
4eea2f17d3 forgotten modification to the news files 2013-12-27 13:00:45 +02:00
Dominik Picheta
be5e13671c Remove assert in asyncio which causes problems.
This assert keeps failing occassionally in nimbuild causing it to crash.
According to logic it shouldn't, but perhaps the socket's writeable
status changes.
2013-12-26 21:32:30 +00:00
Zahary Karadjov
e2594f44bd bugfix: in some contexts, newSeq[T](n) is incorrectly inferred to have a seq[typedesc[T]] type 2013-12-26 01:09:10 +02:00
Satish BD
40bd63f83b Define $ operator for TRune 2013-12-26 00:55:17 +02:00
Satish BD
69b816f07c Define $ operator for TRune 2013-12-26 00:41:43 +02:00
Dominik Picheta
8c1ea5cb3f Added --noBabelPath override. 2013-12-25 22:38:53 +00:00
Zahary Karadjov
86108be24b test case for semistatic 2013-12-25 22:40:06 +02:00
Zahary Karadjov
edab4aaad0 better integration of tyStatic into typeRel 2013-12-25 22:29:44 +02:00
Zahary Karadjov
1d02f2ea53 wip type class reforms (the compiler bootstraps fine)
* replace tfAny and tfAll with tyAnd and tyOr
* integrate matchTypeClass into typeRel
* introduce tyBuiltInTypeClass to handle types such as tuple, object, proc, etc
2013-12-25 19:25:04 +02:00
Araq
9e92455a53 templates can access hidden fields 2013-12-25 14:53:00 +01:00
Zahary Karadjov
299cefdc98 make the current PContext accessible through TCandidate
the goal here is to remove all the hacks from ParamTypeMatch and to handle
all type matching in typeRel (the context there is required to evaluate any static
params and to run the compilation tests of user-defined type classes)
2013-12-25 00:58:22 +02:00
Zahary Karadjov
952dbc4b8f documented static params 2013-12-25 00:32:53 +02:00
Araq
4d01408a46 bootstraps with new template symbol binding rules 2013-12-24 16:42:24 +01:00
Araq
83a0a31276 attempt to merge newtempl 2013-12-24 14:04:18 +01:00
Araq
4203e8955c Merge branch 'newtempl' into devel
Conflicts:
	lib/system.nim
	tests/reject/tenummix.nim
	todo.txt
2013-12-24 02:10:59 +01:00
Araq
84e4710320 bugfix: InvalidSockets needs to be a let variable 2013-12-24 01:39:33 +01:00
Araq
1081c104d0 Merge branch 'vm2' of github.com:Araq/Nimrod into vm2 2013-12-24 01:30:48 +01:00
Araq
feb9af48f1 NoFakeVars progress 2013-12-24 00:21:22 +01:00
Araq
32ef1f8f32 vm: FFI improvements 2013-12-23 20:12:13 +01:00
Billingsly Wetherfordshire
e1fa19fa7a Update os.nim
added file/dirExists synonyms for existsFile/dir
2013-12-23 12:58:22 -06:00
Grzegorz Adam Hankiewicz
f33f15afe8 Adds docstring to rstgen.defaultConfig. 2013-12-23 19:25:53 +01:00
Grzegorz Adam Hankiewicz
1fe8b013ef Adds example to locals() docstring. 2013-12-23 19:25:53 +01:00
Billingsly Wetherfordshire
b3057be2c9 Update endians.nim
adds swapEndian16 function
2013-12-23 11:52:11 -06:00
Araq
4447c1b7e3 tcnstseq works again 2013-12-23 08:28:32 +01:00
Simon Hafner
c3b3339e77 Merge pull request #774 from brihat/master
Correct the spelling of the word 'implicitly'
2013-12-22 21:55:24 -08:00
Satish BD
033938a53a Correct the spelling of the word 'implicitly' 2013-12-23 04:29:50 +02:00
Araq
b76729df1c Merge branch 'master' of https://github.com/Araq/Nimrod into vm2
Conflicts:
	web/news.txt
2013-12-23 01:23:16 +01:00
Araq
9145bcfbb6 new VM: some progress for the FFI support 2013-12-23 01:17:48 +01:00
Miguel
4396270fc7 'Connection' argument in 'Open' was not used, so MySQL host and port were always default ones. Now 'Connection' is treated as 'host:port'. 2013-12-22 20:56:33 +04:00
Michał Zieliński
bdb5c4ad35 Introduce poEvalCommand, poUsePath, fix remaining quoting issues.
- poUsePath is now an alias for poUseShell.
- poEvalCommand should be used when shell evaluation is really needed.
It passes `command` directly to shell/winapi. Requires `args` parameter
to be empty.
2013-12-21 18:46:51 +01:00
Michał Zieliński
3503f1ca33 Normalize whitespace in osproc.nim. 2013-12-21 18:05:19 +01:00
Grzegorz Adam Hankiewicz
52a8226edd Merge pull request #769 from gradha/pr_config_fixes
Renames configuration file to new pattern. Refs #720.
2013-12-21 03:00:45 -08:00
Grzegorz Adam Hankiewicz
7a05b108d5 Renames configuration file to new pattern. Refs #720. 2013-12-21 11:44:17 +01:00
Andreas Rumpf
eae275c114 Merge pull request #742 from onionhammer/master
Added jsondoc compiler switch
2013-12-20 13:28:18 -08:00
Andreas Rumpf
2f7119e9bb Merge pull request #764 from gradha/pr_doc_improvements
Documentation improvements
2013-12-20 13:02:44 -08:00
Andreas Rumpf
f391bfed93 Merge pull request #768 from fowlmouth/patch-2
Update macros.nim
2013-12-20 13:02:03 -08:00
Grzegorz Adam Hankiewicz
7177e0f698 Adds docstring to macros.newIdentDefs. 2013-12-20 21:37:51 +01:00
Billingsly Wetherfordshire
f06c9a77b5 Update macros.nim 2013-12-20 14:23:13 -06:00
Andreas Rumpf
259d205ff6 Merge pull request #759 from zielmicha/stdmsg
Write tracebacks to stderr instead of stdout.
2013-12-20 09:42:39 -08:00
Andreas Rumpf
22e88026af Merge pull request #753 from gradha/pr_idetools_quote
Adds fitting quote to idetools doc.
2013-12-20 09:40:02 -08:00
zah
348ccffecd Merge pull request #767 from gradha/pr_fixes_run_with_out
Fixes run command with outFile
2013-12-20 04:53:42 -08:00
Grzegorz Adam Hankiewicz
c0e2cb2919 Allows passing absolute paths for output. Refs #738.
Previous to this the project base dir was added always, preventing user
specified absolute paths to work.
2013-12-20 13:33:43 +01:00
Grzegorz Adam Hankiewicz
3b38ceac2e Runs user specified outFile if available. Refs #738. 2013-12-20 13:13:09 +01:00
Araq
7ee0763bc5 Merge branch 'master' of github.com:Araq/Nimrod 2013-12-20 00:02:45 +01:00
Araq
4b0e391bb8 no stack tracing for the system module; fixes stack bottom detection 2013-12-20 00:02:04 +01:00
Araq
e2a4d591e5 added libffi for win support 2013-12-19 01:00:51 +01:00
Zahary Karadjov
027f30610e static params: expr[T] is now static[T]
This introduces tyStatic and successfully bootstraps and handles
few simple test cases.  Static params within macros are no longer
treated as PNimrodNodes - they are now equivalent to constants
of the designated type.
2013-12-19 01:06:38 +02:00
Andreas Rumpf
e0f95b5d27 Merge pull request #762 from Varriount/os/fix-removeFile2
Fix os.removeFile behavior on windows (again)
2013-12-18 13:24:20 -08:00
Clay Sweetser
9de92522a6 Further fixes (stupid kdiff automerge) 2013-12-18 16:04:43 -05:00
Clay Sweetser
c26e787e5d os.nim - Modify removeFile to use native Windows API calls 2013-12-18 15:32:26 -05:00
Grzegorz Adam Hankiewicz
9f8db3ae54 Updates idetools docs after changes by #743. 2013-12-18 21:25:49 +01:00
Grzegorz Adam Hankiewicz
e0d6a1cec1 Adds some docstrings to rstgen. 2013-12-18 21:22:22 +01:00
Grzegorz Adam Hankiewicz
f46336ae8b Adds missing `code-block` to macros' docstrings. 2013-12-18 21:22:22 +01:00
Grzegorz Adam Hankiewicz
543d6b3209 Replaces PDoc with var TRstGenerator for documentation.
The PDoc type is a convenience internal alias. Where procs are exported
only documented types should be used to avoid confusing users.
2013-12-18 21:22:10 +01:00
Michał Zieliński
7d5fa3f52d add info about CGI error reporing changes to web/news.txt 2013-12-18 18:21:55 +01:00
Michał Zieliński
101d8bc9c3 Add two CGI example and basic Python CGI server. 2013-12-18 18:19:32 +01:00
Michał Zieliński
74a63c004f Rework CGI error reporting.
- remove 'undocumented' stackTraceNL
- add 'undocumented' errorMessageWriter
- make printing errors for browser optional (for security)
2013-12-18 18:15:39 +01:00
Araq
3d869d4dec case expression with discardable result works 2013-12-18 07:28:25 +01:00
Clay Sweetser
ab2eb884a0 Modified os.removeFile to act correctly when deleting a file that doesn't exist. 2013-12-17 18:03:08 -05:00
Michał Zieliński
646458d328 write exception tracebacks to stdmsg, instead of stdout 2013-12-17 20:42:02 +01:00
Michał Zieliński
db73f3af20 Add stdmsg (an alias to either stdout or stderr). 2013-12-17 20:36:53 +01:00
Grzegorz Adam Hankiewicz
30aef21def Merge pull request #739 from gradha/pr_adds_to_quit_docs
Adds to quit docs
2013-12-17 03:16:02 -08:00
Grzegorz Adam Hankiewicz
911bebe16c Merge pull request #752 from zielmicha/expand-gitignore
Expand gitignore to include all binaries built by ./koch test.
2013-12-17 03:15:24 -08:00
Araq
d46380e718 Merge branch 'master' of github.com:Araq/Nimrod 2013-12-16 22:26:34 +01:00
Araq
132b6b3efe implemented 'injectStmt'; more debug support 2013-12-16 22:26:17 +01:00
Andreas Rumpf
20c69dac9e Merge pull request #737 from zielmicha/quote-shell
quoteIfContainsWhite -> quoteShell
2013-12-16 12:32:14 -08:00
Grzegorz Adam Hankiewicz
78a48b942a Adds fitting quote to idetools doc. 2013-12-15 22:57:29 +01:00
Michał Zieliński
2434324a0c Expand gitignore to include all binaries built by ./koch test. 2013-12-15 15:52:01 +01:00
Araq
f095e51275 more tests work 2013-12-13 21:29:35 +01:00
Araq
8c553fa8a2 Merge branch 'master' into vm2 2013-12-13 15:58:03 +01:00
Araq
328f193292 new VM: globals kinda work 2013-12-13 01:21:23 +01:00
Grzegorz Adam Hankiewicz
01661daf76 Merge pull request #743 from Varriount/tests/comment-caas
Commented out CAAS testing code.
2013-12-12 12:09:13 -08:00
Clay Sweetser
5b3bc28721 Commented out CAAS testing code. 2013-12-12 15:04:28 -05:00
Erik O'Leary
aaf49947e9 Added jsondoc compiler switch
Outputs top-level exported information in JSON
2013-12-12 10:59:30 -06:00
Araq
6db20a4be8 new VM: improvements 2013-12-12 01:34:01 +01:00
Grzegorz Adam Hankiewicz
b4d6a6aafe Adds example to fatal pragma. 2013-12-12 01:00:23 +01:00
Grzegorz Adam Hankiewicz
c6c8366925 Mentions static alternatives to quit(). 2013-12-12 00:57:31 +01:00
Michał Zieliński
39cabcdd27 Use quoteShell in stdlib, where appropriate. 2013-12-11 22:27:39 +01:00
Andreas Rumpf
efc0d8557a Merge pull request #736 from Varriount/os/fix-windows-removefile
Fixed skipFile proc to not skip files that merely start with '.'
2013-12-11 13:20:38 -08:00
Clay Sweetser
33ffe60864 Fixed skipFile proc to not skip files that merely start with '.'
Modified removeFile to reset the read only attribute on files before trying to delete.
2013-12-11 16:16:14 -05:00
Michał Zieliński
c363197275 Deprecate quoteIfContainsWhite in favor of osproc.quoteShell. 2013-12-10 23:00:01 +01:00
Michał Zieliński
b8072bd22e add quoteShell to osproc.nim 2013-12-10 22:56:29 +01:00
Andreas Rumpf
9848f82c03 Merge pull request #730 from zielmicha/fix-parameters
Make parseopt correct (and based on seq[string] as parameters, not string)
2013-12-10 11:53:58 -08:00
Michał Zieliński
8561ef5bc8 use parseopt2 in parseopt2 test 2013-12-10 20:48:18 +01:00
Michał Zieliński
1472b46708 Merge old parseopt.nim into fix-parameters 2013-12-10 20:42:32 +01:00
Michał Zieliński
2e0da6a5c6 Make old parseopt as deprecated. 2013-12-10 20:41:52 +01:00
Michał Zieliński
088d472662 rename new parseopt to parseopt2 2013-12-10 20:33:51 +01:00
Michał Zieliński
896766ae2c Fix : and = precedence in parseopt. 2013-12-10 19:10:06 +01:00
Grzegorz Adam Hankiewicz
016b1e0068 Merge pull request #732 from gradha/pr_reverts_quoting_changes
Reverts "Make quoteIfContainsWhite quote…". Refs #702.
2013-12-10 08:54:05 -08:00
Grzegorz Adam Hankiewicz
da05cf51de Reverts "Make quoteIfContainsWhite quote…". Refs #702.
This reverts commit e7e8c77062 to avoid
tool breakage. A different approach is being worked on #730.
2013-12-10 17:50:47 +01:00
Zahary Karadjov
7120491d05 in successful compilations with verbosity:0, all output is suppressed (useful for combing with --run) 2013-12-10 01:49:30 +02:00
Michał Zieliński
b4716e3b5b Merge branch 'master' of https://github.com/Araq/Nimrod into fix-parameters 2013-12-09 23:38:19 +01:00
Michał Zieliński
d1f3512aba Reimplement parseopt which parses arguments given as a sequence of strings, not single string. 2013-12-09 23:29:16 +01:00
Zahary Karadjov
14dd3113a2 fix computed dynlib names; fixes #718 2013-12-09 23:06:11 +02:00
Michał Zieliński
8dae664159 Add commandLineParams to os.nim.
commandLineParams returns seq of arguments given to program on command line.
2013-12-09 21:45:42 +01:00
Grzegorz Adam Hankiewicz
9486670e93 Merge pull request #727 from gradha/pr_recovers_windows_code
Revert "removed windows". Refs #698.
2013-12-09 09:29:49 -08:00
Grzegorz Adam Hankiewicz
8468e2af3a Revert "removed windows". Refs #698.
This reverts commit 5ab3d66144.
2013-12-09 18:28:11 +01:00
Michał Zieliński
642a0d5563 Normalize whitespace in os.nim.
I can't edit it - trick with asking git to ignore whitespace doesn't
work if I need to change indention level.
2013-12-09 18:03:36 +01:00
Zahary Karadjov
95a6e01ea8 Merge branch 'master' of github.com:Araq/Nimrod into upstream 2013-12-09 00:26:04 +02:00
Zahary Karadjov
de3b7cd413 progress towards adding negative type classes
[unittest bugfixes]
the block form of check now allows comments
errors when inspecting the arguments of var-accepting procs
2013-12-09 00:09:03 +02:00
Grzegorz Adam Hankiewicz
7e9f158494 Merge pull request #721 from gradha/pr_doc_fixes
Doc fixes
2013-12-08 13:45:48 -08:00
Grzegorz Adam Hankiewicz
89215ba6d0 Updates configuration for recent lib removals. Refs #698. 2013-12-08 21:18:06 +01:00
Grzegorz Adam Hankiewicz
410fcf7f52 Fixes strutils reference in macro tutorial. 2013-12-08 18:33:19 +01:00
Grzegorz Adam Hankiewicz
2c315690f2 Merge pull request #717 from gradha/pr_fixes_minor_doc_mistakes
Fixes minor doc mistakes.
2013-12-08 03:56:00 -08:00
Grzegorz Adam Hankiewicz
8526d29365 Adds missing `s` to sligthly odd sentence. 2013-12-08 12:52:54 +01:00
Grzegorz Adam Hankiewicz
53c0012a83 Fixes link to manual in bold section.
Nested inline markup is not possible at the moment, see
http://stackoverflow.com/a/9645684/172690. Maybe this would be a useful
extension to have in nimrod's custom rst engine?
2013-12-08 12:49:21 +01:00
Araq
29357ab556 more tests are green 2013-12-08 01:47:07 +01:00
Michał Zieliński
febe71b99a Merge branch 'master' of github.com:zielmicha/Nimrod 2013-12-07 23:10:04 +01:00
Andreas Rumpf
5cdfa4b1af Merge pull request #702 from zielmicha/master
Make quoteIfContainsWhite quote argument, so it can be safely passed to shell.
2013-12-07 13:59:50 -08:00
Michał Zieliński
e7e8c77062 Make quoteIfContainsWhite quote argument, so it can be safely passed to shell.
On Windows put it in double quotes and escape double quotes using backslash.
On Posix put it in single quotes and escape single quotes using '"'"'.

This commit changes what quoteIfContainsWhite does, but before that change it
was used incorrectly all over standard library, which caused security issues.
2013-12-07 22:56:02 +01:00
Zahary Karadjov
208924b929 fixes #708
It's unclear to me why for variables were treated as globals.
This is likely to cause many problems, but in this particular case
it was breaking the unittest/insepectArgs recursive function (the
for loop variable has a different value in each stack frame)
2013-12-07 21:23:22 +02:00
Zahary Karadjov
1e26047c3b adding some provisions for writing lower-level unit tests targeting specific sub-systems of the compiler
see sigmatch as an example.
tests are compiled only when the compiler is compiled with -d:selftest
to execute them, just run the resulting binary without arguments
2013-12-07 20:30:44 +02:00
Araq
430c8d8b52 new VM supports 'getAst' 2013-12-06 20:29:37 +01:00
Araq
4ffe6a8282 new VM: passes more tests 2013-12-06 01:48:02 +01:00
Araq
3560827a28 makes 'reject' tests green 2013-12-05 11:28:45 +01:00
Araq
c0a3d44060 bugfix: keywords are sorted 2013-12-05 10:45:36 +01:00
Araq
5eba93d584 Merge branch 'master' into vm2
Conflicts:
	compiler/sem.nim
2013-12-05 00:03:27 +01:00
Grzegorz Adam Hankiewicz
ed760c0397 Merge pull request #706 from hiteshjasani/master
Add docs for connecting to postgres with keyword/value connection.
2013-12-04 14:25:03 -08:00
Hitesh Jasani
20661c9c46 Add docs for connecting to postgres with keyword/value connection
strings.
2013-12-04 14:01:25 -05:00
Andreas Rumpf
2264875237 Merge pull request #698 from fowlmouth/smallstdlib
removed x11
2013-12-04 07:52:22 -08:00
Araq
32d2327be0 don't use memset for temps unless necessary 2013-12-03 13:30:58 +01:00
fowlmouth
5ab3d66144 removed windows 2013-12-03 00:14:20 -06:00
fowlmouth
dc27f87257 removed deprecated libraries from nimrod.cfg 2013-12-02 23:48:22 -06:00
fowlmouth
4f0eeaa55e fixes compiler.lists.bringToFront 2013-12-02 23:47:56 -06:00
Araq
5cb60ffbe0 Merge branch 'master' of github.com:Araq/Nimrod 2013-12-03 01:59:59 +01:00
Araq
fe983b1309 fixes a regression where memset was used without including <string.h> 2013-12-03 01:59:38 +01:00
Grzegorz Adam Hankiewicz
0628d85a6a Merge pull request #676 from gradha/pr_expands_macro_tutorial
Expands tutorial macro section with step by step guide.
2013-12-02 15:15:09 -08:00
Grzegorz Adam Hankiewicz
a195e94e88 Merge pull request #687 from gradha/pr_documents_tuple_unpacking
Adds to tutorial info about unpacking tuples.
2013-12-02 15:14:31 -08:00
Grzegorz Adam Hankiewicz
6e451d4f33 Merge pull request #695 from gradha/pr_adds_htmlparser_example
Adds an example to htmlparser showing how to save changes.
2013-12-02 15:13:40 -08:00
onionhammer
b5ac234771 Renamed nimrod.cfg to nimrod.nimrod.cfg 2013-12-02 23:57:47 +01:00
Erik O'Leary
e145231a1d Updated cfg file processing
No longer look at deprecated file.cfg, compiler will only look at
file.nimrod.cfg
2013-12-02 23:57:47 +01:00
Grzegorz Adam Hankiewicz
ed0cb19909 Merge pull request #703 from gradha/pr_fixes_htmlparser_whitespace
Makes htmlparser handle whitespace. Refs #694.
2013-12-02 14:39:22 -08:00
Grzegorz Adam Hankiewicz
dc9e17503e Makes htmlparser handle whitespace. Refs #694.
Without the flag, htmlparser will ignore some significant whitespace in
HTML files. A more correct fix would be to not reuse the xml parser
since the rules for HTML are slightly different, but this will do for
the moment.
2013-12-02 20:55:55 +01:00
fowlmouth
6577093d2d Removed lua, python, tcl, cairo 2013-12-01 21:19:32 -06:00
fowlmouth
0b4805f366 Removed opengl 2013-12-01 21:17:50 -06:00
fowlmouth
ee520689d7 removed gtk2 2013-12-01 21:15:48 -06:00
fowlmouth
944b4685b9 removed x11 2013-12-01 21:10:06 -06:00
Grzegorz Adam Hankiewicz
d1284ff33d Mentions tuple unpacking only works in var/let blocks. 2013-12-01 21:07:50 +01:00
Reimer Behrends
68b7779bc7 Fixes various issues with shallow copying.
* The {.shallow.} pragma is now properly respected for objects and
  tuples that are not handled by genGenericAsgn(). Mirroring the
  decision in generic assignments, whether an assignment is shallow
  depends on the destination of the assignment, but not the source.
* String literals and complex inline constants are now properly assigned
  a location kind of locData.
* Assignments from a locData source will now force deep copying to
  occur, even if shallowCopy or {.shallow.} is being used. This
  avoids potential crashes from `shallowCopy s, "xxx"` or from
  `shallowCopy t, ("a", "b")`.
2013-12-01 19:15:43 +01:00
Araq
5dcfa97fb9 fixes #696 2013-12-01 17:02:56 +01:00
Araq
387b7d857d Merge branch 'master' of github.com:Araq/Nimrod 2013-12-01 14:04:29 +01:00
Araq
f59e502382 better error message for implicitly available modules 2013-12-01 14:04:15 +01:00
Andreas Rumpf
5bf395040f Merge pull request #684 from gradha/pr_clarifies_docs
Clarifies wording of newSeq proc docstrings.
2013-11-30 16:25:44 -08:00
Grzegorz Adam Hankiewicz
f91a34c9e6 Adds an example to htmlparser showing how to save changes. 2013-11-30 21:03:41 +01:00
Araq
0d193a446b updated fsmonitor module 2013-11-30 03:28:31 +01:00
Araq
b3d759ca6d fixes #681 2013-11-30 03:15:14 +01:00
Araq
2dcbc6493a fixes #686 2013-11-29 20:42:12 +01:00
Araq
f10a23e669 removed 'system.eval' 2013-11-27 09:44:53 +01:00
Grzegorz Adam Hankiewicz
0a953de3a8 Adds to tutorial info about unpacking tuples. 2013-11-26 13:34:54 +01:00
Araq
4855055bca Merge branch 'master' of https://github.com/Araq/Nimrod 2013-11-25 13:06:11 +01:00
Araq
9035d15ed2 next steps for FFI support 2013-11-25 13:04:11 +01:00
Grzegorz Adam Hankiewicz
936c71df70 Clarifies wording of newSeq proc docstrings. 2013-11-22 22:54:24 +01:00
Dominik Picheta
b893bd074f Modified website links in readme. 2013-11-21 22:47:02 +00:00
Andreas Rumpf
e469bdb6fa Merge pull request #657 from gradha/pr_stackoverflow_link
Adds link to stackoverflow nimrod tag in support section.
2013-11-19 13:43:34 -08:00
Grzegorz Adam Hankiewicz
3a494f5d8d Corrects grammar and span of italics in text. 2013-11-19 22:35:05 +01:00
Grzegorz Adam Hankiewicz
c3e7a970c6 Modifies example to use splitLines. 2013-11-19 22:33:02 +01:00
Araq
d0f7db0828 always call the linker; fixes #660 2013-11-19 15:41:20 +01:00
Araq
cd1f96d421 fixes #663 2013-11-19 15:11:44 +01:00
Araq
98cf1c412a garbage-in-garbage-out principle for unicode errors; fixes #674 2013-11-19 14:39:27 +01:00
Araq
80377c20f9 fixes #678 2013-11-19 14:35:03 +01:00
Araq
619356dd08 bugfix: '$' for TPort 2013-11-19 14:06:39 +01:00
Andreas Rumpf
fb810e25c4 Merge pull request #680 from Varriount/core/fix-generic-crashes
Prevent lambdas from crashing if given implicit generic parameters.
2013-11-19 02:34:22 -08:00
Andreas Rumpf
a3163aa2cf Merge pull request #677 from gradha/pr_fixes_times_calculation
Fixes times.toSeconds to handle hours and minutes correctly.
2013-11-19 02:31:58 -08:00
Andreas Rumpf
220e20e7f2 Merge pull request #666 from gradha/pr_links_algorithm_module
Links algorithm module from library index.
2013-11-19 02:25:17 -08:00
Clay Sweetser
c9d6e04636 Merge branch 'core/fix-generic-crashes' of github.com:Varriount/Nimrod into core/fix-generic-crashes 2013-11-18 17:27:40 -05:00
Clay Sweetser
f279d465d0 Prevent lambdas from crashing if given implicit generic parameters.
Fixes issues #599 and #641 (and possibly other generic-related issues)
2013-11-18 17:26:53 -05:00
Dominik Picheta
aeca551f5b Merge pull request #670 from onionhammer/master
Added timestamp to TIRCEvent
2013-11-17 14:47:05 -08:00
Zahary Karadjov
a068aaed3c simple unit test and better documentation for the user defined type classes 2013-11-17 22:50:26 +02:00
Grzegorz Adam Hankiewicz
d037aec415 Fixes times.toSeconds to handle hours and minutes correctly. 2013-11-17 21:31:05 +01:00
Zahary Karadjov
4cea15d274 improvements for the is operator; implemented the type lifting rule in user-defined type classes 2013-11-17 16:28:42 +02:00
Grzegorz Adam Hankiewicz
38eb67de83 Expands tutorial macro section with step by step guide. 2013-11-16 20:45:57 +01:00
Erik O'Leary
1a6742e651 Fixed http header parsing issue
If second half of http header line was empty, server would crash with
EInvalidIndex

https://gist.github.com/onionhammer/7487452
2013-11-15 10:47:25 -06:00
Clay Sweetser
d77370694c Prevent lambdas from crashing if given implicit generic parameters. 2013-11-14 12:32:35 -05:00
Erik O'Leary
b5965d05a2 Added timestamp to TIRCEvent 2013-11-13 13:20:45 -06:00
Zahary Karadjov
31dd66acbf support for multiple test variables and var qualifiers in user-defined type classes 2013-11-13 02:24:08 +02:00
Grzegorz Adam Hankiewicz
0ff1ba0a6d Links algorithm module from library index. 2013-11-08 12:20:45 +01:00
Araq
4cda0861f5 tcnstseq works again 2013-11-07 00:25:54 +01:00
Araq
27ec76dd3a VM now supports lambda lifting 2013-11-06 08:37:20 +01:00
Zahary Karadjov
9061b8961e failing test for static params 2013-11-05 21:55:46 +02:00
Andreas Rumpf
7a93a5f18e Merge pull request #659 from markhend/master
a few typos
2013-11-03 11:55:26 -08:00
Mark Henderson
7b1ebe896c a few typos 2013-11-03 13:01:21 -06:00
Grzegorz Adam Hankiewicz
45f9c5b942 Adds link to stackoverflow nimrod tag in support section. 2013-11-03 10:16:31 +01:00
Araq
993cdb82b6 Merge branch 'master' of github.com:Araq/Nimrod 2013-10-31 22:34:15 +01:00
Araq
f73cec7f01 GC: even more stress testing 2013-10-31 22:32:27 +01:00
Araq
eb72857ea2 added $ for oids 2013-10-31 22:30:59 +01:00
Andreas Rumpf
528f972d17 Merge pull request #631 from mflamer/master
LockFree Hash Table 0.1
2013-10-31 13:43:19 -07:00
Dominik Picheta
471c0aa634 Epoll now works. 2013-10-31 15:07:14 +00:00
Dominik Picheta
526f9da463 Epoll wrapper + selectors module. 2013-10-31 02:45:17 +00:00
Mark Flamer
f8206cb357 better better fix for Issue #629 Recursive generic types not working 2013-10-30 16:09:00 -07:00
Andreas Rumpf
2a1f8baac4 Merge pull request #646 from onionhammer/patch-1
Added base64 encode overload for arrays of integers/bytes
2013-10-30 10:10:11 -07:00
Dominik Picheta
78123520a9 Implemented boolean socket options.
Added reuseAddr for httpserver and scgi.
2013-10-30 16:40:03 +00:00
Dominik Picheta
0663c883e5 TPort is now uint16 and other small sockets fixes. 2013-10-30 14:35:30 +00:00
onionhammer
6901a8cb13 Added base64 encode overload for arrays of integers/bytes 2013-10-30 09:08:05 -05:00
Mark Flamer
4330c986db better fix for Issue #629 Recursive generic types not working 2013-10-29 20:48:40 -07:00
Araq
be45263623 jump optimizer works 2013-10-29 16:47:40 +01:00
Araq
b4e25a6372 new VM is getting stable 2013-10-29 01:07:59 +01:00
Andreas Rumpf
4013fc56a3 Merge pull request #625 from Varriount/sequences/add-ranged-insertions-deletions
Added insertion and deletion functions that accept a range.
2013-10-27 11:17:55 -07:00
Andreas Rumpf
b51858159a Merge pull request #627 from Varriount/internal-documentation/add-debug-info
Internal documentation/add debug info
2013-10-27 11:13:49 -07:00
Andreas Rumpf
ed8289e2c5 Merge pull request #639 from gradha/pr_fixes_execProcesses
Fixes execProcesses wait order. Refs #379.
2013-10-27 11:02:34 -07:00
Grzegorz Adam Hankiewicz
0eb0a887d8 Fixes execProcesses wait order. Refs #379.
Closing the stream of the process might terminate it too early for
waitForExit to gather any useful results.
2013-10-27 18:15:42 +01:00
Varriount
ea92682b98 Apply changes suggested by Araq
Added documentation examples, added defaults
2013-10-27 03:44:55 -04:00
Mark Flamer
9df232911c fix for Issue #629 Recursive generic types not working 2013-10-25 19:04:14 -07:00
Araq
6ea538cec3 computed goto now works; some progress on the new VM 2013-10-25 13:30:34 +02:00
Dominik Picheta
53752ccaab Fixed breaking changes introduced by the last commit. 2013-10-24 19:17:45 +01:00
Dominik Picheta
09b6b94509 Fixed asyncio crash when sending buffered data after connection was terminated. 2013-10-24 19:02:13 +01:00
Dominik Picheta
f5023ac544 Fixed sockets on Win32. 2013-10-23 21:07:26 +01:00
Dominik Picheta
f695bb0b6f Fixed socket compilation problems on Windows. 2013-10-23 18:30:03 +01:00
Dominik Picheta
8231deffd0 Made TSocketHandle distinct and fixed problems it caused for SSL. 2013-10-23 18:07:00 +01:00
Varriount
4f16e627ba Changed backslash to forward slash
Changed backslash to forward slash (why I used a backslash in the first place, I have no idea).
2013-10-23 01:32:13 -04:00
Mark Flamer
7832f25abf Mersenne twister random number generator 2013-10-22 15:02:58 -07:00
Mark Flamer
6fbc96fec4 LockFree Hash Table 0.1 2013-10-22 14:24:38 -07:00
Simon Hafner
a352109ade Merge pull request #630 from mflamer/master
remove whitespace
2013-10-22 07:24:35 -07:00
Mark Flamer
b27aae4bf9 more whitespace removal 2013-10-21 21:36:53 -07:00
Mark Flamer
129e72de70 remove extra white space 2013-10-21 21:33:34 -07:00
Andreas Rumpf
a74a93d885 Merge pull request #628 from mflamer/master
fix for Issue #626 - Distinct and generics not working together
2013-10-21 15:37:45 -07:00
Mark Flamer
01e43fbe83 fix for Issue #626 - Distinct and generics not working together 2013-10-21 11:43:41 -07:00
Clay Sweetser
3f502123ea Added some information on sequences. 2013-10-21 14:26:09 -04:00
Clay Sweetser
f8272eba94 Added instructions on using koch to compile nimrod with GDB support. 2013-10-21 14:26:08 -04:00
Clay Sweetser
314e526f75 Added an insertion function that inserts elements of an openarray.
Added a deletion function that allows elements between two positions in a sequence to be deleted
2013-10-20 13:06:07 -04:00
Dominik Picheta
d94a870de4 Fixed definition of seqShallowFlag. 2013-10-19 21:13:17 +01:00
Dominik Picheta
199c4d21bd Fixed regression on ARM caused by the changed behaviour of noStackFrame in commit ac474a2812. 2013-10-19 21:01:32 +01:00
Araq
ca12bf76f5 opcLdGlobal bugfix 2013-10-16 17:26:07 +02:00
Araq
3d18053370 some complex macros work 2013-10-16 16:41:24 +02:00
Andreas Rumpf
eb4f012239 Merge pull request #617 from markuspf/master
Add DragonFly as essentially a clone of FreeBSD
2013-10-15 13:17:09 -07:00
Andreas Rumpf
b4df3cade6 Merge pull request #615 from fowlmouth/patch-10
Update xlib.nim
2013-10-15 13:16:41 -07:00
Andreas Rumpf
acd285e00f Merge pull request #622 from rbehrends/master
Exposed process file handles in osproc module.
2013-10-15 13:13:39 -07:00
Andreas Rumpf
7d06489712 Merge pull request #624 from Varriount/win64/fix-sockets
Added a TSocketHandle type to winlean.nim and posix.nim
2013-10-15 13:11:00 -07:00
Clay Sweetser
229d83f6c6 Added a TSocketHandle type to winlean.nim and posix.nim
Edited sockets.nim and asyncio.nim to use the new TSocketHandle type.
2013-10-15 13:53:44 -04:00
Araq
6a9baf3fd7 compiler bootstraps with new VM 2013-10-15 08:06:54 +02:00
Araq
5659a1662e attempt to improve line information for '!=' etc. templates 2013-10-15 07:57:32 +02:00
Araq
52d1a637b9 fixed definition of culong on win64 2013-10-15 07:53:10 +02:00
Dominik Picheta
b753edec1d Add compressBound proc to zlib wrapper. 2013-10-13 00:41:57 +01:00
Reimer Behrends
f103cb4538 Exposed process file handles in osproc module.
The file handles of a PProcess instance can now be accessed through
the inputHandle(), outputHandle(), and errorHandle() methods.

Also tidied up documentation for stream accessor procs a bit.
2013-10-12 14:03:29 +02:00
Dominik Picheta
2555e500b6 Fixed async send in ftpclient module. 2013-10-11 19:20:45 +01:00
Markus Pfeiffer
5ce369ad46 Add DragonFly as essentially a clone of FreeBSD 2013-10-09 23:58:18 +01:00
Araq
98defd5a56 fixes #616 2013-10-10 00:55:54 +02:00
Araq
f9861e1fab cooler quote for c2nim 2013-10-10 00:45:15 +02:00
Araq
67e9f2861e some fixes for win64 2013-10-10 00:39:10 +02:00
Billingsly Wetherfordshire
4c7098e362 Update keysym.nim
properly type all the keysyms
2013-10-09 14:34:44 -07:00
Billingsly Wetherfordshire
8f2efd0b16 Update xutil.nim
removed converter
2013-10-09 14:34:17 -07:00
Billingsly Wetherfordshire
2c1c5f7a13 Update glx.nim
glx attributes should be int32
2013-10-08 18:05:55 -07:00
Billingsly Wetherfordshire
fd6f806194 Update xutil.nim 2013-10-08 18:04:58 -07:00
Billingsly Wetherfordshire
b226c8ca79 Update xlib.nim
remove -d:MACROS requirement for xlib shortcut functions
2013-10-08 18:02:52 -07:00
Araq
96529063bf Merge branch 'master' of https://github.com/Araq/Nimrod 2013-10-07 21:36:43 +02:00
Araq
9bf32ff72d bugfix: package names should not contain '.' 2013-10-07 21:36:31 +02:00
Dominik Picheta
3d8b883c15 Fixes problems parsing XML docs with multiple PIs. 2013-10-07 17:17:52 +01:00
Araq
90d25919f3 implemented top level asm statements 2013-10-07 06:38:04 +02:00
Araq
bb365ca424 niminst: yet another bugfix 2013-10-07 06:27:20 +02:00
Araq
eaf4da0411 niminst: slashify was a stupid idea 2013-10-06 16:41:56 +02:00
Araq
27215e89f9 Merge branch 'master' of https://github.com/Araq/Nimrod 2013-10-06 00:10:54 +02:00
Araq
ac474a2812 'noStackFrame' implies 'naked' in the generated C code 2013-10-06 00:10:45 +02:00
Andreas Rumpf
cb1a278e00 Merge pull request #613 from ventor3000/basic_geom
Fixed small typobug in basic 3d
2013-10-05 12:09:14 -07:00
Andreas Rumpf
b700e0d2f8 Merge pull request #604 from reactormonk/master
moved eqproc to the correct magic position
2013-10-05 12:07:26 -07:00
Robert Persson
ace919a0cd Fixed small typobug in basic 3d 2013-10-02 10:24:22 +02:00
Araq
422327c010 fixed another semicolon related parsing bug 2013-10-02 07:57:30 +02:00
Araq
a943905d6c fixes #609 2013-10-01 20:24:37 +02:00
Araq
f857a842fc debug GC works now 2013-10-01 17:14:30 +02:00
Araq
1a792d46d0 first version of the debug GC; doesn't work yet 2013-10-01 08:44:09 +02:00
Araq
7a2fad1e35 Merge branch 'master' of https://github.com/Araq/Nimrod 2013-09-28 00:04:13 +02:00
Araq
30f1877135 fixes for niminst 2013-09-28 00:03:47 +02:00
Araq
2f0671eb79 examples from the talk part of test suite 2013-09-27 08:45:14 +02:00
Simon Hafner
ab31ad2704 don't mess with semfold, use vars instead 2013-09-26 15:10:54 -05:00
Simon Hafner
becd55dced moved eqproc to the correct magic position
also added mEqCString to evalOps so the test runs
2013-09-26 15:05:00 -05:00
Simon Hafner
e1c2aa2ddd Revert "deleted EqProc so the magic aligns again" - wrong remote.
This reverts commit d7c8b3ad06.
2013-09-26 14:31:02 -05:00
Simon Hafner
d7c8b3ad06 deleted EqProc so the magic aligns again 2013-09-26 14:27:52 -05:00
Araq
a0b82db402 the compiler can now deal with multiple modules of the same name 2013-09-26 17:34:46 +02:00
Araq
c085a1b4f0 documentation improvements 2013-09-25 08:44:57 +02:00
Araq
9bfcdc40ef JS codegen: supports more builtins 2013-09-24 23:56:23 +02:00
Araq
e3ecc328a1 fixes #593 2013-09-24 21:45:22 +02:00
Araq
8b5aa221ad support for multiple modules of the same name; niminst supports 'platforms'; minor bugfixes 2013-09-24 16:07:07 +02:00
Araq
83584bf889 implemented 'import a as b' 2013-09-24 09:36:31 +02:00
Araq
367abca382 support for --cs:partial 2013-09-24 09:32:49 +02:00
Araq
c11398ea0d bugfix: typos in os.nim 2013-09-24 09:27:00 +02:00
Araq
05d12897a2 changed parentDir to return the empty string on error 2013-09-24 09:22:29 +02:00
Araq
f1e789bfc2 fixes #576 2013-09-18 02:58:18 +02:00
Araq
51672aef72 should fix newly introduced bugs wrt TR macros 2013-09-18 02:03:56 +02:00
Araq
9de3bc8ef6 improvements for TR macros 2013-09-17 23:43:07 +02:00
Araq
823cb494a5 Merge pull request #561 from fenekku/master
glColor*v now accept vector (array) as input (as in original lib)
2013-09-11 13:27:37 -07:00
Araq
1e2ec3642d Merge branch 'master' of github.com:Araq/Nimrod 2013-09-11 00:22:06 +02:00
Araq
0a851c869f c2nim: added some scope operator parsing 2013-09-11 00:07:39 +02:00
Araq
596496f695 fixes #566 2013-09-11 00:00:11 +02:00
Araq
4d86b8a83c fixes #588 2013-09-10 23:49:53 +02:00
Araq
c6d428d47d Merge pull request #548 from ventor3000/master
Added basic2d module
2013-09-10 14:21:01 -07:00
Araq
275c7ccf82 fixes #575 2013-09-10 22:04:12 +02:00
Araq
138db5a85d disabled M&S GC again 2013-09-10 00:46:02 +02:00
Araq
f659b6a0d9 Merge branch 'master' of github.com:Araq/Nimrod 2013-09-10 00:40:19 +02:00
Araq
db19b18241 cn2im: basic C++ support 2013-09-10 00:40:06 +02:00
Araq
094d7fd4b1 added 'newLit' 2013-09-10 00:37:23 +02:00
Zahary Karadjov
f05ac0cb23 fix regressions affecting the echo magic and the creating of rod files
the markAndSweep GC was not responsible for the regressions so
this commit restores its use
2013-09-07 11:55:19 +03:00
Araq
ff1273a312 Merge branch 'master' of github.com:Araq/Nimrod 2013-09-06 00:26:04 +02:00
Araq
827dc054fb bugfix: --gc:none -d:useMalloc works again 2013-09-06 00:25:48 +02:00
Zahary Karadjov
0ade885617 reverting the GC change 2013-09-05 12:35:42 +03:00
Araq
40b379859c resolved the conflict 2013-09-03 23:46:41 +02:00
Araq
891f871ba7 better support for GNU's assembler 2013-09-03 23:44:31 +02:00
zah
6fa72c5d9d Merge pull request #586 from mflamer/master
Add arity typetrait
2013-09-03 09:05:12 -07:00
Mark Flamer
73aba23a49 Add arity typetrait 2013-09-02 18:20:00 -07:00
Zahary Karadjov
6a04757e6d switching the compiler to the markAndSweep collector
This produces faster bootstrapping, works properly for the caas mode
and fixes the Aporia build on a mac
2013-09-03 03:18:09 +03:00
Zahary Karadjov
6082595e96 Merge branch 'type-classes' into upstream 2013-09-03 03:14:56 +03:00
Zahary Karadjov
c8c8d2035a partially documented the new features 2013-09-03 03:14:22 +03:00
fenekku
0ce885e8c8 Color vectors (second line endings fix attempt) 2013-09-02 18:43:19 -04:00
fenekku
c57103f2d8 Color vectors (first line endings fix attempt) 2013-09-02 10:59:42 -04:00
Araq
39da6979ad use realpath in a posix compliant way 2013-09-01 22:53:02 +02:00
Araq
f2b9af6ae1 bugfix: line information for comments 2013-09-01 18:50:03 +02:00
Araq
a95c0608b9 some fixes for Haiku 2013-09-01 17:29:29 +02:00
Araq
e7f0544154 Merge branch 'master' of github.com:Araq/Nimrod 2013-09-01 15:54:46 +02:00
Araq
6825a69a70 -d:nocaas mode for easier bootstrapping on exotic OSes (Haiku) 2013-09-01 15:54:32 +02:00
Araq
62ed6b0aaf Merge pull request #580 from gradha/pr_adds_equality_for_arrays
Adds equality comparison for arrays.
2013-09-01 01:39:31 -07:00
Araq
8087f51d14 fixes #582 2013-09-01 10:36:13 +02:00
Araq
0464a1071e Merge branch 'master' of github.com:Araq/Nimrod 2013-08-31 20:45:47 +02:00
Araq
023bd63d39 fixes #398 2013-08-31 20:45:34 +02:00
Zahary Karadjov
b5d833b329 implemented the using statement 2013-08-31 19:40:36 +03:00
Araq
9c6de08db0 fixes #516 2013-08-31 16:45:10 +02:00
Araq
84bd794588 Merge pull request #579 from gradha/pr_fixes_xmltree_macro_docstring
Fixes xmltree <> macro docstring.
2013-08-31 07:33:30 -07:00
Araq
b40ab4dc9e fixes #554, fixes #179 2013-08-31 11:49:33 +02:00
Araq
1161482ec2 fixes #459 2013-08-31 11:22:49 +02:00
Araq
e698d6255b fixes #563 2013-08-31 10:03:41 +02:00
Araq
6cc06cd35d fixes #569; C++ codegen works again 2013-08-31 02:07:52 +02:00
Araq
4d9b2f671a fixes #578 2013-08-30 22:47:14 +02:00
Araq
cf689f7472 bugfix: conversions to float32 are allowed again but of lower priority 2013-08-30 21:47:55 +02:00
Araq
74c24f3e6d conversions to float32 are allowed again but of lower priority 2013-08-30 21:40:47 +02:00
Araq
0c133b3f02 tester compiles again 2013-08-30 18:14:19 +02:00
Araq
8710118b2c Merge branch 'master' of github.com:Araq/Nimrod 2013-08-30 12:44:27 +02:00
Araq
a17076cf4f fixes #572 2013-08-30 12:44:09 +02:00
Araq
7056ceda67 float64 is now an alias to 'float'; fixes #545 2013-08-30 12:24:54 +02:00
Araq
1ad1980f1f bugfix: 'not x of y' requires () 2013-08-30 12:16:18 +02:00
Araq
5f943cf4bc docgen: more newlines in the output to support primitive postprocessors 2013-08-29 23:18:02 +02:00
Zahary Karadjov
01ccb52a00 minor improvement towards tgenericshardcases 2013-08-28 01:10:51 +03:00
Zahary Karadjov
52b00630c8 fix tisop
Adding nil checks on the exit paths for semCompiles errors.
This was probably not needed before, because semIndirectOp
had a special detection for semCompiles contexts. We could
try to restore these, but wouldn't this just postpone the crashes
until someone tries the same expressions in nimrod check?

One of the previous commits also used errorNode to avoid
returning nil. This may be an alaternative approach.
2013-08-27 01:51:02 +03:00
Zahary Karadjov
9cc23118be fix tcompiles 2013-08-27 01:01:03 +03:00
Zahary Karadjov
dc33638cb2 proper discrimination between csEmpty and csNoMatch
fixes twrongtupleaccess and topaque
2013-08-27 00:08:47 +03:00
Zahary Karadjov
bdeaee4a33 fix tnoop
This commit requires further investigation.

Fixing semExpr(nkCall) once and for all to work with sym-choices and to
allow overloading with immediate templates and macros will probably set
this straight too.
2013-08-26 23:43:39 +03:00
Zahary Karadjov
28d9398de7 implemented delegators and improved the error messages of unmatched type classes 2013-08-26 23:29:24 +03:00
Dominik Picheta
c934a33ccd Implemented ability to connect through proxies for the httpclient module. 2013-08-26 18:02:45 +01:00
Zahary Karadjov
89086a8e19 prevent eval crashes due to PContext-dependent ops not being available in evalConstExpr 2013-08-25 18:11:28 +03:00
Zahary Karadjov
6378fbd66e working code for simple cases of user-defined type classes 2013-08-25 12:17:40 +03:00
Zahary Karadjov
03577bc936 fix parsing of `proc foo(x: distinct Type)` 2013-08-24 23:44:37 +03:00
Dominik Picheta
18033026cb Removed outdated bootstrapping info from install.txt 2013-08-23 23:14:27 +01:00
Zahary Karadjov
037a1a3e0f parsing of user defined type classes 2013-08-23 21:36:56 +03:00
Zahary Karadjov
56d75bd23b implemented and documented the new typedesc binding rules 2013-08-23 15:43:27 +03:00
Zahary Karadjov
8682ed9bd0 pass-through of static int generic params to arrays when late instantiation is disabled 2013-08-23 01:10:20 +03:00
Zahary Karadjov
fee2a7ecfa Experimental support for delayed instantiation of generics
This postpones the semantic pass over the generic's body until
the generic is instantiated. There are several pros and cons for
this method and the capabilities that it enables may still be possible
in the old framework if we teach it a few new trick. Such an attempt
will follow in the next commits.

pros:
1) It allows macros to be expanded during generic instantiation that
will provide the body of the generic. See ``tmacrogenerics``.
2) The instantiation code is dramatically simplified. Dealing with unknown
types in the generic's body pre-pass requires a lot of hacky code and error
silencing in semTypeNode. See ``tgenericshardcases``.

cons:
1) There is a performance penalty of roughly 5% when bootstrapping.
2) Certain errors that used to be detected in the previous pre-pass won't
be detected with the new scheme until instantiation.
2013-08-23 01:10:20 +03:00
Grzegorz Adam Hankiewicz
b7b19348a7 Adds equality comparison for arrays. 2013-08-22 23:09:31 +02:00
Grzegorz Adam Hankiewicz
64cf8d3893 Fixes xmltree <> macro docstring. 2013-08-22 23:01:15 +02:00
Araq
a8c8a85135 Merge branch 'master' of github.com:Araq/Nimrod 2013-08-22 19:28:58 +02:00
Araq
cf38d635bf implemented opcTypeTrait 2013-08-22 19:28:34 +02:00
Araq
3940bd5b84 GC: added static cycleGC checks 2013-08-22 19:20:45 +02:00
Araq
6f1fc1b5ba fixed and documented computedGoto pragma 2013-08-22 08:38:47 +02:00
Zahary Karadjov
ca3a4ce672 hacky fix for generic constraints matching 2013-08-19 01:48:25 +03:00
Zahary Karadjov
4980ef85e2 check the owners of generic instantiations properly and fix tinvalidclosure 2013-08-19 01:45:16 +03:00
Zahary Karadjov
b01d9b6181 work-in-progress for compiling generics in their owner module 2013-08-19 01:45:16 +03:00
Zahary Karadjov
3e79e9f981 some steps to improve the type mismatches with the new
generic instantiation logic
2013-08-19 01:45:16 +03:00
Zahary Karadjov
8b933e470e fixes iterating over enums 2013-08-19 01:36:04 +03:00
Zahary Karadjov
c6d0611112 Revert "Revert "made some tests green"" 2013-08-19 01:35:33 +03:00
Zahary Karadjov
a453d8d64d Revert "Revert "further fixes for void stripping. fixes tvoid.""
This reverts commit d11cf5d191.
2013-08-19 01:30:17 +03:00
Zahary Karadjov
cefa16ae77 Revert "Revert "fix threading tests""
This reverts commit 9c45e33d8c.
2013-08-19 01:29:58 +03:00
Zahary Karadjov
fc858927f0 Revert "Revert "fix tforwardgeneric""
This reverts commit e3f93241c3.
2013-08-19 01:29:47 +03:00
Zahary Karadjov
f760bc243b Revert "Revert "static and default params for generics""
This reverts commit 0662ec4a43.
2013-08-19 01:29:37 +03:00
Zahary Karadjov
ea54aa386c Revert "Revert "allow keyword params for the [] and {} operators""
This reverts commit b7ea4a7e65.
2013-08-19 01:29:22 +03:00
Zahary Karadjov
19eeb3556e remerge "allow void as field type" 2013-08-19 01:29:01 +03:00
Zahary Karadjov
6ddd4e6a3f Revert "Revert "bugfix: emulated thread vars used in combination with the mark & sweep GC""
This reverts commit 75c586bbe1.
2013-08-19 01:27:05 +03:00
Zahary Karadjov
dfb5cb3c5d remerge "Fixes #267" 2013-08-19 01:26:37 +03:00
Zahary Karadjov
f127bc387a Revert "Revert "test cases for the new features""
This reverts commit e1b668c868.
2013-08-19 01:17:07 +03:00
Araq
50403afb5c fixes base64 module 2013-08-15 00:22:48 +02:00
Araq
d53f313599 implemented computed goto support 2013-08-13 11:21:02 +02:00
Araq
1633e22aec Merge branch 'master' of github.com:Araq/Nimrod 2013-08-11 18:48:59 +02:00
Araq
d18c82a9ef new VM: preparations for evalMacroCall 2013-08-11 18:48:33 +02:00
Araq
db027faf38 fixes a long standing channels bug 2013-08-09 00:25:31 +02:00
Araq
a294d45fd6 Merge branch 'master' of github.com:Araq/Nimrod 2013-08-08 21:11:20 +02:00
Araq
288cd05f89 new VM: register allocator bugfix; implemented more magics 2013-08-08 21:10:54 +02:00
Zahary Karadjov
5dfc0d0d19 Take into account dirty buffers in suggest output; Fixes zah/nimrod.vim#14 2013-08-07 18:58:46 +03:00
Araq
06b3852143 Merge branch 'master' of github.com:Araq/Nimrod 2013-08-07 01:40:37 +02:00
Araq
aefa0da8a6 new VM: implemented constructors and jump optimizer 2013-08-07 01:40:08 +02:00
Araq
ee9aee6c00 bugfix createDir for solaris 2013-08-07 01:36:15 +02:00
Zahary Karadjov
5c32156a71 fixes #534 2013-08-07 00:01:58 +03:00
fenekku
0ec9e3aeb7 glColor*v now accept vector as input (as in original lib) 2013-08-04 18:30:22 -04:00
Dominik Picheta
015b814e6a Updated bootstrap instructions. Removed csources.zip. 2013-08-04 22:24:21 +01:00
Dominik Picheta
201e4d2835 Modified the behaviour of the build scripts to accommodate new C sources
repo.
2013-08-04 19:41:20 +01:00
Dominik Picheta
8ac7bda244 sockets.send now throws an exception when a non-blocking socket is
passed to it.
2013-08-04 19:13:29 +01:00
Araq
30bb68d48a new VM: next steps 2013-08-03 21:14:57 +02:00
Dominik Picheta
ec86d5db0f Improved documentation for macros.newProc. 2013-07-31 23:44:09 +01:00
Araq
9589acd00e fixes #532 2013-08-01 00:16:29 +02:00
Araq
3ae6043e7e Merge pull request #533 from gradha/pr_helper_procs
Adds some helper procs
2013-07-31 12:59:22 -07:00
Araq
3ab4b3d58f Merge pull request #530 from EXetoC/master
Missing SDL_image symbols
2013-07-31 12:48:33 -07:00
Araq
c96a4406e4 Merge pull request #523 from exhu/x11fix
X11, cairo bindings fixes
2013-07-31 12:47:41 -07:00
Araq
731c6f9083 'nimrod pretty' usable 2013-07-31 20:35:04 +02:00
ventor3000
347de6b08c Forgot publicity star on symbol 2013-07-31 07:44:55 +02:00
Araq
805959378d 'nirmod pretty': almost working 2013-07-31 02:50:17 +02:00
Araq
e5be2e9f97 'nimrod pretty': next steps 2013-07-30 21:10:45 +02:00
ventor3000
e6cedc2b8c Some minor fixes
Fixed som wrong spellings in cooments, reordering
some arguments to be mor uniform, and fixed a small bug in
isUniform for 3d matrix.
2013-07-30 18:15:39 +02:00
Araq
d640121ce6 lfFullExternalName for 'nimrod pretty' 2013-07-30 17:15:58 +02:00
Araq
fd2a808266 fixes token's column information 2013-07-30 08:45:00 +02:00
Araq
28ad262a46 'nimrod pretty': next steps, doesn't work yet 2013-07-29 23:52:08 +02:00
Araq
6810a0e3e3 'nimrod pretty' command: next steps 2013-07-29 22:56:32 +02:00
Araq
d6d665b0c0 Merge branch 'master' of github.com:Araq/Nimrod 2013-07-29 01:21:53 +02:00
Araq
ef975d277a new vm: further progress 2013-07-29 01:21:32 +02:00
ventor3000
7c2fcd4ad9 Some doc. fixes 2013-07-28 00:17:03 +02:00
ventor3000
e1db8d11ad basic3d module and some fixes in basic2d
Added the basic3d module. Standard 3d maths but still reimplemented
evrywhere.
2013-07-27 23:56:01 +02:00
Dominik Picheta
c5c6ef6e2b Fixes graphics.drawEllipse.
It failed because a Natural cannot be negative but drawEllipse tried to
set negative values to a Natural variable; this variable's type was
changed to an Int.
2013-07-27 11:18:13 +01:00
Dominik Picheta
e33af13ae3 Fixes #543.
Changed signature of SetVideoMode so that the flags param is a uint32.
2013-07-27 11:03:28 +01:00
Araq
27b7ecbbff new vm: lots of fixes 2013-07-27 01:28:31 +02:00
Araq
fca23d1675 bugfix: system.& for sequences 2013-07-27 01:28:13 +02:00
ventor3000
1c46fdf600 Fixed stupid mistake when clamping acos 2013-07-26 21:18:30 +02:00
Araq
698eac2a94 new vm: can execute simple programs 2013-07-26 12:17:36 +02:00
ventor3000
854a000b44 Some minor changes 2013-07-26 10:49:22 +02:00
Araq
05108cf81c Merge branch 'master' of github.com:Araq/Nimrod 2013-07-25 23:40:29 +02:00
Araq
f3a2eec13b attempt to make C codegen aware of 'gensym' 2013-07-25 23:40:15 +02:00
Dominik Picheta
e360d048ba Added macros.newIfStmt and macros.newVarStmt. 2013-07-25 22:15:34 +01:00
Araq
a59874e312 Merge branch 'master' of github.com:Araq/Nimrod 2013-07-25 22:40:47 +02:00
Araq
02c86567ee new vm: next steps 2013-07-25 22:40:25 +02:00
Araq
2c3d1fa954 bugfix: gensym 2013-07-25 21:25:40 +02:00
ventor3000
6912463585 Added file header 2013-07-25 16:01:40 +02:00
ventor3000
97810e1850 Added basic2d module
Module for basic 2d computation
2013-07-25 15:40:05 +02:00
Araq
3e0899359b new evaluation engine: next steps 2013-07-25 08:37:37 +02:00
Araq
bdbf0f863d Merge branch 'master' of github.com:Araq/Nimrod 2013-07-24 23:07:45 +02:00
Araq
9acdf94cc0 fixes #531 2013-07-24 23:07:28 +02:00
Araq
8ac68a4d94 Merge pull request #527 from jbe/master
export pointer types for SDL event objects
2013-07-24 13:35:20 -07:00
Araq
b1d4dfa6b1 fixes #544 2013-07-24 22:32:09 +02:00
Araq
f9426bfcd5 added macros.genSym 2013-07-24 21:58:17 +02:00
Araq
b403b41aec Merge branch 'master' of github.com:Araq/Nimrod 2013-07-24 21:40:08 +02:00
Araq
b30e237a37 first steps to a new evaluation engine 2013-07-24 21:39:39 +02:00
Dominik Picheta
325c167e2a Fixes OSError deprecation warning. 2013-07-21 11:08:28 +01:00
Araq
84534ce4b8 Merge branch 'master' of github.com:Araq/Nimrod 2013-07-20 20:18:21 +02:00
Araq
aa88e150da 'modules' module from 'main'; minor bugfixes 2013-07-20 20:17:23 +02:00
Grzegorz Adam Hankiewicz
55bcd0ba1e Adds findAll() convenience procs to xmltree. 2013-07-20 00:06:23 +02:00
Grzegorz Adam Hankiewicz
e7be3d873f Notes kind() getter is used to read TXmlNode.k field. 2013-07-19 23:25:22 +02:00
Grzegorz Adam Hankiewicz
c0b78276e8 Adds convenience expandTilde proc around getHomeDir. 2013-07-19 23:20:06 +02:00
Grzegorz Adam Hankiewicz
68cfb25c11 Adds convenience copyFileWithPermissions to os module. 2013-07-19 22:52:11 +02:00
Araq
bfbdb1f028 refactorings for the eval engine; bugfix: clean templates as accessors 2013-07-19 22:22:20 +02:00
EXetoC
1e3934e464 dynlib 2013-07-18 23:25:29 +02:00
Dominik Picheta
a932d201d2 Rebuilt C Sources. 2013-07-18 20:46:03 +01:00
EXetoC
6e4dfc8eb5 Add missing SDL symbols. 2013-07-18 20:28:09 +02:00
Dominik Picheta
f3b4240b87 Fixed libzip path for Arch Linux. 2013-07-17 22:29:21 +01:00
Dominik Picheta
0226cca832 Rebuilt csources. 2013-07-17 22:28:49 +01:00
jbe
2c2ae2adb2 export pointer types for SDL event objects 2013-07-17 00:52:32 +02:00
Simon Hafner
952f560d0a Merge pull request #524 from gradha/pr_misc_docs
Miscellaneous doc tweaks
2013-07-15 19:43:19 -07:00
Grzegorz Adam Hankiewicz
2ee228d5d1 Documents copyFile not copying attributes on posix. 2013-07-16 02:56:50 +02:00
Grzegorz Adam Hankiewicz
ec6e267351 Warns to not modify string findAll is iterating over. 2013-07-16 02:00:25 +02:00
Grzegorz Adam Hankiewicz
67cea2b9b5 Explains parseHex initialization quirk. 2013-07-16 01:11:20 +02:00
Grzegorz Adam Hankiewicz
b5811cc73c Adds some examples to JoinPath and / procs. 2013-07-16 00:47:49 +02:00
Yury Benesh
02ca9e3b59 Moved complex pragmas for xlib and cairo into separate included files. Fixed xkb bindings. 2013-07-15 16:06:53 +03:00
Araq
1af2d94860 Merge pull request #519 from gradha/pr_guards_against_nil_ast
Avoids usefulFact recursion with nil parameter. Fixes #518.
2013-07-09 15:05:46 -07:00
Grzegorz Adam Hankiewicz
172945de31 Avoids usefulFact recursion with nil parameter. Fixes #518. 2013-07-09 23:31:13 +02:00
Yury Benesh
f54cb2e323 Fixed xrender.nim for use_pkg_config 2013-07-09 23:30:11 +03:00
Yury Benesh
3c9864c9d3 Added use_pkg_config, use_pkg_config_static conditionals to xlib, cairo 2013-07-09 21:58:22 +03:00
Araq
dbb87bc557 Merge pull request #504 from ventor3000/master
modules poly and numeric added
2013-07-07 16:06:58 -07:00
Araq
6feedc9cff Merge pull request #515 from gradha/pr_idetools_improvements
Idetools improvements
2013-07-07 16:05:17 -07:00
Araq
bd1c878af4 Merge pull request #514 from exhu/fix_csource_tmpl
Fix for Issue #510 : Moved linker flags to the end of cmd line in build.sh and bat templates
2013-07-07 16:03:06 -07:00
Araq
f841447c75 Merge pull request #513 from gradha/pr_extends_align
Extends align proc with default padding parameter.
2013-07-07 16:01:51 -07:00
Araq
54df6a30c5 Merge pull request #512 from gradha/pr_documents_gorgeous_pragmas
Documents passC/passL pragmas. Refs #506.
2013-07-07 16:01:08 -07:00
Yury Benesh
f74e296f84 Fixed XClientMessageEvent struct, added equals operator fot TAtom from unsigned, added xclient union field access proc to XEvent 2013-07-07 23:01:11 +03:00
Robert Persson
5a18100816 Fixed some minor stuff in module poly
Removed the stupid initPolyFromDegree which only served ro re-allocate
results. Also fixed some minor stuff with nil return values in roots.
2013-07-07 01:50:10 +02:00
Robert Persson
0d2f8d5079 Optimized integrate function in module poly
Rewrote the integrate function since the old one was quite hacky. The
new one is about 7 times faster in release and 3 times faster in debug
2013-07-07 01:26:00 +02:00
Yury Benesh
127253c8d5 Some fixes to xlib wrapper 2013-07-06 23:39:15 +03:00
Grzegorz Adam Hankiewicz
2f0f1d0a3f Adds idetools failure case for re"" being reported as a module. 2013-07-06 20:20:58 +02:00
Grzegorz Adam Hankiewicz
baf4f8c9eb Documents idetools skMacro with failure test case. 2013-07-06 20:00:12 +02:00
Grzegorz Adam Hankiewicz
383d047763 Documents idetools skLabel with failure test case. 2013-07-06 19:42:36 +02:00
Grzegorz Adam Hankiewicz
4ed44fc634 Moves caasdriver comments into idetools document. 2013-07-06 18:51:37 +02:00
Grzegorz Adam Hankiewicz
9e649ffdf2 Mentions expected order of idetools suggest results. 2013-07-06 18:03:27 +02:00
Grzegorz Adam Hankiewicz
9b76435280 Adds caas and idetools keywords to The One And Only Great Index. 2013-07-06 18:03:27 +02:00
Grzegorz Adam Hankiewicz
b22af9776d Forces removal of nimcache dir for all caas runs.
Now some test cases fail because they can't use a previous nimcache
directory (which potentially could have wrong compiled code anyway).
2013-07-06 18:03:19 +02:00
Grzegorz Adam Hankiewicz
4583c4ea0a Adds more idetools suggest failure cases. 2013-07-06 16:51:55 +02:00
Yury Benesh
e5ed6aec0e Moved linker flags to the end of cmd line in build.sh and bat templates 2013-07-06 10:40:32 +03:00
Grzegorz Adam Hankiewicz
65b899030d Extends align proc with default padding parameter. 2013-07-05 21:37:30 +02:00
Grzegorz Adam Hankiewicz
6bab7a5bda Documents passC/passL pragmas. Refs #506. 2013-07-05 16:33:52 +02:00
Araq
ebd45529c1 Merge pull request #509 from EXetoC/patch-1
Modify babelpath
2013-07-04 23:51:24 -07:00
Araq
c61488cf9d Merge pull request #508 from gradha/patch-1
Silences debug echo.
2013-07-04 23:48:54 -07:00
Erik Johansson Andersson
72ec035eba Modify babelpath
Babel looks in this dir now.
2013-07-04 20:41:35 +02:00
Yury Benesh
a080277f84 Added pkg-config support to xlib, xrender, cairo, cairoxlib 2013-07-04 19:38:27 +03:00
Yury Benesh
37b660dd78 Fixed libX11, libXrender bindings for macos and linux. 2013-07-04 17:45:44 +03:00
Grzegorz Adam Hankiewicz
dd60372226 Silences debug echo. 2013-07-04 16:18:36 +02:00
Robert Persson
ce1399db2d Optimized divMod in poly
Made a huge speed improvement in debug mode. Only a few % in release,
but the memory load should be somewhat lower.
2013-07-03 12:44:26 +02:00
Robert Persson
2cae55ae04 Fixed a mixed bag of stuff poly and numeric 2013-07-03 01:15:31 +02:00
Araq
3e4dec3cf4 Merge pull request #485 from gradha/pr_suggest_case
Adds idetools --suggest test case. Refs #484.
2013-07-02 11:58:59 -07:00
Robert Persson
d1a90c6ec6 Cleanup of poly an numeric modules
Removed some test code
2013-07-02 20:55:27 +02:00
Araq
b5946751b8 Merge branch 'master' of github.com:Araq/Nimrod 2013-07-02 19:45:26 +02:00
Araq
bfca977d5f fixes #505 2013-07-02 19:44:40 +02:00
Araq
c1155cd2a5 fixes #503 2013-07-02 19:32:12 +02:00
Robert Persson
85dbc2d306 Added poly and numeric modules 2013-07-02 16:01:41 +02:00
Grzegorz Adam Hankiewicz
f7f1408168 Adds idetools --suggest test case. Refs #484.
1) There are too many suggestions for the given prefix.
2) The suggestions don't take into account the preceeding type.
3) trackDirty only works on caas mode.
2013-07-02 12:28:22 +02:00
Araq
0c18e05336 Merge pull request #502 from nihathrael/master
Order suggestion output by scope and then by item name.
2013-07-01 11:47:13 -07:00
Thomas Kinnen
cb3915c5e1 Order suggestion output by scope and then by item name. 2013-07-01 20:32:26 +02:00
Araq
dfe195a4a1 fixes #501 2013-07-01 20:25:38 +02:00
Araq
9b4be8a739 bugfix: -o option doesn't crash the compiler anymore 2013-07-01 20:17:36 +02:00
Araq
6c8e740b57 made parseBiggestFloat faster for large exponents 2013-07-01 00:33:11 +02:00
Araq
30f8568570 fixes --os:standalone 2013-06-30 22:10:04 +02:00
Araq
1a5e30b053 made some tests green 2013-06-30 21:55:05 +02:00
Araq
52851b722d --os:standalone works again 2013-06-30 21:15:28 +02:00
Araq
651103ff32 2n attempt to fix niminst on the testing machines 2013-06-29 10:28:28 +02:00
Araq
1bdc0d1dd3 fixes lots of regressions 2013-06-29 10:04:18 +02:00
Araq
43de61f37b bugfix: pragmas allowed for implicit generics 2013-06-29 09:08:57 +02:00
Araq
117a77e106 Merge branch 'master' of github.com:Araq/Nimrod 2013-06-29 01:52:06 +02:00
Araq
8f0d0250cd bugfix: typo 2013-06-29 01:51:42 +02:00
Araq
7b946ec025 Merge pull request #486 from gradha/pr_idetools_docs
Adds idetools docs
2013-06-28 14:43:30 -07:00
Araq
693d019654 Merge pull request #487 from gradha/pr_no_more_slurping
Improves highlite module
2013-06-28 14:41:44 -07:00
Araq
93158a53a8 got rid of debug calls 2013-06-28 23:40:09 +02:00
Araq
a8542fbe06 some small performance improvement for the evaluator 2013-06-28 23:36:43 +02:00
Araq
976d5b18ed small REPL improvements 2013-06-28 16:40:01 +02:00
Araq
2ca05eeb16 var tuple unpacking works at compile time 2013-06-28 08:40:49 +02:00
Araq
df8e151408 implements nicer floating point literals 2013-06-27 22:22:49 +02:00
Araq
86d64b2f5e attempt to make libzip work on the testing machines 2013-06-27 21:41:53 +02:00
Araq
b6f2902905 Merge branch 'master' of github.com:Araq/Nimrod 2013-06-27 19:57:24 +02:00
Araq
83876b1b81 bugfix: rendering of typ|typ2 2013-06-27 19:57:01 +02:00
Araq
139562cc64 implements the 'codegenDecl' pragma 2013-06-27 18:13:11 +02:00
Araq
6d7ad66982 attempt to use the lib.so for libzip 2013-06-27 16:34:21 +02:00
Dominik Picheta
a9f2c3ffaf Fixed OSError + recvLine deprecation warnings. 2013-06-27 15:06:30 +01:00
Araq
e599fdd60d bugfix: marshal supports unsigned numbers 2013-06-27 08:39:41 +02:00
Araq
8d4f5038d0 fixes #488 2013-06-27 08:19:03 +02:00
Araq
ed56b8c173 fixes #442 2013-06-27 08:06:55 +02:00
Araq
82ceca0717 fixes #492 2013-06-27 07:43:04 +02:00
Araq
3ff572ffcd Merge branch 'master' of github.com:Araq/Nimrod 2013-06-27 01:05:19 +02:00
Araq
a674c039fb fixed a long standing xml parser bug; html parser bugfixes + speed improvements 2013-06-27 01:04:56 +02:00
Dominik Picheta
9686d92bfc Fixed OSError deprecation warnings. 2013-06-26 00:00:07 +01:00
Dominik Picheta
5d3b5eb700 Merge pull request #489 from onionhammer/patch-1
Fix: OpenSSL on Windows
2013-06-25 13:17:58 -07:00
Dominik Picheta
bacb20a379 Deprecated OSError, and modified it to require an explicit OS error code.
The deprecated functions include the OSError and OSErrorMsg, the name did not change however the signature of the new functions did. They now require a TOSErrorCode value be passed to them. This value can be retrieved using OSLastError. The reason this was done is because on Windows any win api call can reset the last error code to 0, this change allows the user to immediately grab the error code and worry about the string representation later if needs be.
2013-06-25 20:10:28 +01:00
Dominik Picheta
9540a93d95 Fixed terminal module so that it doesn't raise an EOS exception when stdout is redirected. 2013-06-22 19:57:12 +01:00
Dominik Picheta
317675d5e5 Changed the type of gboolean to a distinct cint. 2013-06-22 19:42:26 +01:00
Dominik Picheta
d23d14897a Symlinks are now expanded in os.getAppFilename on Mac OS X. 2013-06-22 00:15:07 +01:00
Dominik Picheta
2bb4a853ec Send buffer will be respected now when closing async SCGI clients. 2013-06-21 16:01:31 +01:00
Dominik Picheta
a1e823b038 Added an asyncio.isSendDataBuffered procedure. 2013-06-21 16:07:13 +02:00
onionhammer
705e8e929a Fix: OpenSSL on Windows
Updated CRYPTO_malloc_init to no longer call CRYPTO_set_mem_functions if compiling for windows

Updated ERR_load_BIO_strings to import from DLLUtilName instead of DLLSSLName

Updated OpenSSL_add_all_algorithms to import from DLLUtilName instead of DLLSSLName
2013-06-20 17:52:30 -05:00
Grzegorz Adam Hankiewicz
579d0f6f41 Adds highlite to tests suite. 2013-06-18 22:18:44 +02:00
Grzegorz Adam Hankiewicz
4c7607e074 Adds previous slurping as runnable testcase. 2013-06-18 21:42:53 +02:00
Grzegorz Adam Hankiewicz
5b1caed806 Replaces relative file slurping with hardcoded array. 2013-06-18 21:01:12 +02:00
Grzegorz Adam Hankiewicz
a1da2b713b Adds idetools hierarchy nesting test. 2013-06-16 22:39:38 +02:00
Grzegorz Adam Hankiewicz
1f8c5c37d3 Adds idetools test to verify --usages, reuses testcase. 2013-06-16 22:39:38 +02:00
Grzegorz Adam Hankiewicz
25f45cace1 Adds idetools test to check declaration proc signatures. 2013-06-16 22:39:38 +02:00
Grzegorz Adam Hankiewicz
b15f585273 Adds idetoos testcase to verify returned signatures.
At the moment too many of them return proc.
2013-06-16 22:39:38 +02:00
Grzegorz Adam Hankiewicz
d2def332fd Adds $SILENT replacement to reduce test output verbosity. 2013-06-16 22:39:38 +02:00
Grzegorz Adam Hankiewicz
d18d6ba019 Starts idetools specific documentation. 2013-06-16 22:39:38 +02:00
Grzegorz Adam Hankiewicz
1dfea2a362 Lists available idetools caas switches. 2013-06-15 15:43:36 +02:00
Araq
ff1d68c50b fixes #481 2013-06-13 15:19:55 +02:00
Araq
2464da5b26 Merge branch 'master' of github.com:Araq/Nimrod 2013-06-13 01:40:35 +02:00
Araq
d4c91bbd85 improvements for 'not nil' checking 2013-06-13 01:40:11 +02:00
zah
b1f4ade874 Merge pull request #478 from gradha/pr_idetools
More idetools additions
2013-06-12 02:25:25 -07:00
Araq
0097305953 bugfixes for the guarded data flow analysis 2013-06-12 00:41:02 +02:00
Grzegorz Adam Hankiewicz
b4ea608b65 Removes the nimcache symbol directory for each run. 2013-06-11 22:34:37 +02:00
Grzegorz Adam Hankiewicz
28041461b7 Adds symbol proc run mode as suggested by Zahary.
To avoid collision each test case uses a different nimcache directory
based on the input test filename.
2013-06-11 17:23:48 +02:00
Grzegorz Adam Hankiewicz
10c441deed Enables trackDirty query for idetools proc mode. 2013-06-11 16:49:43 +02:00
Grzegorz Adam Hankiewicz
41c51a11d3 Adds $TESTNIM and $MODULE as variables to test cases. 2013-06-11 16:49:04 +02:00
Araq
38faa64b12 Merge branch 'master' of github.com:Araq/Nimrod 2013-06-11 00:32:27 +02:00
Araq
c156f2d493 next steps for guarded data flow analysis 2013-06-11 00:31:40 +02:00
Grzegorz Adam Hankiewicz
fe18117fb2 Adds idetools testcase for dynamic dispatch. Refs #477. 2013-06-10 23:07:36 +02:00
Grzegorz Adam Hankiewicz
b0ba4caf64 Renames test cases to be more human friendly. 2013-06-10 23:06:49 +02:00
Grzegorz Adam Hankiewicz
c7a4412f8a Adds skMethod example to idetools api test. 2013-06-10 22:42:16 +02:00
Araq
281424dded Merge pull request #476 from gradha/pr_fix_idetools_taintmode
Fixes recent idetools breakage
2013-06-10 13:10:19 -07:00
Grzegorz Adam Hankiewicz
b7a4a9a6ce Fixes usage of public API caasTestsRunner in tester. 2013-06-10 22:06:38 +02:00
Grzegorz Adam Hankiewicz
d8f349f201 Fixes caasdriver for --taintMode:on compilation. 2013-06-10 22:01:00 +02:00
zah
6cafb2619a Merge pull request #470 from gradha/pr_idetools_tests
Adds idetools tests
2013-06-10 04:14:49 -07:00
Araq
8f97f3180a made tests green 2013-06-10 00:17:10 +02:00
Araq
be4fd48ab8 fixes 465 2013-06-09 23:51:29 +02:00
Araq
c5e07af902 Merge pull request #473 from gradha/pr_doc_improvements
Doc improvements
2013-06-09 14:43:33 -07:00
Araq
0696ab09b1 Merge pull request #475 from gradha/pr_macosx_gnu_readline
Wraps variables inside `when` for macosx. Fixes #461.
2013-06-09 14:40:30 -07:00
Araq
3f35e2d39e resolved conflict; added missing files 2013-06-09 23:33:32 +02:00
Araq
23ef565a3c implemented large parts of the 'not nil' checking 2013-06-09 23:29:43 +02:00
Grzegorz Adam Hankiewicz
07d19df80f Wraps variables inside when for macosx. Refs #461. 2013-06-09 22:51:27 +02:00
Grzegorz Adam Hankiewicz
05c2d9bd73 Adds docutils modules to lib index, fixes :idx: markers. 2013-06-09 16:10:41 +02:00
Grzegorz Adam Hankiewicz
19a36c9acb Documents shortcut array syntax. Refs #397. 2013-06-09 15:35:21 +02:00
Grzegorz Adam Hankiewicz
a7e70e6229 Adds distinct and borrow to the one and only true index. 2013-06-09 15:23:53 +02:00
Grzegorz Adam Hankiewicz
1bbabd1e81 Removes CaasRun prefix from suggest-compile.txt test.
The --trackDirty switch should work the same for ProcRun, so it's a bug
that it doesn't dump the same suggestion information as in server mode.
2013-06-08 20:48:39 +02:00
zah
97eb4bd0ff documented trackDirty 2013-06-08 11:19:45 +03:00
Grzegorz Adam Hankiewicz
b0e7170965 Adds idetools testcase. Refs #416. 2013-06-07 22:06:04 +02:00
Grzegorz Adam Hankiewicz
27ebd3ce2e Adds comments to output, can help debug failure logs. 2013-06-07 21:43:27 +02:00
Grzegorz Adam Hankiewicz
0d333fdcb4 Adds idetools test case. Refs #416. 2013-06-07 21:38:07 +02:00
Grzegorz Adam Hankiewicz
f11a3b2324 Adds generic idetools api test case.
At the moment three lines of the test case fail in proc mode.
2013-06-07 21:24:45 +02:00
Grzegorz Adam Hankiewicz
1d813167c4 Implements prefixes for comments or specific mode runs. 2013-06-07 20:28:02 +02:00
Grzegorz Adam Hankiewicz
8f76092b89 Runs all caas tests also in process mode.
This requires changing a little bit the test cases to avoid specifying
the filename as the last parameter. The trackDirty switch still doesn't
work for process mode. Also revers some SuccessX which I think were
hidden in the amount of output verbosity.
2013-06-07 19:47:33 +02:00
Grzegorz Adam Hankiewicz
9b0e03cb2e Replaces dirname with osproc.parentDir. 2013-06-07 18:51:52 +02:00
Grzegorz Adam Hankiewicz
298f546be0 Adds embedded comment describing program usage. 2013-06-07 18:47:31 +02:00
Grzegorz Adam Hankiewicz
18725aab28 Adds verbose switch, by default reports only failures. 2013-06-07 18:32:43 +02:00
Grzegorz Adam Hankiewicz
2793170fed Makes caasdriver exit with number of errors.
Also displays result and separator after each test.
2013-06-07 18:25:57 +02:00
Araq
b92c87e2ec Merge pull request #467 from fowlmouth/patch-9
use proper types in lua
2013-06-06 14:18:55 -07:00
Araq
ce378d8984 Merge pull request #464 from fowlmouth/patch-8
made macros.dumptree and dumplisp immediate, deprecated the *_imm versions
2013-06-06 14:16:16 -07:00
Araq
9604df8431 fixes #466 2013-06-06 23:15:05 +02:00
Billingsly Wetherfordshire
463267ce12 cleaned up lualib.nim 2013-06-06 03:51:38 -06:00
Billingsly Wetherfordshire
05f0444c02 cleaned up lua.nim 2013-06-06 03:51:10 -06:00
Billingsly Wetherfordshire
516e0cb71a use proper types in lua
* ints changed to cint
* the source has been cleaned up with {.push/pop.}
* lua 5.2 has been removed (it is incompatible)
2013-06-06 03:49:31 -06:00
Billingsly Wetherfordshire
7ea77d93e3 Update news.txt 2013-06-04 22:33:55 -06:00
Billingsly Wetherfordshire
4255eb511e made macros.dumptree and dumplisp immediate, deprecated the *_imm versions 2013-06-04 22:28:20 -06:00
Araq
2aaa8f7909 implemented dataflow analysis; activate via --warning[Uninit]:on 2013-06-04 21:58:39 +02:00
Araq
f7c0cc976d fixes #456 2013-06-04 08:02:53 +02:00
Araq
2f5d5e3ba7 fixes #451 2013-06-04 07:48:46 +02:00
Araq
b487ebaaba new scoping rules for 'if' now active 2013-06-04 01:11:55 +02:00
Araq
b767f34b6b manyloc test should be green again 2013-06-04 00:58:43 +02:00
Araq
7d6556ffe7 tiny doc improvement 2013-06-03 19:33:20 +02:00
Araq
b3ac785f95 fixes semicolon parsing issue 2013-06-03 08:05:32 +02:00
Araq
865a43050d fixes #385 2013-06-03 01:21:21 +02:00
Araq
dcff5571a2 Merge branch 'master' of github.com:Araq/Nimrod 2013-06-02 21:52:35 +02:00
Araq
4308f32255 astToStr is now immediate 2013-06-02 21:52:04 +02:00
Araq
fa062ca0c4 next steps to a luajit codegen 2013-06-02 21:50:56 +02:00
Dominik Picheta
e56fdfc4be Added unittest module to docgen. 2013-05-31 12:46:21 +01:00
Araq
2ec3e6b49e more accurate effects for times.nim; bugfix for the JS codegen 2013-05-31 12:20:55 +02:00
Araq
ddedefd4c4 Merge branch 'master' of github.com:Araq/Nimrod 2013-05-31 02:28:33 +02:00
Araq
7d58b9247e Merge pull request #455 from fowlmouth/patch-7
rename json.existsKey to hasKey, deprecates existsKey
2013-05-30 17:27:53 -07:00
Araq
24955f8358 fixes #458 2013-05-31 02:27:05 +02:00
Araq
1c6ce881ec another attempt to implement #448 2013-05-31 01:36:15 +02:00
Araq
8c211113f2 better error message for subtle nil errors 2013-05-31 01:27:03 +02:00
Araq
a8ba628bcd Revert "fixes #267"
This reverts commit 7fccdedcb5.
2013-05-27 23:20:41 +02:00
Araq
75c586bbe1 Revert "bugfix: emulated thread vars used in combination with the mark & sweep GC"
This reverts commit 420789c278.
2013-05-27 23:20:20 +02:00
Araq
ede5ce9ac1 Revert "allow void as a field type"
This reverts commit aea27a7ce4.
2013-05-27 23:19:44 +02:00
Araq
b7ea4a7e65 Revert "allow keyword params for the [] and {} operators"
This reverts commit bfff1ac8b2.
2013-05-27 23:19:11 +02:00
Araq
0662ec4a43 Revert "static and default params for generics"
This reverts commit 46813bbe4e.
2013-05-27 23:18:38 +02:00
Araq
e3f93241c3 Revert "fix tforwardgeneric"
This reverts commit d82a032566.
2013-05-27 23:18:15 +02:00
Araq
9c45e33d8c Revert "fix threading tests"
This reverts commit d5fffc032f.
2013-05-27 23:17:48 +02:00
Araq
d11cf5d191 Revert "further fixes for void stripping. fixes tvoid."
This reverts commit 4ae4005f80.
2013-05-27 23:17:18 +02:00
Araq
c67abd7e61 Revert "more test made green"
This reverts commit 911e6e710f.
2013-05-27 23:16:56 +02:00
Araq
e1b668c868 Revert "test cases for the new features"
This reverts commit 66653e8f14.
2013-05-27 23:16:00 +02:00
Billingsly Wetherfordshire
65d3e51650 rename json.existsKey to hasKey, deprecates existsKey 2013-05-27 03:32:51 -07:00
Zahary Karadjov
66653e8f14 test cases for the new features 2013-05-26 22:15:30 +03:00
Zahary Karadjov
911e6e710f more test made green
the lambda lifting was trying too hard to ignore generic prods
isGenericRoutine was producing false-negatives and only
this allowed for some of the warning and error messages
to be triggered.

some files with mixed line endings were fixed
2013-05-26 21:06:39 +03:00
Zahary Karadjov
4ae4005f80 further fixes for void stripping. fixes tvoid. 2013-05-26 18:06:01 +03:00
Zahary Karadjov
d5fffc032f fix threading tests
* more type names are valid expressions now
* void is properly stripped off during generic instantiation
2013-05-26 16:23:23 +03:00
Zahary Karadjov
d82a032566 fix tforwardgeneric 2013-05-26 15:12:09 +03:00
Zahary Karadjov
46813bbe4e static and default params for generics 2013-05-26 13:59:39 +03:00
Zahary Karadjov
bfff1ac8b2 allow keyword params for the [] and {} operators
conceptually, these operators are not very different from regular procs in the way
they are defined and overloaded. keyword params for them are admittedly less useful,
but they improve consistency and may help with generic instantiations once default
generic parameters are supported.
2013-05-26 11:14:23 +03:00
Zahary Karadjov
aea27a7ce4 allow void as a field type 2013-05-26 11:14:23 +03:00
Zahary Karadjov
420789c278 bugfix: emulated thread vars used in combination with the mark & sweep GC
resulted in invalid code generation
2013-05-26 11:14:23 +03:00
Zahary Karadjov
7fccdedcb5 fixes #267 2013-05-26 11:14:23 +03:00
Araq
c093139494 fixes #411 2013-05-26 01:53:24 +02:00
Araq
0715496d72 implements #448 2013-05-26 01:33:23 +02:00
Araq
ca02dfab48 implements #397 2013-05-26 01:19:19 +02:00
Araq
da93b591e2 preparations for version 0.9.4 2013-05-25 23:37:40 +02:00
Araq
d9185a9580 Merge branch 'master' of github.com:Araq/Nimrod 2013-05-25 15:49:02 +02:00
Araq
f9641790b5 added FAQ about 'proc' 2013-05-25 15:48:46 +02:00
Dominik Picheta
3001ed54f9 Fixed overflow in sockets.parseIP4. 2013-05-24 19:43:37 +01:00
Araq
4e3ac4319b Merge branch 'master' of github.com:Araq/Nimrod 2013-05-24 00:33:42 +02:00
Araq
7a744fcb17 Merge pull request #445 from gradha/pr_web_improvements
Some web improvements
2013-05-23 15:33:06 -07:00
Araq
72457052fc Merge branch 'master' of github.com:Araq/Nimrod 2013-05-24 00:25:07 +02:00
Araq
1284a34fc3 add c2nim,pas2nim to the install packages 2013-05-24 00:24:35 +02:00
Grzegorz Adam Hankiewicz
515a5a4444 Implements basic rss generation for website news. 2013-05-23 00:17:27 +02:00
Grzegorz Adam Hankiewicz
834efe018a Adds link to irc logs. 2013-05-22 23:47:36 +02:00
Simon Hafner
f72fdf44f6 removed unsupported compilers from the FAQ 2013-05-21 15:40:11 -05:00
Araq
42dde41241 Merge branch 'master' of github.com:Araq/Nimrod 2013-05-21 22:39:03 +02:00
Araq
9fd21ba2db fixed typos in the manual; kept trimcc tool up to date 2013-05-21 22:36:46 +02:00
Simon Hafner
d6a642e064 better editor support FAQ 2013-05-21 15:35:32 -05:00
Simon Hafner
b597855d6f removed GCC FAQ - not an issue anymore 2013-05-21 15:27:19 -05:00
Simon Hafner
e3c3130488 add FAQ about editor support 2013-05-21 13:15:30 -05:00
Simon Hafner
959adc6218 added "standalone" to possible OS options 2013-05-20 19:16:43 -05:00
Araq
51c6356ea7 added gamera edition to the website 2013-05-21 00:26:03 +02:00
Araq
064df34ae4 made some tests green 2013-05-16 08:54:58 +02:00
Araq
886a1ab15d 'bind' default for clean templates 2013-05-15 00:28:55 +02:00
1077 changed files with 53611 additions and 80786 deletions

405
.gitignore vendored
View File

@@ -58,12 +58,16 @@ examples/cross_calculator/android/tags
# Generated files.
/compile.json
/compiler/c2nim/c2nim
/compiler/nimrod.dot
/compiler/pas2nim/pas2nim
/compiler/service
/examples/allany
/examples/cairoex
/examples/cgiex
/examples/cgi/cgi_stacktrace
/examples/cgi/example
/examples/curlex
/examples/debugging
/examples/docstrings
/examples/filterex
/examples/fizzbuzz
@@ -89,6 +93,12 @@ examples/cross_calculator/android/tags
/examples/pythonex
/examples/sdlex
/examples/statcsv
/examples/talk/dsl
/examples/talk/formatoptimizer
/examples/talk/hoisting
/examples/talk/lazyeval
/examples/talk/quasiquote
/examples/talk/tags
/examples/tclex
/examples/transff
/examples/tunit
@@ -96,10 +106,13 @@ examples/cross_calculator/android/tags
/examples/x11ex
/lib/libnimrtl.dylib
/lib/libserver.dylib
/lib/packages/docutils/highlite
/lib/pure/actors
/lib/pure/algorithm
/lib/pure/asyncio
/lib/pure/base64
/lib/pure/basic2d
/lib/pure/basic3d
/lib/pure/browsers
/lib/pure/cgi
/lib/pure/collections/sequtils
@@ -111,6 +124,7 @@ examples/cross_calculator/android/tags
/lib/pure/encodings
/lib/pure/endians
/lib/pure/events
/lib/pure/fsmonitor
/lib/pure/ftpclient
/lib/pure/gentabs
/lib/pure/hashes
@@ -127,19 +141,23 @@ examples/cross_calculator/android/tags
/lib/pure/math
/lib/pure/md5
/lib/pure/memfiles
/lib/pure/mersenne
/lib/pure/mimetypes
/lib/pure/nimprof
/lib/pure/numeric
/lib/pure/oids
/lib/pure/os
/lib/pure/osproc
/lib/pure/parsecfg
/lib/pure/parsecsv
/lib/pure/parseopt
/lib/pure/parseopt2
/lib/pure/parsesql
/lib/pure/parseurl
/lib/pure/parseutils
/lib/pure/parsexml
/lib/pure/pegs
/lib/pure/poly
/lib/pure/redis
/lib/pure/romans
/lib/pure/ropes
@@ -167,4 +185,391 @@ examples/cross_calculator/android/tags
/run.json
/testresults.html
/testresults.json
/tests/caas/absurd_nesting
/tests/caas/completion_dot_syntax_main
/tests/caasdriver
/tests/caas/forward_declarations
/tests/caas/idetools_api
/tests/caas/imported
/tests/caas/issue_416_template_shift
/tests/caas/issue_452_export_shift
/tests/caas/issue_477_dynamic_dispatch
/tests/caas/its_full_of_procs
/tests/caas/main
/tests/caas/SymbolProcRun.*/
/tests/ccg/tmissingbracket
/tests/compile/talias
/tests/compile/tambsym2
/tests/compile/tarrindx
/tests/compile/tassign
/tests/compile/tbindoverload
/tests/compile/tcan_alias_generic
/tests/compile/tcan_alias_specialised_generic
/tests/compile/tcan_inherit_generic
/tests/compile/tcan_specialise_generic
/tests/compile/tccgen1
/tests/compile/tclosure4
/tests/compile/tclosurebug2
/tests/compile/tcmdline
/tests/compile/tcodegenbug1
/tests/compile/tcolonisproc
/tests/compile/tcolors
/tests/compile/tcommontype
/tests/compile/tcompiles
/tests/compile/tcomputedgoto
/tests/compile/tconsteval
/tests/compile/tconstraints
/tests/compile/tconvcolors
/tests/compile/tcputime
/tests/compile/tdefaultprocparam
/tests/compile/tdictdestruct
/tests/compile/tdiscardable
/tests/compile/tdllvar
/tests/compile/tdumpast
/tests/compile/tdumpast2
/tests/compile/techo
/tests/compile/teffects1
/tests/compile/temptyecho
/tests/compile/tendian
/tests/compile/tenum
/tests/compile/tenum2
/tests/compile/tenum3
/tests/compile/teval1
/tests/compile/texport
/tests/compile/tfib
/tests/compile/tforwardgeneric
/tests/compile/tforwty
/tests/compile/tforwty2
/tests/compile/tgeneric
/tests/compile/tgeneric2
/tests/compile/tgeneric3
/tests/compile/tgeneric4
/tests/compile/tgenericmatcher
/tests/compile/tgenericmatcher2
/tests/compile/tgenericprocvar
/tests/compile/tgenericprop
/tests/compile/tgenericrefs
/tests/compile/tgenerictmpl
/tests/compile/tgenericvariant
/tests/compile/tgensymgeneric
/tests/compile/tgetstartmilsecs
/tests/compile/tglobalforvar
/tests/compile/thallo
/tests/compile/theaproots
/tests/compile/thexrange
/tests/compile/thygienictempl
/tests/compile/tident
/tests/compile/timplicititems
/tests/compile/timplictderef
/tests/compile/tinheritref
/tests/compile/tio
/tests/compile/tircbot
/tests/compile/titer
/tests/compile/titer2
/tests/compile/titer_no_tuple_unpack
/tests/compile/titerovl
/tests/compile/tlastmod
/tests/compile/tlinearscanend
/tests/compile/tloops
/tests/compile/tmacro1
/tests/compile/tmacro2
/tests/compile/tmacroaspragma
/tests/compile/tmacrostmt
/tests/compile/tmandelbrot
/tests/compile/tmarshal
/tests/compile/tmath
/tests/compile/tmatrix1
/tests/compile/tmatrix2
/tests/compile/tmongo
/tests/compile/tnamedparamanonproc
/tests/compile/tnamedparams
/tests/compile/tnestedproc
/tests/compile/tnew
/tests/compile/tnewsets
/tests/compile/tnewuns
/tests/compile/tnoargopenarray
/tests/compile/tnoforward
/tests/compile/tobjconstr2
/tests/compile/tobjcov
/tests/compile/tobject2
/tests/compile/tobject3
/tests/compile/tobjects
/tests/compile/toop
/tests/compile/toptions
/tests/compile/tos
/tests/compile/toverprc
/tests/compile/tparedef
/tests/compile/tparscfg
/tests/compile/tparsefloat
/tests/compile/tparsopt
/tests/compile/tposix
/tests/compile/tprep
/tests/compile/tprocvars
/tests/compile/tpush
/tests/compile/tquicksort
/tests/compile/tquit
/tests/compile/tradix
/tests/compile/treadln
/tests/compile/treadx
/tests/compile/trecmod
/tests/compile/trecmod2
/tests/compile/trectuple
/tests/compile/trectuples
/tests/compile/tredef
/tests/compile/trepr
/tests/compile/tsecondarrayproperty
/tests/compile/tseq2
/tests/compile/tseqcon2
/tests/compile/tshadow_magic_type
/tests/compile/tsizeof
/tests/compile/tslurp
/tests/compile/tsockets
/tests/compile/tsortcall
/tests/compile/tspecialised_is_equivalent
/tests/compile/tstrace
/tests/compile/tstrdesc
/tests/compile/tstrdist
/tests/compile/tstreams
/tests/compile/tstrset
/tests/compile/tstrtabs
/tests/compile/ttableconstr
/tests/compile/ttempl
/tests/compile/ttempl3
/tests/compile/ttempl4
/tests/compile/ttempl5
/tests/compile/ttemplreturntype
/tests/compile/tthread_generic
/tests/compile/ttime
/tests/compile/ttuple1
/tests/compile/ttypeclasses
/tests/compile/ttypeconverter1
/tests/compile/tuserpragma
/tests/compile/tvoid
/tests/compile/twalker
/tests/compile/typalias
/tests/dll/client
/tests/gc/closureleak
/tests/gc/cycleleak
/tests/gc/gcbench
/tests/gc/gcleak
/tests/gc/gcleak2
/tests/gc/gcleak3
/tests/gc/gctest
/tests/gc/weakrefs
/tests/manyloc/argument_parser/ex_wget
/tests/manyloc/nake/nakefile
/tests/manyloc/packages/noconflicts
/tests/manyloc/standalone/barebone
/tests/patterns/targlist
/tests/patterns/tcse
/tests/patterns/thoist
/tests/patterns/tmatrix
/tests/patterns/tnoalias
/tests/patterns/tnoendlessrec
/tests/patterns/tor
/tests/patterns/tpartial
/tests/patterns/tstar
/tests/patterns/tstmtlist
/tests/reject/t99bott
/tests/reject/tcheckedfield1
/tests/reject/tdeprecated
/tests/reject/tdisallowif
/tests/reject/tuninit1
/tests/rodfiles/aconv
/tests/rodfiles/bconv
/tests/rodfiles/bmethods
/tests/rodfiles/bmethods2
/tests/rodfiles/deada
/tests/rodfiles/deada2
/tests/rodfiles/hallo
/tests/rodfiles/hallo2
/tests/rodfiles/tgeneric1
/tests/rodfiles/tgeneric2
/tests/run/tack
/tests/run/tactiontable
/tests/run/tambsym2
/tests/run/tambsys
/tests/run/tanontuples
/tests/run/tarray
/tests/run/tarray2
/tests/run/tarray3
/tests/run/tarraycons
/tests/run/tassert
/tests/run/tastoverload1
/tests/run/tasynciossl
/tests/run/tasyncudp
/tests/run/tbind1
/tests/run/tbind3
/tests/run/tbintre2
/tests/run/tbintree
/tests/run/tborrow
/tests/run/tbug499771
/tests/run/tbug511622
/tests/run/tcase_setconstr
/tests/run/tcasestm
/tests/run/tcgbug
/tests/run/tclosure2
/tests/run/tclosure3
/tests/run/tcnstseq
/tests/run/tcnstseq2
/tests/run/tcnstseq3
/tests/run/tconcat
/tests/run/tconstr2
/tests/run/tcontinue
/tests/run/tcontinuexc
/tests/run/tcopy
/tests/run/tcountup
/tests/run/tcritbits
/tests/run/tcurrncy
/tests/run/tdestructor
/tests/run/tdrdobbs_examples
/tests/run/temit
/tests/run/tenumhole
/tests/run/tenumitems
/tests/run/teventemitter
/tests/run/tevents
/tests/run/texceptions
/tests/run/texcpt1
/tests/run/texcsub
/tests/run/texplicitgeneric1
/tests/run/tfieldindex
/tests/run/tfielditerator
/tests/run/tfielditerator2
/tests/run/tfilter
/tests/run/tfinally
/tests/run/tfinally2
/tests/run/tfinally3
/tests/run/tfinalobj
/tests/run/tfloat1
/tests/run/tfloat2
/tests/run/tfloat3
/tests/run/tformat
/tests/run/tfriends
/tests/run/tgenericassign
/tests/run/tgenericassigntuples
/tests/run/tgenericconverter
/tests/run/tgenericprocvar
/tests/run/tgenerics1
/tests/run/tgensym
/tests/run/tglobal
/tests/run/thashes
/tests/run/thexlit
/tests/run/thintoff
/tests/run/tidgen
/tests/run/tindent1
/tests/run/tinit
/tests/run/tinterf
/tests/run/tints
/tests/run/tisopr
/tests/run/titer3
/tests/run/titer5
/tests/run/titer6
/tests/run/titer7
/tests/run/titer8
/tests/run/titer9
/tests/run/titerslice
/tests/run/titervaropenarray
/tests/run/tkoeniglookup
/tests/run/tlet
/tests/run/tlists
/tests/run/tlocals
/tests/run/tlowhigh
/tests/run/tmacro2
/tests/run/tmacro3
/tests/run/tmacro4
/tests/run/tmacros1
/tests/run/tmath
/tests/run/tmatrix
/tests/run/tmemoization
/tests/run/tmethods1
/tests/run/tmixin
/tests/run/tmoditer
/tests/run/tmultim1
/tests/run/tmultim2
/tests/run/tmultim3
/tests/run/tmultim4
/tests/run/tmultim6
/tests/run/tnamedenumfields
/tests/run/tnestif
/tests/run/tnestprc
/tests/run/tnewderef
/tests/run/tnodeadlocks
/tests/run/tobjasgn
/tests/run/tobjconstr
/tests/run/tobject
/tests/run/tofopr
/tests/run/tonraise
/tests/run/toop1
/tests/run/topenarrayrepr
/tests/run/topenlen
/tests/run/toprprec
/tests/run/toverflw
/tests/run/toverflw2
/tests/run/toverl2
/tests/run/toverl3
/tests/run/toverwr
/tests/run/tovfint
/tests/run/tpatterns
/tests/run/tpegs
/tests/run/tpos
/tests/run/tprecedence
/tests/run/tprintf
/tests/run/tprocvar
/tests/run/tquotewords
/tests/run/tregex
/tests/run/treguse
/tests/run/trepr
/tests/run/treraise
/tests/run/tromans
/tests/run/tseqcon
/tests/run/tseqtuple
/tests/run/tsequtils
/tests/run/tsets
/tests/run/tsets2
/tests/run/tsidee2
/tests/run/tsidee3
/tests/run/tsimmeth
/tests/run/tsimplesort
/tests/run/tslices
/tests/run/tsortdev
/tests/run/tsplit
/tests/run/tstempl
/tests/run/tstmtexprs
/tests/run/tstrange
/tests/run/tstringinterp
/tests/run/tstrlits
/tests/run/tstrutil
/tests/run/tsubrange
/tests/run/tsubrange2
/tests/run/ttables
/tests/run/ttables2
/tests/run/ttoseq
/tests/run/ttypedesc1
/tests/run/tunhandledexc
/tests/run/tunidecode
/tests/run/tunittests
/tests/run/tuserassert
/tests/run/tvarargs_vs_generic
/tests/run/tvardecl
/tests/run/tvariantasgn
/tests/run/tvariantstack
/tests/run/tvarious1
/tests/run/tvarnums
/tests/run/tvarres1
/tests/run/tvarres2
/tests/run/tvartup
/tests/run/tvtable
/tests/run/twrongexc
/tests/run/txmlgen
/tests/run/txmltree
/tests/run/tzeroarray
/tests/system/helpers/readall_echo
/tests/system/io
/tests/system/params
/tests/tester
/tests/threads/tactors
/tests/threads/tactors2
/tests/threads/tthreadanalysis2
/tests/threads/tthreadanalysis3
/tests/threads/tthreadheapviolation1
/tools/nimgrep

1
bin/empty.txt Normal file
View File

@@ -0,0 +1 @@
This file keeps several tools from deleting this subdirectory.

200
build.bat
View File

@@ -1,200 +0,0 @@
@echo off
REM Generated by niminst
SET CC=gcc
SET LINKER=gcc
SET COMP_FLAGS=-w -O3 -fno-strict-aliasing
SET LINK_FLAGS=
REM call the compiler:
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\nimrod.c -o build\1_1\nimrod.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\nimrod.c -o build\1_1\nimrod.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\system.c -o build\1_1\system.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\system.c -o build\1_1\system.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\commands.c -o build\1_1\commands.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\commands.c -o build\1_1\commands.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\os.c -o build\1_1\os.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\os.c -o build\1_1\os.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\strutils.c -o build\1_1\strutils.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\strutils.c -o build\1_1\strutils.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\parseutils.c -o build\1_1\parseutils.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\parseutils.c -o build\1_1\parseutils.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\times.c -o build\1_1\times.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\times.c -o build\1_1\times.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\winlean.c -o build\1_1\winlean.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\winlean.c -o build\1_1\winlean.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\msgs.c -o build\1_1\msgs.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\msgs.c -o build\1_1\msgs.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\options.c -o build\1_1\options.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\options.c -o build\1_1\options.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\lists.c -o build\1_1\lists.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\lists.c -o build\1_1\lists.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\strtabs.c -o build\1_1\strtabs.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\strtabs.c -o build\1_1\strtabs.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\hashes.c -o build\1_1\hashes.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\hashes.c -o build\1_1\hashes.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\tables.c -o build\1_1\tables.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\tables.c -o build\1_1\tables.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\math.c -o build\1_1\math.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\math.c -o build\1_1\math.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\sockets.c -o build\1_1\sockets.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\sockets.c -o build\1_1\sockets.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\ropes.c -o build\1_1\ropes.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\ropes.c -o build\1_1\ropes.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\platform.c -o build\1_1\platform.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\platform.c -o build\1_1\platform.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\crc.c -o build\1_1\crc.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\crc.c -o build\1_1\crc.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\nversion.c -o build\1_1\nversion.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\nversion.c -o build\1_1\nversion.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\condsyms.c -o build\1_1\condsyms.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\condsyms.c -o build\1_1\condsyms.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\ast.c -o build\1_1\ast.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\ast.c -o build\1_1\ast.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\idents.c -o build\1_1\idents.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\idents.c -o build\1_1\idents.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\intsets.c -o build\1_1\intsets.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\intsets.c -o build\1_1\intsets.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\idgen.c -o build\1_1\idgen.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\idgen.c -o build\1_1\idgen.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\astalgo.c -o build\1_1\astalgo.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\astalgo.c -o build\1_1\astalgo.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\rodutils.c -o build\1_1\rodutils.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\rodutils.c -o build\1_1\rodutils.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\extccomp.c -o build\1_1\extccomp.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\extccomp.c -o build\1_1\extccomp.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\osproc.c -o build\1_1\osproc.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\osproc.c -o build\1_1\osproc.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\streams.c -o build\1_1\streams.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\streams.c -o build\1_1\streams.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\wordrecg.c -o build\1_1\wordrecg.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\wordrecg.c -o build\1_1\wordrecg.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\babelcmd.c -o build\1_1\babelcmd.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\babelcmd.c -o build\1_1\babelcmd.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\lexer.c -o build\1_1\lexer.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\lexer.c -o build\1_1\lexer.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\nimlexbase.c -o build\1_1\nimlexbase.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\nimlexbase.c -o build\1_1\nimlexbase.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\llstream.c -o build\1_1\llstream.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\llstream.c -o build\1_1\llstream.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\nimconf.c -o build\1_1\nimconf.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\nimconf.c -o build\1_1\nimconf.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\main.c -o build\1_1\main.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\main.c -o build\1_1\main.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\syntaxes.c -o build\1_1\syntaxes.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\syntaxes.c -o build\1_1\syntaxes.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\parser.c -o build\1_1\parser.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\parser.c -o build\1_1\parser.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\pbraces.c -o build\1_1\pbraces.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\pbraces.c -o build\1_1\pbraces.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\filters.c -o build\1_1\filters.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\filters.c -o build\1_1\filters.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\renderer.c -o build\1_1\renderer.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\renderer.c -o build\1_1\renderer.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\filter_tmpl.c -o build\1_1\filter_tmpl.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\filter_tmpl.c -o build\1_1\filter_tmpl.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\rodread.c -o build\1_1\rodread.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\rodread.c -o build\1_1\rodread.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\types.c -o build\1_1\types.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\types.c -o build\1_1\types.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\trees.c -o build\1_1\trees.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\trees.c -o build\1_1\trees.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\memfiles.c -o build\1_1\memfiles.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\memfiles.c -o build\1_1\memfiles.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\rodwrite.c -o build\1_1\rodwrite.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\rodwrite.c -o build\1_1\rodwrite.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\passes.c -o build\1_1\passes.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\passes.c -o build\1_1\passes.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\magicsys.c -o build\1_1\magicsys.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\magicsys.c -o build\1_1\magicsys.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\nimsets.c -o build\1_1\nimsets.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\nimsets.c -o build\1_1\nimsets.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\bitsets.c -o build\1_1\bitsets.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\bitsets.c -o build\1_1\bitsets.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\semthreads.c -o build\1_1\semthreads.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\semthreads.c -o build\1_1\semthreads.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\importer.c -o build\1_1\importer.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\importer.c -o build\1_1\importer.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\lookups.c -o build\1_1\lookups.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\lookups.c -o build\1_1\lookups.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\semdata.c -o build\1_1\semdata.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\semdata.c -o build\1_1\semdata.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\treetab.c -o build\1_1\treetab.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\treetab.c -o build\1_1\treetab.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\evals.c -o build\1_1\evals.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\evals.c -o build\1_1\evals.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\semfold.c -o build\1_1\semfold.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\semfold.c -o build\1_1\semfold.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\saturate.c -o build\1_1\saturate.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\saturate.c -o build\1_1\saturate.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\transf.c -o build\1_1\transf.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\transf.c -o build\1_1\transf.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\cgmeth.c -o build\1_1\cgmeth.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\cgmeth.c -o build\1_1\cgmeth.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\sempass2.c -o build\1_1\sempass2.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\sempass2.c -o build\1_1\sempass2.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\lambdalifting.c -o build\1_1\lambdalifting.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\lambdalifting.c -o build\1_1\lambdalifting.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\evaltempl.c -o build\1_1\evaltempl.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\evaltempl.c -o build\1_1\evaltempl.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\sem.c -o build\1_1\sem.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\sem.c -o build\1_1\sem.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\procfind.c -o build\1_1\procfind.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\procfind.c -o build\1_1\procfind.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\pragmas.c -o build\1_1\pragmas.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\pragmas.c -o build\1_1\pragmas.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\semtypinst.c -o build\1_1\semtypinst.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\semtypinst.c -o build\1_1\semtypinst.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\sigmatch.c -o build\1_1\sigmatch.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\sigmatch.c -o build\1_1\sigmatch.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\parampatterns.c -o build\1_1\parampatterns.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\parampatterns.c -o build\1_1\parampatterns.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\docgen.c -o build\1_1\docgen.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\docgen.c -o build\1_1\docgen.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\rstast.c -o build\1_1\rstast.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\rstast.c -o build\1_1\rstast.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\rst.c -o build\1_1\rst.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\rst.c -o build\1_1\rst.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\rstgen.c -o build\1_1\rstgen.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\rstgen.c -o build\1_1\rstgen.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\highlite.c -o build\1_1\highlite.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\highlite.c -o build\1_1\highlite.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\algorithm.c -o build\1_1\algorithm.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\algorithm.c -o build\1_1\algorithm.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\aliases.c -o build\1_1\aliases.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\aliases.c -o build\1_1\aliases.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\patterns.c -o build\1_1\patterns.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\patterns.c -o build\1_1\patterns.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\cgen.c -o build\1_1\cgen.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\cgen.c -o build\1_1\cgen.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\ccgutils.c -o build\1_1\ccgutils.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\ccgutils.c -o build\1_1\ccgutils.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\cgendata.c -o build\1_1\cgendata.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\cgendata.c -o build\1_1\cgendata.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\ccgmerge.c -o build\1_1\ccgmerge.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\ccgmerge.c -o build\1_1\ccgmerge.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\jsgen.c -o build\1_1\jsgen.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\jsgen.c -o build\1_1\jsgen.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\json.c -o build\1_1\json.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\json.c -o build\1_1\json.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\lexbase.c -o build\1_1\lexbase.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\lexbase.c -o build\1_1\lexbase.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\unicode.c -o build\1_1\unicode.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\unicode.c -o build\1_1\unicode.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\passaux.c -o build\1_1\passaux.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\passaux.c -o build\1_1\passaux.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\depends.c -o build\1_1\depends.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\depends.c -o build\1_1\depends.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\docgen2.c -o build\1_1\docgen2.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\docgen2.c -o build\1_1\docgen2.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\service.c -o build\1_1\service.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\service.c -o build\1_1\service.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\parseopt.c -o build\1_1\parseopt.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\parseopt.c -o build\1_1\parseopt.o
ECHO %LINKER% %LINK_FLAGS% -o bin\nimrod.exe build\1_1\nimrod.o build\1_1\system.o build\1_1\commands.o build\1_1\os.o build\1_1\strutils.o build\1_1\parseutils.o build\1_1\times.o build\1_1\winlean.o build\1_1\msgs.o build\1_1\options.o build\1_1\lists.o build\1_1\strtabs.o build\1_1\hashes.o build\1_1\tables.o build\1_1\math.o build\1_1\sockets.o build\1_1\ropes.o build\1_1\platform.o build\1_1\crc.o build\1_1\nversion.o build\1_1\condsyms.o build\1_1\ast.o build\1_1\idents.o build\1_1\intsets.o build\1_1\idgen.o build\1_1\astalgo.o build\1_1\rodutils.o build\1_1\extccomp.o build\1_1\osproc.o build\1_1\streams.o build\1_1\wordrecg.o build\1_1\babelcmd.o build\1_1\lexer.o build\1_1\nimlexbase.o build\1_1\llstream.o build\1_1\nimconf.o build\1_1\main.o build\1_1\syntaxes.o build\1_1\parser.o build\1_1\pbraces.o build\1_1\filters.o build\1_1\renderer.o build\1_1\filter_tmpl.o build\1_1\rodread.o build\1_1\types.o build\1_1\trees.o build\1_1\memfiles.o build\1_1\rodwrite.o build\1_1\passes.o build\1_1\magicsys.o build\1_1\nimsets.o build\1_1\bitsets.o build\1_1\semthreads.o build\1_1\importer.o build\1_1\lookups.o build\1_1\semdata.o build\1_1\treetab.o build\1_1\evals.o build\1_1\semfold.o build\1_1\saturate.o build\1_1\transf.o build\1_1\cgmeth.o build\1_1\sempass2.o build\1_1\lambdalifting.o build\1_1\evaltempl.o build\1_1\sem.o build\1_1\procfind.o build\1_1\pragmas.o build\1_1\semtypinst.o build\1_1\sigmatch.o build\1_1\parampatterns.o build\1_1\docgen.o build\1_1\rstast.o build\1_1\rst.o build\1_1\rstgen.o build\1_1\highlite.o build\1_1\algorithm.o build\1_1\aliases.o build\1_1\patterns.o build\1_1\cgen.o build\1_1\ccgutils.o build\1_1\cgendata.o build\1_1\ccgmerge.o build\1_1\jsgen.o build\1_1\json.o build\1_1\lexbase.o build\1_1\unicode.o build\1_1\passaux.o build\1_1\depends.o build\1_1\docgen2.o build\1_1\service.o build\1_1\parseopt.o
%LINKER% %LINK_FLAGS% -o bin\nimrod.exe build\1_1\nimrod.o build\1_1\system.o build\1_1\commands.o build\1_1\os.o build\1_1\strutils.o build\1_1\parseutils.o build\1_1\times.o build\1_1\winlean.o build\1_1\msgs.o build\1_1\options.o build\1_1\lists.o build\1_1\strtabs.o build\1_1\hashes.o build\1_1\tables.o build\1_1\math.o build\1_1\sockets.o build\1_1\ropes.o build\1_1\platform.o build\1_1\crc.o build\1_1\nversion.o build\1_1\condsyms.o build\1_1\ast.o build\1_1\idents.o build\1_1\intsets.o build\1_1\idgen.o build\1_1\astalgo.o build\1_1\rodutils.o build\1_1\extccomp.o build\1_1\osproc.o build\1_1\streams.o build\1_1\wordrecg.o build\1_1\babelcmd.o build\1_1\lexer.o build\1_1\nimlexbase.o build\1_1\llstream.o build\1_1\nimconf.o build\1_1\main.o build\1_1\syntaxes.o build\1_1\parser.o build\1_1\pbraces.o build\1_1\filters.o build\1_1\renderer.o build\1_1\filter_tmpl.o build\1_1\rodread.o build\1_1\types.o build\1_1\trees.o build\1_1\memfiles.o build\1_1\rodwrite.o build\1_1\passes.o build\1_1\magicsys.o build\1_1\nimsets.o build\1_1\bitsets.o build\1_1\semthreads.o build\1_1\importer.o build\1_1\lookups.o build\1_1\semdata.o build\1_1\treetab.o build\1_1\evals.o build\1_1\semfold.o build\1_1\saturate.o build\1_1\transf.o build\1_1\cgmeth.o build\1_1\sempass2.o build\1_1\lambdalifting.o build\1_1\evaltempl.o build\1_1\sem.o build\1_1\procfind.o build\1_1\pragmas.o build\1_1\semtypinst.o build\1_1\sigmatch.o build\1_1\parampatterns.o build\1_1\docgen.o build\1_1\rstast.o build\1_1\rst.o build\1_1\rstgen.o build\1_1\highlite.o build\1_1\algorithm.o build\1_1\aliases.o build\1_1\patterns.o build\1_1\cgen.o build\1_1\ccgutils.o build\1_1\cgendata.o build\1_1\ccgmerge.o build\1_1\jsgen.o build\1_1\json.o build\1_1\lexbase.o build\1_1\unicode.o build\1_1\passaux.o build\1_1\depends.o build\1_1\docgen2.o build\1_1\service.o build\1_1\parseopt.o
ECHO SUCCESS

1
build/empty.txt Normal file
View File

@@ -0,0 +1 @@
This file keeps several tools from deleting this subdirectory.

View File

@@ -1,200 +0,0 @@
@echo off
REM Generated by niminst
SET CC=gcc
SET LINKER=gcc
SET COMP_FLAGS=-w -O3 -fno-strict-aliasing
SET LINK_FLAGS=
REM call the compiler:
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\nimrod.c -o build\1_2\nimrod.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\nimrod.c -o build\1_2\nimrod.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\system.c -o build\1_2\system.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\system.c -o build\1_2\system.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\commands.c -o build\1_2\commands.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\commands.c -o build\1_2\commands.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\os.c -o build\1_2\os.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\os.c -o build\1_2\os.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\strutils.c -o build\1_2\strutils.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\strutils.c -o build\1_2\strutils.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\parseutils.c -o build\1_2\parseutils.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\parseutils.c -o build\1_2\parseutils.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\times.c -o build\1_2\times.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\times.c -o build\1_2\times.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\winlean.c -o build\1_2\winlean.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\winlean.c -o build\1_2\winlean.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\msgs.c -o build\1_2\msgs.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\msgs.c -o build\1_2\msgs.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\options.c -o build\1_2\options.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\options.c -o build\1_2\options.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\lists.c -o build\1_2\lists.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\lists.c -o build\1_2\lists.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\strtabs.c -o build\1_2\strtabs.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\strtabs.c -o build\1_2\strtabs.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\hashes.c -o build\1_2\hashes.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\hashes.c -o build\1_2\hashes.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\tables.c -o build\1_2\tables.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\tables.c -o build\1_2\tables.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\math.c -o build\1_2\math.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\math.c -o build\1_2\math.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\sockets.c -o build\1_2\sockets.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\sockets.c -o build\1_2\sockets.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\ropes.c -o build\1_2\ropes.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\ropes.c -o build\1_2\ropes.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\platform.c -o build\1_2\platform.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\platform.c -o build\1_2\platform.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\crc.c -o build\1_2\crc.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\crc.c -o build\1_2\crc.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\nversion.c -o build\1_2\nversion.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\nversion.c -o build\1_2\nversion.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\condsyms.c -o build\1_2\condsyms.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\condsyms.c -o build\1_2\condsyms.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\ast.c -o build\1_2\ast.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\ast.c -o build\1_2\ast.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\idents.c -o build\1_2\idents.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\idents.c -o build\1_2\idents.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\intsets.c -o build\1_2\intsets.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\intsets.c -o build\1_2\intsets.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\idgen.c -o build\1_2\idgen.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\idgen.c -o build\1_2\idgen.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\astalgo.c -o build\1_2\astalgo.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\astalgo.c -o build\1_2\astalgo.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\rodutils.c -o build\1_2\rodutils.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\rodutils.c -o build\1_2\rodutils.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\extccomp.c -o build\1_2\extccomp.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\extccomp.c -o build\1_2\extccomp.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\osproc.c -o build\1_2\osproc.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\osproc.c -o build\1_2\osproc.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\streams.c -o build\1_2\streams.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\streams.c -o build\1_2\streams.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\wordrecg.c -o build\1_2\wordrecg.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\wordrecg.c -o build\1_2\wordrecg.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\babelcmd.c -o build\1_2\babelcmd.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\babelcmd.c -o build\1_2\babelcmd.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\lexer.c -o build\1_2\lexer.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\lexer.c -o build\1_2\lexer.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\nimlexbase.c -o build\1_2\nimlexbase.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\nimlexbase.c -o build\1_2\nimlexbase.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\llstream.c -o build\1_2\llstream.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\llstream.c -o build\1_2\llstream.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\nimconf.c -o build\1_2\nimconf.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\nimconf.c -o build\1_2\nimconf.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\main.c -o build\1_2\main.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\main.c -o build\1_2\main.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\syntaxes.c -o build\1_2\syntaxes.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\syntaxes.c -o build\1_2\syntaxes.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\parser.c -o build\1_2\parser.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\parser.c -o build\1_2\parser.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\pbraces.c -o build\1_2\pbraces.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\pbraces.c -o build\1_2\pbraces.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\filters.c -o build\1_2\filters.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\filters.c -o build\1_2\filters.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\renderer.c -o build\1_2\renderer.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\renderer.c -o build\1_2\renderer.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\filter_tmpl.c -o build\1_2\filter_tmpl.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\filter_tmpl.c -o build\1_2\filter_tmpl.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\rodread.c -o build\1_2\rodread.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\rodread.c -o build\1_2\rodread.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\types.c -o build\1_2\types.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\types.c -o build\1_2\types.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\trees.c -o build\1_2\trees.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\trees.c -o build\1_2\trees.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\memfiles.c -o build\1_2\memfiles.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\memfiles.c -o build\1_2\memfiles.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\rodwrite.c -o build\1_2\rodwrite.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\rodwrite.c -o build\1_2\rodwrite.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\passes.c -o build\1_2\passes.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\passes.c -o build\1_2\passes.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\magicsys.c -o build\1_2\magicsys.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\magicsys.c -o build\1_2\magicsys.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\nimsets.c -o build\1_2\nimsets.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\nimsets.c -o build\1_2\nimsets.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\bitsets.c -o build\1_2\bitsets.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\bitsets.c -o build\1_2\bitsets.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\semthreads.c -o build\1_2\semthreads.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\semthreads.c -o build\1_2\semthreads.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\importer.c -o build\1_2\importer.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\importer.c -o build\1_2\importer.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\lookups.c -o build\1_2\lookups.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\lookups.c -o build\1_2\lookups.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\semdata.c -o build\1_2\semdata.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\semdata.c -o build\1_2\semdata.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\treetab.c -o build\1_2\treetab.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\treetab.c -o build\1_2\treetab.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\evals.c -o build\1_2\evals.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\evals.c -o build\1_2\evals.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\semfold.c -o build\1_2\semfold.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\semfold.c -o build\1_2\semfold.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\saturate.c -o build\1_2\saturate.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\saturate.c -o build\1_2\saturate.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\transf.c -o build\1_2\transf.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\transf.c -o build\1_2\transf.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\cgmeth.c -o build\1_2\cgmeth.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\cgmeth.c -o build\1_2\cgmeth.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\sempass2.c -o build\1_2\sempass2.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\sempass2.c -o build\1_2\sempass2.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\lambdalifting.c -o build\1_2\lambdalifting.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\lambdalifting.c -o build\1_2\lambdalifting.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\evaltempl.c -o build\1_2\evaltempl.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\evaltempl.c -o build\1_2\evaltempl.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\sem.c -o build\1_2\sem.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\sem.c -o build\1_2\sem.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\procfind.c -o build\1_2\procfind.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\procfind.c -o build\1_2\procfind.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\pragmas.c -o build\1_2\pragmas.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\pragmas.c -o build\1_2\pragmas.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\semtypinst.c -o build\1_2\semtypinst.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\semtypinst.c -o build\1_2\semtypinst.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\sigmatch.c -o build\1_2\sigmatch.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\sigmatch.c -o build\1_2\sigmatch.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\parampatterns.c -o build\1_2\parampatterns.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\parampatterns.c -o build\1_2\parampatterns.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\docgen.c -o build\1_2\docgen.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\docgen.c -o build\1_2\docgen.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\rstast.c -o build\1_2\rstast.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\rstast.c -o build\1_2\rstast.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\rst.c -o build\1_2\rst.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\rst.c -o build\1_2\rst.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\rstgen.c -o build\1_2\rstgen.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\rstgen.c -o build\1_2\rstgen.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\highlite.c -o build\1_2\highlite.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\highlite.c -o build\1_2\highlite.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\algorithm.c -o build\1_2\algorithm.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\algorithm.c -o build\1_2\algorithm.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\aliases.c -o build\1_2\aliases.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\aliases.c -o build\1_2\aliases.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\patterns.c -o build\1_2\patterns.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\patterns.c -o build\1_2\patterns.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\cgen.c -o build\1_2\cgen.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\cgen.c -o build\1_2\cgen.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\ccgutils.c -o build\1_2\ccgutils.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\ccgutils.c -o build\1_2\ccgutils.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\cgendata.c -o build\1_2\cgendata.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\cgendata.c -o build\1_2\cgendata.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\ccgmerge.c -o build\1_2\ccgmerge.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\ccgmerge.c -o build\1_2\ccgmerge.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\jsgen.c -o build\1_2\jsgen.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\jsgen.c -o build\1_2\jsgen.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\json.c -o build\1_2\json.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\json.c -o build\1_2\json.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\lexbase.c -o build\1_2\lexbase.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\lexbase.c -o build\1_2\lexbase.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\unicode.c -o build\1_2\unicode.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\unicode.c -o build\1_2\unicode.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\passaux.c -o build\1_2\passaux.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\passaux.c -o build\1_2\passaux.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\depends.c -o build\1_2\depends.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\depends.c -o build\1_2\depends.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\docgen2.c -o build\1_2\docgen2.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\docgen2.c -o build\1_2\docgen2.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\service.c -o build\1_2\service.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\service.c -o build\1_2\service.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\parseopt.c -o build\1_2\parseopt.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\parseopt.c -o build\1_2\parseopt.o
ECHO %LINKER% %LINK_FLAGS% -o bin\nimrod.exe build\1_2\nimrod.o build\1_2\system.o build\1_2\commands.o build\1_2\os.o build\1_2\strutils.o build\1_2\parseutils.o build\1_2\times.o build\1_2\winlean.o build\1_2\msgs.o build\1_2\options.o build\1_2\lists.o build\1_2\strtabs.o build\1_2\hashes.o build\1_2\tables.o build\1_2\math.o build\1_2\sockets.o build\1_2\ropes.o build\1_2\platform.o build\1_2\crc.o build\1_2\nversion.o build\1_2\condsyms.o build\1_2\ast.o build\1_2\idents.o build\1_2\intsets.o build\1_2\idgen.o build\1_2\astalgo.o build\1_2\rodutils.o build\1_2\extccomp.o build\1_2\osproc.o build\1_2\streams.o build\1_2\wordrecg.o build\1_2\babelcmd.o build\1_2\lexer.o build\1_2\nimlexbase.o build\1_2\llstream.o build\1_2\nimconf.o build\1_2\main.o build\1_2\syntaxes.o build\1_2\parser.o build\1_2\pbraces.o build\1_2\filters.o build\1_2\renderer.o build\1_2\filter_tmpl.o build\1_2\rodread.o build\1_2\types.o build\1_2\trees.o build\1_2\memfiles.o build\1_2\rodwrite.o build\1_2\passes.o build\1_2\magicsys.o build\1_2\nimsets.o build\1_2\bitsets.o build\1_2\semthreads.o build\1_2\importer.o build\1_2\lookups.o build\1_2\semdata.o build\1_2\treetab.o build\1_2\evals.o build\1_2\semfold.o build\1_2\saturate.o build\1_2\transf.o build\1_2\cgmeth.o build\1_2\sempass2.o build\1_2\lambdalifting.o build\1_2\evaltempl.o build\1_2\sem.o build\1_2\procfind.o build\1_2\pragmas.o build\1_2\semtypinst.o build\1_2\sigmatch.o build\1_2\parampatterns.o build\1_2\docgen.o build\1_2\rstast.o build\1_2\rst.o build\1_2\rstgen.o build\1_2\highlite.o build\1_2\algorithm.o build\1_2\aliases.o build\1_2\patterns.o build\1_2\cgen.o build\1_2\ccgutils.o build\1_2\cgendata.o build\1_2\ccgmerge.o build\1_2\jsgen.o build\1_2\json.o build\1_2\lexbase.o build\1_2\unicode.o build\1_2\passaux.o build\1_2\depends.o build\1_2\docgen2.o build\1_2\service.o build\1_2\parseopt.o
%LINKER% %LINK_FLAGS% -o bin\nimrod.exe build\1_2\nimrod.o build\1_2\system.o build\1_2\commands.o build\1_2\os.o build\1_2\strutils.o build\1_2\parseutils.o build\1_2\times.o build\1_2\winlean.o build\1_2\msgs.o build\1_2\options.o build\1_2\lists.o build\1_2\strtabs.o build\1_2\hashes.o build\1_2\tables.o build\1_2\math.o build\1_2\sockets.o build\1_2\ropes.o build\1_2\platform.o build\1_2\crc.o build\1_2\nversion.o build\1_2\condsyms.o build\1_2\ast.o build\1_2\idents.o build\1_2\intsets.o build\1_2\idgen.o build\1_2\astalgo.o build\1_2\rodutils.o build\1_2\extccomp.o build\1_2\osproc.o build\1_2\streams.o build\1_2\wordrecg.o build\1_2\babelcmd.o build\1_2\lexer.o build\1_2\nimlexbase.o build\1_2\llstream.o build\1_2\nimconf.o build\1_2\main.o build\1_2\syntaxes.o build\1_2\parser.o build\1_2\pbraces.o build\1_2\filters.o build\1_2\renderer.o build\1_2\filter_tmpl.o build\1_2\rodread.o build\1_2\types.o build\1_2\trees.o build\1_2\memfiles.o build\1_2\rodwrite.o build\1_2\passes.o build\1_2\magicsys.o build\1_2\nimsets.o build\1_2\bitsets.o build\1_2\semthreads.o build\1_2\importer.o build\1_2\lookups.o build\1_2\semdata.o build\1_2\treetab.o build\1_2\evals.o build\1_2\semfold.o build\1_2\saturate.o build\1_2\transf.o build\1_2\cgmeth.o build\1_2\sempass2.o build\1_2\lambdalifting.o build\1_2\evaltempl.o build\1_2\sem.o build\1_2\procfind.o build\1_2\pragmas.o build\1_2\semtypinst.o build\1_2\sigmatch.o build\1_2\parampatterns.o build\1_2\docgen.o build\1_2\rstast.o build\1_2\rst.o build\1_2\rstgen.o build\1_2\highlite.o build\1_2\algorithm.o build\1_2\aliases.o build\1_2\patterns.o build\1_2\cgen.o build\1_2\ccgutils.o build\1_2\cgendata.o build\1_2\ccgmerge.o build\1_2\jsgen.o build\1_2\json.o build\1_2\lexbase.o build\1_2\unicode.o build\1_2\passaux.o build\1_2\depends.o build\1_2\docgen2.o build\1_2\service.o build\1_2\parseopt.o
ECHO SUCCESS

View File

@@ -42,7 +42,7 @@ proc isPartOfAux(n: PNode, b: PType, marker: var TIntSet): TAnalysisResult =
proc isPartOfAux(a, b: PType, marker: var TIntSet): TAnalysisResult =
result = arNo
if a == nil or b == nil: return
if ContainsOrIncl(marker, a.id): return
if containsOrIncl(marker, a.id): return
if compareTypes(a, b, dcEqIgnoreDistinct): return arYes
case a.kind
of tyObject:
@@ -54,11 +54,11 @@ proc isPartOfAux(a, b: PType, marker: var TIntSet): TAnalysisResult =
for i in countup(0, sonsLen(a) - 1):
result = isPartOfAux(a.sons[i], b, marker)
if result == arYes: return
else: nil
else: discard
proc isPartOf(a, b: PType): TAnalysisResult =
## checks iff 'a' can be part of 'b'. Iterates over VALUE types!
var marker = InitIntSet()
var marker = initIntSet()
# watch out: parameters reversed because I'm too lazy to change the code...
result = isPartOfAux(b, a, marker)
@@ -115,7 +115,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
var x = if a[1].kind == nkHiddenStdConv: a[1][1] else: a[1]
var y = if b[1].kind == nkHiddenStdConv: b[1][1] else: b[1]
if SameValue(x, y): result = arYes
if sameValue(x, y): result = arYes
else: result = arNo
# else: maybe and no are accurate
else:
@@ -140,7 +140,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
result = isPartOf(a[1], b[1])
of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
result = isPartOf(a[0], b[0])
else: nil
else: discard
# Calls return a new location, so a default of ``arNo`` is fine.
else:
# go down recursively; this is quite demanding:
@@ -177,6 +177,6 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
if isPartOf(a.typ, b.typ) != arNo:
result = isPartOf(a[0], b)
if result == arNo: result = arMaybe
else: nil
else: nil
else: discard
else: discard

View File

@@ -13,7 +13,7 @@ import
msgs, hashes, nversion, options, strutils, crc, ropes, idents, lists,
intsets, idgen
type
type
TCallingConvention* = enum
ccDefault, # proc has no explicit calling convention
ccStdCall, # procedure is stdcall
@@ -62,7 +62,7 @@ type
nkTripleStrLit, # a triple string literal """
nkNilLit, # the nil literal
# end of atoms
nkMetaNode, # difficult to explain; represents itself
nkMetaNode_Obsolete, # difficult to explain; represents itself
# (used for macros)
nkDotCall, # used to temporarily flag a nkCall node;
# this is used
@@ -131,7 +131,7 @@ type
nkFormalParams, # formal parameters
nkOfInherit, # inherited from symbol
nkModule, # the syntax tree of a module
nkImportAs, # a 'as' b in an import statement
nkProcDef, # a proc
nkMethodDef, # a method
nkConverterDef, # a converter
@@ -178,6 +178,7 @@ type
nkIncludeStmt, # an include statement
nkBindStmt, # a bind statement
nkMixinStmt, # a mixin statement
nkUsingStmt, # an using statement
nkCommentStmt, # a comment statement
nkStmtListExpr, # a statement list followed by an expr; this is used
# to allow powerful multi-line templates
@@ -187,9 +188,15 @@ type
nkStmtListType, # a statement list ending in a type; for macros
nkBlockType, # a statement block ending in a type; for macros
# types as syntactic trees:
nkWith, # distinct with `foo`
nkWithout, # distinct without `foo`
nkTypeOfExpr, # type(1+2)
nkObjectTy, # object body
nkTupleTy, # tuple body
nkTypeClassTy, # user-defined type class
nkStaticTy, # ``static[T]``
nkRecList, # list of object parts
nkRecCase, # case section of object
nkRecWhen, # when section of object
@@ -211,11 +218,11 @@ type
nkClosure, # (prc, env)-pair (internally used for code gen)
nkGotoState, # used for the state machine (for iterators)
nkState, # give a label to a code section (for iterators)
nkBreakState # special break statement for easier code generation
nkBreakState, # special break statement for easier code generation
TNodeKinds* = set[TNodeKind]
type
TSymFlag* = enum # already 30 flags!
TSymFlag* = enum # already 32 flags!
sfUsed, # read access of sym (for warnings) or simply used
sfExported, # symbol is exported from module
sfFromGeneric, # symbol is instantiation of a generic; this is needed
@@ -229,13 +236,14 @@ type
sfVolatile, # variable is volatile
sfRegister, # variable should be placed in a register
sfPure, # object is "pure" that means it has no type-information
# enum is "pure", its values need qualified access
# variable is "pure"; it's an explicit "global"
sfNoSideEffect, # proc has no side effects
sfSideEffect, # proc may have side effects; cannot prove it has none
sfMainModule, # module is the main module
sfSystemModule, # module is the system module
sfNoReturn, # proc never returns (an exit proc)
sfAddrTaken, # the variable's address is taken (ex- or implicitely);
sfAddrTaken, # the variable's address is taken (ex- or implicitly);
# *OR*: a proc is indirectly called (used as first class)
sfCompilerProc, # proc is a compiler proc, that is a C proc that is
# needed for the code generator
@@ -254,7 +262,7 @@ type
# for interfacing with C++, JS
sfNamedParamCall, # symbol needs named parameter call syntax in target
# language; for interfacing with Objective C
sfDiscardable, # returned value may be discarded implicitely
sfDiscardable, # returned value may be discarded implicitly
sfDestructor, # proc is destructor
sfGenSym # symbol is 'gensym'ed; do not add to symbol table
@@ -278,11 +286,12 @@ const
# the compiler will avoid printing such names
# in user messages.
sfHoist* = sfVolatile ## proc return value can be hoisted
sfNoForward* = sfRegister
# forward declarations are not required (per module)
sfNoRoot* = sfBorrow # a local variable is provably no root so it doesn't
# require RC ops
const
# getting ready for the future expr/stmt merge
nkWhen* = nkWhenStmt
@@ -290,7 +299,7 @@ const
nkEffectList* = nkArgList
# hacks ahead: an nkEffectList is a node with 4 children:
exceptionEffects* = 0 # exceptions at position 0
readEffects* = 1 # read effects at position 1
usesEffects* = 1 # read effects at position 1
writeEffects* = 2 # write effects at position 2
tagEffects* = 3 # user defined tag ('gc', 'time' etc.)
effectListLen* = 4 # list of effects list
@@ -331,13 +340,70 @@ type
tyConst, tyMutable, tyVarargs,
tyIter, # unused
tyProxy # used as errornous type (for idetools)
tyTypeClass,
tyBuiltInTypeClass #\
# Type such as the catch-all object, tuple, seq, etc
tyUserTypeClass #\
# the body of a user-defined type class
tyUserTypeClassInst #\
# Instance of a parametric user-defined type class.
# Structured similarly to tyGenericInst.
# tyGenericInst represents concrete types, while
# this is still a "generic param" that will bind types
# and resolves them during sigmatch and instantiation.
tyCompositeTypeClass #\
# Type such as seq[Number]
# The notes for tyUserTypeClassInst apply here as well
# sons[0]: the original expression used by the user.
# sons[1]: fully expanded and instantiated meta type
# (potentially following aliases)
tyAnd, tyOr, tyNot #\
# boolean type classes such as `string|int`,`not seq`,
# `Sortable and Enumable`, etc
tyAnything #\
# a type class matching any type
tyStatic #\
# a value known at compile type (the underlying type is .base)
tyFromExpr #\
# This is a type representing an expression that depends
# on generic parameters (the exprsesion is stored in t.n)
# It will be converted to a real type only during generic
# instantiation and prior to this it has the potential to
# be any type.
tyFieldAccessor #\
# Expressions such as Type.field (valid in contexts such
# as the `is` operator and magics like `high` and `low`).
# Could be lifted to a single argument proc returning the
# field value.
# sons[0]: type of containing object or tuple
# sons[1]: field type
# .n: nkDotExpr storing the field name
static:
# remind us when TTypeKind stops to fit in a single 64-bit word
assert TTypeKind.high.ord <= 63
const
tyPureObject* = tyTuple
GcTypeKinds* = {tyRef, tySequence, tyString}
tyError* = tyProxy # as an errornous node should match everything
tyUnknownTypes* = {tyError, tyFromExpr}
tyTypeClasses* = {tyBuiltInTypeClass, tyCompositeTypeClass,
tyUserTypeClass, tyUserTypeClassInst,
tyAnd, tyOr, tyNot, tyAnything}
tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyExpr} + tyTypeClasses
type
TTypeKinds* = set[TTypeKind]
@@ -351,9 +417,14 @@ type
# efficiency
nfTransf, # node has been transformed
nfSem # node has been checked for semantics
nfDotField # the call can use a dot operator
nfDotSetter # the call can use a setter dot operarator
nfExplicitCall # x.y() was used instead of x.y
nfExprCall # this is an attempt to call a regular expression
nfIsRef # this node is a 'ref' node; used for the VM
TNodeFlags* = set[TNodeFlag]
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 19)
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 28)
tfVarargs, # procedure has C styled varargs
tfNoSideEffect, # procedure type does not allow side effects
tfFinal, # is the object final?
@@ -361,26 +432,40 @@ type
tfAcyclic, # type is acyclic (for GC optimization)
tfEnumHasHoles, # enum cannot be mapped into a range
tfShallow, # type can be shallow copied on assignment
tfThread, # proc type is marked as ``thread``
tfThread, # proc type is marked as ``thread``; alias for ``gcsafe``
tfFromGeneric, # type is an instantiation of a generic; this is needed
# because for instantiations of objects, structural
# type equality has to be used
tfInstantiated, # XXX: used to mark generic params after instantiation.
# if the concrete type happens to be an implicit generic
# this can lead to invalid proc signatures in the second
# pass of semProcTypeNode performed after instantiation.
# this won't be needed if we don't perform this redundant
# second pass (stay tuned).
tfUnresolved, # marks unresolved typedesc/static params: e.g.
# proc foo(T: typedesc, list: seq[T]): var T
# proc foo(L: static[int]): array[L, int]
# can be attached to ranges to indicate that the range
# depends on unresolved static params.
tfRetType, # marks return types in proc (used to detect type classes
# used as return types for return type inference)
tfAll, # type class requires all constraints to be met (default)
tfAny, # type class requires any constraint to be met
tfCapturesEnv, # whether proc really captures some environment
tfByCopy, # pass object/tuple by copy (C backend)
tfByRef, # pass object/tuple by reference (C backend)
tfIterator, # type is really an iterator, not a tyProc
tfShared, # type is 'shared'
tfNotNil # type cannot be 'nil'
tfNotNil, # type cannot be 'nil'
tfNeedsInit, # type constains a "not nil" constraint somewhere or some
# other type so that it requires inititalization
tfHasShared, # type constains a "shared" constraint modifier somewhere
tfHasMeta, # type contains "wildcard" sub-types such as generic params
# or other type classes
tfHasGCedMem, # type contains GC'ed memory
tfPacked
tfHasStatic
tfGenericTypeParam
tfImplicitTypeParam
tfWildcard # consider a proc like foo[T, I](x: Type[T, I])
# T and I here can bind to both typedesc and static types
# before this is determined, we'll consider them to be a
# wildcard type.
tfGuarded # guarded pointer
tfBorrowDot # distinct type borrows '.'
TTypeFlags* = set[TTypeFlag]
@@ -402,7 +487,8 @@ type
skResult, # special 'result' variable
skProc, # a proc
skMethod, # a method
skIterator, # an iterator
skIterator, # an inline iterator
skClosureIterator, # a resumable closure iterator
skConverter, # a type converter
skMacro, # a macro
skTemplate, # a template; currently also misused for user-defined
@@ -414,12 +500,16 @@ type
skStub, # symbol is a stub and not yet loaded from the ROD
# file (it is loaded on demand, which may
# mean: never)
skPackage # symbol is a package (used for canonicalization)
TSymKinds* = set[TSymKind]
const
routineKinds* = {skProc, skMethod, skIterator, skConverter,
skMacro, skTemplate}
routineKinds* = {skProc, skMethod, skIterator, skClosureIterator,
skConverter, skMacro, skTemplate}
tfIncompleteStruct* = tfVarargs
tfUncheckedArray* = tfVarargs
tfUnion* = tfNoSideEffect
tfGcSafe* = tfThread
skError* = skUnknown
# type flags that are essential for type equality:
@@ -470,7 +560,7 @@ type
mFloat, mFloat32, mFloat64, mFloat128,
mBool, mChar, mString, mCstring,
mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc,
mVoidType, mPNimrodNode,
mVoidType, mPNimrodNode, mShared, mGuarded, mLock, mSpawn,
mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion, mNimrodMajor,
mNimrodMinor, mNimrodPatch, mCpuEndian, mHostOS, mHostCPU, mAppType,
mNaN, mInf, mNegInf,
@@ -481,7 +571,7 @@ type
mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr,
mNBindSym, mLocals, mNCallSite,
mEqIdent, mEqNimrodNode, mNHint, mNWarning, mNError,
mInstantiationInfo, mGetTypeInfo
mInstantiationInfo, mGetTypeInfo, mNGenSym
# things that we can evaluate safely at compile time, even if not asked for it:
const
@@ -524,23 +614,25 @@ type
PType* = ref TType
PSym* = ref TSym
TNode*{.final, acyclic.} = object # on a 32bit machine, this takes 32 bytes
when defined(useNodeIds):
id*: int
typ*: PType
comment*: string
info*: TLineInfo
flags*: TNodeFlags
case Kind*: TNodeKind
case kind*: TNodeKind
of nkCharLit..nkUInt64Lit:
intVal*: biggestInt
intVal*: BiggestInt
of nkFloatLit..nkFloat128Lit:
floatVal*: biggestFloat
floatVal*: BiggestFloat
of nkStrLit..nkTripleStrLit:
strVal*: string
of nkSym:
sym*: PSym
of nkIdent:
ident*: PIdent
else:
else:
sons*: TNodeSeq
comment*: string
TSymSeq* = seq[PSym]
TStrTable* = object # a table[PIdent] of PSym
@@ -611,6 +703,7 @@ type
TScope* = object
depthLevel*: int
symbols*: TStrTable
usingSyms*: seq[PNode]
parent*: PScope
PScope* = ref TScope
@@ -619,8 +712,9 @@ type
TSym* {.acyclic.} = object of TIdObj
# proc and type instantiations are cached in the generic symbol
case kind*: TSymKind
of skType:
of skType, skGenericParam:
typeInstCache*: seq[PType]
typScope*: PScope
of routineKinds:
procInstCache*: seq[PInstantiation]
scope*: PScope # the scope where the proc was defined
@@ -629,6 +723,11 @@ type
# this is because in incremental compilation, when a module is about to
# be replaced with a newer version, we must decrement the usage count
# of all previously used generics.
# For 'import as' we copy the module symbol but shallowCopy the 'tab'
# and set the 'usedGenerics' to ... XXX gah! Better set module.name
# instead? But this doesn't work either. --> We need an skModuleAlias?
# No need, just leave it as skModule but set the owner accordingly and
# check for the owner when touching 'usedGenerics'.
usedGenerics*: seq[PInstantiation]
tab*: TStrTable # interface table for modules
else: nil
@@ -657,12 +756,15 @@ type
# (or not in symbol table)
# for modules, an unique index corresponding
# to the module's fileIdx
# for variables a slot index for the evaluator
# for routines a superop-ID
offset*: int # offset of record field
loc*: TLoc
annex*: PLib # additional fields (seldom used, so we use a
# reference to another object to safe space)
constraint*: PNode # additional constraints like 'lit|result'
constraint*: PNode # additional constraints like 'lit|result'; also
# misused for the codegenDecl pragma in the hope
# it won't cause problems
TTypeSeq* = seq[PType]
TType* {.acyclic.} = object of TIdObj # \
@@ -678,6 +780,9 @@ type
# for record types a nkRecord node
# for enum types a list of symbols
# for tyInt it can be the int literal
# for procs and tyGenericBody, it's the
# the body of the user-defined type class
# formal param list
# else: unused
destructor*: PSym # destructor. warning: nil here may not necessary
# mean that there is no destructor.
@@ -732,19 +837,24 @@ type
counter*: int
data*: TObjectSeq
TImplication* = enum
impUnknown, impNo, impYes
# BUGFIX: a module is overloadable so that a proc can have the
# same name as an imported module. This is necessary because of
# the poor naming choices in the standard library.
const
OverloadableSyms* = {skProc, skMethod, skIterator, skConverter,
skModule, skTemplate, skMacro}
OverloadableSyms* = {skProc, skMethod, skIterator, skClosureIterator,
skConverter, skModule, skTemplate, skMacro}
GenericTypes*: TTypeKinds = {tyGenericInvokation, tyGenericBody,
tyGenericParam}
StructuralEquivTypes*: TTypeKinds = {tyArrayConstr, tyNil, tyTuple, tyArray,
tySet, tyRange, tyPtr, tyRef, tyVar, tySequence, tyProc, tyOpenArray,
tyVarargs}
ConcreteTypes*: TTypeKinds = { # types of the expr that may occur in::
# var x = expr
tyBool, tyChar, tyEnum, tyArray, tyObject,
@@ -758,22 +868,26 @@ const
tyTuple, tySequence}
NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr, tySequence,
tyProc, tyString, tyError}
ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType, skIterator,
ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType,
skIterator, skClosureIterator,
skMacro, skTemplate, skConverter, skEnumField, skLet, skStub}
PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16, nfAllConst}
PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16,
nfDotSetter, nfDotField,
nfAllConst,nfIsRef}
namePos* = 0
patternPos* = 1 # empty except for term rewriting macros
genericParamsPos* = 2
paramsPos* = 3
pragmasPos* = 4
exceptionPos* = 5 # will be used for exception tracking
optimizedCodePos* = 5 # will be used for exception tracking
bodyPos* = 6 # position of body; use rodread.getBody() instead!
resultPos* = 7
dispatcherPos* = 8 # caution: if method has no 'result' it can be position 5!
dispatcherPos* = 8 # caution: if method has no 'result' it can be position 7!
nkCallKinds* = {nkCall, nkInfix, nkPrefix, nkPostfix,
nkCommand, nkCallStrLit, nkHiddenCallConv}
nkLiterals* = {nkCharLit..nkTripleStrLit}
nkLambdaKinds* = {nkLambda, nkDo}
declarativeDefs* = {nkProcDef, nkMethodDef, nkIteratorDef, nkConverterDef}
procDefs* = nkLambdaKinds + declarativeDefs
@@ -782,12 +896,19 @@ const
nkStrKinds* = {nkStrLit..nkTripleStrLit}
skLocalVars* = {skVar, skLet, skForVar, skParam, skResult}
skProcKinds* = {skProc, skTemplate, skMacro, skIterator, skClosureIterator,
skMethod, skConverter}
skIterators* = {skIterator, skClosureIterator}
lfFullExternalName* = lfParamCopy # \
# only used when 'gCmd == cmdPretty': Indicates that the symbol has been
# imported via 'importc: "fullname"' and no format string.
# creator procs:
proc NewSym*(symKind: TSymKind, Name: PIdent, owner: PSym,
proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym,
info: TLineInfo): PSym
proc NewType*(kind: TTypeKind, owner: PSym): PType
proc newType*(kind: TTypeKind, owner: PSym): PType
proc newNode*(kind: TNodeKind): PNode
proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode
proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode
@@ -858,6 +979,13 @@ template `{}=`*(n: PNode, i: int, s: PNode): stmt =
var emptyNode* = newNode(nkEmpty)
# There is a single empty node that is shared! Do not overwrite it!
var anyGlobal* = newSym(skVar, getIdent("*"), nil, unknownLineInfo())
proc isMetaType*(t: PType): bool =
return t.kind in tyMetaTypes or
(t.kind == tyStatic and t.n == nil) or
tfHasMeta in t.flags
proc linkTo*(t: PType, s: PSym): PType {.discardable.} =
t.sym = s
s.typ = t
@@ -874,7 +1002,7 @@ template fileIdx*(c: PSym): int32 =
template filename*(c: PSym): string =
# XXX: this should be used only on module symbols
c.position.int32.toFileName
c.position.int32.toFilename
proc appendToModule*(m: PSym, n: PNode) =
## The compiler will use this internally to add nodes that will be
@@ -893,7 +1021,7 @@ const # for all kind of hash tables:
proc copyStrTable(dest: var TStrTable, src: TStrTable) =
dest.counter = src.counter
if isNil(src.data): return
setlen(dest.data, len(src.data))
setLen(dest.data, len(src.data))
for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
proc copyIdTable(dest: var TIdTable, src: TIdTable) =
@@ -905,18 +1033,25 @@ proc copyIdTable(dest: var TIdTable, src: TIdTable) =
proc copyTable(dest: var TTable, src: TTable) =
dest.counter = src.counter
if isNil(src.data): return
setlen(dest.data, len(src.data))
setLen(dest.data, len(src.data))
for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
proc copyObjectSet(dest: var TObjectSet, src: TObjectSet) =
dest.counter = src.counter
if isNil(src.data): return
setlen(dest.data, len(src.data))
setLen(dest.data, len(src.data))
for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
proc discardSons(father: PNode) =
father.sons = nil
when defined(useNodeIds):
const nodeIdToDebug* = 482228 # 612794
#612840 # 612905 # 614635 # 614637 # 614641
# 423408
#429107 # 430443 # 441048 # 441090 # 441153
var gNodeId: int
proc newNode(kind: TNodeKind): PNode =
new(result)
result.kind = kind
@@ -924,6 +1059,12 @@ proc newNode(kind: TNodeKind): PNode =
result.info.fileIndex = int32(- 1)
result.info.col = int16(- 1)
result.info.line = int16(- 1)
when defined(useNodeIds):
result.id = gNodeId
if result.id == nodeIdToDebug:
echo "KIND ", result.kind
writeStackTrace()
inc gNodeId
proc newIntNode(kind: TNodeKind, intVal: BiggestInt): PNode =
result = newNode(kind)
@@ -941,6 +1082,10 @@ proc newStrNode(kind: TNodeKind, strVal: string): PNode =
result = newNode(kind)
result.strVal = strVal
proc withInfo*(n: PNode, info: TLineInfo): PNode =
n.info = info
return n
proc newIdentNode(ident: PIdent, info: TLineInfo): PNode =
result = newNode(nkIdent)
result.ident = ident
@@ -962,6 +1107,12 @@ proc newNodeI(kind: TNodeKind, info: TLineInfo): PNode =
new(result)
result.kind = kind
result.info = info
when defined(useNodeIds):
result.id = gNodeId
if result.id == nodeIdToDebug:
echo "KIND ", result.kind
writeStackTrace()
inc gNodeId
proc newNodeI*(kind: TNodeKind, info: TLineInfo, children: int): PNode =
new(result)
@@ -969,6 +1120,12 @@ proc newNodeI*(kind: TNodeKind, info: TLineInfo, children: int): PNode =
result.info = info
if children > 0:
newSeq(result.sons, children)
when defined(useNodeIds):
result.id = gNodeId
if result.id == nodeIdToDebug:
echo "KIND ", result.kind
writeStackTrace()
inc gNodeId
proc newNode*(kind: TNodeKind, info: TLineInfo, sons: TNodeSeq = @[],
typ: PType = nil): PNode =
@@ -978,16 +1135,18 @@ proc newNode*(kind: TNodeKind, info: TLineInfo, sons: TNodeSeq = @[],
result.typ = typ
# XXX use shallowCopy here for ownership transfer:
result.sons = sons
when defined(useNodeIds):
result.id = gNodeId
if result.id == nodeIdToDebug:
echo "KIND ", result.kind
writeStackTrace()
inc gNodeId
proc newNodeIT(kind: TNodeKind, info: TLineInfo, typ: PType): PNode =
result = newNode(kind)
result.info = info
result.typ = typ
proc newMetaNodeIT*(tree: PNode, info: TLineInfo, typ: PType): PNode =
result = newNodeIT(nkMetaNode, info, typ)
result.add(tree)
var emptyParams = newNode(nkFormalParams)
emptyParams.addSon(emptyNode)
@@ -1000,15 +1159,15 @@ proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode,
pragmas, exceptions, body]
proc NewType(kind: TTypeKind, owner: PSym): PType =
proc newType(kind: TTypeKind, owner: PSym): PType =
new(result)
result.kind = kind
result.owner = owner
result.size = - 1
result.align = 2 # default alignment
result.id = getID()
when debugIds:
RegisterId(result)
when debugIds:
registerId(result)
#if result.id < 2000 then
# MessageOut(typeKindToStr[kind] & ' has id: ' & toString(result.id))
@@ -1040,24 +1199,23 @@ proc assignType(dest, src: PType) =
for i in countup(0, sonsLen(src) - 1): dest.sons[i] = src.sons[i]
proc copyType(t: PType, owner: PSym, keepId: bool): PType =
result = newType(t.Kind, owner)
result = newType(t.kind, owner)
assignType(result, t)
if keepId:
result.id = t.id
else:
result.id = getID()
when debugIds: RegisterId(result)
when debugIds: registerId(result)
result.sym = t.sym # backend-info should not be copied
proc copySym(s: PSym, keepId: bool = false): PSym =
result = newSym(s.kind, s.name, s.owner, s.info)
result.ast = nil # BUGFIX; was: s.ast which made problems
#result.ast = nil # BUGFIX; was: s.ast which made problems
result.typ = s.typ
if keepId:
result.id = s.id
else:
result.id = getID()
when debugIds: RegisterId(result)
when debugIds: registerId(result)
result.flags = s.flags
result.magic = s.magic
if s.kind == skModule:
@@ -1066,13 +1224,27 @@ proc copySym(s: PSym, keepId: bool = false): PSym =
result.position = s.position
result.loc = s.loc
result.annex = s.annex # BUGFIX
proc createModuleAlias*(s: PSym, newIdent: PIdent, info: TLineInfo): PSym =
result = newSym(s.kind, newIdent, s.owner, info)
# keep ID!
result.ast = s.ast
result.id = s.id
result.flags = s.flags
system.shallowCopy(result.tab, s.tab)
result.options = s.options
result.position = s.position
result.loc = s.loc
result.annex = s.annex
# XXX once usedGenerics is used, ensure module aliases keep working!
assert s.usedGenerics == nil
proc NewSym(symKind: TSymKind, Name: PIdent, owner: PSym,
proc newSym(symKind: TSymKind, name: PIdent, owner: PSym,
info: TLineInfo): PSym =
# generates a symbol and initializes the hash field too
new(result)
result.Name = Name
result.Kind = symKind
result.name = name
result.kind = symKind
result.flags = {}
result.info = info
result.options = gOptions
@@ -1080,36 +1252,36 @@ proc NewSym(symKind: TSymKind, Name: PIdent, owner: PSym,
result.offset = - 1
result.id = getID()
when debugIds:
RegisterId(result)
registerId(result)
#if result.id < 2000:
# MessageOut(name.s & " has id: " & toString(result.id))
proc initStrTable(x: var TStrTable) =
x.counter = 0
newSeq(x.data, startSize)
newSeq(x.data, StartSize)
proc newStrTable*: TStrTable =
initStrTable(result)
proc initTable(x: var TTable) =
x.counter = 0
newSeq(x.data, startSize)
newSeq(x.data, StartSize)
proc initIdTable(x: var TIdTable) =
x.counter = 0
newSeq(x.data, startSize)
newSeq(x.data, StartSize)
proc initObjectSet(x: var TObjectSet) =
x.counter = 0
newSeq(x.data, startSize)
newSeq(x.data, StartSize)
proc initIdNodeTable(x: var TIdNodeTable) =
x.counter = 0
newSeq(x.data, startSize)
newSeq(x.data, StartSize)
proc initNodeTable(x: var TNodeTable) =
x.counter = 0
newSeq(x.data, startSize)
newSeq(x.data, StartSize)
proc sonsLen(n: PType): int =
if isNil(n.sons): result = 0
@@ -1123,7 +1295,7 @@ proc newSons(father: PType, length: int) =
if isNil(father.sons):
newSeq(father.sons, length)
else:
setlen(father.sons, length)
setLen(father.sons, length)
proc sonsLen(n: PNode): int =
if isNil(n.sons): result = 0
@@ -1133,16 +1305,43 @@ proc newSons(father: PNode, length: int) =
if isNil(father.sons):
newSeq(father.sons, length)
else:
setlen(father.sons, length)
setLen(father.sons, length)
proc addSon*(father, son: PType) {.deprecated.} =
if isNil(father.sons): father.sons = @[]
add(father.sons, son)
#assert((father.kind != tyGenericInvokation) or (son.kind != tyGenericInst))
proc skipTypes*(t: PType, kinds: TTypeKinds): PType =
result = t
while result.kind in kinds: result = lastSon(result)
proc isGCedMem*(t: PType): bool {.inline.} =
result = t.kind in {tyString, tyRef, tySequence} or
t.kind == tyProc and t.callConv == ccClosure
proc propagateToOwner*(owner, elem: PType) =
const HaveTheirOwnEmpty = {tySequence, tySet}
owner.flags = owner.flags + (elem.flags * {tfHasShared, tfHasMeta})
if tfNotNil in elem.flags:
if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvokation}:
owner.flags.incl tfNotNil
elif owner.kind notin HaveTheirOwnEmpty:
owner.flags.incl tfNeedsInit
if tfNeedsInit in elem.flags:
if owner.kind in HaveTheirOwnEmpty: discard
else: owner.flags.incl tfNeedsInit
if tfShared in elem.flags:
owner.flags.incl tfHasShared
if elem.isMetaType:
owner.flags.incl tfHasMeta
if owner.kind != tyProc:
if elem.isGCedMem or tfHasGCedMem in elem.flags:
owner.flags.incl tfHasGCedMem
proc rawAddSon*(father, son: PType) =
if isNil(father.sons): father.sons = @[]
add(father.sons, son)
if not son.isNil: propagateToOwner(father, son)
proc addSon(father, son: PNode) =
assert son != nil
@@ -1157,7 +1356,7 @@ proc delSon(father: PNode, idx: int) =
if isNil(father.sons): return
var length = sonsLen(father)
for i in countup(idx, length - 2): father.sons[i] = father.sons[i + 1]
setlen(father.sons, length - 1)
setLen(father.sons, length - 1)
proc copyNode(src: PNode): PNode =
# does not copy its sons!
@@ -1167,13 +1366,16 @@ proc copyNode(src: PNode): PNode =
result.info = src.info
result.typ = src.typ
result.flags = src.flags * PersistentNodeFlags
case src.Kind
when defined(useNodeIds):
if result.id == nodeIdToDebug:
echo "COMES FROM ", src.id
case src.kind
of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
of nkFloatLit..nkFloat128Lit: result.floatVal = src.floatVal
of nkSym: result.sym = src.sym
of nkIdent: result.ident = src.ident
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
else: nil
else: discard
proc shallowCopy*(src: PNode): PNode =
# does not copy its sons, but provides space for them:
@@ -1182,7 +1384,10 @@ proc shallowCopy*(src: PNode): PNode =
result.info = src.info
result.typ = src.typ
result.flags = src.flags * PersistentNodeFlags
case src.Kind
when defined(useNodeIds):
if result.id == nodeIdToDebug:
echo "COMES FROM ", src.id
case src.kind
of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
of nkFloatLit..nkFloat128Lit: result.floatVal = src.floatVal
of nkSym: result.sym = src.sym
@@ -1198,7 +1403,10 @@ proc copyTree(src: PNode): PNode =
result.info = src.info
result.typ = src.typ
result.flags = src.flags * PersistentNodeFlags
case src.Kind
when defined(useNodeIds):
if result.id == nodeIdToDebug:
echo "COMES FROM ", src.id
case src.kind
of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
of nkFloatLit..nkFloat128Lit: result.floatVal = src.floatVal
of nkSym: result.sym = src.sym
@@ -1256,14 +1464,14 @@ proc sonsNotNil(n: PNode): bool =
return false
result = true
proc getInt*(a: PNode): biggestInt =
proc getInt*(a: PNode): BiggestInt =
case a.kind
of nkIntLit..nkUInt64Lit: result = a.intVal
else:
internalError(a.info, "getInt")
result = 0
proc getFloat*(a: PNode): biggestFloat =
proc getFloat*(a: PNode): BiggestFloat =
case a.kind
of nkFloatLit..nkFloat128Lit: result = a.floatVal
else:
@@ -1287,13 +1495,25 @@ proc getStrOrChar*(a: PNode): string =
proc isGenericRoutine*(s: PSym): bool =
case s.kind
of skProc, skTemplate, skMacro, skIterator, skMethod, skConverter:
result = s.ast != nil and s.ast[genericParamsPos].kind != nkEmpty
else: nil
of skProcKinds:
result = sfFromGeneric in s.flags or
(s.ast != nil and s.ast[genericParamsPos].kind != nkEmpty)
else: discard
proc skipGenericOwner*(s: PSym): PSym =
internalAssert s.kind in skProcKinds
## Generic instantiations are owned by their originating generic
## symbol. This proc skips such owners and goes straigh to the owner
## of the generic itself (the module or the enclosing proc).
result = if sfFromGeneric in s.flags: s.owner.owner
else: s.owner
proc originatingModule*(s: PSym): PSym =
result = s.owner
while result.kind != skModule: result = result.owner
proc isRoutine*(s: PSym): bool {.inline.} =
result = s.kind in {skProc, skTemplate, skMacro, skIterator, skMethod,
skConverter}
result = s.kind in skProcKinds
proc hasPattern*(s: PSym): bool {.inline.} =
result = isRoutine(s) and s.ast.sons[patternPos].kind != nkEmpty
@@ -1301,9 +1521,13 @@ proc hasPattern*(s: PSym): bool {.inline.} =
iterator items*(n: PNode): PNode =
for i in 0.. <n.len: yield n.sons[i]
iterator pairs*(n: PNode): tuple[i: int, n: PNode] =
for i in 0.. <n.len: yield (i, n.sons[i])
proc isAtom*(n: PNode): bool {.inline.} =
result = n.kind >= nkNone and n.kind <= nkNilLit
proc isEmptyType*(t: PType): bool {.inline.} =
## 'void' and 'stmt' types are often equivalent to 'nil' these days:
result = t == nil or t.kind in {tyEmpty, tyStmt}

View File

@@ -24,35 +24,35 @@ proc symToYaml*(n: PSym, indent: int = 0, maxRecDepth: int = - 1): PRope
proc lineInfoToStr*(info: TLineInfo): PRope
# ----------------------- node sets: ---------------------------------------
proc ObjectSetContains*(t: TObjectSet, obj: PObject): bool
proc objectSetContains*(t: TObjectSet, obj: PObject): bool
# returns true whether n is in t
proc ObjectSetIncl*(t: var TObjectSet, obj: PObject)
proc objectSetIncl*(t: var TObjectSet, obj: PObject)
# include an element n in the table t
proc ObjectSetContainsOrIncl*(t: var TObjectSet, obj: PObject): bool
proc objectSetContainsOrIncl*(t: var TObjectSet, obj: PObject): bool
# more are not needed ...
# ----------------------- (key, val)-Hashtables ----------------------------
proc TablePut*(t: var TTable, key, val: PObject)
proc TableGet*(t: TTable, key: PObject): PObject
proc tablePut*(t: var TTable, key, val: PObject)
proc tableGet*(t: TTable, key: PObject): PObject
type
TCmpProc* = proc (key, closure: PObject): bool {.nimcall.} # true if found
proc TableSearch*(t: TTable, key, closure: PObject,
proc tableSearch*(t: TTable, key, closure: PObject,
comparator: TCmpProc): PObject
# return val as soon as comparator returns true; if this never happens,
# nil is returned
# ----------------------- str table -----------------------------------------
proc StrTableContains*(t: TStrTable, n: PSym): bool
proc StrTableAdd*(t: var TStrTable, n: PSym)
proc StrTableGet*(t: TStrTable, name: PIdent): PSym
proc strTableContains*(t: TStrTable, n: PSym): bool
proc strTableAdd*(t: var TStrTable, n: PSym)
proc strTableGet*(t: TStrTable, name: PIdent): PSym
type
TTabIter*{.final.} = object # consider all fields here private
h*: THash # current hash
proc InitTabIter*(ti: var TTabIter, tab: TStrTable): PSym
proc NextIter*(ti: var TTabIter, tab: TStrTable): PSym
proc initTabIter*(ti: var TTabIter, tab: TStrTable): PSym
proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym
# usage:
# var
# i: TTabIter
@@ -69,8 +69,8 @@ type
name*: PIdent
proc InitIdentIter*(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym
proc NextIdentIter*(ti: var TIdentIter, tab: TStrTable): PSym
proc initIdentIter*(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym
proc nextIdentIter*(ti: var TIdentIter, tab: TStrTable): PSym
# these are for debugging only: They are not really deprecated, but I want
# the warning so that release versions do not contain debugging statements:
@@ -79,15 +79,14 @@ proc debug*(n: PType) {.deprecated.}
proc debug*(n: PNode) {.deprecated.}
# --------------------------- ident tables ----------------------------------
proc IdTableGet*(t: TIdTable, key: PIdObj): PObject
proc IdTableGet*(t: TIdTable, key: int): PObject
proc IdTablePut*(t: var TIdTable, key: PIdObj, val: PObject)
proc IdTableHasObjectAsKey*(t: TIdTable, key: PIdObj): bool
proc idTableGet*(t: TIdTable, key: PIdObj): PObject
proc idTableGet*(t: TIdTable, key: int): PObject
proc idTablePut*(t: var TIdTable, key: PIdObj, val: PObject)
proc idTableHasObjectAsKey*(t: TIdTable, key: PIdObj): bool
# checks if `t` contains the `key` (compared by the pointer value, not only
# `key`'s id)
proc IdNodeTableGet*(t: TIdNodeTable, key: PIdObj): PNode
proc IdNodeTablePut*(t: var TIdNodeTable, key: PIdObj, val: PNode)
proc writeIdNodeTable*(t: TIdNodeTable)
proc idNodeTableGet*(t: TIdNodeTable, key: PIdObj): PNode
proc idNodeTablePut*(t: var TIdNodeTable, key: PIdObj, val: PNode)
# ---------------------------------------------------------------------------
@@ -111,9 +110,9 @@ type
data*: TIIPairSeq
proc initIITable*(x: var TIITable)
proc IITableGet*(t: TIITable, key: int): int
proc IITablePut*(t: var TIITable, key, val: int)
proc initIiTable*(x: var TIITable)
proc iiTableGet*(t: TIITable, key: int): int
proc iiTablePut*(t: var TIITable, key, val: int)
# implementation
@@ -129,7 +128,7 @@ proc skipConvTakeType*(n: PNode): PNode =
result = n.skipConv
result.typ = n.typ
proc SameValue*(a, b: PNode): bool =
proc sameValue*(a, b: PNode): bool =
result = false
case a.kind
of nkCharLit..nkInt64Lit:
@@ -141,7 +140,7 @@ proc SameValue*(a, b: PNode): bool =
else:
# don't raise an internal error for 'nimrod check':
#InternalError(a.info, "SameValue")
nil
discard
proc leValue*(a, b: PNode): bool =
# a <= b?
@@ -156,7 +155,13 @@ proc leValue*(a, b: PNode): bool =
else:
# don't raise an internal error for 'nimrod check':
#InternalError(a.info, "leValue")
nil
discard
proc weakLeValue*(a, b: PNode): TImplication =
if a.kind notin nkLiterals or b.kind notin nkLiterals:
result = impUnknown
else:
result = if leValue(a, b): impYes else: impNo
proc lookupInRecord(n: PNode, field: PIdent): PSym =
result = nil
@@ -166,7 +171,7 @@ proc lookupInRecord(n: PNode, field: PIdent): PSym =
result = lookupInRecord(n.sons[i], field)
if result != nil: return
of nkRecCase:
if (n.sons[0].kind != nkSym): InternalError(n.info, "lookupInRecord")
if (n.sons[0].kind != nkSym): internalError(n.info, "lookupInRecord")
result = lookupInRecord(n.sons[0], field)
if result != nil: return
for i in countup(1, sonsLen(n) - 1):
@@ -182,14 +187,14 @@ proc lookupInRecord(n: PNode, field: PIdent): PSym =
proc getModule(s: PSym): PSym =
result = s
assert((result.kind == skModule) or (result.owner != result))
while (result != nil) and (result.kind != skModule): result = result.owner
while result != nil and result.kind != skModule: result = result.owner
proc getSymFromList(list: PNode, ident: PIdent, start: int = 0): PSym =
for i in countup(start, sonsLen(list) - 1):
if list.sons[i].kind == nkSym:
result = list.sons[i].sym
if result.name.id == ident.id: return
else: InternalError(list.info, "getSymFromList")
else: internalError(list.info, "getSymFromList")
result = nil
proc hashNode(p: PObject): THash =
@@ -203,7 +208,7 @@ proc spaces(x: int): PRope =
# returns x spaces
result = toRope(repeatChar(x))
proc toYamlChar(c: Char): string =
proc toYamlChar(c: char): string =
case c
of '\0'..'\x1F', '\x80'..'\xFF': result = "\\u" & strutils.toHex(ord(c), 4)
of '\'', '\"', '\\': result = '\\' & c
@@ -216,7 +221,7 @@ proc makeYamlString*(s: string): PRope =
const MaxLineLength = 64
result = nil
var res = "\""
for i in countup(0, len(s) - 1):
for i in countup(0, if s.isNil: -1 else: (len(s)-1)):
if (i + 1) mod MaxLineLength == 0:
add(res, '\"')
add(res, "\n")
@@ -262,7 +267,7 @@ proc strTableToYaml(n: TStrTable, marker: var TIntSet, indent: int,
app(result, "]")
assert(mycount == n.counter)
proc ropeConstr(indent: int, c: openarray[PRope]): PRope =
proc ropeConstr(indent: int, c: openArray[PRope]): PRope =
# array of (name, value) pairs
var istr = spaces(indent + 2)
result = toRope("{")
@@ -277,7 +282,7 @@ proc symToYamlAux(n: PSym, marker: var TIntSet, indent: int,
maxRecDepth: int): PRope =
if n == nil:
result = toRope("null")
elif ContainsOrIncl(marker, n.id):
elif containsOrIncl(marker, n.id):
result = ropef("\"$1 @$2\"", [toRope(n.name.s), toRope(
strutils.toHex(cast[TAddress](n), sizeof(n) * 2))])
else:
@@ -298,7 +303,7 @@ proc typeToYamlAux(n: PType, marker: var TIntSet, indent: int,
maxRecDepth: int): PRope =
if n == nil:
result = toRope("null")
elif ContainsOrIncl(marker, n.id):
elif containsOrIncl(marker, n.id):
result = ropef("\"$1 @$2\"", [toRope($n.kind), toRope(
strutils.toHex(cast[TAddress](n), sizeof(n) * 2))])
else:
@@ -315,7 +320,7 @@ proc typeToYamlAux(n: PType, marker: var TIntSet, indent: int,
makeYamlString($n.kind),
toRope("sym"), symToYamlAux(n.sym, marker,
indent + 2, maxRecDepth - 1), toRope("n"), treeToYamlAux(n.n, marker,
indent + 2, maxRecDepth - 1), toRope("flags"), FlagsToStr(n.flags),
indent + 2, maxRecDepth - 1), toRope("flags"), flagsToStr(n.flags),
toRope("callconv"),
makeYamlString(CallingConvToStr[n.callConv]),
toRope("size"), toRope(n.size),
@@ -336,9 +341,12 @@ proc treeToYamlAux(n: PNode, marker: var TIntSet, indent: int,
appf(result, ",$N$1\"intVal\": $2", [istr, toRope(n.intVal)])
of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
appf(result, ",$N$1\"floatVal\": $2",
[istr, toRope(n.floatVal.ToStrMaxPrecision)])
[istr, toRope(n.floatVal.toStrMaxPrecision)])
of nkStrLit..nkTripleStrLit:
appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
if n.strVal.isNil:
appf(result, ",$N$1\"strVal\": null", [istr])
else:
appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
of nkSym:
appf(result, ",$N$1\"sym\": $2",
[istr, symToYamlAux(n.sym, marker, indent + 2, maxRecDepth)])
@@ -360,15 +368,15 @@ proc treeToYamlAux(n: PNode, marker: var TIntSet, indent: int,
appf(result, "$N$1}", [spaces(indent)])
proc treeToYaml(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope =
var marker = InitIntSet()
var marker = initIntSet()
result = treeToYamlAux(n, marker, indent, maxRecDepth)
proc typeToYaml(n: PType, indent: int = 0, maxRecDepth: int = - 1): PRope =
var marker = InitIntSet()
var marker = initIntSet()
result = typeToYamlAux(n, marker, indent, maxRecDepth)
proc symToYaml(n: PSym, indent: int = 0, maxRecDepth: int = - 1): PRope =
var marker = InitIntSet()
var marker = initIntSet()
result = symToYamlAux(n, marker, indent, maxRecDepth)
proc debugTree(n: PNode, indent: int, maxRecDepth: int): PRope
@@ -406,9 +414,12 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int): PRope =
appf(result, ",$N$1\"intVal\": $2", [istr, toRope(n.intVal)])
of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
appf(result, ",$N$1\"floatVal\": $2",
[istr, toRope(n.floatVal.ToStrMaxPrecision)])
[istr, toRope(n.floatVal.toStrMaxPrecision)])
of nkStrLit..nkTripleStrLit:
appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
if n.strVal.isNil:
appf(result, ",$N$1\"strVal\": null", [istr])
else:
appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
of nkSym:
appf(result, ",$N$1\"sym\": $2_$3",
[istr, toRope(n.sym.name.s), toRope(n.sym.id)])
@@ -430,11 +441,16 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int): PRope =
appf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
appf(result, "$N$1}", [spaces(indent)])
proc debug(n: PSym) =
#writeln(stdout, ropeToStr(symToYaml(n, 0, 1)))
writeln(stdout, ropeToStr(ropef("$1_$2: $3, $4", [
toRope(n.name.s), toRope(n.id), flagsToStr(n.flags),
flagsToStr(n.loc.flags)])))
proc debug(n: PSym) =
if n == nil:
writeln(stdout, "null")
elif n.kind == skUnknown:
writeln(stdout, "skUnknown")
else:
#writeln(stdout, ropeToStr(symToYaml(n, 0, 1)))
writeln(stdout, ropeToStr(ropef("$1_$2: $3, $4, $5", [
toRope(n.name.s), toRope(n.id), flagsToStr(n.flags),
flagsToStr(n.loc.flags), lineInfoToStr(n.info)])))
proc debug(n: PType) =
writeln(stdout, ropeToStr(debugType(n)))
@@ -451,18 +467,18 @@ proc nextTry(h, maxHash: THash): THash =
# generates each int in range(maxHash) exactly once (see any text on
# random-number generation for proof).
proc objectSetContains(t: TObjectSet, obj: PObject): bool =
proc objectSetContains(t: TObjectSet, obj: PObject): bool =
# returns true whether n is in t
var h: THash = hashNode(obj) and high(t.data) # start with real hash value
while t.data[h] != nil:
if (t.data[h] == obj):
while t.data[h] != nil:
if t.data[h] == obj:
return true
h = nextTry(h, high(t.data))
result = false
proc objectSetRawInsert(data: var TObjectSeq, obj: PObject) =
var h: THash = HashNode(obj) and high(data)
while data[h] != nil:
proc objectSetRawInsert(data: var TObjectSeq, obj: PObject) =
var h: THash = hashNode(obj) and high(data)
while data[h] != nil:
assert(data[h] != obj)
h = nextTry(h, high(data))
assert(data[h] == nil)
@@ -470,8 +486,8 @@ proc objectSetRawInsert(data: var TObjectSeq, obj: PObject) =
proc objectSetEnlarge(t: var TObjectSet) =
var n: TObjectSeq
newSeq(n, len(t.data) * growthFactor)
for i in countup(0, high(t.data)):
newSeq(n, len(t.data) * GrowthFactor)
for i in countup(0, high(t.data)):
if t.data[i] != nil: objectSetRawInsert(n, t.data[i])
swap(t.data, n)
@@ -482,7 +498,7 @@ proc objectSetIncl(t: var TObjectSet, obj: PObject) =
proc objectSetContainsOrIncl(t: var TObjectSet, obj: PObject): bool =
# returns true if obj is already in the string table:
var h: THash = HashNode(obj) and high(t.data)
var h: THash = hashNode(obj) and high(t.data)
while true:
var it = t.data[h]
if it == nil: break
@@ -498,7 +514,7 @@ proc objectSetContainsOrIncl(t: var TObjectSet, obj: PObject): bool =
inc(t.counter)
result = false
proc TableRawGet(t: TTable, key: PObject): int =
proc tableRawGet(t: TTable, key: PObject): int =
var h: THash = hashNode(key) and high(t.data) # start with real hash value
while t.data[h].key != nil:
if t.data[h].key == key:
@@ -506,7 +522,7 @@ proc TableRawGet(t: TTable, key: PObject): int =
h = nextTry(h, high(t.data))
result = -1
proc TableSearch(t: TTable, key, closure: PObject,
proc tableSearch(t: TTable, key, closure: PObject,
comparator: TCmpProc): PObject =
var h: THash = hashNode(key) and high(t.data) # start with real hash value
while t.data[h].key != nil:
@@ -517,13 +533,13 @@ proc TableSearch(t: TTable, key, closure: PObject,
h = nextTry(h, high(t.data))
result = nil
proc TableGet(t: TTable, key: PObject): PObject =
var index = TableRawGet(t, key)
proc tableGet(t: TTable, key: PObject): PObject =
var index = tableRawGet(t, key)
if index >= 0: result = t.data[index].val
else: result = nil
proc TableRawInsert(data: var TPairSeq, key, val: PObject) =
var h: THash = HashNode(key) and high(data)
proc tableRawInsert(data: var TPairSeq, key, val: PObject) =
var h: THash = hashNode(key) and high(data)
while data[h].key != nil:
assert(data[h].key != key)
h = nextTry(h, high(data))
@@ -531,23 +547,23 @@ proc TableRawInsert(data: var TPairSeq, key, val: PObject) =
data[h].key = key
data[h].val = val
proc TableEnlarge(t: var TTable) =
proc tableEnlarge(t: var TTable) =
var n: TPairSeq
newSeq(n, len(t.data) * growthFactor)
newSeq(n, len(t.data) * GrowthFactor)
for i in countup(0, high(t.data)):
if t.data[i].key != nil: TableRawInsert(n, t.data[i].key, t.data[i].val)
if t.data[i].key != nil: tableRawInsert(n, t.data[i].key, t.data[i].val)
swap(t.data, n)
proc TablePut(t: var TTable, key, val: PObject) =
var index = TableRawGet(t, key)
proc tablePut(t: var TTable, key, val: PObject) =
var index = tableRawGet(t, key)
if index >= 0:
t.data[index].val = val
else:
if mustRehash(len(t.data), t.counter): TableEnlarge(t)
TableRawInsert(t.data, key, val)
if mustRehash(len(t.data), t.counter): tableEnlarge(t)
tableRawInsert(t.data, key, val)
inc(t.counter)
proc StrTableContains(t: TStrTable, n: PSym): bool =
proc strTableContains(t: TStrTable, n: PSym): bool =
var h: THash = n.name.h and high(t.data) # start with real hash value
while t.data[h] != nil:
if (t.data[h] == n):
@@ -555,18 +571,35 @@ proc StrTableContains(t: TStrTable, n: PSym): bool =
h = nextTry(h, high(t.data))
result = false
proc StrTableRawInsert(data: var TSymSeq, n: PSym) =
proc strTableRawInsert(data: var TSymSeq, n: PSym) =
var h: THash = n.name.h and high(data)
while data[h] != nil:
if data[h] == n:
# allowed for 'export' feature:
#InternalError(n.info, "StrTableRawInsert: " & n.name.s)
return
h = nextTry(h, high(data))
assert(data[h] == nil)
data[h] = n
if sfImmediate notin n.flags:
# fast path:
while data[h] != nil:
if data[h] == n:
# allowed for 'export' feature:
#InternalError(n.info, "StrTableRawInsert: " & n.name.s)
return
h = nextTry(h, high(data))
assert(data[h] == nil)
data[h] = n
else:
# slow path; we have to ensure immediate symbols are preferred for
# symbol lookups.
# consider the chain: foo (immediate), foo, bar, bar (immediate)
# then bar (immediate) gets replaced with foo (immediate) and the non
# immediate foo is picked! Thus we need to replace it with the first
# slot that has in fact the same identifier stored in it!
var favPos = -1
while data[h] != nil:
if data[h] == n: return
if favPos < 0 and data[h].name.id == n.name.id: favPos = h
h = nextTry(h, high(data))
assert(data[h] == nil)
data[h] = n
if favPos >= 0: swap data[h], data[favPos]
proc SymTabReplaceRaw(data: var TSymSeq, prevSym: PSym, newSym: PSym) =
proc symTabReplaceRaw(data: var TSymSeq, prevSym: PSym, newSym: PSym) =
assert prevSym.name.h == newSym.name.h
var h: THash = prevSym.name.h and high(data)
while data[h] != nil:
@@ -576,22 +609,22 @@ proc SymTabReplaceRaw(data: var TSymSeq, prevSym: PSym, newSym: PSym) =
h = nextTry(h, high(data))
assert false
proc SymTabReplace*(t: var TStrTable, prevSym: PSym, newSym: PSym) =
SymTabReplaceRaw(t.data, prevSym, newSym)
proc symTabReplace*(t: var TStrTable, prevSym: PSym, newSym: PSym) =
symTabReplaceRaw(t.data, prevSym, newSym)
proc StrTableEnlarge(t: var TStrTable) =
proc strTableEnlarge(t: var TStrTable) =
var n: TSymSeq
newSeq(n, len(t.data) * growthFactor)
newSeq(n, len(t.data) * GrowthFactor)
for i in countup(0, high(t.data)):
if t.data[i] != nil: StrTableRawInsert(n, t.data[i])
if t.data[i] != nil: strTableRawInsert(n, t.data[i])
swap(t.data, n)
proc StrTableAdd(t: var TStrTable, n: PSym) =
if mustRehash(len(t.data), t.counter): StrTableEnlarge(t)
StrTableRawInsert(t.data, n)
proc strTableAdd(t: var TStrTable, n: PSym) =
if mustRehash(len(t.data), t.counter): strTableEnlarge(t)
strTableRawInsert(t.data, n)
inc(t.counter)
proc StrTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
# returns true if n is already in the string table:
# It is essential that `n` is written nevertheless!
# This way the newest redefinition is picked by the semantic analyses!
@@ -605,15 +638,15 @@ proc StrTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
return true # found it
h = nextTry(h, high(t.data))
if mustRehash(len(t.data), t.counter):
StrTableEnlarge(t)
StrTableRawInsert(t.data, n)
strTableEnlarge(t)
strTableRawInsert(t.data, n)
else:
assert(t.data[h] == nil)
t.data[h] = n
inc(t.counter)
result = false
proc StrTableGet(t: TStrTable, name: PIdent): PSym =
proc strTableGet(t: TStrTable, name: PIdent): PSym =
var h: THash = name.h and high(t.data)
while true:
result = t.data[h]
@@ -621,19 +654,19 @@ proc StrTableGet(t: TStrTable, name: PIdent): PSym =
if result.name.id == name.id: break
h = nextTry(h, high(t.data))
proc InitIdentIter(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym =
proc initIdentIter(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym =
ti.h = s.h
ti.name = s
if tab.Counter == 0: result = nil
else: result = NextIdentIter(ti, tab)
if tab.counter == 0: result = nil
else: result = nextIdentIter(ti, tab)
proc NextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
var h, start: THash
h = ti.h and high(tab.data)
start = h
result = tab.data[h]
while result != nil:
if result.Name.id == ti.name.id: break
if result.name.id == ti.name.id: break
h = nextTry(h, high(tab.data))
if h == start:
result = nil
@@ -641,13 +674,13 @@ proc NextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
result = tab.data[h]
ti.h = nextTry(h, high(tab.data))
proc NextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
excluding: TIntSet): PSym =
var h: THash = ti.h and high(tab.data)
var start = h
result = tab.data[h]
while result != nil:
if result.Name.id == ti.name.id and not Contains(excluding, result.id):
if result.name.id == ti.name.id and not contains(excluding, result.id):
break
h = nextTry(h, high(tab.data))
if h == start:
@@ -655,35 +688,35 @@ proc NextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
break
result = tab.data[h]
ti.h = nextTry(h, high(tab.data))
if result != nil and Contains(excluding, result.id): result = nil
if result != nil and contains(excluding, result.id): result = nil
proc FirstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent,
proc firstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent,
excluding: TIntSet): PSym =
ti.h = s.h
ti.name = s
if tab.Counter == 0: result = nil
else: result = NextIdentExcluding(ti, tab, excluding)
if tab.counter == 0: result = nil
else: result = nextIdentExcluding(ti, tab, excluding)
proc InitTabIter(ti: var TTabIter, tab: TStrTable): PSym =
proc initTabIter(ti: var TTabIter, tab: TStrTable): PSym =
ti.h = 0 # we start by zero ...
if tab.counter == 0:
result = nil # FIX 1: removed endless loop
else:
result = NextIter(ti, tab)
result = nextIter(ti, tab)
proc NextIter(ti: var TTabIter, tab: TStrTable): PSym =
proc nextIter(ti: var TTabIter, tab: TStrTable): PSym =
result = nil
while (ti.h <= high(tab.data)):
result = tab.data[ti.h]
Inc(ti.h) # ... and increment by one always
inc(ti.h) # ... and increment by one always
if result != nil: break
iterator items*(tab: TStrTable): PSym =
var it: TTabIter
var s = InitTabIter(it, tab)
var s = initTabIter(it, tab)
while s != nil:
yield s
s = NextIter(it, tab)
s = nextIter(it, tab)
proc hasEmptySlot(data: TIdPairSeq): bool =
for h in countup(0, high(data)):
@@ -691,27 +724,27 @@ proc hasEmptySlot(data: TIdPairSeq): bool =
return true
result = false
proc IdTableRawGet(t: TIdTable, key: int): int =
proc idTableRawGet(t: TIdTable, key: int): int =
var h: THash
h = key and high(t.data) # start with real hash value
while t.data[h].key != nil:
if (t.data[h].key.id == key):
if t.data[h].key.id == key:
return h
h = nextTry(h, high(t.data))
result = - 1
proc IdTableHasObjectAsKey(t: TIdTable, key: PIdObj): bool =
var index = IdTableRawGet(t, key.id)
proc idTableHasObjectAsKey(t: TIdTable, key: PIdObj): bool =
var index = idTableRawGet(t, key.id)
if index >= 0: result = t.data[index].key == key
else: result = false
proc IdTableGet(t: TIdTable, key: PIdObj): PObject =
var index = IdTableRawGet(t, key.id)
proc idTableGet(t: TIdTable, key: PIdObj): PObject =
var index = idTableRawGet(t, key.id)
if index >= 0: result = t.data[index].val
else: result = nil
proc IdTableGet(t: TIdTable, key: int): PObject =
var index = IdTableRawGet(t, key)
proc idTableGet(t: TIdTable, key: int): PObject =
var index = idTableRawGet(t, key)
if index >= 0: result = t.data[index].val
else: result = nil
@@ -720,7 +753,7 @@ iterator pairs*(t: TIdTable): tuple[key: int, value: PObject] =
if t.data[i].key != nil:
yield (t.data[i].key.id, t.data[i].val)
proc IdTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: PObject) =
proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: PObject) =
var h: THash
h = key.id and high(data)
while data[h].key != nil:
@@ -730,33 +763,30 @@ proc IdTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: PObject) =
data[h].key = key
data[h].val = val
proc IdTablePut(t: var TIdTable, key: PIdObj, val: PObject) =
proc idTablePut(t: var TIdTable, key: PIdObj, val: PObject) =
var
index: int
n: TIdPairSeq
index = IdTableRawGet(t, key.id)
index = idTableRawGet(t, key.id)
if index >= 0:
assert(t.data[index].key != nil)
t.data[index].val = val
else:
if mustRehash(len(t.data), t.counter):
newSeq(n, len(t.data) * growthFactor)
newSeq(n, len(t.data) * GrowthFactor)
for i in countup(0, high(t.data)):
if t.data[i].key != nil:
IdTableRawInsert(n, t.data[i].key, t.data[i].val)
idTableRawInsert(n, t.data[i].key, t.data[i].val)
assert(hasEmptySlot(n))
swap(t.data, n)
IdTableRawInsert(t.data, key, val)
idTableRawInsert(t.data, key, val)
inc(t.counter)
iterator IdTablePairs*(t: TIdTable): tuple[key: PIdObj, val: PObject] =
iterator idTablePairs*(t: TIdTable): tuple[key: PIdObj, val: PObject] =
for i in 0 .. high(t.data):
if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
proc writeIdNodeTable(t: TIdNodeTable) =
nil
proc IdNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int =
proc idNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int =
var h: THash
h = key.id and high(t.data) # start with real hash value
while t.data[h].key != nil:
@@ -765,17 +795,17 @@ proc IdNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int =
h = nextTry(h, high(t.data))
result = - 1
proc IdNodeTableGet(t: TIdNodeTable, key: PIdObj): PNode =
proc idNodeTableGet(t: TIdNodeTable, key: PIdObj): PNode =
var index: int
index = IdNodeTableRawGet(t, key)
index = idNodeTableRawGet(t, key)
if index >= 0: result = t.data[index].val
else: result = nil
proc IdNodeTableGetLazy*(t: TIdNodeTable, key: PIdObj): PNode =
proc idNodeTableGetLazy*(t: TIdNodeTable, key: PIdObj): PNode =
if not isNil(t.data):
result = IdNodeTableGet(t, key)
result = idNodeTableGet(t, key)
proc IdNodeTableRawInsert(data: var TIdNodePairSeq, key: PIdObj, val: PNode) =
proc idNodeTableRawInsert(data: var TIdNodePairSeq, key: PIdObj, val: PNode) =
var h: THash
h = key.id and high(data)
while data[h].key != nil:
@@ -785,25 +815,25 @@ proc IdNodeTableRawInsert(data: var TIdNodePairSeq, key: PIdObj, val: PNode) =
data[h].key = key
data[h].val = val
proc IdNodeTablePut(t: var TIdNodeTable, key: PIdObj, val: PNode) =
var index = IdNodeTableRawGet(t, key)
proc idNodeTablePut(t: var TIdNodeTable, key: PIdObj, val: PNode) =
var index = idNodeTableRawGet(t, key)
if index >= 0:
assert(t.data[index].key != nil)
t.data[index].val = val
else:
if mustRehash(len(t.data), t.counter):
var n: TIdNodePairSeq
newSeq(n, len(t.data) * growthFactor)
newSeq(n, len(t.data) * GrowthFactor)
for i in countup(0, high(t.data)):
if t.data[i].key != nil:
IdNodeTableRawInsert(n, t.data[i].key, t.data[i].val)
idNodeTableRawInsert(n, t.data[i].key, t.data[i].val)
swap(t.data, n)
IdNodeTableRawInsert(t.data, key, val)
idNodeTableRawInsert(t.data, key, val)
inc(t.counter)
proc IdNodeTablePutLazy*(t: var TIdNodeTable, key: PIdObj, val: PNode) =
proc idNodeTablePutLazy*(t: var TIdNodeTable, key: PIdObj, val: PNode) =
if isNil(t.data): initIdNodeTable(t)
IdNodeTablePut(t, key, val)
idNodeTablePut(t, key, val)
iterator pairs*(t: TIdNodeTable): tuple[key: PIdObj, val: PNode] =
for i in 0 .. high(t.data):
@@ -811,24 +841,23 @@ iterator pairs*(t: TIdNodeTable): tuple[key: PIdObj, val: PNode] =
proc initIITable(x: var TIITable) =
x.counter = 0
newSeq(x.data, startSize)
for i in countup(0, startSize - 1): x.data[i].key = InvalidKey
newSeq(x.data, StartSize)
for i in countup(0, StartSize - 1): x.data[i].key = InvalidKey
proc IITableRawGet(t: TIITable, key: int): int =
proc iiTableRawGet(t: TIITable, key: int): int =
var h: THash
h = key and high(t.data) # start with real hash value
while t.data[h].key != InvalidKey:
if (t.data[h].key == key):
return h
if t.data[h].key == key: return h
h = nextTry(h, high(t.data))
result = - 1
result = -1
proc IITableGet(t: TIITable, key: int): int =
var index = IITableRawGet(t, key)
proc iiTableGet(t: TIITable, key: int): int =
var index = iiTableRawGet(t, key)
if index >= 0: result = t.data[index].val
else: result = InvalidKey
proc IITableRawInsert(data: var TIIPairSeq, key, val: int) =
proc iiTableRawInsert(data: var TIIPairSeq, key, val: int) =
var h: THash
h = key and high(data)
while data[h].key != InvalidKey:
@@ -838,19 +867,19 @@ proc IITableRawInsert(data: var TIIPairSeq, key, val: int) =
data[h].key = key
data[h].val = val
proc IITablePut(t: var TIITable, key, val: int) =
var index = IITableRawGet(t, key)
proc iiTablePut(t: var TIITable, key, val: int) =
var index = iiTableRawGet(t, key)
if index >= 0:
assert(t.data[index].key != InvalidKey)
t.data[index].val = val
else:
if mustRehash(len(t.data), t.counter):
var n: TIIPairSeq
newSeq(n, len(t.data) * growthFactor)
newSeq(n, len(t.data) * GrowthFactor)
for i in countup(0, high(n)): n[i].key = InvalidKey
for i in countup(0, high(t.data)):
if t.data[i].key != InvalidKey:
IITableRawInsert(n, t.data[i].key, t.data[i].val)
iiTableRawInsert(n, t.data[i].key, t.data[i].val)
swap(t.data, n)
IITableRawInsert(t.data, key, val)
iiTableRawInsert(t.data, key, val)
inc(t.counter)

View File

@@ -13,7 +13,7 @@ import parseutils, strutils, strtabs, os, options, msgs, lists
proc addPath*(path: string, info: TLineInfo) =
if not contains(options.searchPaths, path):
lists.PrependStr(options.searchPaths, path)
lists.prependStr(options.searchPaths, path)
proc versionSplitPos(s: string): int =
result = s.len-2
@@ -45,9 +45,9 @@ proc `<.`(a, b: string): bool =
proc addPackage(packages: PStringTable, p: string) =
let x = versionSplitPos(p)
let name = p.subStr(0, x-1)
let name = p.substr(0, x-1)
if x < p.len:
let version = p.subStr(x+1)
let version = p.substr(x+1)
if packages[name] <. version:
packages[name] = version
else:
@@ -60,8 +60,8 @@ iterator chosen(packages: PStringTable): string =
proc addBabelPath(p: string, info: TLineInfo) =
if not contains(options.searchPaths, p):
if gVerbosity >= 1: Message(info, hintPath, p)
lists.PrependStr(options.lazyPaths, p)
if gVerbosity >= 1: message(info, hintPath, p)
lists.prependStr(options.lazyPaths, p)
proc addPathWithNimFiles(p: string, info: TLineInfo) =
proc hasNimFile(dir: string): bool =

View File

@@ -18,53 +18,53 @@ type
const
ElemSize* = sizeof(int8) * 8
proc BitSetInit*(b: var TBitSet, length: int)
proc BitSetUnion*(x: var TBitSet, y: TBitSet)
proc BitSetDiff*(x: var TBitSet, y: TBitSet)
proc BitSetSymDiff*(x: var TBitSet, y: TBitSet)
proc BitSetIntersect*(x: var TBitSet, y: TBitSet)
proc BitSetIncl*(x: var TBitSet, elem: BiggestInt)
proc BitSetExcl*(x: var TBitSet, elem: BiggestInt)
proc BitSetIn*(x: TBitSet, e: BiggestInt): bool
proc BitSetEquals*(x, y: TBitSet): bool
proc BitSetContains*(x, y: TBitSet): bool
proc bitSetInit*(b: var TBitSet, length: int)
proc bitSetUnion*(x: var TBitSet, y: TBitSet)
proc bitSetDiff*(x: var TBitSet, y: TBitSet)
proc bitSetSymDiff*(x: var TBitSet, y: TBitSet)
proc bitSetIntersect*(x: var TBitSet, y: TBitSet)
proc bitSetIncl*(x: var TBitSet, elem: BiggestInt)
proc bitSetExcl*(x: var TBitSet, elem: BiggestInt)
proc bitSetIn*(x: TBitSet, e: BiggestInt): bool
proc bitSetEquals*(x, y: TBitSet): bool
proc bitSetContains*(x, y: TBitSet): bool
# implementation
proc BitSetIn(x: TBitSet, e: BiggestInt): bool =
proc bitSetIn(x: TBitSet, e: BiggestInt): bool =
result = (x[int(e div ElemSize)] and toU8(int(1 shl (e mod ElemSize)))) !=
toU8(0)
proc BitSetIncl(x: var TBitSet, elem: BiggestInt) =
proc bitSetIncl(x: var TBitSet, elem: BiggestInt) =
assert(elem >= 0)
x[int(elem div ElemSize)] = x[int(elem div ElemSize)] or
toU8(int(1 shl (elem mod ElemSize)))
proc BitSetExcl(x: var TBitSet, elem: BiggestInt) =
proc bitSetExcl(x: var TBitSet, elem: BiggestInt) =
x[int(elem div ElemSize)] = x[int(elem div ElemSize)] and
not toU8(int(1 shl (elem mod ElemSize)))
proc BitSetInit(b: var TBitSet, length: int) =
proc bitSetInit(b: var TBitSet, length: int) =
newSeq(b, length)
proc BitSetUnion(x: var TBitSet, y: TBitSet) =
proc bitSetUnion(x: var TBitSet, y: TBitSet) =
for i in countup(0, high(x)): x[i] = x[i] or y[i]
proc BitSetDiff(x: var TBitSet, y: TBitSet) =
proc bitSetDiff(x: var TBitSet, y: TBitSet) =
for i in countup(0, high(x)): x[i] = x[i] and not y[i]
proc BitSetSymDiff(x: var TBitSet, y: TBitSet) =
proc bitSetSymDiff(x: var TBitSet, y: TBitSet) =
for i in countup(0, high(x)): x[i] = x[i] xor y[i]
proc BitSetIntersect(x: var TBitSet, y: TBitSet) =
proc bitSetIntersect(x: var TBitSet, y: TBitSet) =
for i in countup(0, high(x)): x[i] = x[i] and y[i]
proc BitSetEquals(x, y: TBitSet): bool =
proc bitSetEquals(x, y: TBitSet): bool =
for i in countup(0, high(x)):
if x[i] != y[i]:
return false
result = true
proc BitSetContains(x, y: TBitSet): bool =
proc bitSetContains(x, y: TBitSet): bool =
for i in countup(0, high(x)):
if (x[i] and not y[i]) != int8(0):
return false

View File

@@ -19,6 +19,7 @@ c2nim - C to Nimrod source converter
Usage: c2nim [options] inputfile [options]
Options:
-o, --out:FILE set output filename
--cpp process C++ input file
--dynlib:SYMBOL import from dynlib: SYMBOL will be used for the import
--header:HEADER_FILE import from a HEADER_FILE (discouraged!)
--cdecl annotate procs with ``{.cdecl.}``
@@ -31,25 +32,38 @@ Options:
--skipinclude do not convert ``#include`` to ``import``
--typeprefixes generate ``T`` and ``P`` type prefixes
--skipcomments do not copy comments
--ignoreRValueRefs translate C++'s ``T&&`` to ``T`` instead ``of var T``
--keepBodies keep C++'s method bodies
--spliceHeader parse and emit header before source file
-v, --version write c2nim's version
-h, --help show this help
"""
proc main(infile, outfile: string, options: PParserOptions) =
var start = getTime()
var stream = LLStreamOpen(infile, fmRead)
proc parse(infile: string, options: PParserOptions): PNode =
var stream = llStreamOpen(infile, fmRead)
if stream == nil: rawMessage(errCannotOpenFile, infile)
var p: TParser
openParser(p, infile, stream, options)
var module = parseUnit(p)
result = parseUnit(p)
closeParser(p)
renderModule(module, outfile)
proc main(infile, outfile: string, options: PParserOptions, spliceHeader: bool) =
var start = getTime()
if spliceHeader and infile.splitFile.ext == ".c" and existsFile(infile.changeFileExt(".h")):
var header_module = parse(infile.changeFileExt(".h"), options)
var source_module = parse(infile, options)
for n in source_module:
addson(header_module, n)
renderModule(header_module, outfile)
else:
renderModule(parse(infile, options), outfile)
rawMessage(hintSuccessX, [$gLinesCompiled, $(getTime() - start),
formatSize(getTotalMem())])
var
infile = ""
outfile = ""
spliceHeader = false
parserOptions = newParserOptions()
for kind, key, val in getopt():
case kind
@@ -63,6 +77,7 @@ for kind, key, val in getopt():
stdout.write(Version & "\n")
quit(0)
of "o", "out": outfile = val
of "spliceheader": spliceHeader = true
else:
if not parserOptions.setOption(key, val):
stdout.writeln("[Error] unknown option: " & key)
@@ -74,4 +89,4 @@ else:
if outfile.len == 0:
outfile = changeFileExt(infile, "nim")
infile = addFileExt(infile, "h")
main(infile, outfile, parserOptions)
main(infile, outfile, parserOptions, spliceHeader)

View File

@@ -82,6 +82,8 @@ type
pxParLe, pxBracketLe, pxCurlyLe, # this order is important
pxParRi, pxBracketRi, pxCurlyRi, # for macro argument parsing!
pxComma, pxSemiColon, pxColon,
pxAngleRi # '>' but determined to be the end of a
# template's angle bracket
TTokKinds* = set[TTokKind]
type
@@ -101,7 +103,7 @@ type
inDirective: bool
proc getTok*(L: var TLexer, tok: var TToken)
proc PrintTok*(tok: TToken)
proc printTok*(tok: TToken)
proc `$`*(tok: TToken): string
# implementation
@@ -136,7 +138,7 @@ proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
var info = newLineInfo(L.fileIdx, L.linenumber, pos - L.lineStart)
msgs.GlobalError(info, msg, arg)
proc TokKindToStr*(k: TTokKind): string =
proc tokKindToStr*(k: TTokKind): string =
case k
of pxEof: result = "[EOF]"
of pxInvalid: result = "[invalid]"
@@ -202,15 +204,16 @@ proc TokKindToStr*(k: TTokKind): string =
of pxColon: result = ":"
of pxCurlyLe: result = "{"
of pxCurlyRi: result = "}"
of pxAngleRi: result = "> [end of template]"
proc `$`(tok: TToken): string =
case tok.xkind
of pxSymbol, pxInvalid, pxStarComment, pxLineComment, pxStrLit: result = tok.s
of pxIntLit, pxInt64Lit: result = $tok.iNumber
of pxFloatLit: result = $tok.fNumber
else: result = TokKindToStr(tok.xkind)
else: result = tokKindToStr(tok.xkind)
proc PrintTok(tok: TToken) =
proc printTok(tok: TToken) =
writeln(stdout, $tok)
proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
@@ -220,12 +223,12 @@ proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
while true:
if buf[pos] in chars:
add(tok.s, buf[pos])
Inc(pos)
inc(pos)
else:
break
if buf[pos] == '_':
add(tok.s, '_')
Inc(pos)
inc(pos)
L.bufPos = pos
proc isFloatLiteral(s: string): bool =
@@ -236,7 +239,7 @@ proc isFloatLiteral(s: string): bool =
proc getNumber2(L: var TLexer, tok: var TToken) =
var pos = L.bufpos + 2 # skip 0b
tok.base = base2
var xi: biggestInt = 0
var xi: BiggestInt = 0
var bits = 0
while true:
case L.buf[pos]
@@ -261,7 +264,7 @@ proc getNumber2(L: var TLexer, tok: var TToken) =
proc getNumber8(L: var TLexer, tok: var TToken) =
var pos = L.bufpos + 1 # skip 0
tok.base = base8
var xi: biggestInt = 0
var xi: BiggestInt = 0
var bits = 0
while true:
case L.buf[pos]
@@ -286,7 +289,7 @@ proc getNumber8(L: var TLexer, tok: var TToken) =
proc getNumber16(L: var TLexer, tok: var TToken) =
var pos = L.bufpos + 2 # skip 0x
tok.base = base16
var xi: biggestInt = 0
var xi: BiggestInt = 0
var bits = 0
while true:
case L.buf[pos]
@@ -312,19 +315,34 @@ proc getNumber16(L: var TLexer, tok: var TToken) =
else: tok.xkind = pxIntLit
L.bufpos = pos
proc getFloating(L: var TLexer, tok: var TToken) =
matchUnderscoreChars(L, tok, {'0'..'9'})
if L.buf[L.bufpos] in {'e', 'E'}:
add(tok.s, L.buf[L.bufpos])
inc(L.bufpos)
if L.buf[L.bufpos] in {'+', '-'}:
add(tok.s, L.buf[L.bufpos])
inc(L.bufpos)
matchUnderscoreChars(L, tok, {'0'..'9'})
proc getNumber(L: var TLexer, tok: var TToken) =
tok.base = base10
matchUnderscoreChars(L, tok, {'0'..'9'})
if (L.buf[L.bufpos] == '.') and (L.buf[L.bufpos + 1] in {'0'..'9'}):
add(tok.s, '.')
if L.buf[L.bufpos] == '.':
add(tok.s, "0.")
inc(L.bufpos)
matchUnderscoreChars(L, tok, {'e', 'E', '+', '-', '0'..'9'})
getFloating(L, tok)
else:
matchUnderscoreChars(L, tok, {'0'..'9'})
if L.buf[L.bufpos] == '.':
add(tok.s, '.')
inc(L.bufpos)
getFloating(L, tok)
try:
if isFloatLiteral(tok.s):
tok.fnumber = parseFloat(tok.s)
tok.xkind = pxFloatLit
else:
tok.iNumber = ParseInt(tok.s)
tok.iNumber = parseInt(tok.s)
if (tok.iNumber < low(int32)) or (tok.iNumber > high(int32)):
tok.xkind = pxInt64Lit
else:
@@ -336,10 +354,10 @@ proc getNumber(L: var TLexer, tok: var TToken) =
# ignore type suffix:
while L.buf[L.bufpos] in {'A'..'Z', 'a'..'z'}: inc(L.bufpos)
proc HandleCRLF(L: var TLexer, pos: int): int =
proc handleCRLF(L: var TLexer, pos: int): int =
case L.buf[pos]
of CR: result = nimlexbase.HandleCR(L, pos)
of LF: result = nimlexbase.HandleLF(L, pos)
of CR: result = nimlexbase.handleCR(L, pos)
of LF: result = nimlexbase.handleLF(L, pos)
else: result = pos
proc escape(L: var TLexer, tok: var TToken, allowEmpty=false) =
@@ -379,6 +397,23 @@ proc escape(L: var TLexer, tok: var TToken, allowEmpty=false) =
xi = (xi shl 3) or (ord(L.buf[L.bufpos]) - ord('0'))
inc(L.bufpos)
add(tok.s, chr(xi))
of 'x':
var xi = 0
inc(L.bufpos)
while true:
case L.buf[L.bufpos]
of '0'..'9':
xi = `shl`(xi, 4) or (ord(L.buf[L.bufpos]) - ord('0'))
inc(L.bufpos)
of 'a'..'f':
xi = `shl`(xi, 4) or (ord(L.buf[L.bufpos]) - ord('a') + 10)
inc(L.bufpos)
of 'A'..'F':
xi = `shl`(xi, 4) or (ord(L.buf[L.bufpos]) - ord('A') + 10)
inc(L.bufpos)
else:
break
add(tok.s, chr(xi))
elif not allowEmpty:
lexMessage(L, errInvalidCharacterConstant)
@@ -402,7 +437,7 @@ proc getString(L: var TLexer, tok: var TToken) =
while true:
case buf[pos]
of '\"':
Inc(pos)
inc(pos)
break
of CR:
pos = nimlexbase.HandleCR(L, pos)
@@ -424,7 +459,7 @@ proc getString(L: var TLexer, tok: var TToken) =
pos = L.bufpos
else:
add(tok.s, buf[pos])
Inc(pos)
inc(pos)
L.bufpos = pos
tok.xkind = pxStrLit
@@ -435,7 +470,7 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
var c = buf[pos]
if c notin SymChars: break
add(tok.s, c)
Inc(pos)
inc(pos)
L.bufpos = pos
tok.xkind = pxSymbol
@@ -472,7 +507,7 @@ proc scanStarComment(L: var TLexer, tok: var TToken) =
while true:
case buf[pos]
of CR, LF:
pos = HandleCRLF(L, pos)
pos = handleCRLF(L, pos)
buf = L.buf
add(tok.s, "\n#")
# skip annoying stars as line prefix: (eg.
@@ -508,12 +543,12 @@ proc skip(L: var TLexer, tok: var TToken) =
if L.inDirective:
while buf[pos] in {' ', '\t'}: inc(pos)
if buf[pos] in {CR, LF}:
pos = HandleCRLF(L, pos)
pos = handleCRLF(L, pos)
buf = L.buf
of ' ', Tabulator:
Inc(pos) # newline is special:
inc(pos) # newline is special:
of CR, LF:
pos = HandleCRLF(L, pos)
pos = handleCRLF(L, pos)
buf = L.buf
if L.inDirective:
tok.xkind = pxNewLine
@@ -556,13 +591,13 @@ proc getTok(L: var TLexer, tok: var TToken) =
of 'b', 'B': getNumber2(L, tok)
of '1'..'7': getNumber8(L, tok)
else: getNumber(L, tok)
elif c in {'1'..'9'}:
elif c in {'1'..'9'} or (c == '.' and L.buf[L.bufpos+1] in {'0'..'9'}):
getNumber(L, tok)
else:
case c
of ';':
tok.xkind = pxSemicolon
Inc(L.bufpos)
inc(L.bufpos)
of '/':
if L.buf[L.bufpos + 1] == '/':
scanLineComment(L, tok)
@@ -577,9 +612,9 @@ proc getTok(L: var TLexer, tok: var TToken) =
inc(L.bufpos)
of ',':
tok.xkind = pxComma
Inc(L.bufpos)
inc(L.bufpos)
of '(':
Inc(L.bufpos)
inc(L.bufpos)
tok.xkind = pxParLe
of '*':
inc(L.bufpos)
@@ -589,13 +624,13 @@ proc getTok(L: var TLexer, tok: var TToken) =
else:
tok.xkind = pxStar
of ')':
Inc(L.bufpos)
inc(L.bufpos)
tok.xkind = pxParRi
of '[':
Inc(L.bufpos)
inc(L.bufpos)
tok.xkind = pxBracketLe
of ']':
Inc(L.bufpos)
inc(L.bufpos)
tok.xkind = pxBracketRi
of '.':
inc(L.bufpos)
@@ -605,10 +640,10 @@ proc getTok(L: var TLexer, tok: var TToken) =
else:
tok.xkind = pxDot
of '{':
Inc(L.bufpos)
inc(L.bufpos)
tok.xkind = pxCurlyLe
of '}':
Inc(L.bufpos)
inc(L.bufpos)
tok.xkind = pxCurlyRi
of '+':
inc(L.bufpos)
@@ -749,4 +784,4 @@ proc getTok(L: var TLexer, tok: var TToken) =
tok.s = $c
tok.xkind = pxInvalid
lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
Inc(L.bufpos)
inc(L.bufpos)

File diff suppressed because it is too large Load Diff

View File

@@ -26,7 +26,7 @@ proc skipLine(p: var TParser) =
proc parseDefineBody(p: var TParser, tmplDef: PNode): string =
if p.tok.xkind == pxCurlyLe or
(p.tok.xkind == pxSymbol and (
declKeyword(p.tok.s) or stmtKeyword(p.tok.s))):
declKeyword(p, p.tok.s) or stmtKeyword(p.tok.s))):
addSon(tmplDef, statement(p))
result = "stmt"
elif p.tok.xkind in {pxLineComment, pxNewLine}:
@@ -103,7 +103,7 @@ proc parseDefBody(p: var TParser, m: var TMacro, params: seq[string]) =
m.body.add(tok)
of pxDirConc:
# just ignore this token: this implements token merging correctly
nil
discard
else:
m.body.add(p.tok)
# we do not want macro expansion here:
@@ -166,7 +166,7 @@ proc parseStmtList(p: var TParser): PNode =
of pxDirectiveParLe, pxDirective:
case p.tok.s
of "else", "endif", "elif": break
else: nil
else: discard
addSon(result, statement(p))
proc eatEndif(p: var TParser) =
@@ -226,7 +226,7 @@ proc skipUntilElifElseEndif(p: var TParser): TEndifMarker =
proc parseIfdef(p: var TParser): PNode =
getTok(p) # skip #ifdef
ExpectIdent(p)
expectIdent(p)
case p.tok.s
of "__cplusplus":
skipUntilEndif(p)
@@ -245,7 +245,7 @@ proc parseIfdef(p: var TParser): PNode =
proc parseIfndef(p: var TParser): PNode =
result = ast.emptyNode
getTok(p) # skip #ifndef
ExpectIdent(p)
expectIdent(p)
if p.tok.s == c2nimSymbol:
skipLine(p)
case skipUntilElifElseEndif(p)
@@ -282,11 +282,11 @@ proc parseIfDir(p: var TParser): PNode =
proc parsePegLit(p: var TParser): TPeg =
var col = getColumn(p.lex) + 2
getTok(p)
if p.tok.xkind != pxStrLit: ExpectIdent(p)
if p.tok.xkind != pxStrLit: expectIdent(p)
try:
result = parsePeg(
pattern = if p.tok.xkind == pxStrLit: p.tok.s else: escapePeg(p.tok.s),
filename = p.lex.fileIdx.ToFilename,
filename = p.lex.fileIdx.toFilename,
line = p.lex.linenumber,
col = col)
getTok(p)
@@ -295,7 +295,7 @@ proc parsePegLit(p: var TParser): TPeg =
proc parseMangleDir(p: var TParser) =
var pattern = parsePegLit(p)
if p.tok.xkind != pxStrLit: ExpectIdent(p)
if p.tok.xkind != pxStrLit: expectIdent(p)
p.options.mangleRules.add((pattern, p.tok.s))
getTok(p)
eatNewLine(p, nil)
@@ -323,10 +323,10 @@ proc parseDir(p: var TParser): PNode =
discard setOption(p.options, p.tok.s)
getTok(p)
eatNewLine(p, nil)
of "dynlib", "header", "prefix", "suffix":
of "dynlib", "header", "prefix", "suffix", "class":
var key = p.tok.s
getTok(p)
if p.tok.xkind != pxStrLit: ExpectIdent(p)
if p.tok.xkind != pxStrLit: expectIdent(p)
discard setOption(p.options, key, p.tok.s)
getTok(p)
eatNewLine(p, nil)

View File

@@ -0,0 +1,240 @@
/////////////////////////////////////////////////////////////////////////////
// Name: wx/matrix.h
// Purpose: wxTransformMatrix class. NOT YET USED
// Author: Chris Breeze, Julian Smart
// Modified by: Klaas Holwerda
// Created: 01/02/97
// RCS-ID: $Id$
// Copyright: (c) Julian Smart, Chris Breeze
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#ifndef _WX_MATRIXH__
#define _WX_MATRIXH__
//! headerfiles="matrix.h wx/object.h"
#include "wx/object.h"
#include "wx/math.h"
//! codefiles="matrix.cpp"
// A simple 3x3 matrix. This may be replaced by a more general matrix
// class some day.
//
// Note: this is intended to be used in wxDC at some point to replace
// the current system of scaling/translation. It is not yet used.
#def WXDLLIMPEXP_CORE
#header "wxmatrix.h"
//:definition
// A 3x3 matrix to do 2D transformations.
// It can be used to map data to window coordinates,
// and also for manipulating your own data.
// For example drawing a picture (composed of several primitives)
// at a certain coordinate and angle within another parent picture.
// At all times m_isIdentity is set if the matrix itself is an Identity matrix.
// It is used where possible to optimize calculations.
class WXDLLIMPEXP_CORE wxTransformMatrix: public wxObject<string, string<ubyte>>
{
public:
wxTransformMatrix(void);
wxTransformMatrix(const wxTransformMatrix& mat);
~wxTransformMatrix(void);
//get the value in the matrix at col,row
//rows are horizontal (second index of m_matrix member)
//columns are vertical (first index of m_matrix member)
double GetValue(int col, int row) const;
//set the value in the matrix at col,row
//rows are horizontal (second index of m_matrix member)
//columns are vertical (first index of m_matrix member)
void SetValue(int col, int row, double value);
void operator = (const wxTransformMatrix& mat);
bool operator == (const wxTransformMatrix& mat) const;
bool operator != (const module::gah::wxTransformMatrix& mat) const;
//multiply every element by t
wxTransformMatrix& operator*=(const double& t);
//divide every element by t
wxTransformMatrix& operator/=(const double& t);
//add matrix m to this t
wxTransformMatrix& operator+=(const wxTransformMatrix& m);
//subtract matrix m from this
wxTransformMatrix& operator-=(const wxTransformMatrix& m);
//multiply matrix m with this
wxTransformMatrix& operator*=(const wxTransformMatrix& m);
// constant operators
//multiply every element by t and return result
wxTransformMatrix operator*(const double& t) const;
//divide this matrix by t and return result
wxTransformMatrix operator/(const double& t) const;
//add matrix m to this and return result
wxTransformMatrix operator+(const wxTransformMatrix& m) const;
//subtract matrix m from this and return result
wxTransformMatrix operator-(const wxTransformMatrix& m) const;
//multiply this by matrix m and return result
wxTransformMatrix operator*(const wxTransformMatrix& m) const;
wxTransformMatrix operator-() const;
//rows are horizontal (second index of m_matrix member)
//columns are vertical (first index of m_matrix member)
double& operator()(int col, int row);
//rows are horizontal (second index of m_matrix member)
//columns are vertical (first index of m_matrix member)
double operator()(int col, int row) const;
// Invert matrix
bool Invert(void);
// Make into identity matrix
bool Identity(void);
// Is the matrix the identity matrix?
// Only returns a flag, which is set whenever an operation
// is done.
inline bool IsIdentity(void) const { return m_isIdentity; }
// This does an actual check.
inline bool IsIdentity1(void) const ;
//Scale by scale (isotropic scaling i.e. the same in x and y):
//!ex:
//!code: | scale 0 0 |
//!code: matrix' = | 0 scale 0 | x matrix
//!code: | 0 0 scale |
bool Scale(double scale);
//Scale with center point and x/y scale
//
//!ex:
//!code: | xs 0 xc(1-xs) |
//!code: matrix' = | 0 ys yc(1-ys) | x matrix
//!code: | 0 0 1 |
wxTransformMatrix& Scale(const double &xs, const double &ys,const double &xc, const double &yc);
// mirror a matrix in x, y
//!ex:
//!code: | -1 0 0 |
//!code: matrix' = | 0 -1 0 | x matrix
//!code: | 0 0 1 |
wxTransformMatrix<float>& Mirror(bool x=true, bool y=false);
// Translate by dx, dy:
//!ex:
//!code: | 1 0 dx |
//!code: matrix' = | 0 1 dy | x matrix
//!code: | 0 0 1 |
bool Translate(double x, double y);
// Rotate clockwise by the given number of degrees:
//!ex:
//!code: | cos sin 0 |
//!code: matrix' = | -sin cos 0 | x matrix
//!code: | 0 0 1 |
bool Rotate(double angle);
//Rotate counter clockwise with point of rotation
//
//!ex:
//!code: | cos(r) -sin(r) x(1-cos(r))+y(sin(r)|
//!code: matrix' = | sin(r) cos(r) y(1-cos(r))-x(sin(r)| x matrix
//!code: | 0 0 1 |
wxTransformMatrix& Rotate(const double &r, const double &x, const double &y);
// Transform X value from logical to device
inline double TransformX(double x) const;
// Transform Y value from logical to device
inline double TransformY(double y) const;
// Transform a point from logical to device coordinates
bool TransformPoint(double x, double y, double& tx, double& ty) const;
// Transform a point from device to logical coordinates.
// Example of use:
// wxTransformMatrix mat = dc.GetTransformation();
// mat.Invert();
// mat.InverseTransformPoint(x, y, x1, y1);
// OR (shorthand:)
// dc.LogicalToDevice(x, y, x1, y1);
// The latter is slightly less efficient if we're doing several
// conversions, since the matrix is inverted several times.
// N.B. 'this' matrix is the inverse at this point
bool InverseTransformPoint(double x, double y, double& tx, double& ty) const;
double Get_scaleX();
double Get_scaleY();
double GetRotation();
void SetRotation(double rotation);
public:
double m_matrix[3][3];
bool m_isIdentity;
};
/*
Chris Breeze reported, that
some functions of wxTransformMatrix cannot work because it is not
known if he matrix has been inverted. Be careful when using it.
*/
// Transform X value from logical to device
// warning: this function can only be used for this purpose
// because no rotation is involved when mapping logical to device coordinates
// mirror and scaling for x and y will be part of the matrix
// if you have a matrix that is rotated, eg a shape containing a matrix to place
// it in the logical coordinate system, use TransformPoint
inline double wxTransformMatrix::TransformX(double x) const
{
//normally like this, but since no rotation is involved (only mirror and scale)
//we can do without Y -> m_matrix[1]{0] is -sin(rotation angle) and therefore zero
//(x * m_matrix[0][0] + y * m_matrix[1][0] + m_matrix[2][0]))
return (m_isIdentity ? x : (x * m_matrix[0][0] + m_matrix[2][0]));
}
// Transform Y value from logical to device
// warning: this function can only be used for this purpose
// because no rotation is involved when mapping logical to device coordinates
// mirror and scaling for x and y will be part of the matrix
// if you have a matrix that is rotated, eg a shape containing a matrix to place
// it in the logical coordinate system, use TransformPoint
inline double wxTransformMatrix::TransformY(double y) const
{
//normally like this, but since no rotation is involved (only mirror and scale)
//we can do without X -> m_matrix[0]{1] is sin(rotation angle) and therefore zero
//(x * m_matrix[0][1] + y * m_matrix[1][1] + m_matrix[2][1]))
return (m_isIdentity ? y : (y * m_matrix[1][1] + m_matrix[2][1]));
}
// Is the matrix the identity matrix?
// Each operation checks whether the result is still the identity matrix and sets a flag.
inline bool wxTransformMatrix::IsIdentity1(void) const
{
return
( wxIsSameDouble(m_matrix[0][0], 1.0) &&
wxIsSameDouble(m_matrix[1][1], 1.0) &&
wxIsSameDouble(m_matrix[2][2], 1.0) &&
wxIsSameDouble(m_matrix[1][0], 0.0) &&
wxIsSameDouble(m_matrix[2][0], 0.0) &&
wxIsSameDouble(m_matrix[0][1], 0.0) &&
wxIsSameDouble(m_matrix[2][1], 0.0) &&
wxIsSameDouble(m_matrix[0][2], 0.0) &&
wxIsSameDouble(m_matrix[1][2], 0.0) );
}
// Calculates the determinant of a 2 x 2 matrix
inline double wxCalculateDet(double a11, double a21, double a12, double a22)
{
return a11 * a22 - a12 * a21;
}
#endif // _WX_MATRIXH__

View File

@@ -0,0 +1,33 @@
#include <stdlib.h>
#include <stdio.h>
int rand(void);
int id2(void) {
return (int *)1;
}
int id(void (*f)(void)) {
f();
((void (*)(int))f)(10);
return 10;
return (20+1);
return (int *)id;
}
int main() {
float f = .2,
g = 2.,
h = 1.0+rand(),
i = 1.0e+3;
int j, a;
for(j = 0, a = 10; j < 0; j++, a++) ;
do {
printf("howdy");
} while(--i, 0);
if(1)
printf("1"); // error from this comment
else
printf("2");
return '\x00';
}

View File

@@ -0,0 +1,3 @@
struct foo {
int x,y,z;
};

416
compiler/canonicalizer.nim Normal file
View File

@@ -0,0 +1,416 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements the canonalization for the various caching mechanisms.
import strutils, db_sqlite, md5
var db: TDbConn
# We *hash* the relevant information into 128 bit hashes. This should be good
# enough to prevent any collisions.
type
TUid = distinct MD5Digest
# For name mangling we encode these hashes via a variant of base64 (called
# 'base64a') and prepend the *primary* identifier to ease the debugging pain.
# So a signature like:
#
# proc gABI(c: PCtx; n: PNode; opc: TOpcode; a, b: TRegister; imm: BiggestInt)
#
# is mangled into:
# gABI_MTdmOWY5MTQ1MDcyNGQ3ZA
#
# This is a good compromise between correctness and brevity. ;-)
const
cb64 = [
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
"O", "P", "Q", "R", "S", "T" "U", "V", "W", "X", "Y", "Z",
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n",
"o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"_A", "_B"]
proc toBase64a(s: cstring, len: int): string =
## encodes `s` into base64 representation. After `lineLen` characters, a
## `newline` is added.
result = newStringOfCap(((len + 2) div 3) * 4)
var i = 0
while i < s.len - 2:
let a = ord(s[i])
let b = ord(s[i+1])
let c = ord(s[i+2])
result.add cb64[a shr 2]
result.add cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
result.add cb64[((b and 0x0F) shl 2) or ((c and 0xC0) shr 6)]
result.add cb64[c and 0x3F]
inc(i, 3)
if i < s.len-1:
let a = ord(s[i])
let b = ord(s[i+1])
result.add cb64[a shr 2]
result.add cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
result.add cb64[((b and 0x0F) shl 2)]
elif i < s.len:
let a = ord(s[i])
result.add cb64[a shr 2]
result.add cb64[(a and 3) shl 4]
proc toBase64a(u: TUid): string = toBase64a(cast[cstring](u), sizeof(u))
proc `&=`(c: var MD5Context, s: string) = md5Update(c, s, s.len)
proc hashSym(c: var MD5Context, s: PSym) =
if sfAnon in s.flags or s.kind == skGenericParam:
c &= ":anon"
else:
var it = s.owner
while it != nil:
hashSym(c, it)
c &= "."
it = s.owner
c &= s.name.s
proc hashTree(c: var MD5Context, n: PNode) =
if n == nil:
c &= "\255"
return
var k = n.kind
md5Update(c, cast[cstring](addr(k)), 1)
# we really must not hash line information. 'n.typ' is debatable but
# shouldn't be necessary for now and avoids potential infinite recursions.
case n.kind
of nkEmpty, nkNilLit, nkType: discard
of nkIdent:
c &= n.ident.s
of nkSym:
hashSym(c, n.sym)
of nkCharLit..nkUInt64Lit:
var v = n.intVal
md5Update(c, cast[cstring](addr(v)), sizeof(v))
of nkFloatLit..nkFloat64Lit:
var v = n.floatVal
md5Update(c, cast[cstring](addr(v)), sizeof(v))
of nkStrLit..nkTripleStrLit:
c &= n.strVal
else:
for i in 0.. <n.len: hashTree(c, n.sons[i])
proc hashType(c: var MD5Context, t: PType) =
# modelled after 'typeToString'
if t == nil:
c &= "\254"
return
var k = t.kind
md5Update(c, cast[cstring](addr(k)), 1)
if t.sym != nil and sfAnon notin t.sym.flags:
# t.n for literals, but not for e.g. objects!
if t.kind in {tyFloat, tyInt}: c.hashNode(t.n)
c.hashSym(t.sym)
case t.kind
of tyGenericBody, tyGenericInst, tyGenericInvokation:
for i in countup(0, sonsLen(t) -1 -ord(t.kind != tyGenericInvokation)):
c.hashType t.sons[i]
of tyUserTypeClass:
internalAssert t.sym != nil and t.sym.owner != nil
c &= t.sym.owner.name.s
of tyUserTypeClassInst:
let body = t.base
c.hashSym body.sym
for i in countup(1, sonsLen(t) - 2):
c.hashType t.sons[i]
of tyFromExpr, tyFieldAccessor:
c.hashTree(t.n)
of tyArrayConstr:
c.hashTree(t.sons[0].n)
c.hashType(t.sons[1])
of tyTuple:
if t.n != nil:
assert(sonsLen(t.n) == sonsLen(t))
for i in countup(0, sonsLen(t.n) - 1):
assert(t.n.sons[i].kind == nkSym)
c &= t.n.sons[i].sym.name.s
c &= ":"
c.hashType(t.sons[i])
c &= ","
else:
for i in countup(0, sonsLen(t) - 1): c.hashType t.sons[i]
of tyRange:
c.hashTree(t.n)
c.hashType(t.sons[0])
of tyProc:
c &= (if tfIterator in t.flags: "iterator " else: "proc ")
for i in 0.. <t.len: c.hashType(t.sons[i])
md5Update(c, cast[cstring](addr(t.callConv)), 1)
if tfNoSideEffect in t.flags: c &= ".noSideEffect"
if tfThread in t.flags: c &= ".thread"
else:
for i in 0.. <t.len: c.hashType(t.sons[i])
if tfShared in t.flags: c &= "shared"
if tfNotNil in t.flags: c &= "not nil"
proc canonConst(n: PNode): TUid =
var c: MD5Context
md5Init(c)
c.hashTree(n)
c.hashType(n.typ)
md5Final(c, MD5Digest(result))
proc canonSym(s: PSym): TUid =
var c: MD5Context
md5Init(c)
c.hashSym(s)
md5Final(c, MD5Digest(result))
proc pushType(w: PRodWriter, t: PType) =
# check so that the stack does not grow too large:
if iiTableGet(w.index.tab, t.id) == InvalidKey:
w.tstack.add(t)
proc pushSym(w: PRodWriter, s: PSym) =
# check so that the stack does not grow too large:
if iiTableGet(w.index.tab, s.id) == InvalidKey:
w.sstack.add(s)
proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
result: var string) =
if n == nil:
# nil nodes have to be stored too:
result.add("()")
return
result.add('(')
encodeVInt(ord(n.kind), result)
# we do not write comments for now
# Line information takes easily 20% or more of the filesize! Therefore we
# omit line information if it is the same as the father's line information:
if fInfo.fileIndex != n.info.fileIndex:
result.add('?')
encodeVInt(n.info.col, result)
result.add(',')
encodeVInt(n.info.line, result)
result.add(',')
encodeVInt(fileIdx(w, toFilename(n.info)), result)
elif fInfo.line != n.info.line:
result.add('?')
encodeVInt(n.info.col, result)
result.add(',')
encodeVInt(n.info.line, result)
elif fInfo.col != n.info.col:
result.add('?')
encodeVInt(n.info.col, result)
var f = n.flags * PersistentNodeFlags
if f != {}:
result.add('$')
encodeVInt(cast[int32](f), result)
if n.typ != nil:
result.add('^')
encodeVInt(n.typ.id, result)
pushType(w, n.typ)
case n.kind
of nkCharLit..nkInt64Lit:
if n.intVal != 0:
result.add('!')
encodeVBiggestInt(n.intVal, result)
of nkFloatLit..nkFloat64Lit:
if n.floatVal != 0.0:
result.add('!')
encodeStr($n.floatVal, result)
of nkStrLit..nkTripleStrLit:
if n.strVal != "":
result.add('!')
encodeStr(n.strVal, result)
of nkIdent:
result.add('!')
encodeStr(n.ident.s, result)
of nkSym:
result.add('!')
encodeVInt(n.sym.id, result)
pushSym(w, n.sym)
else:
for i in countup(0, sonsLen(n) - 1):
encodeNode(w, n.info, n.sons[i], result)
add(result, ')')
proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
var oldLen = result.len
result.add('<')
if loc.k != low(loc.k): encodeVInt(ord(loc.k), result)
if loc.s != low(loc.s):
add(result, '*')
encodeVInt(ord(loc.s), result)
if loc.flags != {}:
add(result, '$')
encodeVInt(cast[int32](loc.flags), result)
if loc.t != nil:
add(result, '^')
encodeVInt(cast[int32](loc.t.id), result)
pushType(w, loc.t)
if loc.r != nil:
add(result, '!')
encodeStr(ropeToStr(loc.r), result)
if loc.a != 0:
add(result, '?')
encodeVInt(loc.a, result)
if oldLen + 1 == result.len:
# no data was necessary, so remove the '<' again:
setLen(result, oldLen)
else:
add(result, '>')
proc encodeType(w: PRodWriter, t: PType, result: var string) =
if t == nil:
# nil nodes have to be stored too:
result.add("[]")
return
# we need no surrounding [] here because the type is in a line of its own
if t.kind == tyForward: internalError("encodeType: tyForward")
# for the new rodfile viewer we use a preceeding [ so that the data section
# can easily be disambiguated:
add(result, '[')
encodeVInt(ord(t.kind), result)
add(result, '+')
encodeVInt(t.id, result)
if t.n != nil:
encodeNode(w, unknownLineInfo(), t.n, result)
if t.flags != {}:
add(result, '$')
encodeVInt(cast[int32](t.flags), result)
if t.callConv != low(t.callConv):
add(result, '?')
encodeVInt(ord(t.callConv), result)
if t.owner != nil:
add(result, '*')
encodeVInt(t.owner.id, result)
pushSym(w, t.owner)
if t.sym != nil:
add(result, '&')
encodeVInt(t.sym.id, result)
pushSym(w, t.sym)
if t.size != - 1:
add(result, '/')
encodeVBiggestInt(t.size, result)
if t.align != 2:
add(result, '=')
encodeVInt(t.align, result)
encodeLoc(w, t.loc, result)
for i in countup(0, sonsLen(t) - 1):
if t.sons[i] == nil:
add(result, "^()")
else:
add(result, '^')
encodeVInt(t.sons[i].id, result)
pushType(w, t.sons[i])
proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) =
add(result, '|')
encodeVInt(ord(lib.kind), result)
add(result, '|')
encodeStr(ropeToStr(lib.name), result)
add(result, '|')
encodeNode(w, info, lib.path, result)
proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
if s == nil:
# nil nodes have to be stored too:
result.add("{}")
return
# we need no surrounding {} here because the symbol is in a line of its own
encodeVInt(ord(s.kind), result)
result.add('+')
encodeVInt(s.id, result)
result.add('&')
encodeStr(s.name.s, result)
if s.typ != nil:
result.add('^')
encodeVInt(s.typ.id, result)
pushType(w, s.typ)
result.add('?')
if s.info.col != -1'i16: encodeVInt(s.info.col, result)
result.add(',')
if s.info.line != -1'i16: encodeVInt(s.info.line, result)
result.add(',')
encodeVInt(fileIdx(w, toFilename(s.info)), result)
if s.owner != nil:
result.add('*')
encodeVInt(s.owner.id, result)
pushSym(w, s.owner)
if s.flags != {}:
result.add('$')
encodeVInt(cast[int32](s.flags), result)
if s.magic != mNone:
result.add('@')
encodeVInt(ord(s.magic), result)
if s.options != w.options:
result.add('!')
encodeVInt(cast[int32](s.options), result)
if s.position != 0:
result.add('%')
encodeVInt(s.position, result)
if s.offset != - 1:
result.add('`')
encodeVInt(s.offset, result)
encodeLoc(w, s.loc, result)
if s.annex != nil: encodeLib(w, s.annex, s.info, result)
if s.constraint != nil:
add(result, '#')
encodeNode(w, unknownLineInfo(), s.constraint, result)
# lazy loading will soon reload the ast lazily, so the ast needs to be
# the last entry of a symbol:
if s.ast != nil:
# we used to attempt to save space here by only storing a dummy AST if
# it is not necessary, but Nimrod's heavy compile-time evaluation features
# make that unfeasible nowadays:
encodeNode(w, s.info, s.ast, result)
proc createDb() =
db.exec(sql"""
create table if not exists Module(
id integer primary key,
name varchar(256) not null,
fullpath varchar(256) not null,
interfHash varchar(256) not null,
fullHash varchar(256) not null,
created timestamp not null default (DATETIME('now')),
);""")
db.exec(sql"""
create table if not exists Symbol(
id integer primary key,
module integer not null,
name varchar(max) not null,
data varchar(max) not null,
created timestamp not null default (DATETIME('now')),
foreign key (module) references module(id)
);""")
db.exec(sql"""
create table if not exists Type(
id integer primary key,
module integer not null,
name varchar(max) not null,
data varchar(max) not null,
created timestamp not null default (DATETIME('now')),
foreign key (module) references module(id)
);""")
#db.exec(sql"""
# --create unique index if not exists TsstNameIx on TestResult(name);
# """, [])

View File

@@ -73,7 +73,7 @@ proc isInCurrentFrame(p: BProc, n: PNode): bool =
result = false
of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
result = isInCurrentFrame(p, n.sons[0])
else: nil
else: discard
proc openArrayLoc(p: BProc, n: PNode): PRope =
var a: TLoc
@@ -88,7 +88,7 @@ proc openArrayLoc(p: BProc, n: PNode): PRope =
result = ropef("$1->data, $1->$2", [a.rdLoc, lenField()])
of tyArray, tyArrayConstr:
result = ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))])
else: InternalError("openArrayLoc: " & typeToString(a.t))
else: internalError("openArrayLoc: " & typeToString(a.t))
proc genArgStringToCString(p: BProc,
n: PNode): PRope {.inline.} =
@@ -146,7 +146,8 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
proc addComma(r: PRope): PRope =
result = if r == nil: r else: con(r, ~", ")
const CallPattern = "$1.ClEnv? $1.ClPrc($3$1.ClEnv) : (($4)($1.ClPrc))($2)"
const PatProc = "$1.ClEnv? $1.ClPrc($3$1.ClEnv):(($4)($1.ClPrc))($2)"
const PatIter = "$1.ClPrc($3$1.ClEnv)" # we know the env exists
var op: TLoc
initLocExpr(p, ri.sons[0], op)
var pl: PRope
@@ -164,9 +165,10 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
if i < length - 1: app(pl, ~", ")
template genCallPattern {.dirty.} =
lineF(p, cpsStmts, CallPattern & ";$n", op.r, pl, pl.addComma, rawProc)
lineF(p, cpsStmts, callPattern & ";$n", op.r, pl, pl.addComma, rawProc)
let rawProc = getRawProcType(p, typ)
let callPattern = if tfIterator in typ.flags: PatIter else: PatProc
if typ.sons[0] != nil:
if isInvalidReturnType(typ.sons[0]):
if sonsLen(ri) > 1: app(pl, ~", ")
@@ -190,7 +192,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
assert(d.t != nil) # generate an assignment to d:
var list: TLoc
initLoc(list, locCall, d.t, OnUnknown)
list.r = ropef(CallPattern, op.r, pl, pl.addComma, rawProc)
list.r = ropef(callPattern, op.r, pl, pl.addComma, rawProc)
genAssignment(p, d, list, {}) # no need for deep copying
else:
genCallPattern()
@@ -243,7 +245,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
for i in countup(3, length-1):
assert(sonsLen(typ) == sonsLen(typ.n))
if i >= sonsLen(typ):
InternalError(ri.info, "varargs for objective C method?")
internalError(ri.info, "varargs for objective C method?")
assert(typ.n.sons[i].kind == nkSym)
var param = typ.n.sons[i].sym
app(pl, ~" ")
@@ -290,6 +292,7 @@ proc genCall(p: BProc, e: PNode, d: var TLoc) =
genNamedParamCall(p, e, d)
else:
genPrefixCall(p, nil, e, d)
postStmtActions(p)
when false:
if d.s == onStack and containsGarbageCollectedRef(d.t): keepAlive(p, d)
@@ -303,6 +306,7 @@ proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) =
genNamedParamCall(p, ri, d)
else:
genPrefixCall(p, le, ri, d)
postStmtActions(p)
when false:
if d.s == onStack and containsGarbageCollectedRef(d.t): keepAlive(p, d)

File diff suppressed because it is too large Load Diff

View File

@@ -108,7 +108,7 @@ proc genMergeInfo*(m: BModule): PRope =
s.add("labels:")
encodeVInt(m.labels, s)
s.add(" hasframe:")
encodeVInt(ord(m.FrameDeclared), s)
encodeVInt(ord(m.frameDeclared), s)
s.add(tnl)
s.add("*/")
result = s.toRope
@@ -119,8 +119,8 @@ proc skipWhite(L: var TBaseLexer) =
var pos = L.bufpos
while true:
case ^pos
of CR: pos = nimlexbase.HandleCR(L, pos)
of LF: pos = nimlexbase.HandleLF(L, pos)
of CR: pos = nimlexbase.handleCR(L, pos)
of LF: pos = nimlexbase.handleLF(L, pos)
of ' ': inc pos
else: break
L.bufpos = pos
@@ -129,8 +129,8 @@ proc skipUntilCmd(L: var TBaseLexer) =
var pos = L.bufpos
while true:
case ^pos
of CR: pos = nimlexbase.HandleCR(L, pos)
of LF: pos = nimlexbase.HandleLF(L, pos)
of CR: pos = nimlexbase.handleCR(L, pos)
of LF: pos = nimlexbase.handleLF(L, pos)
of '\0': break
of '/':
if ^(pos+1) == '*' and ^(pos+2) == '\t':
@@ -145,33 +145,6 @@ proc atEndMark(buf: cstring, pos: int): bool =
while s < NimMergeEndMark.len and buf[pos+s] == NimMergeEndMark[s]: inc s
result = s == NimMergeEndMark.len
when false:
proc readVerbatimSection(L: var TBaseLexer): PRope =
var pos = L.bufpos
var buf = L.buf
result = newMutableRope(30_000)
while true:
case buf[pos]
of CR:
pos = nimlexbase.HandleCR(L, pos)
buf = L.buf
result.data.add(tnl)
of LF:
pos = nimlexbase.HandleLF(L, pos)
buf = L.buf
result.data.add(tnl)
of '\0':
InternalError("ccgmerge: expected: " & NimMergeEndMark)
break
else:
if atEndMark(buf, pos):
inc pos, NimMergeEndMark.len
break
result.data.add(buf[pos])
inc pos
L.bufpos = pos
freezeMutableRope(result)
proc readVerbatimSection(L: var TBaseLexer): PRope =
var pos = L.bufpos
var buf = L.buf
@@ -179,15 +152,15 @@ proc readVerbatimSection(L: var TBaseLexer): PRope =
while true:
case buf[pos]
of CR:
pos = nimlexbase.HandleCR(L, pos)
pos = nimlexbase.handleCR(L, pos)
buf = L.buf
r.add(tnl)
of LF:
pos = nimlexbase.HandleLF(L, pos)
pos = nimlexbase.handleLF(L, pos)
buf = L.buf
r.add(tnl)
of '\0':
InternalError("ccgmerge: expected: " & NimMergeEndMark)
internalError("ccgmerge: expected: " & NimMergeEndMark)
break
else:
if atEndMark(buf, pos):
@@ -208,7 +181,7 @@ proc readKey(L: var TBaseLexer, result: var string) =
if buf[pos] != ':': internalError("ccgmerge: ':' expected")
L.bufpos = pos + 1 # skip ':'
proc NewFakeType(id: int): PType =
proc newFakeType(id: int): PType =
new(result)
result.id = id
@@ -224,7 +197,7 @@ proc readTypeCache(L: var TBaseLexer, result: var TIdTable) =
# XXX little hack: we create a "fake" type object with the correct Id
# better would be to adapt the data structure to not even store the
# object as key, but only the Id
IdTablePut(result, newFakeType(key), value.toRope)
idTablePut(result, newFakeType(key), value.toRope)
inc L.bufpos
proc readIntSet(L: var TBaseLexer, result: var TIntSet) =
@@ -249,14 +222,14 @@ proc processMergeInfo(L: var TBaseLexer, m: BModule) =
of "declared": readIntSet(L, m.declaredThings)
of "typeInfo": readIntSet(L, m.typeInfoMarker)
of "labels": m.labels = decodeVInt(L.buf, L.bufpos)
of "hasframe": m.FrameDeclared = decodeVInt(L.buf, L.bufpos) != 0
else: InternalError("ccgmerge: unkown key: " & k)
of "hasframe": m.frameDeclared = decodeVInt(L.buf, L.bufpos) != 0
else: internalError("ccgmerge: unkown key: " & k)
when not defined(nimhygiene):
{.pragma: inject.}
template withCFile(cfilename: string, body: stmt) {.immediate.} =
var s = LLStreamOpen(cfilename, fmRead)
var s = llStreamOpen(cfilename, fmRead)
if s == nil: return
var L {.inject.}: TBaseLexer
openBaseLexer(L, s)
@@ -285,7 +258,7 @@ proc readMergeSections(cfilename: string, m: var TMergeSections) =
withCFile(cfilename):
readKey(L, k)
if k == "NIM_merge_INFO":
nil
discard
elif ^L.bufpos == '*' and ^(L.bufpos+1) == '/':
inc(L.bufpos, 2)
# read back into section
@@ -300,9 +273,9 @@ proc readMergeSections(cfilename: string, m: var TMergeSections) =
if sectionB >= 0 and sectionB <= high(TCProcSection).int:
m.p[TCProcSection(sectionB)] = verbatim
else:
InternalError("ccgmerge: unknown section: " & k)
internalError("ccgmerge: unknown section: " & k)
else:
InternalError("ccgmerge: '*/' expected")
internalError("ccgmerge: '*/' expected")
proc mergeRequired*(m: BModule): bool =
for i in cfsHeaders..cfsProcs:
@@ -323,4 +296,3 @@ proc mergeFiles*(cfilename: string, m: BModule) =
m.s[i] = con(old.f[i], m.s[i])
for i in low(TCProcSection)..high(TCProcSection):
m.initProc.s(i) = con(old.p[i], m.initProc.s(i))

View File

@@ -16,7 +16,7 @@ const
# above X strings a hash-switch for strings is generated
proc registerGcRoot(p: BProc, v: PSym) =
if gSelectedGc in {gcMarkAndSweep, gcGenerational} and
if gSelectedGC in {gcMarkAndSweep, gcGenerational} and
containsGarbageCollectedRef(v.loc.t):
# we register a specialized marked proc here; this has the advantage
# that it works out of the box for thread local storage then :-)
@@ -26,7 +26,7 @@ proc registerGcRoot(p: BProc, v: PSym) =
proc genVarTuple(p: BProc, n: PNode) =
var tup, field: TLoc
if n.kind != nkVarTuple: InternalError(n.info, "genVarTuple")
if n.kind != nkVarTuple: internalError(n.info, "genVarTuple")
var L = sonsLen(n)
genLineDir(p, n)
initLocExpr(p, n.sons[L-1], tup)
@@ -45,7 +45,7 @@ proc genVarTuple(p: BProc, n: PNode) =
if t.kind == tyTuple:
field.r = ropef("$1.Field$2", [rdLoc(tup), toRope(i)])
else:
if t.n.sons[i].kind != nkSym: InternalError(n.info, "genVarTuple")
if t.n.sons[i].kind != nkSym: internalError(n.info, "genVarTuple")
field.r = ropef("$1.$2",
[rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)])
putLocIntoDest(p, v.loc, field)
@@ -62,9 +62,10 @@ proc startBlock(p: BProc, start: TFormatStr = "{$n",
lineCg(p, cpsStmts, start, args)
inc(p.labels)
result = len(p.blocks)
setlen(p.blocks, result + 1)
setLen(p.blocks, result + 1)
p.blocks[result].id = p.labels
p.blocks[result].nestedTryStmts = p.nestedTryStmts.len.int16
p.blocks[result].nestedExceptStmts = p.inExceptBlock.int16
proc assignLabel(b: var TBlock): PRope {.inline.} =
b.label = con("LA", b.id.toRope)
@@ -81,7 +82,7 @@ proc endBlock(p: BProc, blockEnd: PRope) =
let topBlock = p.blocks.len-1
# the block is merged into the parent block
app(p.blocks[topBlock-1].sections[cpsStmts], p.blocks[topBlock].blockBody)
setlen(p.blocks, topBlock)
setLen(p.blocks, topBlock)
# this is done after the block is popped so $n is
# properly indented when pretty printing is enabled
line(p, cpsStmts, blockEnd)
@@ -126,7 +127,7 @@ proc genGotoState(p: BProc, n: PNode) =
var a: TLoc
initLocExpr(p, n.sons[0], a)
lineF(p, cpsStmts, "switch ($1) {$n", [rdLoc(a)])
p.BeforeRetNeeded = true
p.beforeRetNeeded = true
lineF(p, cpsStmts, "case -1: goto BeforeRet;$n", [])
for i in 0 .. lastOrd(n.sons[0].typ):
lineF(p, cpsStmts, "case $1: goto STATE$1;$n", [toRope(i)])
@@ -137,7 +138,7 @@ proc genBreakState(p: BProc, n: PNode) =
if n.sons[0].kind == nkClosure:
# XXX this produces quite inefficient code!
initLocExpr(p, n.sons[0].sons[1], a)
lineF(p, cpsStmts, "if (($1->Field0) < 0) break;$n", [rdLoc(a)])
lineF(p, cpsStmts, "if (((NI*) $1)[0] < 0) break;$n", [rdLoc(a)])
else:
initLocExpr(p, n.sons[0], a)
# the environment is guaranteed to contain the 'state' field at offset 0:
@@ -151,7 +152,8 @@ proc genSingleVar(p: BProc, a: PNode) =
var targetProc = p
var immediateAsgn = a.sons[2].kind != nkEmpty
if sfGlobal in v.flags:
if v.owner.kind != skModule:
if sfPure in v.flags:
# v.owner.kind != skModule:
targetProc = p.module.preInitProc
assignGlobalVar(targetProc, v)
# XXX: be careful here.
@@ -199,7 +201,7 @@ proc genConstStmt(p: BProc, t: PNode) =
for i in countup(0, sonsLen(t) - 1):
var it = t.sons[i]
if it.kind == nkCommentStmt: continue
if it.kind != nkConstDef: InternalError(t.info, "genConstStmt")
if it.kind != nkConstDef: internalError(t.info, "genConstStmt")
var c = it.sons[0].sym
if c.typ.containsCompileTimeOnly: continue
if sfFakeConst in c.flags:
@@ -231,73 +233,162 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
# Lend:
var
a: TLoc
Lelse: TLabel
lelse: TLabel
if not isEmptyType(n.typ) and d.k == locNone:
getTemp(p, n.typ, d)
genLineDir(p, n)
let Lend = getLabel(p)
let lend = getLabel(p)
for i in countup(0, sonsLen(n) - 1):
let it = n.sons[i]
if it.len == 2:
when newScopeForIf: startBlock(p)
initLocExpr(p, it.sons[0], a)
Lelse = getLabel(p)
lelse = getLabel(p)
inc(p.labels)
lineFF(p, cpsStmts, "if (!$1) goto $2;$n",
"br i1 $1, label %LOC$3, label %$2$nLOC$3: $n",
[rdLoc(a), Lelse, toRope(p.labels)])
[rdLoc(a), lelse, toRope(p.labels)])
when not newScopeForIf: startBlock(p)
expr(p, it.sons[1], d)
endBlock(p)
if sonsLen(n) > 1:
lineFF(p, cpsStmts, "goto $1;$n", "br label %$1$n", [Lend])
fixLabel(p, Lelse)
lineFF(p, cpsStmts, "goto $1;$n", "br label %$1$n", [lend])
fixLabel(p, lelse)
elif it.len == 1:
startBlock(p)
expr(p, it.sons[0], d)
endBlock(p)
else: internalError(n.info, "genIf()")
if sonsLen(n) > 1: fixLabel(p, Lend)
if sonsLen(n) > 1: fixLabel(p, lend)
proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
# Called by return and break stmts.
# Deals with issues faced when jumping out of try/except/finally stmts,
proc blockLeaveActions(p: BProc, howMany: int) =
var L = p.nestedTryStmts.len
# danger of endless recursion! we workaround this here by a temp stack
var stack: seq[PNode]
newSeq(stack, howMany)
for i in countup(1, howMany):
stack[i-1] = p.nestedTryStmts[L-i]
setLen(p.nestedTryStmts, L-howMany)
newSeq(stack, 0)
var alreadyPoppedCnt = p.inExceptBlock
for tryStmt in items(stack):
for i in countup(1, howManyTrys):
if gCmd != cmdCompileToCpp:
# Pop safe points generated by try
if alreadyPoppedCnt > 0:
dec alreadyPoppedCnt
else:
linefmt(p, cpsStmts, "#popSafePoint();$n")
# Pop this try-stmt of the list of nested trys
# so we don't infinite recurse on it in the next step.
var tryStmt = p.nestedTryStmts.pop
stack.add(tryStmt)
# Find finally-stmt for this try-stmt
# and generate a copy of its sons
var finallyStmt = lastSon(tryStmt)
if finallyStmt.kind == nkFinally:
genStmts(p, finallyStmt.sons[0])
# push old elements again:
for i in countdown(howMany-1, 0):
for i in countdown(howManyTrys-1, 0):
p.nestedTryStmts.add(stack[i])
if gCmd != cmdCompileToCpp:
for i in countdown(p.inExceptBlock-1, 0):
# Pop exceptions that was handled by the
# except-blocks we are in
for i in countdown(howManyExcepts-1, 0):
linefmt(p, cpsStmts, "#popCurrentException();$n")
proc genReturnStmt(p: BProc, t: PNode) =
p.beforeRetNeeded = true
genLineDir(p, t)
if (t.sons[0].kind != nkEmpty): genStmts(p, t.sons[0])
blockLeaveActions(p, min(1, p.nestedTryStmts.len))
blockLeaveActions(p,
howManyTrys = p.nestedTryStmts.len,
howManyExcepts = p.inExceptBlock)
if (p.finallySafePoints.len > 0):
# If we're in a finally block, and we came here by exception
# consume it before we return.
var safePoint = p.finallySafePoints[p.finallySafePoints.len-1]
linefmt(p, cpsStmts, "if ($1.status != 0) #popCurrentException();$n", safePoint)
lineFF(p, cpsStmts, "goto BeforeRet;$n", "br label %BeforeRet$n", [])
proc genComputedGoto(p: BProc; n: PNode) =
# first pass: Generate array of computed labels:
var casePos = -1
var arraySize: int
for i in 0 .. <n.len:
let it = n.sons[i]
if it.kind == nkCaseStmt:
if lastSon(it).kind != nkOfBranch:
localError(it.info,
"case statement must be exhaustive for computed goto"); return
casePos = i
let aSize = lengthOrd(it.sons[0].typ)
if aSize > 10_000:
localError(it.info,
"case statement has too many cases for computed goto"); return
arraySize = aSize.int
if firstOrd(it.sons[0].typ) != 0:
localError(it.info,
"case statement has to start at 0 for computed goto"); return
if casePos < 0:
localError(n.info, "no case statement found for computed goto"); return
var id = p.labels+1
inc p.labels, arraySize+1
let tmp = ropef("TMP$1", id.toRope)
var gotoArray = ropef("static void* $#[$#] = {", tmp, arraySize.toRope)
for i in 1..arraySize-1:
gotoArray.appf("&&TMP$#, ", (id+i).toRope)
gotoArray.appf("&&TMP$#};$n", (id+arraySize).toRope)
line(p, cpsLocals, gotoArray)
let topBlock = p.blocks.len-1
let oldBody = p.blocks[topBlock].sections[cpsStmts]
p.blocks[topBlock].sections[cpsStmts] = nil
for j in casePos+1 .. <n.len: genStmts(p, n.sons[j])
let tailB = p.blocks[topBlock].sections[cpsStmts]
p.blocks[topBlock].sections[cpsStmts] = nil
for j in 0 .. casePos-1: genStmts(p, n.sons[j])
let tailA = p.blocks[topBlock].sections[cpsStmts]
p.blocks[topBlock].sections[cpsStmts] = oldBody.con(tailA)
let caseStmt = n.sons[casePos]
var a: TLoc
initLocExpr(p, caseStmt.sons[0], a)
# first goto:
lineF(p, cpsStmts, "goto *$#[$#];$n", tmp, a.rdLoc)
for i in 1 .. <caseStmt.len:
startBlock(p)
let it = caseStmt.sons[i]
for j in 0 .. it.len-2:
if it.sons[j].kind == nkRange:
localError(it.info, "range notation not available for computed goto")
return
let val = getOrdValue(it.sons[j])
lineF(p, cpsStmts, "TMP$#:$n", intLiteral(val+id+1))
genStmts(p, it.lastSon)
#for j in casePos+1 .. <n.len: genStmts(p, n.sons[j]) # tailB
#for j in 0 .. casePos-1: genStmts(p, n.sons[j]) # tailA
app(p.s(cpsStmts), tailB)
app(p.s(cpsStmts), tailA)
var a: TLoc
initLocExpr(p, caseStmt.sons[0], a)
lineF(p, cpsStmts, "goto *$#[$#];$n", tmp, a.rdLoc)
endBlock(p)
proc genWhileStmt(p: BProc, t: PNode) =
# we don't generate labels here as for example GCC would produce
# significantly worse code
var
a: TLoc
Labl: TLabel
labl: TLabel
assert(sonsLen(t) == 2)
inc(p.withinLoop)
genLineDir(p, t)
@@ -309,7 +400,15 @@ proc genWhileStmt(p: BProc, t: PNode) =
if (t.sons[0].kind != nkIntLit) or (t.sons[0].intVal == 0):
let label = assignLabel(p.blocks[p.breakIdx])
lineF(p, cpsStmts, "if (!$1) goto $2;$n", [rdLoc(a), label])
genStmts(p, t.sons[1])
var loopBody = t.sons[1]
if loopBody.stmtsContainPragma(wComputedGoto) and
hasComputedGoto in CC[cCompiler].props:
# for closure support weird loop bodies are generated:
if loopBody.len == 2 and loopBody.sons[0].kind == nkEmpty:
loopBody = loopBody.sons[1]
genComputedGoto(p, loopBody)
else:
genStmts(p, loopBody)
if optProfiler in p.options:
# invoke at loop body exit:
@@ -338,7 +437,7 @@ proc genParForStmt(p: BProc, t: PNode) =
preserveBreakIdx:
let forLoopVar = t.sons[0].sym
var rangeA, rangeB: TLoc
assignLocalVar(P, forLoopVar)
assignLocalVar(p, forLoopVar)
#initLoc(forLoopVar.loc, locLocalVar, forLoopVar.typ, onStack)
#discard mangleName(forLoopVar)
let call = t.sons[1]
@@ -370,9 +469,11 @@ proc genBreakStmt(p: BProc, t: PNode) =
# an unnamed 'break' can only break a loop after 'transf' pass:
while idx >= 0 and not p.blocks[idx].isLoop: dec idx
if idx < 0 or not p.blocks[idx].isLoop:
InternalError(t.info, "no loop to break")
internalError(t.info, "no loop to break")
let label = assignLabel(p.blocks[idx])
blockLeaveActions(p, p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts)
blockLeaveActions(p,
p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts,
p.inExceptBlock - p.blocks[idx].nestedExceptStmts)
genLineDir(p, t)
lineF(p, cpsStmts, "goto $1;$n", [label])
@@ -391,7 +492,7 @@ proc genRaiseStmt(p: BProc, t: PNode) =
genSimpleBlock(p, finallyBlock.sons[0])
if t.sons[0].kind != nkEmpty:
var a: TLoc
InitLocExpr(p, t.sons[0], a)
initLocExpr(p, t.sons[0], a)
var e = rdLoc(a)
var typ = skipTypes(t.sons[0].typ, abstractPtrs)
genLineDir(p, t)
@@ -421,16 +522,16 @@ proc genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
labId, until: int): TLabel =
var Lend = getLabel(p)
var lend = getLabel(p)
for i in 1..until:
lineF(p, cpsStmts, "LA$1: ;$n", [toRope(labId + i)])
if t.sons[i].kind == nkOfBranch:
var length = sonsLen(t.sons[i])
exprBlock(p, t.sons[i].sons[length - 1], d)
lineF(p, cpsStmts, "goto $1;$n", [Lend])
lineF(p, cpsStmts, "goto $1;$n", [lend])
else:
exprBlock(p, t.sons[i].sons[0], d)
result = Lend
result = lend
proc genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
rangeFormat, eqFormat: TFormatStr,
@@ -457,8 +558,8 @@ proc genCaseGeneric(p: BProc, t: PNode, d: var TLoc,
rangeFormat, eqFormat: TFormatStr) =
var a: TLoc
initLocExpr(p, t.sons[0], a)
var Lend = genIfForCaseUntil(p, t, d, rangeFormat, eqFormat, sonsLen(t)-1, a)
fixLabel(p, Lend)
var lend = genIfForCaseUntil(p, t, d, rangeFormat, eqFormat, sonsLen(t)-1, a)
fixLabel(p, lend)
proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
branches: var openArray[PRope]) =
@@ -502,25 +603,25 @@ proc genStringCase(p: BProc, t: PNode, d: var TLoc) =
if t.sons[sonsLen(t)-1].kind != nkOfBranch:
lineF(p, cpsStmts, "goto LA$1;$n", [toRope(p.labels)])
# third pass: generate statements
var Lend = genCaseSecondPass(p, t, d, labId, sonsLen(t)-1)
fixLabel(p, Lend)
var lend = genCaseSecondPass(p, t, d, labId, sonsLen(t)-1)
fixLabel(p, lend)
else:
genCaseGeneric(p, t, d, "", "if (#eqStrings($1, $2)) goto $3;$n")
proc branchHasTooBigRange(b: PNode): bool =
for i in countup(0, sonsLen(b)-2):
# last son is block
if (b.sons[i].Kind == nkRange) and
if (b.sons[i].kind == nkRange) and
b.sons[i].sons[1].intVal - b.sons[i].sons[0].intVal > RangeExpandLimit:
return true
proc IfSwitchSplitPoint(p: BProc, n: PNode): int =
proc ifSwitchSplitPoint(p: BProc, n: PNode): int =
for i in 1..n.len-1:
var branch = n[i]
var stmtBlock = lastSon(branch)
if stmtBlock.stmtsContainPragma(wLinearScanEnd):
result = i
elif hasSwitchRange notin CC[ccompiler].props:
elif hasSwitchRange notin CC[cCompiler].props:
if branch.kind == nkOfBranch and branchHasTooBigRange(branch):
result = i
@@ -528,7 +629,7 @@ proc genCaseRange(p: BProc, branch: PNode) =
var length = branch.len
for j in 0 .. length-2:
if branch[j].kind == nkRange:
if hasSwitchRange in CC[ccompiler].props:
if hasSwitchRange in CC[cCompiler].props:
lineF(p, cpsStmts, "case $1 ... $2:$n", [
genLiteral(p, branch[j][0]),
genLiteral(p, branch[j][1])])
@@ -536,18 +637,18 @@ proc genCaseRange(p: BProc, branch: PNode) =
var v = copyNode(branch[j][0])
while v.intVal <= branch[j][1].intVal:
lineF(p, cpsStmts, "case $1:$n", [genLiteral(p, v)])
Inc(v.intVal)
inc(v.intVal)
else:
lineF(p, cpsStmts, "case $1:$n", [genLiteral(p, branch[j])])
proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
# analyse 'case' statement:
var splitPoint = IfSwitchSplitPoint(p, n)
var splitPoint = ifSwitchSplitPoint(p, n)
# generate if part (might be empty):
var a: TLoc
initLocExpr(p, n.sons[0], a)
var Lend = if splitPoint > 0: genIfForCaseUntil(p, n, d,
var lend = if splitPoint > 0: genIfForCaseUntil(p, n, d,
rangeFormat = "if ($1 >= $2 && $1 <= $3) goto $4;$n",
eqFormat = "if ($1 == $2) goto $3;$n",
splitPoint, a) else: nil
@@ -566,10 +667,10 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
hasDefault = true
exprBlock(p, branch.lastSon, d)
lineF(p, cpsStmts, "break;$n")
if (hasAssume in CC[ccompiler].props) and not hasDefault:
if (hasAssume in CC[cCompiler].props) and not hasDefault:
lineF(p, cpsStmts, "default: __assume(0);$n")
lineF(p, cpsStmts, "}$n")
if Lend != nil: fixLabel(p, Lend)
if lend != nil: fixLabel(p, lend)
proc genCase(p: BProc, t: PNode, d: var TLoc) =
genLineDir(p, t)
@@ -628,7 +729,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
expr(p, t.sons[0], d)
length = sonsLen(t)
endBlock(p, ropecg(p.module, "} catch (NimException& $1) {$n", [exc]))
if optStackTrace in p.Options:
if optStackTrace in p.options:
linefmt(p, cpsStmts, "#setFrame((TFrame*)&F);$n")
inc p.inExceptBlock
i = 1
@@ -701,6 +802,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
#
if not isEmptyType(t.typ) and d.k == locNone:
getTemp(p, t.typ, d)
discard lists.includeStr(p.module.headerFiles, "<setjmp.h>")
genLineDir(p, t)
var safePoint = getTempName()
discard cgsym(p.module, "E_Base")
@@ -715,7 +817,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
endBlock(p)
startBlock(p, "else {$n")
linefmt(p, cpsStmts, "#popSafePoint();$n")
if optStackTrace in p.Options:
if optStackTrace in p.options:
linefmt(p, cpsStmts, "#setFrame((TFrame*)&F);$n")
inc p.inExceptBlock
var i = 1
@@ -748,35 +850,57 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
discard pop(p.nestedTryStmts)
endBlock(p) # end of else block
if i < length and t.sons[i].kind == nkFinally:
p.finallySafePoints.add(safePoint)
exprBlock(p, t.sons[i].sons[0], d)
discard pop(p.finallySafePoints)
linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", safePoint)
proc genAsmOrEmitStmt(p: BProc, t: PNode): PRope =
for i in countup(0, sonsLen(t) - 1):
case t.sons[i].Kind
of nkStrLit..nkTripleStrLit:
app(result, t.sons[i].strVal)
of nkSym:
proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): PRope =
var res = ""
for i in countup(0, sonsLen(t) - 1):
case t.sons[i].kind
of nkStrLit..nkTripleStrLit:
res.add(t.sons[i].strVal)
of nkSym:
var sym = t.sons[i].sym
if sym.kind in {skProc, skIterator, skMethod}:
if sym.kind in {skProc, skIterator, skClosureIterator, skMethod}:
var a: TLoc
initLocExpr(p, t.sons[i], a)
app(result, rdLoc(a))
else:
res.add(rdLoc(a).ropeToStr)
else:
var r = sym.loc.r
if r == nil:
# if no name has already been given,
# it doesn't matter much:
r = mangleName(sym)
sym.loc.r = r # but be consequent!
app(result, r)
else: InternalError(t.sons[i].info, "genAsmOrEmitStmt()")
res.add(r.ropeToStr)
else: internalError(t.sons[i].info, "genAsmOrEmitStmt()")
if isAsmStmt and hasGnuAsm in CC[cCompiler].props:
for x in splitLines(res):
var j = 0
while x[j] in {' ', '\t'}: inc(j)
if x[j] == ':' and x[j+1] == '"' or x[j] == '"':
# some clobber register list:
app(result, x); app(result, tnl)
elif x[j] != '\0':
# ignore empty lines
app(result, "\"")
app(result, x)
app(result, "\\n\"\n")
else:
result = res.toRope
proc genAsmStmt(p: BProc, t: PNode) =
assert(t.kind == nkAsmStmt)
genLineDir(p, t)
var s = genAsmOrEmitStmt(p, t)
lineF(p, cpsStmts, CC[ccompiler].asmStmtFrmt, [s])
var s = genAsmOrEmitStmt(p, t, isAsmStmt=true)
if p.prc == nil:
# top level asm statement?
appf(p.module.s[cfsProcHeaders], CC[cCompiler].asmStmtFrmt, [s])
else:
lineF(p, cpsStmts, CC[cCompiler].asmStmtFrmt, [s])
proc genEmit(p: BProc, t: PNode) =
genLineDir(p, t)
@@ -793,7 +917,7 @@ var
proc genBreakPoint(p: BProc, t: PNode) =
var name: string
if optEndb in p.Options:
if optEndb in p.options:
if t.kind == nkExprColonExpr:
assert(t.sons[1].kind in {nkStrLit..nkTripleStrLit})
name = normalize(t.sons[1].strVal)
@@ -807,7 +931,7 @@ proc genBreakPoint(p: BProc, t: PNode) =
makeCString(name)])
proc genWatchpoint(p: BProc, n: PNode) =
if optEndb notin p.Options: return
if optEndb notin p.options: return
var a: TLoc
initLocExpr(p, n.sons[1], a)
let typ = skipTypes(n.sons[1].typ, abstractVarRange)
@@ -821,10 +945,15 @@ proc genPragma(p: BProc, n: PNode) =
case whichPragma(it)
of wEmit: genEmit(p, it)
of wBreakpoint: genBreakPoint(p, it)
of wWatchpoint: genWatchpoint(p, it)
else: nil
of wWatchPoint: genWatchpoint(p, it)
of wInjectStmt:
var p = newProc(nil, p.module)
p.options = p.options - {optLineTrace, optStackTrace}
genStmts(p, it.sons[1])
p.module.injectStmt = p.s(cpsStmts)
else: discard
proc FieldDiscriminantCheckNeeded(p: BProc, asgn: PNode): bool =
proc fieldDiscriminantCheckNeeded(p: BProc, asgn: PNode): bool =
if optFieldCheck in p.options:
var le = asgn.sons[0]
if le.kind == nkCheckedFieldExpr:
@@ -840,7 +969,7 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
assert t.kind == tyObject
discard genTypeInfo(p.module, t)
var L = lengthOrd(field.typ)
if not ContainsOrIncl(p.module.declaredThings, field.id):
if not containsOrIncl(p.module.declaredThings, field.id):
appcg(p.module, cfsVars, "extern $1",
discriminatorTableDecl(p.module, t, field))
lineCg(p, cpsStmts,
@@ -853,7 +982,7 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) =
var dotExpr = e.sons[0]
var d: PSym
if dotExpr.kind == nkCheckedFieldExpr: dotExpr = dotExpr.sons[0]
InitLocExpr(p, e.sons[0], a)
initLocExpr(p, e.sons[0], a)
getTemp(p, a.t, tmp)
expr(p, e.sons[1], tmp)
genDiscriminantCheck(p, a, tmp, dotExpr.sons[0].typ, dotExpr.sons[1].sym)
@@ -861,9 +990,9 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) =
proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
genLineDir(p, e)
if not FieldDiscriminantCheckNeeded(p, e):
if not fieldDiscriminantCheckNeeded(p, e):
var a: TLoc
InitLocExpr(p, e.sons[0], a)
initLocExpr(p, e.sons[0], a)
if fastAsgn: incl(a.flags, lfNoDeepCopy)
assert(a.t != nil)
loadInto(p, e.sons[0], e.sons[1], a)
@@ -873,4 +1002,4 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
proc genStmts(p: BProc, t: PNode) =
var a: TLoc
expr(p, t, a)
InternalAssert a.k in {locNone, locTemp}
internalAssert a.k in {locNone, locTemp, locLocalVar}

View File

@@ -12,12 +12,12 @@
# included from cgen.nim
proc emulatedThreadVars(): bool {.inline.} =
proc emulatedThreadVars(): bool =
result = {optThreads, optTlsEmulation} <= gGlobalOptions
proc AccessThreadLocalVar(p: BProc, s: PSym) =
if emulatedThreadVars() and not p.ThreadVarAccessed:
p.ThreadVarAccessed = true
proc accessThreadLocalVar(p: BProc, s: PSym) =
if emulatedThreadVars() and not p.threadVarAccessed:
p.threadVarAccessed = true
p.module.usesThreadVars = true
appf(p.procSec(cpsLocals), "\tNimThreadVars* NimTV;$n")
app(p.procSec(cpsInit),
@@ -55,7 +55,7 @@ proc generateThreadLocalStorage(m: BModule) =
for t in items(nimtvDeps): discard getTypeDesc(m, t)
appf(m.s[cfsSeqTypes], "typedef struct {$1} NimThreadVars;$n", [nimtv])
proc GenerateThreadVarsSize(m: BModule) =
proc generateThreadVarsSize(m: BModule) =
if nimtv != nil:
app(m.s[cfsProcs],
"NI NimThreadVarsSize(){return (NI)sizeof(NimThreadVars);}" & tnl)

View File

@@ -28,7 +28,7 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, n: PNode) =
for i in countup(0, sonsLen(n) - 1):
genTraverseProc(c, accessor, n.sons[i])
of nkRecCase:
if (n.sons[0].kind != nkSym): InternalError(n.info, "genTraverseProc")
if (n.sons[0].kind != nkSym): internalError(n.info, "genTraverseProc")
var p = c.p
let disc = n.sons[0].sym
lineF(p, cpsStmts, "switch ($1.$2) {$n", accessor, disc.loc.r)
@@ -74,7 +74,7 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
genTraverseProc(c, accessor.parentObj, typ.sons[i])
if typ.n != nil: genTraverseProc(c, accessor, typ.n)
of tyTuple:
let typ = GetUniqueType(typ)
let typ = getUniqueType(typ)
for i in countup(0, sonsLen(typ) - 1):
genTraverseProc(c, rfmt(nil, "$1.Field$2", accessor, i.toRope), typ.sons[i])
of tyRef, tyString, tySequence:
@@ -83,7 +83,7 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
if typ.callConv == ccClosure:
lineCg(p, cpsStmts, c.visitorFrmt, rfmt(nil, "$1.ClEnv", accessor))
else:
nil
discard
proc genTraverseProcSeq(c: var TTraversalClosure, accessor: PRope, typ: PType) =
var p = c.p
@@ -111,7 +111,7 @@ proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): PRope =
lineF(p, cpsInit, "a = ($1)p;$n", t)
c.p = p
assert typ.kind != tyTypedesc
assert typ.kind != tyTypeDesc
if typ.kind == tySequence:
genTraverseProcSeq(c, "a".toRope, typ)
else:
@@ -127,18 +127,22 @@ proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): PRope =
m.s[cfsProcHeaders].appf("$1;$n", header)
m.s[cfsProcs].app(generatedProc)
proc genTraverseProcForGlobal(m: BModule, s: PSym): PRope =
discard genTypeInfo(m, s.loc.t)
var c: TTraversalClosure
var p = newProc(nil, m)
var sLoc = s.loc.r
result = getGlobalTempName()
if sfThread in s.flags and emulatedThreadVars():
accessThreadLocalVar(p, s)
sLoc = con("NimTV->", sLoc)
c.visitorFrmt = "#nimGCvisit((void*)$1, 0);$n"
c.p = p
let header = ropef("N_NIMCALL(void, $1)()", result)
genTraverseProc(c, s.loc.r, s.loc.t)
genTraverseProc(c, sLoc, s.loc.t)
let generatedProc = ropef("$1 {$n$2$3$4}$n",
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)])

View File

@@ -25,7 +25,7 @@ proc mangleField(name: string): string =
of 'A'..'Z':
add(result, chr(ord(name[i]) - ord('A') + ord('a')))
of '_':
nil
discard
of 'a'..'z', '0'..'9':
add(result, name[i])
else:
@@ -48,7 +48,7 @@ proc mangle(name: string): string =
of 'A'..'Z':
add(result, chr(ord(name[i]) - ord('A') + ord('a')))
of '_':
nil
discard
of 'a'..'z', '0'..'9':
add(result, name[i])
else:
@@ -69,17 +69,17 @@ proc mangleName(s: PSym): PRope =
if result == nil:
if gCmd == cmdCompileToLLVM:
case s.kind
of skProc, skMethod, skConverter, skConst, skIterator:
of skProc, skMethod, skConverter, skConst, skIterators:
result = ~"@"
of skVar, skForVar, skResult, skLet:
if sfGlobal in s.flags: result = ~"@"
else: result = ~"%"
of skTemp, skParam, skType, skEnumField, skModule:
result = ~"%"
else: InternalError(s.info, "mangleName")
else: internalError(s.info, "mangleName")
when oKeepVariableNames:
let keepOrigName = s.kind in skLocalVars - {skForVar} and
{sfFromGeneric, sfGlobal, sfShadowed} * s.flags == {} and
{sfFromGeneric, sfGlobal, sfShadowed, sfGenSym} * s.flags == {} and
not isKeyword(s.name)
# XXX: This is still very experimental
#
@@ -150,7 +150,7 @@ proc getTypeName(typ: PType): PRope =
typ.loc.r = if gCmd != cmdCompileToLLVM: con(typ.typeName, typ.id.toRope)
else: con([~"%", typ.typeName, typ.id.toRope])
result = typ.loc.r
if result == nil: InternalError("getTypeName: " & $typ.kind)
if result == nil: internalError("getTypeName: " & $typ.kind)
proc mapSetType(typ: PType): TCTypeKind =
case int(getSize(typ))
@@ -183,9 +183,9 @@ proc mapType(typ: PType): TCTypeKind =
else: internalError("mapType")
of tyRange: result = mapType(typ.sons[0])
of tyPtr, tyVar, tyRef:
var base = skipTypes(typ.sons[0], typedescInst)
var base = skipTypes(typ.lastSon, typedescInst)
case base.kind
of tyOpenArray, tyArrayConstr, tyArray, tyVarargs: result = ctArray
of tyOpenArray, tyArrayConstr, tyArray, tyVarargs: result = ctPtrToArray
else: result = ctPtr
of tyPointer: result = ctPtr
of tySequence: result = ctNimSeq
@@ -194,7 +194,7 @@ proc mapType(typ: PType): TCTypeKind =
of tyCString: result = ctCString
of tyInt..tyUInt64:
result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt))
else: InternalError("mapType")
else: internalError("mapType")
proc mapReturnType(typ: PType): TCTypeKind =
if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr
@@ -229,11 +229,11 @@ const
"stdcall $1", "ccc $1", "safecall $1", "syscall $1", "$1 alwaysinline",
"$1 noinline", "fastcc $1", "ccc $1", "$1"]
proc CacheGetType(tab: TIdTable, key: PType): PRope =
proc cacheGetType(tab: TIdTable, key: PType): PRope =
# returns nil if we need to declare this type
# since types are now unique via the ``GetUniqueType`` mechanism, this slow
# linear search is not necessary anymore:
result = PRope(IdTableGet(tab, key))
result = PRope(idTableGet(tab, key))
proc getTempName(): PRope =
result = rfmt(nil, "TMP$1", toRope(backendId()))
@@ -246,7 +246,7 @@ proc ccgIntroducedPtr(s: PSym): bool =
assert skResult != s.kind
if tfByRef in pt.flags: return true
elif tfByCopy in pt.flags: return false
case pt.Kind
case pt.kind
of tyObject:
if (optByRef in s.options) or (getSize(pt) > platform.floatSize * 2):
result = true # requested anyway
@@ -262,14 +262,14 @@ proc ccgIntroducedPtr(s: PSym): bool =
proc fillResult(param: PSym) =
fillLoc(param.loc, locParam, param.typ, ~"Result",
OnStack)
if (mapReturnType(param.typ) != ctArray) and IsInvalidReturnType(param.typ):
if (mapReturnType(param.typ) != ctArray) and isInvalidReturnType(param.typ):
incl(param.loc.flags, lfIndirect)
param.loc.s = OnUnknown
proc getParamTypeDesc(m: BModule, t: PType, check: var TIntSet): PRope =
when false:
if t.Kind in {tyRef, tyPtr, tyVar}:
var b = skipTypes(t.sons[0], typedescInst)
var b = skipTypes(t.lastson, typedescInst)
if b.kind == tySet and mapSetType(b) == ctArray:
return getTypeDescAux(m, b, check)
result = getTypeDescAux(m, t, check)
@@ -288,7 +288,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
else:
rettype = getTypeDescAux(m, t.sons[0], check)
for i in countup(1, sonsLen(t.n) - 1):
if t.n.sons[i].kind != nkSym: InternalError(t.n.info, "genProcParams")
if t.n.sons[i].kind != nkSym: internalError(t.n.info, "genProcParams")
var param = t.n.sons[i].sym
if isCompileTimeOnly(param.typ): continue
if params != nil: app(params, ~", ")
@@ -305,7 +305,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
var arr = param.typ
if arr.kind == tyVar: arr = arr.sons[0]
var j = 0
while arr.Kind in {tyOpenArray, tyVarargs}:
while arr.kind in {tyOpenArray, tyVarargs}:
# this fixes the 'sort' bug:
if param.typ.kind == tyVar: param.loc.s = OnUnknown
# need to pass hidden parameter:
@@ -344,7 +344,7 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): PRope =
"NI", "NI8", "NI16", "NI32", "NI64",
"NF", "NF32", "NF64", "NF128",
"NU", "NU8", "NU16", "NU32", "NU64",]
case typ.Kind
case typ.kind
of tyPointer:
result = typeNameOrLiteral(typ, "void*")
of tyEnum:
@@ -362,12 +362,12 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): PRope =
of tyString:
discard cgsym(m, "NimStringDesc")
result = typeNameOrLiteral(typ, "NimStringDesc*")
of tyCstring: result = typeNameOrLiteral(typ, "NCSTRING")
of tyCString: result = typeNameOrLiteral(typ, "NCSTRING")
of tyBool: result = typeNameOrLiteral(typ, "NIM_BOOL")
of tyChar: result = typeNameOrLiteral(typ, "NIM_CHAR")
of tyNil: result = typeNameOrLiteral(typ, "0")
of tyInt..tyUInt64:
result = typeNameOrLiteral(typ, NumericalTypeToStr[typ.Kind])
result = typeNameOrLiteral(typ, NumericalTypeToStr[typ.kind])
of tyRange: result = getSimpleTypeDesc(m, typ.sons[0])
else: result = nil
@@ -375,14 +375,17 @@ proc getTypePre(m: BModule, typ: PType): PRope =
if typ == nil: result = toRope("void")
else:
result = getSimpleTypeDesc(m, typ)
if result == nil: result = CacheGetType(m.typeCache, typ)
if result == nil: result = cacheGetType(m.typeCache, typ)
proc structOrUnion(t: PType): PRope =
(if tfUnion in t.flags: toRope("union") else: toRope("struct"))
proc getForwardStructFormat(): string =
if gCmd == cmdCompileToCpp: result = "struct $1;$n"
else: result = "typedef struct $1 $1;$n"
if gCmd == cmdCompileToCpp: result = "$1 $2;$n"
else: result = "typedef $1 $2 $2;$n"
proc getTypeForward(m: BModule, typ: PType): PRope =
result = CacheGetType(m.forwTypeCache, typ)
result = cacheGetType(m.forwTypeCache, typ)
if result != nil: return
result = getTypePre(m, typ)
if result != nil: return
@@ -390,9 +393,10 @@ proc getTypeForward(m: BModule, typ: PType): PRope =
of tySequence, tyTuple, tyObject:
result = getTypeName(typ)
if not isImportedType(typ):
appf(m.s[cfsForwardTypes], getForwardStructFormat(), [result])
IdTablePut(m.forwTypeCache, typ, result)
else: InternalError("getTypeForward(" & $typ.kind & ')')
appf(m.s[cfsForwardTypes], getForwardStructFormat(),
[structOrUnion(typ), result])
idTablePut(m.forwTypeCache, typ, result)
else: internalError("getTypeForward(" & $typ.kind & ')')
proc mangleRecFieldName(field: PSym, rectype: PType): PRope =
if (rectype.sym != nil) and
@@ -400,7 +404,7 @@ proc mangleRecFieldName(field: PSym, rectype: PType): PRope =
result = field.loc.r
else:
result = toRope(mangleField(field.name.s))
if result == nil: InternalError(field.info, "mangleRecFieldName")
if result == nil: internalError(field.info, "mangleRecFieldName")
proc genRecordFieldsAux(m: BModule, n: PNode,
accessExpr: PRope, rectype: PType,
@@ -415,7 +419,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
for i in countup(0, sonsLen(n) - 1):
app(result, genRecordFieldsAux(m, n.sons[i], accessExpr, rectype, check))
of nkRecCase:
if (n.sons[0].kind != nkSym): InternalError(n.info, "genRecordFieldsAux")
if (n.sons[0].kind != nkSym): internalError(n.info, "genRecordFieldsAux")
app(result, genRecordFieldsAux(m, n.sons[0], accessExpr, rectype, check))
uname = toRope(mangle(n.sons[0].sym.name.s) & 'U')
if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, uname])
@@ -437,14 +441,20 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
app(result, genRecordFieldsAux(m, k, ae, rectype, check))
else: internalError("genRecordFieldsAux(record case branch)")
appf(result, "} $1;$n", [uname])
of nkSym:
of nkSym:
field = n.sym
if field.typ.kind == tyEmpty: return
#assert(field.ast == nil)
sname = mangleRecFieldName(field, rectype)
if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, sname])
else: ae = sname
fillLoc(field.loc, locField, field.typ, ae, OnUnknown)
appf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname])
let fieldType = field.loc.t
if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
appf(result, "$1 $2[SEQ_DECL_SIZE];$n",
[getTypeDescAux(m, fieldType.elemType, check), sname])
else:
appf(result, "$1 $2;$n", [getTypeDescAux(m, fieldType, check), sname])
else: internalError(n.info, "genRecordFieldsAux()")
proc getRecordFields(m: BModule, typ: PType, check: var TIntSet): PRope =
@@ -454,23 +464,33 @@ proc getRecordDesc(m: BModule, typ: PType, name: PRope,
check: var TIntSet): PRope =
# declare the record:
var hasField = false
var attribute: PRope =
if tfPacked in typ.flags: toRope(CC[ccompiler].packedPragma)
else: nil
result = ropecg(m, CC[ccompiler].structStmtFmt,
[structOrUnion(typ), name, attribute])
if typ.kind == tyObject:
if typ.sons[0] == nil:
if (typ.sym != nil and sfPure in typ.sym.flags) or tfFinal in typ.flags:
result = ropecg(m, "struct $1 {$n", [name])
appcg(m, result, " {$n", [])
else:
result = ropecg(m, "struct $1 {$n#TNimType* m_type;$n", [name])
appcg(m, result, " {$n#TNimType* m_type;$n", [name, attribute])
hasField = true
elif gCmd == cmdCompileToCpp:
result = ropecg(m, "struct $1 : public $2 {$n",
[name, getTypeDescAux(m, typ.sons[0], check)])
appcg(m, result, " : public $1 {$n",
[getTypeDescAux(m, typ.sons[0], check)])
hasField = true
else:
result = ropecg(m, "struct $1 {$n $2 Sup;$n",
[name, getTypeDescAux(m, typ.sons[0], check)])
appcg(m, result, " {$n $1 Sup;$n",
[getTypeDescAux(m, typ.sons[0], check)])
hasField = true
else:
result = ropef("struct $1 {$n", [name])
appf(result, " {$n", [name])
var desc = getRecordFields(m, typ, check)
if (desc == nil) and not hasField:
appf(result, "char dummy;$n", [])
@@ -479,8 +499,8 @@ proc getRecordDesc(m: BModule, typ: PType, name: PRope,
app(result, "};" & tnl)
proc getTupleDesc(m: BModule, typ: PType, name: PRope,
check: var TIntSet): PRope =
result = ropef("struct $1 {$n", [name])
check: var TIntSet): PRope =
result = ropef("$1 $2 {$n", [structOrUnion(typ), name])
var desc: PRope = nil
for i in countup(0, sonsLen(typ) - 1):
appf(desc, "$1 Field$2;$n",
@@ -496,49 +516,49 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
# returns only the type's name
var
name, rettype, desc, recdesc: PRope
n: biggestInt
n: BiggestInt
t, et: PType
t = getUniqueType(typ)
if t == nil: InternalError("getTypeDescAux: t == nil")
if t == nil: internalError("getTypeDescAux: t == nil")
if t.sym != nil: useHeader(m, t.sym)
result = getTypePre(m, t)
if result != nil: return
if ContainsOrIncl(check, t.id):
InternalError("cannot generate C type for: " & typeToString(typ))
if containsOrIncl(check, t.id):
internalError("cannot generate C type for: " & typeToString(typ))
# XXX: this BUG is hard to fix -> we need to introduce helper structs,
# but determining when this needs to be done is hard. We should split
# C type generation into an analysis and a code generation phase somehow.
case t.Kind
case t.kind
of tyRef, tyPtr, tyVar:
et = getUniqueType(t.sons[0])
et = getUniqueType(t.lastSon)
if et.kind in {tyArrayConstr, tyArray, tyOpenArray, tyVarargs}:
# this is correct! sets have no proper base type, so we treat
# ``var set[char]`` in `getParamTypeDesc`
et = getUniqueType(elemType(et))
case et.Kind
case et.kind
of tyObject, tyTuple:
# no restriction! We have a forward declaration for structs
name = getTypeForward(m, et)
result = con(name, "*")
IdTablePut(m.typeCache, t, result)
idTablePut(m.typeCache, t, result)
pushType(m, et)
of tySequence:
# no restriction! We have a forward declaration for structs
name = getTypeForward(m, et)
result = con(name, "**")
IdTablePut(m.typeCache, t, result)
idTablePut(m.typeCache, t, result)
pushType(m, et)
else:
# else we have a strong dependency :-(
result = con(getTypeDescAux(m, et, check), "*")
IdTablePut(m.typeCache, t, result)
idTablePut(m.typeCache, t, result)
of tyOpenArray, tyVarargs:
et = getUniqueType(t.sons[0])
result = con(getTypeDescAux(m, et, check), "*")
IdTablePut(m.typeCache, t, result)
idTablePut(m.typeCache, t, result)
of tyProc:
result = getTypeName(t)
IdTablePut(m.typeCache, t, result)
idTablePut(m.typeCache, t, result)
genProcParams(m, t, rettype, desc, check)
if not isImportedType(t):
if t.callConv != ccClosure: # procedure vars may need a closure!
@@ -552,14 +572,15 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
of tySequence:
# we cannot use getTypeForward here because then t would be associated
# with the name of the struct, not with the pointer to the struct:
result = CacheGetType(m.forwTypeCache, t)
result = cacheGetType(m.forwTypeCache, t)
if result == nil:
result = getTypeName(t)
if not isImportedType(t):
appf(m.s[cfsForwardTypes], getForwardStructFormat(), [result])
IdTablePut(m.forwTypeCache, t, result)
assert(CacheGetType(m.typeCache, t) == nil)
IdTablePut(m.typeCache, t, con(result, "*"))
appf(m.s[cfsForwardTypes], getForwardStructFormat(),
[structOrUnion(t), result])
idTablePut(m.forwTypeCache, t, result)
assert(cacheGetType(m.typeCache, t) == nil)
idTablePut(m.typeCache, t, con(result, "*"))
if not isImportedType(t):
if skipTypes(t.sons[0], typedescInst).kind != tyEmpty:
const
@@ -578,18 +599,19 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
if n <= 0:
n = 1 # make an array of at least one element
result = getTypeName(t)
IdTablePut(m.typeCache, t, result)
idTablePut(m.typeCache, t, result)
if not isImportedType(t):
appf(m.s[cfsTypes], "typedef $1 $2[$3];$n",
[getTypeDescAux(m, t.sons[1], check), result, ToRope(n)])
[getTypeDescAux(m, t.sons[1], check), result, toRope(n)])
of tyObject, tyTuple:
result = CacheGetType(m.forwTypeCache, t)
result = cacheGetType(m.forwTypeCache, t)
if result == nil:
result = getTypeName(t)
if not isImportedType(t):
appf(m.s[cfsForwardTypes], getForwardStructFormat(), [result])
IdTablePut(m.forwTypeCache, t, result)
IdTablePut(m.typeCache, t, result) # always call for sideeffects:
appf(m.s[cfsForwardTypes], getForwardStructFormat(),
[structOrUnion(t), result])
idTablePut(m.forwTypeCache, t, result)
idTablePut(m.typeCache, t, result) # always call for sideeffects:
if t.kind != tyTuple: recdesc = getRecordDesc(m, t, result, check)
else: recdesc = getTupleDesc(m, t, result, check)
if not isImportedType(t): app(m.s[cfsTypes], recdesc)
@@ -601,7 +623,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
of 8: result = toRope("NU64")
else:
result = getTypeName(t)
IdTablePut(m.typeCache, t, result)
idTablePut(m.typeCache, t, result)
if not isImportedType(t):
appf(m.s[cfsTypes], "typedef NU8 $1[$2];$n",
[result, toRope(getSize(t))])
@@ -609,7 +631,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
tyIter, tyTypeDesc:
result = getTypeDescAux(m, lastSon(t), check)
else:
InternalError("getTypeDescAux(" & $t.kind & ')')
internalError("getTypeDescAux(" & $t.kind & ')')
result = nil
# fixes bug #145:
excl(check, t.id)
@@ -651,7 +673,9 @@ proc finishTypeDescriptions(m: BModule) =
while i < len(m.typeStack):
discard getTypeDesc(m, m.typeStack[i])
inc(i)
template cgDeclFrmt*(s: PSym): string = s.constraint.strVal
proc genProcHeader(m: BModule, prc: PSym): PRope =
var
rettype, params: PRope
@@ -669,12 +693,16 @@ proc genProcHeader(m: BModule, prc: PSym): PRope =
genProcParams(m, prc.typ, rettype, params, check)
# careful here! don't access ``prc.ast`` as that could reload large parts of
# the object graph!
appf(result, "$1($2, $3)$4",
[toRope(CallingConvToStr[prc.typ.callConv]), rettype, prc.loc.r, params])
if prc.constraint.isNil:
appf(result, "$1($2, $3)$4",
[toRope(CallingConvToStr[prc.typ.callConv]), rettype, prc.loc.r,
params])
else:
result = ropef(prc.cgDeclFrmt, [rettype, prc.loc.r, params])
# ------------------ type info generation -------------------------------------
proc genTypeInfo(m: BModule, typ: PType): PRope
proc genTypeInfo(m: BModule, t: PType): PRope
proc getNimNode(m: BModule): PRope =
result = ropef("$1[$2]", [m.typeNodesName, toRope(m.typeNodes)])
inc(m.typeNodes)
@@ -692,7 +720,7 @@ proc isObjLackingTypeField(typ: PType): bool {.inline.} =
result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and
(typ.sons[0] == nil) or isPureObject(typ))
proc genTypeInfoAuxBase(m: BModule, typ: PType, name, base: PRope) =
proc genTypeInfoAuxBase(m: BModule, typ: PType, name, base: PRope) =
var nimtypeKind: int
#allocMemTI(m, typ, name)
if isObjLackingTypeField(typ):
@@ -730,10 +758,10 @@ proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): PRope =
var objtype = objtype
while lookupInRecord(objtype.n, d.name) == nil:
objtype = objtype.sons[0]
if objType.sym == nil:
InternalError(d.info, "anonymous obj with discriminator")
if objtype.sym == nil:
internalError(d.info, "anonymous obj with discriminator")
result = ropef("NimDT_$1_$2", [
toRope(objType.sym.name.s.mangle), toRope(d.name.s.mangle)])
toRope(objtype.sym.name.s.mangle), toRope(d.name.s.mangle)])
proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): PRope =
discard cgsym(m, "TNimNode")
@@ -901,21 +929,21 @@ type
include ccgtrav
proc genTypeInfo(m: BModule, typ: PType): PRope =
var t = getUniqueType(typ)
proc genTypeInfo(m: BModule, t: PType): PRope =
var t = getUniqueType(t)
result = ropef("NTI$1", [toRope(t.id)])
let owner = typ.skipTypes(typedescPtrs).owner.getModule
if containsOrIncl(m.typeInfoMarker, t.id):
return con("(&".toRope, result, ")".toRope)
let owner = t.skipTypes(typedescPtrs).owner.getModule
if owner != m.module:
# make sure the type info is created in the owner module
discard genTypeInfo(owner.bmod, typ)
# refenrece the type info as extern here
discard genTypeInfo(owner.bmod, t)
# reference the type info as extern here
discard cgsym(m, "TNimType")
discard cgsym(m, "TNimNode")
appf(m.s[cfsVars], "extern TNimType $1; /* $2 */$n",
[result, toRope(typeToString(t))])
return con("(&".toRope, result, ")".toRope)
if ContainsOrIncl(m.typeInfoMarker, t.id):
return con("(&".toRope, result, ")".toRope)
case t.kind
of tyEmpty: result = toRope"0"
of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar:
@@ -941,8 +969,8 @@ proc genTypeInfo(m: BModule, typ: PType): PRope =
# BUGFIX: use consistently RTTI without proper field names; otherwise
# results are not deterministic!
genTupleInfo(m, t, result)
else: InternalError("genTypeInfo(" & $t.kind & ')')
else: internalError("genTypeInfo(" & $t.kind & ')')
result = con("(&".toRope, result, ")".toRope)
proc genTypeSection(m: BModule, n: PNode) =
nil
discard

View File

@@ -22,19 +22,19 @@ proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
of nkPragma:
for i in 0 .. < n.len:
if whichPragma(n[i]) == w: return n[i]
else: nil
else: discard
proc stmtsContainPragma*(n: PNode, w: TSpecialWord): bool =
result = getPragmaStmt(n, w) != nil
proc hashString*(s: string): biggestInt =
proc hashString*(s: string): BiggestInt =
# has to be the same algorithm as system.hashString!
if CPU[targetCPU].bit == 64:
# we have to use the same bitwidth
# as the target CPU
var b = 0'i64
for i in countup(0, len(s) - 1):
b = b +% Ord(s[i])
b = b +% ord(s[i])
b = b +% `shl`(b, 10)
b = b xor `shr`(b, 6)
b = b +% `shl`(b, 3)
@@ -44,7 +44,7 @@ proc hashString*(s: string): biggestInt =
else:
var a = 0'i32
for i in countup(0, len(s) - 1):
a = a +% Ord(s[i]).int32
a = a +% ord(s[i]).int32
a = a +% `shl`(a, 10'i32)
a = a xor `shr`(a, 6'i32)
a = a +% `shl`(a, 3'i32)
@@ -57,7 +57,7 @@ var
gCanonicalTypes: array[TTypeKind, PType]
proc initTypeTables() =
for i in countup(low(TTypeKind), high(TTypeKind)): InitIdTable(gTypeTable[i])
for i in countup(low(TTypeKind), high(TTypeKind)): initIdTable(gTypeTable[i])
proc resetCaches* =
## XXX: fix that more properly
@@ -70,7 +70,7 @@ when false:
for i in countup(low(TTypeKind), high(TTypeKind)):
echo i, " ", gTypeTable[i].counter
proc GetUniqueType*(key: PType): PType =
proc getUniqueType*(key: PType): PType =
# this is a hotspot in the compiler!
if key == nil: return
var k = key.kind
@@ -86,12 +86,12 @@ proc GetUniqueType*(key: PType): PType =
if result == nil:
gCanonicalTypes[k] = key
result = key
of tyTypeDesc, tyTypeClass:
InternalError("value expected, but got a type")
of tyGenericParam:
InternalError("GetUniqueType")
of tyGenericInst, tyDistinct, tyOrdinal, tyMutable, tyConst, tyIter:
result = GetUniqueType(lastSon(key))
of tyTypeDesc, tyTypeClasses, tyGenericParam,
tyFromExpr, tyFieldAccessor:
internalError("GetUniqueType")
of tyGenericInst, tyDistinct, tyOrdinal, tyMutable,
tyConst, tyIter, tyStatic:
result = getUniqueType(lastSon(key))
of tyArrayConstr, tyGenericInvokation, tyGenericBody,
tyOpenArray, tyArray, tySet, tyRange, tyTuple,
tyPtr, tyRef, tySequence, tyForward, tyVarargs, tyProxy, tyVar:
@@ -102,51 +102,50 @@ proc GetUniqueType*(key: PType): PType =
# we have to do a slow linear search because types may need
# to be compared by their structure:
if IdTableHasObjectAsKey(gTypeTable[k], key): return key
if idTableHasObjectAsKey(gTypeTable[k], key): return key
for h in countup(0, high(gTypeTable[k].data)):
var t = PType(gTypeTable[k].data[h].key)
if t != nil and sameBackendType(t, key):
return t
IdTablePut(gTypeTable[k], key, key)
idTablePut(gTypeTable[k], key, key)
result = key
of tyObject:
if tfFromGeneric notin key.flags:
# fast case; lookup per id suffices:
result = PType(IdTableGet(gTypeTable[k], key))
result = PType(idTableGet(gTypeTable[k], key))
if result == nil:
IdTablePut(gTypeTable[k], key, key)
idTablePut(gTypeTable[k], key, key)
result = key
else:
# ugly slow case: need to compare by structure
if IdTableHasObjectAsKey(gTypeTable[k], key): return key
if idTableHasObjectAsKey(gTypeTable[k], key): return key
for h in countup(0, high(gTypeTable[k].data)):
var t = PType(gTypeTable[k].data[h].key)
if t != nil and sameType(t, key):
return t
IdTablePut(gTypeTable[k], key, key)
idTablePut(gTypeTable[k], key, key)
result = key
of tyEnum:
result = PType(IdTableGet(gTypeTable[k], key))
result = PType(idTableGet(gTypeTable[k], key))
if result == nil:
IdTablePut(gTypeTable[k], key, key)
idTablePut(gTypeTable[k], key, key)
result = key
of tyProc:
# tyVar is not 100% correct, but would speeds things up a little:
if key.callConv != ccClosure:
result = key
else:
# ugh, we need the canon here:
if IdTableHasObjectAsKey(gTypeTable[k], key): return key
if idTableHasObjectAsKey(gTypeTable[k], key): return key
for h in countup(0, high(gTypeTable[k].data)):
var t = PType(gTypeTable[k].data[h].key)
if t != nil and sameBackendType(t, key):
return t
IdTablePut(gTypeTable[k], key, key)
idTablePut(gTypeTable[k], key, key)
result = key
proc TableGetType*(tab: TIdTable, key: PType): PObject =
proc tableGetType*(tab: TIdTable, key: PType): PObject =
# returns nil if we need to declare this type
result = IdTableGet(tab, key)
result = idTableGet(tab, key)
if (result == nil) and (tab.counter > 0):
# we have to do a slow linear search because types may need
# to be compared by their structure:
@@ -169,7 +168,7 @@ proc makeLLVMString*(s: string): PRope =
for i in countup(0, len(s) - 1):
if (i + 1) mod MaxLineLength == 0:
app(result, toRope(res))
setlen(res, 0)
setLen(res, 0)
case s[i]
of '\0'..'\x1F', '\x80'..'\xFF', '\"', '\\':
add(res, '\\')
@@ -178,4 +177,4 @@ proc makeLLVMString*(s: string): PRope =
add(res, "\\00\"")
app(result, toRope(res))
InitTypeTables()
initTypeTables()

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2013 Andreas Rumpf
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -14,7 +14,7 @@ import
options, intsets,
nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os,
times, ropes, math, passes, rodread, wordrecg, treetab, cgmeth,
rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases
rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases, lowerings
when options.hasTinyCBackend:
import tccgen
@@ -52,7 +52,7 @@ proc emitLazily(s: PSym): bool {.inline.} =
proc initLoc(result: var TLoc, k: TLocKind, typ: PType, s: TStorageLoc) =
result.k = k
result.s = s
result.t = GetUniqueType(typ)
result.t = getUniqueType(typ)
result.r = nil
result.a = - 1
result.flags = {}
@@ -72,10 +72,15 @@ proc isSimpleConst(typ: PType): bool =
{tyTuple, tyObject, tyArray, tyArrayConstr, tySet, tySequence} and not
(t.kind == tyProc and t.callConv == ccClosure)
proc useStringh(m: BModule) =
if not m.includesStringh:
m.includesStringh = true
discard lists.includeStr(m.headerFiles, "<string.h>")
proc useHeader(m: BModule, sym: PSym) =
if lfHeader in sym.loc.Flags:
if lfHeader in sym.loc.flags:
assert(sym.annex != nil)
discard lists.IncludeStr(m.headerFiles, getStr(sym.annex.path))
discard lists.includeStr(m.headerFiles, getStr(sym.annex.path))
proc cgsym(m: BModule, name: string): PRope
@@ -98,7 +103,7 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
of '0'..'9':
var j = 0
while true:
j = (j * 10) + Ord(frmt[i]) - ord('0')
j = (j * 10) + ord(frmt[i]) - ord('0')
inc(i)
if i >= length or not (frmt[i] in {'0'..'9'}): break
num = j
@@ -111,7 +116,7 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
of 'N':
app(result, rnl)
inc(i)
else: InternalError("ropes: invalid format string $" & frmt[i])
else: internalError("ropes: invalid format string $" & frmt[i])
elif frmt[i] == '#' and frmt[i+1] in IdentStartChars:
inc(i)
var j = i
@@ -123,7 +128,7 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
inc(i, 2)
var j = 0
while frmt[i] in Digits:
j = (j * 10) + Ord(frmt[i]) - ord('0')
j = (j * 10) + ord(frmt[i]) - ord('0')
inc(i)
app(result, cgsym(m, args[j-1].ropeToStr))
var start = i
@@ -189,7 +194,7 @@ when compileTimeRopeFmt:
if i - 1 >= start:
yield (kind: ffLit, value: substr(s, start, i-1), intValue: 0)
macro rfmt(m: BModule, fmt: expr[string], args: varargs[PRope]): expr =
macro rfmt(m: BModule, fmt: static[string], args: varargs[PRope]): expr =
## Experimental optimized rope-formatting operator
## The run-time code it produces will be very fast, but will it speed up
## the compilation of nimrod itself or will the macro execution time
@@ -204,7 +209,7 @@ when compileTimeRopeFmt:
of ffParam:
result.add(args[frag.intValue])
else:
template rfmt(m: BModule, fmt: expr[string], args: varargs[PRope]): expr =
template rfmt(m: BModule, fmt: string, args: varargs[PRope]): expr =
ropecg(m, fmt, args)
proc appcg(m: BModule, c: var PRope, frmt: TFormatStr,
@@ -274,16 +279,22 @@ proc genLineDir(p: BProc, t: PNode) =
if optEmbedOrigSrc in gGlobalOptions:
app(p.s(cpsStmts), con(~"//", t.info.sourceLine, rnl))
genCLineDir(p.s(cpsStmts), t.info.toFullPath, line)
if ({optStackTrace, optEndb} * p.Options == {optStackTrace, optEndb}) and
if ({optStackTrace, optEndb} * p.options == {optStackTrace, optEndb}) and
(p.prc == nil or sfPure notin p.prc.flags):
linefmt(p, cpsStmts, "#endb($1, $2);$n",
line.toRope, makeCString(toFilename(t.info)))
elif ({optLineTrace, optStackTrace} * p.Options ==
elif ({optLineTrace, optStackTrace} * p.options ==
{optLineTrace, optStackTrace}) and
(p.prc == nil or sfPure notin p.prc.flags):
linefmt(p, cpsStmts, "nimln($1, $2);$n",
line.toRope, t.info.quotedFilename)
proc postStmtActions(p: BProc) {.inline.} =
app(p.s(cpsStmts), p.module.injectStmt)
proc accessThreadLocalVar(p: BProc, s: PSym)
proc emulatedThreadVars(): bool {.inline.}
include "ccgtypes.nim"
# ------------------------------ Manager of temporaries ------------------
@@ -308,7 +319,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
takeAddr: bool) =
case analyseObjectWithTypeField(t)
of frNone:
nil
discard
of frHeader:
var r = rdLoc(a)
if not takeAddr: r = ropef("(*$1)", [r])
@@ -340,12 +351,14 @@ proc resetLoc(p: BProc, loc: var TLoc) =
if not isComplexValueType(skipTypes(loc.t, abstractVarRange)):
if containsGcRef:
var nilLoc: TLoc
initLoc(nilLoc, locTemp, loc.t, onStack)
initLoc(nilLoc, locTemp, loc.t, OnStack)
nilLoc.r = toRope("NIM_NIL")
genRefAssign(p, loc, nilLoc, {afSrcIsNil})
else:
linefmt(p, cpsStmts, "$1 = 0;$n", rdLoc(loc))
else:
if optNilCheck in p.options:
linefmt(p, cpsStmts, "#chckNil((void*)$1);$n", addrLoc(loc))
if loc.s != OnStack:
linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
addrLoc(loc), genTypeInfo(p.module, loc.t))
@@ -353,19 +366,24 @@ proc resetLoc(p: BProc, loc: var TLoc) =
# field, so disabling this should be safe:
genObjectInit(p, cpsStmts, loc.t, loc, true)
else:
useStringh(p.module)
linefmt(p, cpsStmts, "memset((void*)$1, 0, sizeof($2));$n",
addrLoc(loc), rdLoc(loc))
# XXX: We can be extra clever here and call memset only
# on the bytes following the m_type field?
genObjectInit(p, cpsStmts, loc.t, loc, true)
proc constructLoc(p: BProc, loc: TLoc, section = cpsStmts) =
proc constructLoc(p: BProc, loc: TLoc, isTemp = false) =
if not isComplexValueType(skipTypes(loc.t, abstractRange)):
linefmt(p, section, "$1 = 0;$n", rdLoc(loc))
linefmt(p, cpsStmts, "$1 = 0;$n", rdLoc(loc))
else:
linefmt(p, section, "memset((void*)$1, 0, sizeof($2));$n",
addrLoc(loc), rdLoc(loc))
genObjectInit(p, section, loc.t, loc, true)
if not isTemp or containsGarbageCollectedRef(loc.t):
# don't use memset for temporary values for performance if we can
# avoid it:
useStringh(p.module)
linefmt(p, cpsStmts, "memset((void*)$1, 0, sizeof($2));$n",
addrLoc(loc), rdLoc(loc))
genObjectInit(p, cpsStmts, loc.t, loc, true)
proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
if sfNoInit notin v.flags:
@@ -379,12 +397,6 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
if not immediateAsgn:
constructLoc(p, v.loc)
proc initTemp(p: BProc, tmp: var TLoc) =
# XXX: This is still suspicious.
# Objects should always be constructed?
if containsGarbageCollectedRef(tmp.t) or isInvalidReturnType(tmp.t):
constructLoc(p, tmp)
proc getTemp(p: BProc, t: PType, result: var TLoc) =
inc(p.labels)
if gCmd == cmdCompileToLLVM:
@@ -397,7 +409,7 @@ proc getTemp(p: BProc, t: PType, result: var TLoc) =
result.t = getUniqueType(t)
result.s = OnStack
result.flags = {}
initTemp(p, result)
constructLoc(p, result, isTemp=true)
proc keepAlive(p: BProc, toKeepAlive: TLoc) =
when false:
@@ -419,6 +431,7 @@ proc keepAlive(p: BProc, toKeepAlive: TLoc) =
if not isComplexValueType(skipTypes(toKeepAlive.t, abstractVarRange)):
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(result), rdLoc(toKeepAlive))
else:
useStringh(p.module)
linefmt(p, cpsStmts,
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
addrLoc(result), addrLoc(toKeepAlive), rdLoc(result))
@@ -486,18 +499,21 @@ proc assignLocalVar(p: BProc, s: PSym) =
fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack)
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
var decl = getTypeDesc(p.module, s.loc.t)
if sfRegister in s.flags: app(decl, " register")
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
# app(decl, " GC_GUARD")
if sfVolatile in s.flags or p.nestedTryStmts.len > 0:
app(decl, " volatile")
appf(decl, " $1;$n", [s.loc.r])
if s.constraint.isNil:
if sfRegister in s.flags: app(decl, " register")
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
# app(decl, " GC_GUARD")
if sfVolatile in s.flags or p.nestedTryStmts.len > 0:
app(decl, " volatile")
appf(decl, " $1;$n", [s.loc.r])
else:
decl = ropef(s.cgDeclFrmt & ";$n", decl, s.loc.r)
line(p, cpsLocals, decl)
localDebugInfo(p, s)
include ccgthreadvars
proc VarInDynamicLib(m: BModule, sym: PSym)
proc varInDynamicLib(m: BModule, sym: PSym)
proc mangleDynLibProc(sym: PSym): PRope
proc assignGlobalVar(p: BProc, s: PSym) =
@@ -506,8 +522,8 @@ proc assignGlobalVar(p: BProc, s: PSym) =
if lfDynamicLib in s.loc.flags:
var q = findPendingModule(p.module, s)
if q != nil and not ContainsOrIncl(q.declaredThings, s.id):
VarInDynamicLib(q, s)
if q != nil and not containsOrIncl(q.declaredThings, s.id):
varInDynamicLib(q, s)
else:
s.loc.r = mangleDynLibProc(s)
return
@@ -516,11 +532,17 @@ proc assignGlobalVar(p: BProc, s: PSym) =
if sfThread in s.flags:
declareThreadVar(p.module, s, sfImportc in s.flags)
else:
if sfImportc in s.flags: app(p.module.s[cfsVars], "extern ")
app(p.module.s[cfsVars], getTypeDesc(p.module, s.loc.t))
if sfRegister in s.flags: app(p.module.s[cfsVars], " register")
if sfVolatile in s.flags: app(p.module.s[cfsVars], " volatile")
appf(p.module.s[cfsVars], " $1;$n", [s.loc.r])
var decl: PRope = nil
var td = getTypeDesc(p.module, s.loc.t)
if s.constraint.isNil:
if sfImportc in s.flags: app(decl, "extern ")
app(decl, td)
if sfRegister in s.flags: app(decl, " register")
if sfVolatile in s.flags: app(decl, " volatile")
appf(decl, " $1;$n", [s.loc.r])
else:
decl = ropef(s.cgDeclFrmt & ";$n", td, s.loc.r)
app(p.module.s[cfsVars], decl)
if p.withinLoop > 0:
# fixes tests/run/tzeroarray:
resetLoc(p, s.loc)
@@ -556,7 +578,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc)
proc genProcPrototype(m: BModule, sym: PSym)
proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc)
proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags)
proc intLiteral(i: biggestInt): PRope
proc intLiteral(i: BiggestInt): PRope
proc genLiteral(p: BProc, n: PNode): PRope
proc initLocExpr(p: BProc, e: PNode, result: var TLoc) =
@@ -588,7 +610,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
var s: TStringSeq = @[]
libCandidates(lib.path.strVal, s)
if gVerbosity >= 2:
MsgWriteln("Dependency: " & lib.path.strVal)
msgWriteln("Dependency: " & lib.path.strVal)
var loadlib: PRope = nil
for i in countup(0, high(s)):
inc(m.labels)
@@ -610,7 +632,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
"if (!($1 = #nimLoadLibrary($2))) #nimLoadLibraryError($2);$n",
[tmp, rdLoc(dest)])
if lib.name == nil: InternalError("loadDynamicLib")
if lib.name == nil: internalError("loadDynamicLib")
proc mangleDynLibProc(sym: PSym): PRope =
if sfCompilerProc in sym.flags:
@@ -619,7 +641,7 @@ proc mangleDynLibProc(sym: PSym): PRope =
else:
result = ropef("Dl_$1", [toRope(sym.id)])
proc SymInDynamicLib(m: BModule, sym: PSym) =
proc symInDynamicLib(m: BModule, sym: PSym) =
var lib = sym.annex
let isCall = isGetProcAddr(lib)
var extname = sym.loc.r
@@ -643,14 +665,14 @@ proc SymInDynamicLib(m: BModule, sym: PSym) =
params, cstringLit(m, m.s[cfsDynLibInit], ropeToStr(extname))])
var last = lastSon(n)
if last.kind == nkHiddenStdConv: last = last.sons[1]
InternalAssert(last.kind == nkStrLit)
internalAssert(last.kind == nkStrLit)
let idx = last.strVal
if idx.len == 0:
app(m.initProc.s(cpsStmts), load)
elif idx.len == 1 and idx[0] in {'0'..'9'}:
app(m.extensionLoaders[idx[0]], load)
else:
InternalError(sym.info, "wrong index: " & idx)
internalError(sym.info, "wrong index: " & idx)
else:
appcg(m, m.s[cfsDynLibInit],
"\t$1 = ($2) #nimGetProcAddr($3, $4);$n",
@@ -660,7 +682,7 @@ proc SymInDynamicLib(m: BModule, sym: PSym) =
"$1 = linkonce global $2 zeroinitializer$n",
[sym.loc.r, getTypeDesc(m, sym.loc.t)])
proc VarInDynamicLib(m: BModule, sym: PSym) =
proc varInDynamicLib(m: BModule, sym: PSym) =
var lib = sym.annex
var extname = sym.loc.r
loadDynamicLib(m, lib)
@@ -675,7 +697,7 @@ proc VarInDynamicLib(m: BModule, sym: PSym) =
appf(m.s[cfsVars], "$2* $1;$n",
[sym.loc.r, getTypeDesc(m, sym.loc.t)])
proc SymInDynamicLibPartial(m: BModule, sym: PSym) =
proc symInDynamicLibPartial(m: BModule, sym: PSym) =
sym.loc.r = mangleDynLibProc(sym)
sym.typ.sym = nil # generate a new name
@@ -683,10 +705,10 @@ proc cgsym(m: BModule, name: string): PRope =
var sym = magicsys.getCompilerProc(name)
if sym != nil:
case sym.kind
of skProc, skMethod, skConverter, skIterator: genProc(m, sym)
of skProc, skMethod, skConverter, skIterators: genProc(m, sym)
of skVar, skResult, skLet: genVarPrototype(m, sym)
of skType: discard getTypeDesc(m, sym.typ)
else: InternalError("cgsym: " & name)
else: internalError("cgsym: " & name)
else:
# we used to exclude the system module from this check, but for DLL
# generation support this sloppyness leads to hard to detect bugs, so
@@ -702,13 +724,13 @@ proc generateHeaders(m: BModule) =
appf(m.s[cfsHeaders], "$N#include \"$1\"$N", [toRope(it.data)])
else:
appf(m.s[cfsHeaders], "$N#include $1$N", [toRope(it.data)])
it = PStrEntry(it.Next)
it = PStrEntry(it.next)
proc retIsNotVoid(s: PSym): bool =
result = (s.typ.sons[0] != nil) and not isInvalidReturnType(s.typ.sons[0])
proc initFrame(p: BProc, procname, filename: PRope): PRope =
discard cgsym(p.module, "pushFrame")
discard cgsym(p.module, "nimFrame")
if p.maxFrameLen > 0:
discard cgsym(p.module, "TVarSlot")
result = rfmt(nil, "\tnimfrs($1, $2, $3, $4)$N",
@@ -725,7 +747,7 @@ proc closureSetup(p: BProc, prc: PSym) =
# prc.ast[paramsPos].last contains the type we're after:
var ls = lastSon(prc.ast[paramsPos])
if ls.kind != nkSym:
InternalError(prc.info, "closure generation failed")
internalError(prc.info, "closure generation failed")
var env = ls.sym
#echo "created environment: ", env.id, " for ", prc.name.s
assignLocalVar(p, env)
@@ -739,6 +761,8 @@ proc genProcAux(m: BModule, prc: PSym) =
var returnStmt: PRope = nil
assert(prc.ast != nil)
if sfPure notin prc.flags and prc.typ.sons[0] != nil:
if resultPos >= prc.ast.len:
internalError(prc.info, "proc has no result symbol")
var res = prc.ast.sons[resultPos].sym # get result symbol
if not isInvalidReturnType(prc.typ.sons[0]):
if sfNoInit in prc.flags: incl(res.flags, sfNoInit)
@@ -753,6 +777,7 @@ proc genProcAux(m: BModule, prc: PSym) =
if skipTypes(res.typ, abstractInst).kind == tyArray:
incl(res.loc.flags, lfIndirect)
res.loc.s = OnUnknown
for i in countup(1, sonsLen(prc.typ.n) - 1):
var param = prc.typ.n.sons[i].sym
if param.typ.isCompileTimeOnly: continue
@@ -760,7 +785,9 @@ proc genProcAux(m: BModule, prc: PSym) =
closureSetup(p, prc)
genStmts(p, prc.getBody) # modifies p.locals, p.init, etc.
var generatedProc: PRope
if sfPure in prc.flags:
if sfPure in prc.flags:
if hasNakedDeclspec in extccomp.CC[extccomp.cCompiler].props:
header = con("__declspec(naked) ", header)
generatedProc = rfmt(nil, "$N$1 {$n$2$3$4}$N$N",
header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts))
else:
@@ -768,7 +795,7 @@ proc genProcAux(m: BModule, prc: PSym) =
app(generatedProc, initGCFrame(p))
if optStackTrace in prc.options:
app(generatedProc, p.s(cpsLocals))
var procname = CStringLit(p, generatedProc, prc.name.s)
var procname = cstringLit(p, generatedProc, prc.name.s)
app(generatedProc, initFrame(p, procname, prc.info.quotedFilename))
else:
app(generatedProc, p.s(cpsLocals))
@@ -786,15 +813,18 @@ proc genProcAux(m: BModule, prc: PSym) =
proc genProcPrototype(m: BModule, sym: PSym) =
useHeader(m, sym)
if lfNoDecl in sym.loc.Flags: return
if lfDynamicLib in sym.loc.Flags:
if lfNoDecl in sym.loc.flags: return
if lfDynamicLib in sym.loc.flags:
if getModule(sym).id != m.module.id and
not ContainsOrIncl(m.declaredThings, sym.id):
not containsOrIncl(m.declaredThings, sym.id):
app(m.s[cfsVars], rfmt(nil, "extern $1 $2;$n",
getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym)))
if gCmd == cmdCompileToLLVM: incl(sym.loc.flags, lfIndirect)
elif not ContainsOrIncl(m.declaredProtos, sym.id):
app(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", genProcHeader(m, sym)))
elif not containsOrIncl(m.declaredProtos, sym.id):
var header = genProcHeader(m, sym)
if sfPure in sym.flags and hasNakedAttribute in CC[cCompiler].props:
header.app(" __attribute__((naked))")
app(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header))
proc genProcNoForward(m: BModule, prc: PSym) =
fillProcLoc(prc)
@@ -804,21 +834,21 @@ proc genProcNoForward(m: BModule, prc: PSym) =
discard cgsym(m, prc.name.s)
return
genProcPrototype(m, prc)
if lfNoDecl in prc.loc.Flags: nil
if lfNoDecl in prc.loc.flags: discard
elif prc.typ.callConv == ccInline:
# We add inline procs to the calling module to enable C based inlining.
# This also means that a check with ``q.declaredThings`` is wrong, we need
# a check for ``m.declaredThings``.
if not ContainsOrIncl(m.declaredThings, prc.id): genProcAux(m, prc)
if not containsOrIncl(m.declaredThings, prc.id): genProcAux(m, prc)
elif lfDynamicLib in prc.loc.flags:
var q = findPendingModule(m, prc)
if q != nil and not ContainsOrIncl(q.declaredThings, prc.id):
SymInDynamicLib(q, prc)
if q != nil and not containsOrIncl(q.declaredThings, prc.id):
symInDynamicLib(q, prc)
else:
SymInDynamicLibPartial(m, prc)
symInDynamicLibPartial(m, prc)
elif sfImportc notin prc.flags:
var q = findPendingModule(m, prc)
if q != nil and not ContainsOrIncl(q.declaredThings, prc.id):
if q != nil and not containsOrIncl(q.declaredThings, prc.id):
genProcAux(q, prc)
proc requestConstImpl(p: BProc, sym: PSym) =
@@ -826,15 +856,15 @@ proc requestConstImpl(p: BProc, sym: PSym) =
useHeader(m, sym)
if sym.loc.k == locNone:
fillLoc(sym.loc, locData, sym.typ, mangleName(sym), OnUnknown)
if lfNoDecl in sym.loc.Flags: return
if lfNoDecl in sym.loc.flags: return
# declare implementation:
var q = findPendingModule(m, sym)
if q != nil and not ContainsOrIncl(q.declaredThings, sym.id):
if q != nil and not containsOrIncl(q.declaredThings, sym.id):
assert q.initProc.module == q
appf(q.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(q, sym.typ), sym.loc.r, genConstExpr(q.initProc, sym.ast)])
# declare header:
if q != m and not ContainsOrIncl(m.declaredThings, sym.id):
if q != m and not containsOrIncl(m.declaredThings, sym.id):
assert(sym.loc.r != nil)
let headerDecl = ropef("extern NIM_CONST $1 $2;$n",
[getTypeDesc(m, sym.loc.t), sym.loc.r])
@@ -847,21 +877,21 @@ proc isActivated(prc: PSym): bool = prc.typ != nil
proc genProc(m: BModule, prc: PSym) =
if sfBorrow in prc.flags or not isActivated(prc): return
fillProcLoc(prc)
if {sfForward, sfFromGeneric} * prc.flags != {}: addForwardedProc(m, prc)
else:
if sfForward in prc.flags: addForwardedProc(m, prc)
else:
genProcNoForward(m, prc)
if {sfExportc, sfCompilerProc} * prc.flags == {sfExportc} and
generatedHeader != nil and lfNoDecl notin prc.loc.Flags:
generatedHeader != nil and lfNoDecl notin prc.loc.flags:
genProcPrototype(generatedHeader, prc)
if prc.typ.callConv == ccInline:
if not ContainsOrIncl(generatedHeader.declaredThings, prc.id):
if not containsOrIncl(generatedHeader.declaredThings, prc.id):
genProcAux(generatedHeader, prc)
proc genVarPrototypeAux(m: BModule, sym: PSym) =
assert(sfGlobal in sym.flags)
useHeader(m, sym)
fillLoc(sym.loc, locGlobalVar, sym.typ, mangleName(sym), OnHeap)
if (lfNoDecl in sym.loc.Flags) or ContainsOrIncl(m.declaredThings, sym.id):
if (lfNoDecl in sym.loc.flags) or containsOrIncl(m.declaredThings, sym.id):
return
if sym.owner.id != m.module.id:
# else we already have the symbol generated!
@@ -883,29 +913,29 @@ proc addIntTypes(result: var PRope) {.inline.} =
appf(result, "#define NIM_INTBITS $1", [
platform.CPU[targetCPU].intSize.toRope])
proc getCopyright(cfilenoext: string): PRope =
if optCompileOnly in gGlobalOptions:
result = ropeff("/* Generated by Nimrod Compiler v$1 */$n" &
"/* (c) 2012 Andreas Rumpf */$n" &
"/* The generated code is subject to the original license. */$n",
"; Generated by Nimrod Compiler v$1$n" &
"; (c) 2012 Andreas Rumpf$n", [toRope(versionAsString)])
else:
result = ropeff("/* Generated by Nimrod Compiler v$1 */$n" &
"/* (c) 2012 Andreas Rumpf */$n" &
"/* The generated code is subject to the original license. */$n" &
"/* Compiled for: $2, $3, $4 */$n" &
"/* Command for C compiler:$n $5 */$n",
"; Generated by Nimrod Compiler v$1$n" &
"; (c) 2012 Andreas Rumpf$n" &
"; Compiled for: $2, $3, $4$n" &
"; Command for LLVM compiler:$n $5$n", [toRope(versionAsString),
toRope(platform.OS[targetOS].name),
toRope(platform.CPU[targetCPU].name),
toRope(extccomp.CC[extccomp.ccompiler].name),
proc getCopyright(cfilenoext: string): PRope =
if optCompileOnly in gGlobalOptions:
result = ropeff("/* Generated by Nimrod Compiler v$1 */$N" &
"/* (c) 2014 Andreas Rumpf */$N" &
"/* The generated code is subject to the original license. */$N",
"; Generated by Nimrod Compiler v$1$N" &
"; (c) 2012 Andreas Rumpf$N", [toRope(VersionAsString)])
else:
result = ropeff("/* Generated by Nimrod Compiler v$1 */$N" &
"/* (c) 2014 Andreas Rumpf */$N" &
"/* The generated code is subject to the original license. */$N" &
"/* Compiled for: $2, $3, $4 */$N" &
"/* Command for C compiler:$n $5 */$N",
"; Generated by Nimrod Compiler v$1$N" &
"; (c) 2014 Andreas Rumpf$N" &
"; Compiled for: $2, $3, $4$N" &
"; Command for LLVM compiler:$N $5$N", [toRope(VersionAsString),
toRope(platform.OS[targetOS].name),
toRope(platform.CPU[targetCPU].name),
toRope(extccomp.CC[extccomp.cCompiler].name),
toRope(getCompileCFileCmd(cfilenoext))])
proc getFileHeader(cfilenoext: string): PRope =
proc getFileHeader(cfilenoext: string): PRope =
result = getCopyright(cfilenoext)
addIntTypes(result)
@@ -913,46 +943,72 @@ proc genFilenames(m: BModule): PRope =
discard cgsym(m, "dbgRegisterFilename")
result = nil
for i in 0.. <fileInfos.len:
result.appf("dbgRegisterFilename($1);$n", fileInfos[i].projPath.makeCString)
result.appf("dbgRegisterFilename($1);$N", fileInfos[i].projPath.makeCString)
proc genMainProc(m: BModule) =
proc genMainProc(m: BModule) =
const
CommonMainBody =
"\tsystemDatInit();$n" &
PreMainBody =
"\tsystemDatInit();$N" &
"\tsystemInit();$N" &
"$1" &
"$2" &
"$3" &
"$4"
MainProcs =
"\tNimMain();$N"
MainProcsWithResult =
MainProcs & "\treturn nim_program_result;$N"
NimMainBody =
"N_CDECL(void, NimMain)(void) {$N" &
"\tPreMain();$N" &
"$1" &
"$2" &
"\tsystemInit();$n" &
"$3" &
"$4"
PosixNimMain =
"int cmdCount;$n" &
"char** cmdLine;$n" &
"char** gEnv;$n" &
"N_CDECL(void, NimMain)(void) {$n" &
CommonMainBody & "}$n"
PosixCMain = "int main(int argc, char** args, char** env) {$n" &
"\tcmdLine = args;$n" & "\tcmdCount = argc;$n" & "\tgEnv = env;$n" &
"\tNimMain();$n" & "\treturn nim_program_result;$n" & "}$n"
StandaloneCMain = "int main(void) {$n" &
"\tNimMain();$n" &
"\treturn 0;$n" & "}$n"
WinNimMain = "N_CDECL(void, NimMain)(void) {$n" &
CommonMainBody & "}$n"
WinCMain = "N_STDCALL(int, WinMain)(HINSTANCE hCurInstance, $n" &
" HINSTANCE hPrevInstance, $n" &
" LPSTR lpCmdLine, int nCmdShow) {$n" &
"\tNimMain();$n" & "\treturn nim_program_result;$n" & "}$n"
WinNimDllMain = "N_LIB_EXPORT N_CDECL(void, NimMain)(void) {$n" &
CommonMainBody & "}$n"
WinCDllMain =
"BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, $n" &
" LPVOID lpvReserved) {$n" &
"\tif(fwdreason == DLL_PROCESS_ATTACH) NimMain();$n" &
"\treturn 1;$n" & "}$n"
"}$N$N"
PosixNimMain =
"int cmdCount;$N" &
"char** cmdLine;$N" &
"char** gEnv;$N" &
NimMainBody
PosixCMain =
"int main(int argc, char** args, char** env) {$N" &
"\tcmdLine = args;$N" &
"\tcmdCount = argc;$N" &
"\tgEnv = env;$N" &
MainProcsWithResult &
"}$N$N"
StandaloneCMain =
"int main(void) {$N" &
MainProcs &
"\treturn 0;$N" &
"}$N$N"
WinNimMain = NimMainBody
WinCMain = "N_STDCALL(int, WinMain)(HINSTANCE hCurInstance, $N" &
" HINSTANCE hPrevInstance, $N" &
" LPSTR lpCmdLine, int nCmdShow) {$N" &
MainProcsWithResult & "}$N$N"
WinNimDllMain = "N_LIB_EXPORT " & NimMainBody
WinCDllMain =
"BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, $N" &
" LPVOID lpvReserved) {$N" &
"\tif(fwdreason == DLL_PROCESS_ATTACH) {$N" & MainProcs & "}$N" &
"\treturn 1;$N}$N$N"
PosixNimDllMain = WinNimDllMain
PosixCDllMain =
"void NIM_POSIX_INIT NimMainInit(void) {$n" &
"\tNimMain();$n}$n"
PosixCDllMain =
"void NIM_POSIX_INIT NimMainInit(void) {$N" &
MainProcs &
"}$N$N"
var nimMain, otherMain: TFormatStr
if platform.targetOS == osWindows and
gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}:
@@ -962,10 +1018,10 @@ proc genMainProc(m: BModule) =
else:
nimMain = WinNimDllMain
otherMain = WinCDllMain
discard lists.IncludeStr(m.headerFiles, "<windows.h>")
discard lists.includeStr(m.headerFiles, "<windows.h>")
elif optGenDynLib in gGlobalOptions:
nimMain = posixNimDllMain
otherMain = posixCDllMain
nimMain = PosixNimDllMain
otherMain = PosixCDllMain
elif platform.targetOS == osStandalone:
nimMain = PosixNimMain
otherMain = StandaloneCMain
@@ -978,18 +1034,25 @@ proc genMainProc(m: BModule) =
let initStackBottomCall = if emulatedThreadVars() or
platform.targetOS == osStandalone: "".toRope
else: ropecg(m, "\t#initStackBottom();$n")
else: ropecg(m, "\t#initStackBottom();$N")
inc(m.labels)
appcg(m, m.s[cfsProcs], nimMain, [mainDatInit, initStackBottomCall,
gBreakpoints, mainModInit, toRope(m.labels)])
appcg(m, m.s[cfsProcs], "void PreMain() {$N" & PreMainBody & "}$N$N", [
mainDatInit, initStackBottomCall, gBreakpoints, otherModsInit])
appcg(m, m.s[cfsProcs], nimMain, [mainModInit, toRope(m.labels)])
if optNoMain notin gGlobalOptions:
appcg(m, m.s[cfsProcs], otherMain, [])
proc getInitName(m: PSym): PRope =
result = ropeff("$1Init", "@$1Init", [toRope(m.name.s)])
proc getDatInitName(m: PSym): PRope =
result = ropeff("$1DatInit", "@$1DatInit", [toRope(m.name.s)])
proc getSomeInitName(m: PSym, suffix: string): PRope =
assert m.kind == skModule
assert m.owner.kind == skPackage
if {sfSystemModule, sfMainModule} * m.flags == {}:
result = m.owner.name.s.mangle.toRope
result.app m.name.s
result.app suffix
proc getInitName(m: PSym): PRope = getSomeInitName(m, "Init")
proc getDatInitName(m: PSym): PRope = getSomeInitName(m, "DatInit")
proc registerModuleToMain(m: PSym) =
var
@@ -999,13 +1062,17 @@ proc registerModuleToMain(m: PSym) =
"declare void $1() noinline$N", [init])
appff(mainModProcs, "N_NOINLINE(void, $1)(void);$N",
"declare void $1() noinline$N", [datInit])
if not (sfSystemModule in m.flags):
appff(mainModInit, "\t$1();$n", "call void ()* $1$n", [init])
appff(mainDatInit, "\t$1();$n", "call void ()* $1$n", [datInit])
if sfSystemModule notin m.flags:
appff(mainDatInit, "\t$1();$N", "call void ()* $1$n", [datInit])
let initCall = ropeff("\t$1();$N", "call void ()* $1$n", [init])
if sfMainModule in m.flags:
app(mainModInit, initCall)
else:
app(otherModsInit, initCall)
proc genInitCode(m: BModule) =
var initname = getInitName(m.module)
var prc = ropeff("N_NOINLINE(void, $1)(void) {$n",
var prc = ropeff("N_NOINLINE(void, $1)(void) {$N",
"define void $1() noinline {$n", [initname])
if m.typeNodes > 0:
appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n",
@@ -1017,35 +1084,38 @@ proc genInitCode(m: BModule) =
app(prc, initGCFrame(m.initProc))
app(prc, genSectionStart(cpsLocals))
app(prc, m.initProc.s(cpsLocals))
app(prc, m.preInitProc.s(cpsLocals))
app(prc, m.initProc.s(cpsLocals))
app(prc, m.postInitProc.s(cpsLocals))
app(prc, genSectionEnd(cpsLocals))
if optStackTrace in m.initProc.options and not m.FrameDeclared:
if optStackTrace in m.initProc.options and not m.frameDeclared:
# BUT: the generated init code might depend on a current frame, so
# declare it nevertheless:
m.FrameDeclared = true
if not m.PreventStackTrace:
var procname = CStringLit(m.initProc, prc, m.module.name.s)
m.frameDeclared = true
if not m.preventStackTrace:
var procname = cstringLit(m.initProc, prc, m.module.name.s)
app(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename))
else:
app(prc, ~"\tvolatile TFrame F; F.len = 0;$N")
app(prc, ~"\tTFrame F; F.len = 0;$N")
app(prc, genSectionStart(cpsInit))
app(prc, m.preInitProc.s(cpsInit))
app(prc, m.initProc.s(cpsInit))
app(prc, m.postInitProc.s(cpsInit))
app(prc, genSectionEnd(cpsInit))
app(prc, genSectionStart(cpsStmts))
app(prc, m.preInitProc.s(cpsStmts))
app(prc, m.initProc.s(cpsStmts))
app(prc, m.postInitProc.s(cpsStmts))
app(prc, genSectionEnd(cpsStmts))
if optStackTrace in m.initProc.options and not m.PreventStackTrace:
if optStackTrace in m.initProc.options and not m.preventStackTrace:
app(prc, deinitFrame(m.initProc))
app(prc, deinitGCFrame(m.initProc))
appf(prc, "}$N$N")
prc.appff("N_NOINLINE(void, $1)(void) {$n",
prc.appff("N_NOINLINE(void, $1)(void) {$N",
"define void $1() noinline {$n", [getDatInitName(m.module)])
for i in cfsTypeInit1..cfsDynLibInit:
@@ -1083,9 +1153,17 @@ proc newPreInitProc(m: BModule): BProc =
# little hack so that unique temporaries are generated:
result.labels = 100_000
proc newPostInitProc(m: BModule): BProc =
result = newProc(nil, m)
# little hack so that unique temporaries are generated:
result.labels = 200_000
proc initProcOptions(m: BModule): TOptions =
if sfSystemModule in m.module.flags: gOptions-{optStackTrace} else: gOptions
proc rawNewModule(module: PSym, filename: string): BModule =
new(result)
InitLinkedList(result.headerFiles)
initLinkedList(result.headerFiles)
result.declaredThings = initIntSet()
result.declaredProtos = initIntSet()
result.cfilename = filename
@@ -1095,34 +1173,41 @@ proc rawNewModule(module: PSym, filename: string): BModule =
result.module = module
result.typeInfoMarker = initIntSet()
result.initProc = newProc(nil, result)
result.initProc.options = gOptions
result.initProc.options = initProcOptions(result)
result.preInitProc = newPreInitProc(result)
result.postInitProc = newPostInitProc(result)
initNodeTable(result.dataCache)
result.typeStack = @[]
result.forwardedProcs = @[]
result.typeNodesName = getTempName()
result.nimTypesName = getTempName()
result.PreventStackTrace = sfSystemModule in module.flags
# no line tracing for the init sections of the system module so that we
# don't generate a TFrame which can confuse the stack botton initialization:
if sfSystemModule in module.flags:
result.preventStackTrace = true
excl(result.preInitProc.options, optStackTrace)
excl(result.postInitProc.options, optStackTrace)
proc nullify[T](arr: var T) =
for i in low(arr)..high(arr):
arr[i] = nil
proc resetModule*(m: var BModule) =
proc resetModule*(m: BModule) =
# between two compilations in CAAS mode, we can throw
# away all the data that was written to disk
InitLinkedList(m.headerFiles)
initLinkedList(m.headerFiles)
m.declaredProtos = initIntSet()
initIdTable(m.forwTypeCache)
m.initProc = newProc(nil, m)
m.initProc.options = gOptions
m.initProc.options = initProcOptions(m)
m.preInitProc = newPreInitProc(m)
m.postInitProc = newPostInitProc(m)
initNodeTable(m.dataCache)
m.typeStack = @[]
m.forwardedProcs = @[]
m.typeNodesName = getTempName()
m.nimTypesName = getTempName()
m.PreventStackTrace = sfSystemModule in m.module.flags
m.preventStackTrace = sfSystemModule in m.module.flags
nullify m.s
m.usesThreadVars = false
m.typeNodes = 0
@@ -1149,11 +1234,11 @@ proc resetCgenModules* =
for m in cgenModules(): resetModule(m)
proc rawNewModule(module: PSym): BModule =
result = rawNewModule(module, module.filename)
result = rawNewModule(module, module.position.int32.toFullPath)
proc newModule(module: PSym): BModule =
# we should create only one cgen module for each module sym
InternalAssert getCgenModule(module) == nil
internalAssert getCgenModule(module) == nil
result = rawNewModule(module)
growCache gModules, module.position
@@ -1161,7 +1246,7 @@ proc newModule(module: PSym): BModule =
if (optDeadCodeElim in gGlobalOptions):
if (sfDeadCodeElim in module.flags):
InternalError("added pending module twice: " & module.filename)
internalError("added pending module twice: " & module.filename)
proc myOpen(module: PSym): PPassContext =
result = newModule(module)
@@ -1192,7 +1277,7 @@ proc writeHeader(m: BModule) =
writeRope(result, m.filename)
proc getCFile(m: BModule): string =
result = changeFileExt(completeCFilePath(m.cfilename), cExt)
result = changeFileExt(completeCFilePath(m.cfilename.withPackageName), cExt)
proc myOpenCached(module: PSym, rd: PRodReader): PPassContext =
assert optSymbolFiles in gGlobalOptions
@@ -1204,7 +1289,7 @@ proc myProcess(b: PPassContext, n: PNode): PNode =
result = n
if b == nil or passes.skipCodegen(n): return
var m = BModule(b)
m.initProc.options = gOptions
m.initProc.options = initProcOptions(m)
genStmts(m.initProc, n)
proc finishModule(m: BModule) =
@@ -1214,19 +1299,19 @@ proc finishModule(m: BModule) =
# a ``for`` loop here
var prc = m.forwardedProcs[i]
if sfForward in prc.flags:
InternalError(prc.info, "still forwarded: " & prc.name.s)
internalError(prc.info, "still forwarded: " & prc.name.s)
genProcNoForward(m, prc)
inc(i)
assert(gForwardedProcsCounter >= i)
dec(gForwardedProcsCounter, i)
setlen(m.forwardedProcs, 0)
setLen(m.forwardedProcs, 0)
proc shouldRecompile(code: PRope, cfile, cfilenoext: string): bool =
result = true
if optForceFullMake notin gGlobalOptions:
var objFile = toObjFile(cfilenoext)
if writeRopeIfNotEqual(code, cfile): return
if ExistsFile(objFile) and os.FileNewer(objFile, cfile): result = false
if existsFile(objFile) and os.fileNewer(objFile, cfile): result = false
else:
writeRope(code, cfile)
@@ -1247,7 +1332,7 @@ proc writeModule(m: BModule, pending: bool) =
if sfMainModule in m.module.flags:
# generate main file:
app(m.s[cfsProcHeaders], mainModProcs)
GenerateThreadVarsSize(m)
generateThreadVarsSize(m)
var code = genModule(m, cfilenoext)
when hasTinyCBackend:
@@ -1264,7 +1349,7 @@ proc writeModule(m: BModule, pending: bool) =
var code = genModule(m, cfilenoext)
writeRope(code, cfile)
addFileToCompile(cfilenoext)
elif not ExistsFile(toObjFile(cfilenoext)):
elif not existsFile(toObjFile(cfilenoext)):
# Consider: first compilation compiles ``system.nim`` and produces
# ``system.c`` but then compilation fails due to an error. This means
# that ``system.o`` is missing, so we need to call the C compiler for it:
@@ -1291,7 +1376,7 @@ proc myClose(b: PPassContext, n: PNode): PNode =
if b == nil or passes.skipCodegen(n): return
var m = BModule(b)
if n != nil:
m.initProc.options = gOptions
m.initProc.options = initProcOptions(m)
genStmts(m.initProc, n)
# cached modules need to registered too:
registerModuleToMain(m.module)

View File

@@ -41,7 +41,8 @@ type
ctInt, ctInt8, ctInt16, ctInt32, ctInt64,
ctFloat, ctFloat32, ctFloat64, ctFloat128,
ctUInt, ctUInt8, ctUInt16, ctUInt32, ctUInt64,
ctArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc, ctCString
ctArray, ctPtrToArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc,
ctCString
TCFileSections* = array[TCFileSection, PRope] # represents a generated C file
TCProcSection* = enum # the sections a generated C proc consists of
cpsLocals, # section of local variables for C proc
@@ -57,17 +58,20 @@ type
sections*: TCProcSections # the code beloging
isLoop*: bool # whether block is a loop
nestedTryStmts*: int16 # how many try statements is it nested into
nestedExceptStmts*: int16 # how many except statements is it nested into
frameLen*: int16
TCProc{.final.} = object # represents C proc that is currently generated
prc*: PSym # the Nimrod proc that this C proc belongs to
BeforeRetNeeded*: bool # true iff 'BeforeRet' label for proc is needed
ThreadVarAccessed*: bool # true if the proc already accessed some threadvar
nestedTryStmts*: seq[PNode] # in how many nested try statements we are
# (the vars must be volatile then)
beforeRetNeeded*: bool # true iff 'BeforeRet' label for proc is needed
threadVarAccessed*: bool # true if the proc already accessed some threadvar
nestedTryStmts*: seq[PNode] # in how many nested try statements we are
# (the vars must be volatile then)
inExceptBlock*: int # are we currently inside an except block?
# leaving such scopes by raise or by return must
# execute any applicable finally blocks
finallySafePoints*: seq[PRope] # For correctly cleaning up exceptions when
# using return in finally statements
labels*: Natural # for generating unique labels in the C proc
blocks*: seq[TBlock] # nested blocks
breakIdx*: int # the block that will be exited
@@ -78,7 +82,7 @@ type
maxFrameLen*: int # max length of frame descriptor
module*: BModule # used to prevent excessive parameter passing
withinLoop*: int # > 0 if we are within a loop
gcFrameId*: natural # for the GC stack marking
gcFrameId*: Natural # for the GC stack marking
gcFrameType*: PRope # the struct {} we put the GC markers into
TTypeSeq* = seq[PType]
@@ -86,11 +90,12 @@ type
module*: PSym
filename*: string
s*: TCFileSections # sections of the C file
PreventStackTrace*: bool # true if stack traces need to be prevented
preventStackTrace*: bool # true if stack traces need to be prevented
usesThreadVars*: bool # true if the module uses a thread var
FrameDeclared*: bool # hack for ROD support so that we don't declare
frameDeclared*: bool # hack for ROD support so that we don't declare
# a frame var twice in an init proc
isHeaderFile*: bool # C source file is the header file
includesStringh*: bool # C source file already includes ``<string.h>``
cfilename*: string # filename of the module (including path,
# without extension)
typeCache*: TIdTable # cache the generated types
@@ -100,21 +105,21 @@ type
headerFiles*: TLinkedList # needed headers to include
typeInfoMarker*: TIntSet # needed for generating type information
initProc*: BProc # code for init procedure
postInitProc*: BProc # code to be executed after the init proc
preInitProc*: BProc # code executed before the init proc
# used for initialization code for
# .global. variables
# (or instantiated generic variables)
typeStack*: TTypeSeq # used for type generation
dataCache*: TNodeTable
forwardedProcs*: TSymSeq # keep forwarded procs here
typeNodes*, nimTypes*: int # used for type info generation
typeNodesName*, nimTypesName*: PRope # used for type info generation
labels*: natural # for generating unique module-scope names
labels*: Natural # for generating unique module-scope names
extensionLoaders*: array['0'..'9', PRope] # special procs for the
# OpenGL wrapper
injectStmt*: PRope
var
mainModProcs*, mainModInit*, mainDatInit*: PRope # parts of the main module
mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: PRope
# varuious parts of the main module
gMapping*: PRope # the generated mapping file (if requested)
gModules*: seq[BModule] = @[] # list of all compiled modules
gForwardedProcsCounter*: int = 0
@@ -139,8 +144,9 @@ proc newProc*(prc: PSym, module: BModule): BProc =
else: result.options = gOptions
newSeq(result.blocks, 1)
result.nestedTryStmts = @[]
result.finallySafePoints = @[]
iterator cgenModules*: var BModule =
iterator cgenModules*: BModule =
for i in 0..high(gModules):
# ultimately, we are iterating over the file ids here.
# some "files" won't have an associated cgen module (like stdin)

View File

@@ -18,16 +18,16 @@ proc genConv(n: PNode, d: PType, downcast: bool): PNode =
var source = skipTypes(n.typ, abstractPtrs)
if (source.kind == tyObject) and (dest.kind == tyObject):
var diff = inheritanceDiff(dest, source)
if diff == high(int): InternalError(n.info, "cgmeth.genConv")
if diff == high(int): internalError(n.info, "cgmeth.genConv")
if diff < 0:
result = newNodeIT(nkObjUpConv, n.info, d)
addSon(result, n)
if downCast: InternalError(n.info, "cgmeth.genConv: no upcast allowed")
if downcast: internalError(n.info, "cgmeth.genConv: no upcast allowed")
elif diff > 0:
result = newNodeIT(nkObjDownConv, n.info, d)
addSon(result, n)
if not downCast:
InternalError(n.info, "cgmeth.genConv: no downcast allowed")
if not downcast:
internalError(n.info, "cgmeth.genConv: no downcast allowed")
else:
result = n
else:
@@ -59,14 +59,14 @@ proc sameMethodBucket(a, b: PSym): bool =
aa = skipTypes(aa, {tyGenericInst})
bb = skipTypes(bb, {tyGenericInst})
if (aa.kind == bb.kind) and (aa.kind in {tyVar, tyPtr, tyRef}):
aa = aa.sons[0]
bb = bb.sons[0]
aa = aa.lastSon
bb = bb.lastSon
else:
break
if sameType(aa, bb) or
(aa.kind == tyObject) and (bb.kind == tyObject) and
(inheritanceDiff(bb, aa) < 0):
nil
discard
else:
return
result = true
@@ -112,12 +112,12 @@ proc relevantCol(methods: TSymSeq, col: int): bool =
if t.kind == tyObject:
for i in countup(1, high(methods)):
let t2 = skipTypes(methods[i].typ.sons[col], skipPtrs)
if not SameType(t2, t):
if not sameType(t2, t):
return true
proc cmpSignatures(a, b: PSym, relevantCols: TIntSet): int =
for col in countup(1, sonsLen(a.typ) - 1):
if Contains(relevantCols, col):
if contains(relevantCols, col):
var aa = skipTypes(a.typ.sons[col], skipPtrs)
var bb = skipTypes(b.typ.sons[col], skipPtrs)
var d = inheritanceDiff(aa, bb)
@@ -126,14 +126,14 @@ proc cmpSignatures(a, b: PSym, relevantCols: TIntSet): int =
proc sortBucket(a: var TSymSeq, relevantCols: TIntSet) =
# we use shellsort here; fast and simple
var N = len(a)
var n = len(a)
var h = 1
while true:
h = 3 * h + 1
if h > N: break
if h > n: break
while true:
h = h div 3
for i in countup(h, N - 1):
for i in countup(h, n - 1):
var v = a[i]
var j = i
while cmpSignatures(a[j - h], v, relevantCols) >= 0:
@@ -154,7 +154,7 @@ proc genDispatcher(methods: TSymSeq, relevantCols: TIntSet): PSym =
var curr = methods[meth] # generate condition:
var cond: PNode = nil
for col in countup(1, paramLen - 1):
if Contains(relevantCols, col):
if contains(relevantCols, col):
var isn = newNodeIT(nkCall, base.info, getSysType(tyBool))
addSon(isn, newSymNode(iss))
addSon(isn, newSymNode(base.typ.n.sons[col].sym))
@@ -195,7 +195,7 @@ proc generateMethodDispatchers*(): PNode =
for bucket in countup(0, len(gMethods) - 1):
var relevantCols = initIntSet()
for col in countup(1, sonsLen(gMethods[bucket][0].typ) - 1):
if relevantCol(gMethods[bucket], col): Incl(relevantCols, col)
if relevantCol(gMethods[bucket], col): incl(relevantCols, col)
sortBucket(gMethods[bucket], relevantCols)
addSon(result, newSymNode(genDispatcher(gMethods[bucket], relevantCols)))

View File

@@ -1,49 +0,0 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
const
CharSize* = SizeOf(Char)
Lrz* = ' '
Apo* = '\''
Tabulator* = '\x09'
ESC* = '\x1B'
CR* = '\x0D'
FF* = '\x0C'
LF* = '\x0A'
BEL* = '\x07'
BACKSPACE* = '\x08'
VT* = '\x0B'
when defined(macos):
DirSep == ':'
"\n" == CR & ""
FirstNLchar == CR
PathSep == ';' # XXX: is this correct?
else:
when defined(unix):
DirSep == '/'
"\n" == LF & ""
FirstNLchar == LF
PathSep == ':'
else:
# windows, dos
DirSep == '\\'
"\n" == CR + LF
FirstNLchar == CR
DriveSeparator == ':'
PathSep == ';'
UpLetters == {'A'..'Z', '\xC0'..'\xDE'}
DownLetters == {'a'..'z', '\xDF'..'\xFF'}
Numbers == {'0'..'9'}
Letters == UpLetters + DownLetters
type
TCharSet* = set[Char]
PCharSet* = ref TCharSet
# implementation

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2013 Andreas Rumpf
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -11,7 +11,7 @@
import
os, msgs, options, nversion, condsyms, strutils, extccomp, platform, lists,
wordrecg, parseutils, babelcmd
wordrecg, parseutils, babelcmd, idents
proc writeCommandLineUsage*()
@@ -21,40 +21,40 @@ type
passCmd2, # second pass over the command line
passPP # preprocessor called ProcessCommand()
proc ProcessCommand*(switch: string, pass: TCmdLinePass)
proc processSwitch*(switch, arg: string, pass: TCmdlinePass, info: TLineInfo)
proc processCommand*(switch: string, pass: TCmdLinePass)
proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo)
# implementation
const
HelpMessage = "Nimrod Compiler Version $1 (" & compileDate & ") [$2: $3]\n" &
"Copyright (c) 2004-2013 by Andreas Rumpf\n"
HelpMessage = "Nimrod Compiler Version $1 (" & CompileDate & ") [$2: $3]\n" &
"Copyright (c) 2006-2014 by Andreas Rumpf\n"
const
Usage = slurp"doc/basicopt.txt".replace("//", "")
AdvancedUsage = slurp"doc/advopt.txt".replace("//", "")
proc getCommandLineDesc(): string =
result = (HelpMessage % [VersionAsString, platform.os[platform.hostOS].name,
cpu[platform.hostCPU].name]) & Usage
result = (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name,
CPU[platform.hostCPU].name]) & Usage
proc HelpOnError(pass: TCmdLinePass) =
proc helpOnError(pass: TCmdLinePass) =
if pass == passCmd1:
MsgWriteln(getCommandLineDesc())
msgWriteln(getCommandLineDesc())
quit(0)
proc writeAdvancedUsage(pass: TCmdLinePass) =
if pass == passCmd1:
MsgWriteln(`%`(HelpMessage, [VersionAsString,
platform.os[platform.hostOS].name,
cpu[platform.hostCPU].name]) & AdvancedUsage)
msgWriteln(`%`(HelpMessage, [VersionAsString,
platform.OS[platform.hostOS].name,
CPU[platform.hostCPU].name]) & AdvancedUsage)
quit(0)
proc writeVersionInfo(pass: TCmdLinePass) =
if pass == passCmd1:
MsgWriteln(`%`(HelpMessage, [VersionAsString,
platform.os[platform.hostOS].name,
cpu[platform.hostCPU].name]))
msgWriteln(`%`(HelpMessage, [VersionAsString,
platform.OS[platform.hostOS].name,
CPU[platform.hostCPU].name]))
quit(0)
var
@@ -62,16 +62,16 @@ var
proc writeCommandLineUsage() =
if not helpWritten:
MsgWriteln(getCommandLineDesc())
msgWriteln(getCommandLineDesc())
helpWritten = true
proc addPrefix(switch: string): string =
if len(switch) == 1: result = "-" & switch
else: result = "--" & switch
proc InvalidCmdLineOption(pass: TCmdLinePass, switch: string, info: TLineInfo) =
if switch == " ": LocalError(info, errInvalidCmdLineOption, "-")
else: LocalError(info, errInvalidCmdLineOption, addPrefix(switch))
proc invalidCmdLineOption(pass: TCmdLinePass, switch: string, info: TLineInfo) =
if switch == " ": localError(info, errInvalidCmdLineOption, "-")
else: localError(info, errInvalidCmdLineOption, addPrefix(switch))
proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass,
info: TLineInfo) =
@@ -86,29 +86,29 @@ proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass,
inc(i)
if i >= len(switch): arg = ""
elif switch[i] in {':', '=', '['}: arg = substr(switch, i + 1)
else: InvalidCmdLineOption(pass, switch, info)
else: invalidCmdLineOption(pass, switch, info)
proc ProcessOnOffSwitch(op: TOptions, arg: string, pass: TCmdlinePass,
proc processOnOffSwitch(op: TOptions, arg: string, pass: TCmdLinePass,
info: TLineInfo) =
case whichKeyword(arg)
of wOn: gOptions = gOptions + op
of wOff: gOptions = gOptions - op
else: LocalError(info, errOnOrOffExpectedButXFound, arg)
else: localError(info, errOnOrOffExpectedButXFound, arg)
proc ProcessOnOffSwitchG(op: TGlobalOptions, arg: string, pass: TCmdlinePass,
proc processOnOffSwitchG(op: TGlobalOptions, arg: string, pass: TCmdLinePass,
info: TLineInfo) =
case whichKeyword(arg)
of wOn: gGlobalOptions = gGlobalOptions + op
of wOff: gGlobalOptions = gGlobalOptions - op
else: LocalError(info, errOnOrOffExpectedButXFound, arg)
else: localError(info, errOnOrOffExpectedButXFound, arg)
proc ExpectArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
if arg == "": LocalError(info, errCmdLineArgExpected, addPrefix(switch))
proc expectArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
if arg == "": localError(info, errCmdLineArgExpected, addPrefix(switch))
proc ExpectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
if arg != "": LocalError(info, errCmdLineNoArgExpected, addPrefix(switch))
proc expectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
if arg != "": localError(info, errCmdLineNoArgExpected, addPrefix(switch))
proc ProcessSpecificNote(arg: string, state: TSpecialWord, pass: TCmdlinePass,
proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
info: TLineInfo) =
var id = "" # arg = "X]:on|off"
var i = 0
@@ -117,21 +117,21 @@ proc ProcessSpecificNote(arg: string, state: TSpecialWord, pass: TCmdlinePass,
add(id, arg[i])
inc(i)
if i < len(arg) and (arg[i] == ']'): inc(i)
else: InvalidCmdLineOption(pass, arg, info)
else: invalidCmdLineOption(pass, arg, info)
if i < len(arg) and (arg[i] in {':', '='}): inc(i)
else: InvalidCmdLineOption(pass, arg, info)
else: invalidCmdLineOption(pass, arg, info)
if state == wHint:
var x = findStr(msgs.HintsToStr, id)
if x >= 0: n = TNoteKind(x + ord(hintMin))
else: InvalidCmdLineOption(pass, arg, info)
else: invalidCmdLineOption(pass, arg, info)
else:
var x = findStr(msgs.WarningsToStr, id)
if x >= 0: n = TNoteKind(x + ord(warnMin))
else: InvalidCmdLineOption(pass, arg, info)
else: invalidCmdLineOption(pass, arg, info)
case whichKeyword(substr(arg, i))
of wOn: incl(gNotes, n)
of wOff: excl(gNotes, n)
else: LocalError(info, errOnOrOffExpectedButXFound, arg)
else: localError(info, errOnOrOffExpectedButXFound, arg)
proc processCompile(filename: string) =
var found = findFile(filename)
@@ -150,14 +150,14 @@ proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool =
of "markandsweep": result = gSelectedGC == gcMarkAndSweep
of "generational": result = gSelectedGC == gcGenerational
of "none": result = gSelectedGC == gcNone
else: LocalError(info, errNoneBoehmRefcExpectedButXFound, arg)
else: localError(info, errNoneBoehmRefcExpectedButXFound, arg)
of "opt":
case arg.normalize
of "speed": result = contains(gOptions, optOptimizeSpeed)
of "size": result = contains(gOptions, optOptimizeSize)
of "none": result = gOptions * {optOptimizeSpeed, optOptimizeSize} == {}
else: LocalError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
else: InvalidCmdLineOption(passCmd1, switch, info)
else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
else: invalidCmdLineOption(passCmd1, switch, info)
proc testCompileOption*(switch: string, info: TLineInfo): bool =
case switch.normalize
@@ -173,11 +173,11 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool =
of "linetrace": result = contains(gOptions, optLineTrace)
of "debugger": result = contains(gOptions, optEndb)
of "profiler": result = contains(gOptions, optProfiler)
of "checks", "x": result = gOptions * checksOptions == checksOptions
of "checks", "x": result = gOptions * ChecksOptions == ChecksOptions
of "floatchecks":
result = gOptions * {optNanCheck, optInfCheck} == {optNanCheck, optInfCheck}
result = gOptions * {optNaNCheck, optInfCheck} == {optNaNCheck, optInfCheck}
of "infchecks": result = contains(gOptions, optInfCheck)
of "nanchecks": result = contains(gOptions, optNanCheck)
of "nanchecks": result = contains(gOptions, optNaNCheck)
of "objchecks": result = contains(gOptions, optObjCheck)
of "fieldchecks": result = contains(gOptions, optFieldCheck)
of "rangechecks": result = contains(gOptions, optRangeCheck)
@@ -194,7 +194,7 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool =
of "tlsemulation": result = contains(gGlobalOptions, optTlsEmulation)
of "implicitstatic": result = contains(gOptions, optImplicitStatic)
of "patterns": result = contains(gOptions, optPatterns)
else: InvalidCmdLineOption(passCmd1, switch, info)
else: invalidCmdLineOption(passCmd1, switch, info)
proc processPath(path: string, notRelativeToProj = false): string =
let p = if notRelativeToProj or os.isAbsolute(path) or
@@ -202,20 +202,20 @@ proc processPath(path: string, notRelativeToProj = false): string =
path
else:
options.gProjectPath / path
result = UnixToNativePath(p % ["nimrod", getPrefixDir(), "lib", libpath,
result = unixToNativePath(p % ["nimrod", getPrefixDir(), "lib", libpath,
"home", removeTrailingDirSep(os.getHomeDir()),
"projectname", options.gProjectName,
"projectpath", options.gProjectPath])
proc trackDirty(arg: string, info: TLineInfo) =
var a = arg.split(',')
if a.len != 4: LocalError(info, errTokenExpected,
if a.len != 4: localError(info, errTokenExpected,
"DIRTY_BUFFER,ORIGINAL_FILE,LINE,COLUMN")
var line, column: int
if parseUtils.parseInt(a[2], line) <= 0:
LocalError(info, errInvalidNumber, a[1])
localError(info, errInvalidNumber, a[1])
if parseUtils.parseInt(a[3], column) <= 0:
LocalError(info, errInvalidNumber, a[2])
localError(info, errInvalidNumber, a[2])
gDirtyBufferIdx = a[0].fileInfoIdx
gDirtyOriginalIdx = a[1].fileInfoIdx
@@ -225,21 +225,21 @@ proc trackDirty(arg: string, info: TLineInfo) =
proc track(arg: string, info: TLineInfo) =
var a = arg.split(',')
if a.len != 3: LocalError(info, errTokenExpected, "FILE,LINE,COLUMN")
if a.len != 3: localError(info, errTokenExpected, "FILE,LINE,COLUMN")
var line, column: int
if parseUtils.parseInt(a[1], line) <= 0:
LocalError(info, errInvalidNumber, a[1])
localError(info, errInvalidNumber, a[1])
if parseUtils.parseInt(a[2], column) <= 0:
LocalError(info, errInvalidNumber, a[2])
localError(info, errInvalidNumber, a[2])
optTrackPos = newLineInfo(a[0], line, column)
msgs.addCheckpoint(optTrackPos)
proc dynlibOverride(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
proc dynlibOverride(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
if pass in {passCmd2, passPP}:
expectArg(switch, arg, pass, info)
options.inclDynlibOverride(arg)
proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
var
theOS: TSystemOS
cpu: TSystemCPU
@@ -249,30 +249,36 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
expectArg(switch, arg, pass, info)
addPath(processPath(arg), info)
of "babelpath":
if pass in {passCmd2, passPP}:
if pass in {passCmd2, passPP} and not options.gNoBabelPath:
expectArg(switch, arg, pass, info)
let path = processPath(arg, notRelativeToProj=true)
babelpath(path, info)
of "nobabelpath":
expectNoArg(switch, arg, pass, info)
options.gNoBabelPath = true
of "excludepath":
expectArg(switch, arg, pass, info)
let path = processPath(arg)
lists.ExcludeStr(options.searchPaths, path)
lists.ExcludeStr(options.lazyPaths, path)
lists.excludeStr(options.searchPaths, path)
lists.excludeStr(options.lazyPaths, path)
of "nimcache":
expectArg(switch, arg, pass, info)
options.nimcacheDir = processPath(arg)
of "out", "o":
expectArg(switch, arg, pass, info)
options.outFile = arg
of "docseesrcurl":
expectArg(switch, arg, pass, info)
options.docSeeSrcUrl = arg
of "mainmodule", "m":
expectArg(switch, arg, pass, info)
optMainModule = arg
of "define", "d":
expectArg(switch, arg, pass, info)
DefineSymbol(arg)
defineSymbol(arg)
of "undef", "u":
expectArg(switch, arg, pass, info)
UndefSymbol(arg)
undefSymbol(arg)
of "compile":
expectArg(switch, arg, pass, info)
if pass in {passCmd2, passPP}: processCompile(arg)
@@ -305,7 +311,7 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
case arg.normalize
of "boehm":
gSelectedGC = gcBoehm
DefineSymbol("boehmgc")
defineSymbol("boehmgc")
of "refc":
gSelectedGC = gcRefc
of "v2":
@@ -319,42 +325,42 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
of "none":
gSelectedGC = gcNone
defineSymbol("nogc")
else: LocalError(info, errNoneBoehmRefcExpectedButXFound, arg)
of "warnings", "w": ProcessOnOffSwitch({optWarns}, arg, pass, info)
of "warning": ProcessSpecificNote(arg, wWarning, pass, info)
of "hint": ProcessSpecificNote(arg, wHint, pass, info)
of "hints": ProcessOnOffSwitch({optHints}, arg, pass, info)
of "threadanalysis": ProcessOnOffSwitchG({optThreadAnalysis}, arg, pass, info)
of "stacktrace": ProcessOnOffSwitch({optStackTrace}, arg, pass, info)
of "linetrace": ProcessOnOffSwitch({optLineTrace}, arg, pass, info)
else: localError(info, errNoneBoehmRefcExpectedButXFound, arg)
of "warnings", "w": processOnOffSwitch({optWarns}, arg, pass, info)
of "warning": processSpecificNote(arg, wWarning, pass, info)
of "hint": processSpecificNote(arg, wHint, pass, info)
of "hints": processOnOffSwitch({optHints}, arg, pass, info)
of "threadanalysis": processOnOffSwitchG({optThreadAnalysis}, arg, pass, info)
of "stacktrace": processOnOffSwitch({optStackTrace}, arg, pass, info)
of "linetrace": processOnOffSwitch({optLineTrace}, arg, pass, info)
of "debugger":
ProcessOnOffSwitch({optEndb}, arg, pass, info)
if optEndb in gOptions: DefineSymbol("endb")
else: UndefSymbol("endb")
processOnOffSwitch({optEndb}, arg, pass, info)
if optEndb in gOptions: defineSymbol("endb")
else: undefSymbol("endb")
of "profiler":
ProcessOnOffSwitch({optProfiler}, arg, pass, info)
if optProfiler in gOptions: DefineSymbol("profiler")
else: UndefSymbol("profiler")
of "checks", "x": ProcessOnOffSwitch(checksOptions, arg, pass, info)
processOnOffSwitch({optProfiler}, arg, pass, info)
if optProfiler in gOptions: defineSymbol("profiler")
else: undefSymbol("profiler")
of "checks", "x": processOnOffSwitch(ChecksOptions, arg, pass, info)
of "floatchecks":
ProcessOnOffSwitch({optNanCheck, optInfCheck}, arg, pass, info)
of "infchecks": ProcessOnOffSwitch({optInfCheck}, arg, pass, info)
of "nanchecks": ProcessOnOffSwitch({optNanCheck}, arg, pass, info)
of "objchecks": ProcessOnOffSwitch({optObjCheck}, arg, pass, info)
of "fieldchecks": ProcessOnOffSwitch({optFieldCheck}, arg, pass, info)
of "rangechecks": ProcessOnOffSwitch({optRangeCheck}, arg, pass, info)
of "boundchecks": ProcessOnOffSwitch({optBoundsCheck}, arg, pass, info)
of "overflowchecks": ProcessOnOffSwitch({optOverflowCheck}, arg, pass, info)
of "linedir": ProcessOnOffSwitch({optLineDir}, arg, pass, info)
of "assertions", "a": ProcessOnOffSwitch({optAssert}, arg, pass, info)
of "deadcodeelim": ProcessOnOffSwitchG({optDeadCodeElim}, arg, pass, info)
of "threads": ProcessOnOffSwitchG({optThreads}, arg, pass, info)
of "tlsemulation": ProcessOnOffSwitchG({optTlsEmulation}, arg, pass, info)
of "taintmode": ProcessOnOffSwitchG({optTaintMode}, arg, pass, info)
processOnOffSwitch({optNaNCheck, optInfCheck}, arg, pass, info)
of "infchecks": processOnOffSwitch({optInfCheck}, arg, pass, info)
of "nanchecks": processOnOffSwitch({optNaNCheck}, arg, pass, info)
of "objchecks": processOnOffSwitch({optObjCheck}, arg, pass, info)
of "fieldchecks": processOnOffSwitch({optFieldCheck}, arg, pass, info)
of "rangechecks": processOnOffSwitch({optRangeCheck}, arg, pass, info)
of "boundchecks": processOnOffSwitch({optBoundsCheck}, arg, pass, info)
of "overflowchecks": processOnOffSwitch({optOverflowCheck}, arg, pass, info)
of "linedir": processOnOffSwitch({optLineDir}, arg, pass, info)
of "assertions", "a": processOnOffSwitch({optAssert}, arg, pass, info)
of "deadcodeelim": processOnOffSwitchG({optDeadCodeElim}, arg, pass, info)
of "threads": processOnOffSwitchG({optThreads}, arg, pass, info)
of "tlsemulation": processOnOffSwitchG({optTlsEmulation}, arg, pass, info)
of "taintmode": processOnOffSwitchG({optTaintMode}, arg, pass, info)
of "implicitstatic":
ProcessOnOffSwitch({optImplicitStatic}, arg, pass, info)
processOnOffSwitch({optImplicitStatic}, arg, pass, info)
of "patterns":
ProcessOnOffSwitch({optPatterns}, arg, pass, info)
processOnOffSwitch({optPatterns}, arg, pass, info)
of "opt":
expectArg(switch, arg, pass, info)
case arg.normalize
@@ -367,7 +373,7 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
of "none":
excl(gOptions, optOptimizeSpeed)
excl(gOptions, optOptimizeSize)
else: LocalError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
of "app":
expectArg(switch, arg, pass, info)
case arg.normalize
@@ -389,7 +395,7 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
excl(gGlobalOptions, optGenGuiApp)
defineSymbol("library")
defineSymbol("staticlib")
else: LocalError(info, errGuiConsoleOrLibExpectedButXFound, arg)
else: localError(info, errGuiConsoleOrLibExpectedButXFound, arg)
of "passc", "t":
expectArg(switch, arg, pass, info)
if pass in {passCmd2, passPP}: extccomp.addCompileOption(arg)
@@ -398,18 +404,18 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
if pass in {passCmd2, passPP}: extccomp.addLinkOption(arg)
of "cincludes":
expectArg(switch, arg, pass, info)
if pass in {passCmd2, passPP}: cIncludes.add arg
if pass in {passCmd2, passPP}: cIncludes.add arg.processPath
of "clibdir":
expectArg(switch, arg, pass, info)
if pass in {passCmd2, passPP}: cLibs.add arg
if pass in {passCmd2, passPP}: cLibs.add arg.processPath
of "clib":
expectArg(switch, arg, pass, info)
if pass in {passCmd2, passPP}: cLinkedLibs.add arg
if pass in {passCmd2, passPP}: cLinkedLibs.add arg.processPath
of "header":
headerFile = arg
incl(gGlobalOptions, optGenIndex)
of "index":
ProcessOnOffSwitchG({optGenIndex}, arg, pass, info)
processOnOffSwitchG({optGenIndex}, arg, pass, info)
of "import":
expectArg(switch, arg, pass, info)
if pass in {passCmd2, passPP}: implicitImports.add arg
@@ -425,19 +431,19 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
of "os":
expectArg(switch, arg, pass, info)
if pass in {passCmd1, passPP}:
theOS = platform.NameToOS(arg)
if theOS == osNone: LocalError(info, errUnknownOS, arg)
theOS = platform.nameToOS(arg)
if theOS == osNone: localError(info, errUnknownOS, arg)
elif theOS != platform.hostOS:
setTarget(theOS, targetCPU)
condsyms.InitDefines()
condsyms.initDefines()
of "cpu":
expectArg(switch, arg, pass, info)
if pass in {passCmd1, passPP}:
cpu = platform.NameToCPU(arg)
if cpu == cpuNone: LocalError(info, errUnknownCPU, arg)
cpu = platform.nameToCPU(arg)
if cpu == cpuNone: localError(info, errUnknownCPU, arg)
elif cpu != platform.hostCPU:
setTarget(targetOS, cpu)
condsyms.InitDefines()
condsyms.initDefines()
of "run", "r":
expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optRun)
@@ -457,7 +463,7 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
expectNoArg(switch, arg, pass, info)
helpOnError(pass)
of "symbolfiles":
ProcessOnOffSwitchG({optSymbolFiles}, arg, pass, info)
processOnOffSwitchG({optSymbolFiles}, arg, pass, info)
of "skipcfg":
expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optSkipConfigFile)
@@ -512,11 +518,18 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
gListFullPaths = true
of "dynliboverride":
dynlibOverride(switch, arg, pass, info)
of "cs":
expectArg(switch, arg, pass, info)
case arg
of "partial": idents.firstCharIsCS = true
of "none": idents.firstCharIsCS = false
else: localError(info, errGenerated,
"'partial' or 'none' expected, but found " & arg)
else:
if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg)
else: InvalidCmdLineOption(pass, switch, info)
else: invalidCmdLineOption(pass, switch, info)
proc ProcessCommand(switch: string, pass: TCmdLinePass) =
proc processCommand(switch: string, pass: TCmdLinePass) =
var cmd, arg: string
splitSwitch(switch, cmd, arg, pass, gCmdLineInfo)
processSwitch(cmd, arg, pass, gCmdLineInfo)

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -10,93 +10,82 @@
# This module handles the conditional symbols.
import
ast, astalgo, hashes, platform, strutils, idents
strtabs, platform, strutils, idents
var gSymbols*: TStrTable
# We need to use a PStringTable here as defined symbols are always guaranteed
# to be style insensitive. Otherwise hell would break lose.
var gSymbols: PStringTable
proc DefineSymbol*(symbol: string) =
var i = getIdent(symbol)
var sym = StrTableGet(gSymbols, i)
if sym == nil:
new(sym) # circumvent the ID mechanism
sym.kind = skConditional
sym.name = i
StrTableAdd(gSymbols, sym)
sym.position = 1
proc defineSymbol*(symbol: string) =
gSymbols[symbol] = "true"
proc UndefSymbol*(symbol: string) =
var sym = StrTableGet(gSymbols, getIdent(symbol))
if sym != nil: sym.position = 0
proc isDefined*(symbol: PIdent): bool =
var sym = StrTableGet(gSymbols, symbol)
result = sym != nil and sym.position == 1
proc undefSymbol*(symbol: string) =
gSymbols[symbol] = "false"
proc isDefined*(symbol: string): bool =
result = isDefined(getIdent(symbol))
if gSymbols.hasKey(symbol):
result = gSymbols[symbol] == "true"
proc isDefined*(symbol: PIdent): bool = isDefined(symbol.s)
iterator definedSymbolNames*: string =
var it: TTabIter
var s = InitTabIter(it, gSymbols)
while s != nil:
if s.position == 1: yield s.name.s
s = nextIter(it, gSymbols)
for key, val in pairs(gSymbols):
if val == "true": yield key
proc countDefinedSymbols*(): int =
var it: TTabIter
var s = InitTabIter(it, gSymbols)
result = 0
while s != nil:
if s.position == 1: inc(result)
s = nextIter(it, gSymbols)
for key, val in pairs(gSymbols):
if val == "true": inc(result)
proc InitDefines*() =
initStrTable(gSymbols)
DefineSymbol("nimrod") # 'nimrod' is always defined
proc initDefines*() =
gSymbols = newStringTable(modeStyleInsensitive)
defineSymbol("nimrod") # 'nimrod' is always defined
# for bootstrapping purposes and old code:
DefineSymbol("nimhygiene")
DefineSymbol("niminheritable")
DefineSymbol("nimmixin")
DefineSymbol("nimeffects")
DefineSymbol("nimbabel")
defineSymbol("nimhygiene")
defineSymbol("niminheritable")
defineSymbol("nimmixin")
defineSymbol("nimeffects")
defineSymbol("nimbabel")
defineSymbol("nimcomputedgoto")
defineSymbol("nimunion")
defineSymbol("nimnewshared")
defineSymbol("nimrequiresnimframe")
# add platform specific symbols:
case targetCPU
of cpuI386: DefineSymbol("x86")
of cpuIa64: DefineSymbol("itanium")
of cpuAmd64: DefineSymbol("x8664")
else: nil
of cpuI386: defineSymbol("x86")
of cpuIa64: defineSymbol("itanium")
of cpuAmd64: defineSymbol("x8664")
else: discard
case targetOS
of osDOS:
DefineSymbol("msdos")
of osDos:
defineSymbol("msdos")
of osWindows:
DefineSymbol("mswindows")
DefineSymbol("win32")
of osLinux, osMorphOS, osSkyOS, osIrix, osPalmOS, osQNX, osAtari, osAix,
defineSymbol("mswindows")
defineSymbol("win32")
of osLinux, osMorphos, osSkyos, osIrix, osPalmos, osQnx, osAtari, osAix,
osHaiku:
# these are all 'unix-like'
DefineSymbol("unix")
DefineSymbol("posix")
defineSymbol("unix")
defineSymbol("posix")
of osSolaris:
DefineSymbol("sunos")
DefineSymbol("unix")
DefineSymbol("posix")
of osNetBSD, osFreeBSD, osOpenBSD:
DefineSymbol("unix")
DefineSymbol("bsd")
DefineSymbol("posix")
of osMacOS:
DefineSymbol("macintosh")
of osMacOSX:
DefineSymbol("macintosh")
DefineSymbol("unix")
DefineSymbol("posix")
else: nil
DefineSymbol("cpu" & $cpu[targetCPU].bit)
DefineSymbol(normalize(endianToStr[cpu[targetCPU].endian]))
DefineSymbol(cpu[targetCPU].name)
DefineSymbol(platform.os[targetOS].name)
defineSymbol("sunos")
defineSymbol("unix")
defineSymbol("posix")
of osNetbsd, osFreebsd, osOpenbsd:
defineSymbol("unix")
defineSymbol("bsd")
defineSymbol("posix")
of osMacos:
defineSymbol("macintosh")
of osMacosx:
defineSymbol("macintosh")
defineSymbol("unix")
defineSymbol("posix")
else: discard
defineSymbol("cpu" & $CPU[targetCPU].bit)
defineSymbol(normalize(EndianToStr[CPU[targetCPU].endian]))
defineSymbol(CPU[targetCPU].name)
defineSymbol(platform.OS[targetOS].name)
if platform.OS[targetOS].props.contains(ospLacksThreadVars):
DefineSymbol("emulatedthreadvars")
defineSymbol("emulatedthreadvars")

View File

@@ -18,8 +18,8 @@ const
InitAdler32* = int32(1)
proc updateCrc32*(val: int8, crc: TCrc32): TCrc32 {.inline.}
proc updateCrc32*(val: Char, crc: TCrc32): TCrc32 {.inline.}
proc crcFromBuf*(buf: Pointer, length: int): TCrc32
proc updateCrc32*(val: char, crc: TCrc32): TCrc32 {.inline.}
proc crcFromBuf*(buf: pointer, length: int): TCrc32
proc strCrc32*(s: string): TCrc32
proc crcFromFile*(filename: string): TCrc32
proc updateAdler32*(adler: int32, buf: pointer, length: int): int32
@@ -75,10 +75,10 @@ const
755167117]
proc updateCrc32(val: int8, crc: TCrc32): TCrc32 =
result = TCrc32(crc32Table[(int(crc) xor (int(val) and 0x000000FF)) and
result = TCrc32(crc32table[(int(crc) xor (int(val) and 0x000000FF)) and
0x000000FF]) xor (crc shr TCrc32(8))
proc updateCrc32(val: Char, crc: TCrc32): TCrc32 =
proc updateCrc32(val: char, crc: TCrc32): TCrc32 =
result = updateCrc32(toU8(ord(val)), crc)
proc strCrc32(s: string): TCrc32 =
@@ -93,7 +93,7 @@ type
TByteArray = array[0..10000000, int8]
PByteArray = ref TByteArray
proc crcFromBuf(buf: Pointer, length: int): TCrc32 =
proc crcFromBuf(buf: pointer, length: int): TCrc32 =
var p = cast[PByteArray](buf)
result = InitCrc32
for i in countup(0, length - 1): result = updateCrc32(p[i], result)
@@ -102,11 +102,11 @@ proc crcFromFile(filename: string): TCrc32 =
const
bufSize = 8000 # don't use 8K for the memory allocator!
var
bin: tfile
bin: TFile
result = InitCrc32
if not open(bin, filename):
return # not equal if file does not exist
var buf = alloc(BufSize)
var buf = alloc(bufSize)
var p = cast[PByteArray](buf)
while true:
var readBytes = readBuffer(bin, buf, bufSize)

View File

@@ -39,11 +39,11 @@ proc addDotDependency(c: PPassContext, n: PNode): PNode =
of nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr:
for i in countup(0, sonsLen(n) - 1): discard addDotDependency(c, n.sons[i])
else:
nil
discard
proc generateDot(project: string) =
writeRope(ropef("digraph $1 {$n$2}$n", [
toRope(changeFileExt(extractFileName(project), "")), gDotGraph]),
toRope(changeFileExt(extractFilename(project), "")), gDotGraph]),
changeFileExt(project, "dot"))
proc myOpen(module: PSym): PPassContext =

View File

@@ -11,10 +11,10 @@
# semantic checking is done for the code. Cross-references are generated
# by knowing how the anchors are going to be named.
import
ast, strutils, strtabs, options, msgs, os, ropes, idents,
wordrecg, syntaxes, renderer, lexer, rstast, rst, rstgen, times, highlite,
importer, sempass2
import
ast, strutils, strtabs, options, msgs, os, ropes, idents,
wordrecg, syntaxes, renderer, lexer, rstast, rst, rstgen, times, highlite,
importer, sempass2, json, xmltree, cgi, typesrenderer
type
TSections = array[TSymKind, PRope]
@@ -23,9 +23,10 @@ type
id: int # for generating IDs
toc, section: TSections
indexValFilename: string
seenSymbols: PStringTable # avoids duplicate symbol generation for HTML.
PDoc* = ref TDocumentor ## Alias to type less.
PDoc* = ref TDocumentor
proc compilerMsgHandler(filename: string, line, col: int,
msgKind: rst.TMsgKind, arg: string) {.procvar.} =
# translate msg kind:
@@ -40,70 +41,77 @@ proc compilerMsgHandler(filename: string, line, col: int,
of mwRedefinitionOfLabel: k = warnRedefinitionOfLabel
of mwUnknownSubstitution: k = warnUnknownSubstitutionX
of mwUnsupportedLanguage: k = warnLanguageXNotSupported
GlobalError(newLineInfo(filename, line, col), k, arg)
globalError(newLineInfo(filename, line, col), k, arg)
proc docgenFindFile(s: string): string {.procvar.} =
result = options.findFile(s)
if result.len == 0:
result = getCurrentDir() / s
if not existsFile(result): result = ""
proc parseRst(text, filename: string,
line, column: int, hasToc: var bool,
rstOptions: TRstParseOptions): PRstNode =
result = rstParse(text, filename, line, column, hasToc, rstOptions,
options.FindFile, compilerMsgHandler)
docgenFindFile, compilerMsgHandler)
proc newDocumentor*(filename: string, config: PStringTable): PDoc =
proc newDocumentor*(filename: string, config: PStringTable): PDoc =
new(result)
initRstGenerator(result[], (if gCmd != cmdRst2Tex: outHtml else: outLatex),
initRstGenerator(result[], (if gCmd != cmdRst2tex: outHtml else: outLatex),
options.gConfigVars, filename, {roSupportRawDirective},
options.FindFile, compilerMsgHandler)
docgenFindFile, compilerMsgHandler)
result.seenSymbols = newStringTable(modeCaseInsensitive)
result.id = 100
proc dispA(dest: var PRope, xml, tex: string, args: openarray[PRope]) =
if gCmd != cmdRst2Tex: appf(dest, xml, args)
proc dispA(dest: var PRope, xml, tex: string, args: openArray[PRope]) =
if gCmd != cmdRst2tex: appf(dest, xml, args)
else: appf(dest, tex, args)
proc getVarIdx(varnames: openarray[string], id: string): int =
for i in countup(0, high(varnames)):
if cmpIgnoreStyle(varnames[i], id) == 0:
proc getVarIdx(varnames: openArray[string], id: string): int =
for i in countup(0, high(varnames)):
if cmpIgnoreStyle(varnames[i], id) == 0:
return i
result = -1
proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openarray[string],
varvalues: openarray[PRope]): PRope =
proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openArray[string],
varvalues: openArray[PRope]): PRope =
var i = 0
var L = len(frmt)
result = nil
var num = 0
while i < L:
if frmt[i] == '$':
while i < L:
if frmt[i] == '$':
inc(i) # skip '$'
case frmt[i]
of '#':
of '#':
app(result, varvalues[num])
inc(num)
inc(i)
of '$':
of '$':
app(result, "$")
inc(i)
of '0'..'9':
of '0'..'9':
var j = 0
while true:
j = (j * 10) + Ord(frmt[i]) - ord('0')
while true:
j = (j * 10) + ord(frmt[i]) - ord('0')
inc(i)
if (i > L + 0 - 1) or not (frmt[i] in {'0'..'9'}): break
if (i > L + 0 - 1) or not (frmt[i] in {'0'..'9'}): break
if j > high(varvalues) + 1: internalError("ropeFormatNamedVars")
num = j
app(result, varvalues[j - 1])
of 'A'..'Z', 'a'..'z', '\x80'..'\xFF':
of 'A'..'Z', 'a'..'z', '\x80'..'\xFF':
var id = ""
while true:
while true:
add(id, frmt[i])
inc(i)
if not (frmt[i] in {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}): break
if not (frmt[i] in {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}): break
var idx = getVarIdx(varnames, id)
if idx >= 0: app(result, varvalues[idx])
else: rawMessage(errUnkownSubstitionVar, id)
of '{':
of '{':
var id = ""
inc(i)
while frmt[i] != '}':
while frmt[i] != '}':
if frmt[i] == '\0': rawMessage(errTokenExpected, "}")
add(id, frmt[i])
inc(i)
@@ -112,7 +120,7 @@ proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openarray[string],
var idx = getVarIdx(varnames, id)
if idx >= 0: app(result, varvalues[idx])
else: rawMessage(errUnkownSubstitionVar, id)
else: InternalError("ropeFormatNamedVars")
else: internalError("ropeFormatNamedVars")
var start = i
while i < L:
if frmt[i] != '$': inc(i)
@@ -124,20 +132,37 @@ proc genComment(d: PDoc, n: PNode): string =
var dummyHasToc: bool
if n.comment != nil and startsWith(n.comment, "##"):
renderRstToOut(d[], parseRst(n.comment, toFilename(n.info),
toLineNumber(n.info), toColumn(n.info),
toLinenumber(n.info), toColumn(n.info),
dummyHasToc, d.options + {roSkipPounds}), result)
proc genRecComment(d: PDoc, n: PNode): PRope =
proc genRecComment(d: PDoc, n: PNode): PRope =
if n == nil: return nil
result = genComment(d, n).toRope
if result == nil:
if result == nil:
if n.kind notin {nkEmpty..nkNilLit}:
for i in countup(0, len(n)-1):
result = genRecComment(d, n.sons[i])
if result != nil: return
if result != nil: return
else:
n.comment = nil
proc getPlainDocstring(n: PNode): string =
## Gets the plain text docstring of a node non destructively.
##
## You need to call this before genRecComment, whose side effects are removal
## of comments from the tree. The proc will recursively scan and return all
## the concatenated ``##`` comments of the node.
result = ""
if n == nil: return
if n.comment != nil and startsWith(n.comment, "##"):
result = n.comment
if result.len < 1:
if n.kind notin {nkEmpty..nkNilLit}:
for i in countup(0, len(n)-1):
result = getPlainDocstring(n.sons[i])
if result.len > 0: return
proc findDocComment(n: PNode): PNode =
if n == nil: return nil
if not isNil(n.comment) and startsWith(n.comment, "##"): return n
@@ -152,16 +177,16 @@ proc extractDocComment*(s: PSym, d: PDoc = nil): string =
if not d.isNil:
var dummyHasToc: bool
renderRstToOut(d[], parseRst(n.comment, toFilename(n.info),
toLineNumber(n.info), toColumn(n.info),
toLinenumber(n.info), toColumn(n.info),
dummyHasToc, d.options + {roSkipPounds}),
result)
else:
result = n.comment.substr(2).replace("\n##", "\n").strip
proc isVisible(n: PNode): bool =
proc isVisible(n: PNode): bool =
result = false
if n.kind == nkPostfix:
if n.len == 2 and n.sons[0].kind == nkIdent:
if n.kind == nkPostfix:
if n.len == 2 and n.sons[0].kind == nkIdent:
var v = n.sons[0].ident
result = v.id == ord(wStar) or v.id == ord(wMinus)
elif n.kind == nkSym:
@@ -171,110 +196,257 @@ proc isVisible(n: PNode): bool =
result = {sfExported, sfFromGeneric, sfForward}*n.sym.flags == {sfExported}
elif n.kind == nkPragmaExpr:
result = isVisible(n.sons[0])
proc getName(d: PDoc, n: PNode, splitAfter = -1): string =
proc getName(d: PDoc, n: PNode, splitAfter = -1): string =
case n.kind
of nkPostfix: result = getName(d, n.sons[1], splitAfter)
of nkPragmaExpr: result = getName(d, n.sons[0], splitAfter)
of nkSym: result = esc(d.target, n.sym.renderDefinitionName, splitAfter)
of nkIdent: result = esc(d.target, n.ident.s, splitAfter)
of nkAccQuoted:
result = esc(d.target, "`")
of nkAccQuoted:
result = esc(d.target, "`")
for i in 0.. <n.len: result.add(getName(d, n[i], splitAfter))
result.add esc(d.target, "`")
else:
internalError(n.info, "getName()")
result = ""
proc getRstName(n: PNode): PRstNode =
proc getRstName(n: PNode): PRstNode =
case n.kind
of nkPostfix: result = getRstName(n.sons[1])
of nkPragmaExpr: result = getRstName(n.sons[0])
of nkSym: result = newRstNode(rnLeaf, n.sym.renderDefinitionName)
of nkIdent: result = newRstNode(rnLeaf, n.ident.s)
of nkAccQuoted:
of nkAccQuoted:
result = getRstName(n.sons[0])
for i in 1 .. <n.len: result.text.add(getRstName(n[i]).text)
else:
internalError(n.info, "getRstName()")
result = nil
proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
if not isVisible(nameNode): return
var name = toRope(getName(d, nameNode))
proc newUniquePlainSymbol(d: PDoc, original: string): string =
## Returns a new unique plain symbol made up from the original.
##
## When a collision is found in the seenSymbols table, new numerical variants
## with underscore + number will be generated.
if not d.seenSymbols.hasKey(original):
result = original
d.seenSymbols[original] = ""
return
# Iterate over possible numeric variants of the original name.
var count = 2
while true:
result = original & "_" & $count
if not d.seenSymbols.hasKey(result):
d.seenSymbols[result] = ""
break
count += 1
proc complexName(k: TSymKind, n: PNode, baseName: string): string =
## Builds a complex unique href name for the node.
##
## Pass as ``baseName`` the plain symbol obtained from the nodeName. The
## format of the returned symbol will be ``baseName(.callable type)?,(param
## type)?(,param type)*``. The callable type part will be added only if the
## node is not a proc, as those are the common ones. The suffix will be a dot
## and a single letter representing the type of the callable. The parameter
## types will be added with a preceeding dash. Return types won't be added.
##
## If you modify the output of this proc, please update the anchor generation
## section of ``doc/docgen.txt``.
result = baseName
case k:
of skProc: result.add(defaultParamSeparator)
of skMacro: result.add(".m" & defaultParamSeparator)
of skMethod: result.add(".e" & defaultParamSeparator)
of skIterator: result.add(".i" & defaultParamSeparator)
of skTemplate: result.add(".t" & defaultParamSeparator)
of skConverter: result.add(".c" & defaultParamSeparator)
else: discard
if len(n) > paramsPos and n[paramsPos].kind == nkFormalParams:
result.add(renderParamTypes(n[paramsPos]))
proc isCallable(n: PNode): bool =
## Returns true if `n` contains a callable node.
case n.kind
of nkProcDef, nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef,
nkConverterDef: result = true
else:
result = false
proc docstringSummary(rstText: string): string =
## Returns just the first line or a brief chunk of text from a rst string.
##
## Most docstrings will contain a one liner summary, so stripping at the
## first newline is usually fine. If after that the content is still too big,
## it is stripped at the first comma, colon or dot, usual english sentence
## separators.
##
## No guarantees are made on the size of the output, but it should be small.
## Also, we hope to not break the rst, but maybe we do. If there is any
## trimming done, an ellipsis unicode char is added.
const maxDocstringChars = 100
assert (rstText.len < 2 or (rstText[0] == '#' and rstText[1] == '#'))
result = rstText.substr(2).strip
var pos = result.find('\L')
if pos > 0:
result.delete(pos, result.len - 1)
result.add("")
if pos < maxDocstringChars:
return
# Try to keep trimming at other natural boundaries.
pos = result.find({'.', ',', ':'})
let last = result.len - 1
if pos > 0 and pos < last:
result.delete(pos, last)
result.add("")
proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
if not isVisible(nameNode): return
let
name = getName(d, nameNode)
nameRope = name.toRope
plainDocstring = getPlainDocstring(n) # call here before genRecComment!
var result: PRope = nil
var literal = ""
var literal, plainName = ""
var kind = tkEof
var comm = genRecComment(d, n) # call this here for the side-effect!
var r: TSrcGen
# Obtain the plain rendered string for hyperlink titles.
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments,
renderNoPragmas, renderNoProcDefs})
while true:
getNextTok(r, kind, literal)
if kind == tkEof:
break
plainName.add(literal)
# Render the HTML hyperlink.
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments})
while true:
while true:
getNextTok(r, kind, literal)
case kind
of tkEof:
break
of tkComment:
dispA(result, "<span class=\"Comment\">$1</span>", "\\spanComment{$1}",
of tkEof:
break
of tkComment:
dispA(result, "<span class=\"Comment\">$1</span>", "\\spanComment{$1}",
[toRope(esc(d.target, literal))])
of tokKeywordLow..tokKeywordHigh:
dispA(result, "<span class=\"Keyword\">$1</span>", "\\spanKeyword{$1}",
of tokKeywordLow..tokKeywordHigh:
dispA(result, "<span class=\"Keyword\">$1</span>", "\\spanKeyword{$1}",
[toRope(literal)])
of tkOpr:
dispA(result, "<span class=\"Operator\">$1</span>", "\\spanOperator{$1}",
of tkOpr:
dispA(result, "<span class=\"Operator\">$1</span>", "\\spanOperator{$1}",
[toRope(esc(d.target, literal))])
of tkStrLit..tkTripleStrLit:
dispA(result, "<span class=\"StringLit\">$1</span>",
of tkStrLit..tkTripleStrLit:
dispA(result, "<span class=\"StringLit\">$1</span>",
"\\spanStringLit{$1}", [toRope(esc(d.target, literal))])
of tkCharLit:
dispA(result, "<span class=\"CharLit\">$1</span>", "\\spanCharLit{$1}",
of tkCharLit:
dispA(result, "<span class=\"CharLit\">$1</span>", "\\spanCharLit{$1}",
[toRope(esc(d.target, literal))])
of tkIntLit..tkUInt64Lit:
dispA(result, "<span class=\"DecNumber\">$1</span>",
of tkIntLit..tkUInt64Lit:
dispA(result, "<span class=\"DecNumber\">$1</span>",
"\\spanDecNumber{$1}", [toRope(esc(d.target, literal))])
of tkFloatLit..tkFloat128Lit:
dispA(result, "<span class=\"FloatNumber\">$1</span>",
of tkFloatLit..tkFloat128Lit:
dispA(result, "<span class=\"FloatNumber\">$1</span>",
"\\spanFloatNumber{$1}", [toRope(esc(d.target, literal))])
of tkSymbol:
dispA(result, "<span class=\"Identifier\">$1</span>",
of tkSymbol:
dispA(result, "<span class=\"Identifier\">$1</span>",
"\\spanIdentifier{$1}", [toRope(esc(d.target, literal))])
of tkSpaces, tkInvalid:
of tkSpaces, tkInvalid:
app(result, literal)
of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
tkBracketDotLe, tkBracketDotRi, tkCurlyDotLe, tkCurlyDotRi, tkParDotLe,
tkParDotRi, tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot,
tkAccent, tkColonColon,
tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr:
dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
tkBracketDotLe, tkBracketDotRi, tkCurlyDotLe, tkCurlyDotRi, tkParDotLe,
tkParDotRi, tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot,
tkAccent, tkColonColon,
tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr:
dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
[toRope(esc(d.target, literal))])
inc(d.id)
app(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"),
["name", "header", "desc", "itemID"],
[name, result, comm, toRope(d.id)]))
app(d.toc[k], ropeFormatNamedVars(getConfigVar("doc.item.toc"),
["name", "header", "desc", "itemID"], [
toRope(getName(d, nameNode, d.splitAfter)), result, comm, toRope(d.id)]))
setIndexTerm(d[], $d.id, getName(d, nameNode))
let
plainNameRope = toRope(xmltree.escape(plainName.strip))
cleanPlainSymbol = renderPlainSymbolName(nameNode)
complexSymbol = complexName(k, n, cleanPlainSymbol)
plainSymbolRope = toRope(cleanPlainSymbol)
plainSymbolEncRope = toRope(URLEncode(cleanPlainSymbol))
itemIDRope = toRope(d.id)
symbolOrId = d.newUniquePlainSymbol(complexSymbol)
symbolOrIdRope = symbolOrId.toRope
symbolOrIdEncRope = URLEncode(symbolOrId).toRope
proc checkForFalse(n: PNode): bool =
result = n.kind == nkIdent and IdentEq(n.ident, "false")
proc traceDeps(d: PDoc, n: PNode) =
var seeSrcRope: PRope = nil
let docItemSeeSrc = getConfigVar("doc.item.seesrc")
if docItemSeeSrc.len > 0 and options.docSeeSrcUrl.len > 0:
let urlRope = ropeFormatNamedVars(options.docSeeSrcUrl,
["path", "line"], [n.info.toFilename.toRope, toRope($n.info.line)])
dispA(seeSrcRope, "$1", "", [ropeFormatNamedVars(docItemSeeSrc,
["path", "line", "url"], [n.info.toFilename.toRope,
toRope($n.info.line), urlRope])])
app(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"),
["name", "header", "desc", "itemID", "header_plain", "itemSym",
"itemSymOrID", "itemSymEnc", "itemSymOrIDEnc", "seeSrc"],
[nameRope, result, comm, itemIDRope, plainNameRope, plainSymbolRope,
symbolOrIdRope, plainSymbolEncRope, symbolOrIdEncRope, seeSrcRope]))
app(d.toc[k], ropeFormatNamedVars(getConfigVar("doc.item.toc"),
["name", "header", "desc", "itemID", "header_plain", "itemSym",
"itemSymOrID", "itemSymEnc", "itemSymOrIDEnc"],
[toRope(getName(d, nameNode, d.splitAfter)), result, comm,
itemIDRope, plainNameRope, plainSymbolRope, symbolOrIdRope,
plainSymbolEncRope, symbolOrIdEncRope]))
# Ironically for types the complexSymbol is *cleaner* than the plainName
# because it doesn't include object fields or documentation comments. So we
# use the plain one for callable elements, and the complex for the rest.
var linkTitle = changeFileExt(extractFilename(d.filename), "") & " : "
if n.isCallable: linkTitle.add(xmltree.escape(plainName.strip))
else: linkTitle.add(xmltree.escape(complexSymbol.strip))
setIndexTerm(d[], symbolOrId, name, linkTitle,
xmltree.escape(plainDocstring.docstringSummary))
proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): PJsonNode =
if not isVisible(nameNode): return
var
name = getName(d, nameNode)
comm = genRecComment(d, n).ropeToStr()
r: TSrcGen
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments})
result = %{ "name": %name, "type": %($k) }
if comm != nil and comm != "":
result["description"] = %comm
if r.buf != nil:
result["code"] = %r.buf
proc checkForFalse(n: PNode): bool =
result = n.kind == nkIdent and identEq(n.ident, "false")
proc traceDeps(d: PDoc, n: PNode) =
const k = skModule
if d.section[k] != nil: app(d.section[k], ", ")
dispA(d.section[k],
"<a class=\"reference external\" href=\"$1.html\">$1</a>",
dispA(d.section[k],
"<a class=\"reference external\" href=\"$1.html\">$1</a>",
"$1", [toRope(getModuleName(n))])
proc generateDoc*(d: PDoc, n: PNode) =
proc generateDoc*(d: PDoc, n: PNode) =
case n.kind
of nkCommentStmt: app(d.modDesc, genComment(d, n))
of nkProcDef:
of nkProcDef:
when useEffectSystem: documentRaises(n)
genItem(d, n, n.sons[namePos], skProc)
of nkMethodDef:
when useEffectSystem: documentRaises(n)
genItem(d, n, n.sons[namePos], skMethod)
of nkIteratorDef:
of nkIteratorDef:
when useEffectSystem: documentRaises(n)
genItem(d, n, n.sons[namePos], skIterator)
of nkMacroDef: genItem(d, n, n.sons[namePos], skMacro)
@@ -284,27 +456,69 @@ proc generateDoc*(d: PDoc, n: PNode) =
genItem(d, n, n.sons[namePos], skConverter)
of nkTypeSection, nkVarSection, nkLetSection, nkConstSection:
for i in countup(0, sonsLen(n) - 1):
if n.sons[i].kind != nkCommentStmt:
if n.sons[i].kind != nkCommentStmt:
# order is always 'type var let const':
genItem(d, n.sons[i], n.sons[i].sons[0],
genItem(d, n.sons[i], n.sons[i].sons[0],
succ(skType, ord(n.kind)-ord(nkTypeSection)))
of nkStmtList:
of nkStmtList:
for i in countup(0, sonsLen(n) - 1): generateDoc(d, n.sons[i])
of nkWhenStmt:
of nkWhenStmt:
# generate documentation for the first branch only:
if not checkForFalse(n.sons[0].sons[0]):
generateDoc(d, lastSon(n.sons[0]))
of nkImportStmt:
for i in 0 .. sonsLen(n)-1: traceDeps(d, n.sons[i])
for i in 0 .. sonsLen(n)-1: traceDeps(d, n.sons[i])
of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0])
else: nil
else: discard
proc genSection(d: PDoc, kind: TSymKind) =
proc generateJson(d: PDoc, n: PNode, jArray: PJsonNode = nil): PJsonNode =
case n.kind
of nkCommentStmt:
if n.comment != nil and startsWith(n.comment, "##"):
let stripped = n.comment.substr(2).strip
result = %{ "comment": %stripped }
of nkProcDef:
when useEffectSystem: documentRaises(n)
result = genJSONItem(d, n, n.sons[namePos], skProc)
of nkMethodDef:
when useEffectSystem: documentRaises(n)
result = genJSONItem(d, n, n.sons[namePos], skMethod)
of nkIteratorDef:
when useEffectSystem: documentRaises(n)
result = genJSONItem(d, n, n.sons[namePos], skIterator)
of nkMacroDef:
result = genJSONItem(d, n, n.sons[namePos], skMacro)
of nkTemplateDef:
result = genJSONItem(d, n, n.sons[namePos], skTemplate)
of nkConverterDef:
when useEffectSystem: documentRaises(n)
result = genJSONItem(d, n, n.sons[namePos], skConverter)
of nkTypeSection, nkVarSection, nkLetSection, nkConstSection:
for i in countup(0, sonsLen(n) - 1):
if n.sons[i].kind != nkCommentStmt:
# order is always 'type var let const':
result = genJSONItem(d, n.sons[i], n.sons[i].sons[0],
succ(skType, ord(n.kind)-ord(nkTypeSection)))
of nkStmtList:
var elem = jArray
if elem == nil: elem = newJArray()
for i in countup(0, sonsLen(n) - 1):
var r = generateJson(d, n.sons[i], elem)
if r != nil:
elem.add(r)
if result == nil: result = elem
of nkWhenStmt:
# generate documentation for the first branch only:
if not checkForFalse(n.sons[0].sons[0]) and jArray != nil:
discard generateJson(d, lastSon(n.sons[0]), jArray)
else: discard
proc genSection(d: PDoc, kind: TSymKind) =
const sectionNames: array[skModule..skTemplate, string] = [
"Imports", "Types", "Vars", "Lets", "Consts", "Vars", "Procs", "Methods",
"Iterators", "Converters", "Macros", "Templates"
"Imports", "Types", "Vars", "Lets", "Consts", "Vars", "Procs", "Methods",
"Iterators", "Iterators", "Converters", "Macros", "Templates"
]
if d.section[kind] == nil: return
if d.section[kind] == nil: return
var title = sectionNames[kind].toRope
d.section[kind] = ropeFormatNamedVars(getConfigVar("doc.section"), [
"sectionid", "sectionTitle", "sectionTitleID", "content"], [
@@ -313,7 +527,7 @@ proc genSection(d: PDoc, kind: TSymKind) =
"sectionid", "sectionTitle", "sectionTitleID", "content"], [
ord(kind).toRope, title, toRope(ord(kind) + 50), d.toc[kind]])
proc genOutFile(d: PDoc): PRope =
proc genOutFile(d: PDoc): PRope =
var
code, content: PRope
title = ""
@@ -321,7 +535,7 @@ proc genOutFile(d: PDoc): PRope =
var tmp = ""
renderTocEntries(d[], j, 1, tmp)
var toc = tmp.toRope
for i in countup(low(TSymKind), high(TSymKind)):
for i in countup(low(TSymKind), high(TSymKind)):
genSection(d, i)
app(toc, d.toc[i])
if toc != nil:
@@ -329,46 +543,46 @@ proc genOutFile(d: PDoc): PRope =
for i in countup(low(TSymKind), high(TSymKind)): app(code, d.section[i])
if d.meta[metaTitle].len != 0: title = d.meta[metaTitle]
else: title = "Module " & extractFilename(changeFileExt(d.filename, ""))
let bodyname = if d.hasToc: "doc.body_toc" else: "doc.body_no_toc"
content = ropeFormatNamedVars(getConfigVar(bodyname), ["title",
content = ropeFormatNamedVars(getConfigVar(bodyname), ["title",
"tableofcontents", "moduledesc", "date", "time", "content"],
[title.toRope, toc, d.modDesc, toRope(getDateStr()),
[title.toRope, toc, d.modDesc, toRope(getDateStr()),
toRope(getClockStr()), code])
if optCompileOnly notin gGlobalOptions:
if optCompileOnly notin gGlobalOptions:
# XXX what is this hack doing here? 'optCompileOnly' means raw output!?
code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",
"tableofcontents", "moduledesc", "date", "time",
"content", "author", "version"],
[title.toRope, toc, d.modDesc, toRope(getDateStr()),
toRope(getClockStr()), content, d.meta[metaAuthor].toRope,
code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",
"tableofcontents", "moduledesc", "date", "time",
"content", "author", "version"],
[title.toRope, toc, d.modDesc, toRope(getDateStr()),
toRope(getClockStr()), content, d.meta[metaAuthor].toRope,
d.meta[metaVersion].toRope])
else:
else:
code = content
result = code
proc generateIndex*(d: PDoc) =
if optGenIndex in gGlobalOptions:
writeIndexFile(d[], splitFile(options.outFile).dir /
splitFile(d.filename).name & indexExt)
writeIndexFile(d[], splitFile(options.outFile).dir /
splitFile(d.filename).name & IndexExt)
proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) =
proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) =
var content = genOutFile(d)
if optStdout in gGlobalOptions:
writeRope(stdout, content)
else:
writeRope(content, getOutFile(filename, outExt), useWarning)
proc CommandDoc*() =
proc commandDoc*() =
var ast = parseFile(gProjectMainIdx)
if ast == nil: return
if ast == nil: return
var d = newDocumentor(gProjectFull, options.gConfigVars)
d.hasToc = true
generateDoc(d, ast)
writeOutput(d, gProjectFull, HtmlExt)
generateIndex(d)
proc CommandRstAux(filename, outExt: string) =
proc commandRstAux(filename, outExt: string) =
var filen = addFileExt(filename, "txt")
var d = newDocumentor(filen, options.gConfigVars)
var rst = parseRst(readFile(filen), filen, 0, 1, d.hasToc,
@@ -381,19 +595,33 @@ proc CommandRstAux(filename, outExt: string) =
writeOutput(d, filename, outExt)
generateIndex(d)
proc CommandRst2Html*() =
CommandRstAux(gProjectFull, HtmlExt)
proc commandRst2Html*() =
commandRstAux(gProjectFull, HtmlExt)
proc CommandRst2TeX*() =
proc commandRst2TeX*() =
splitter = "\\-"
CommandRstAux(gProjectFull, TexExt)
commandRstAux(gProjectFull, TexExt)
proc CommandBuildIndex*() =
proc commandJSON*() =
var ast = parseFile(gProjectMainIdx)
if ast == nil: return
var d = newDocumentor(gProjectFull, options.gConfigVars)
d.hasToc = true
var json = generateJson(d, ast)
var content = newRope(pretty(json))
if optStdout in gGlobalOptions:
writeRope(stdout, content)
else:
echo getOutFile(gProjectFull, JsonExt)
writeRope(content, getOutFile(gProjectFull, JsonExt), useWarning = false)
proc commandBuildIndex*() =
var content = mergeIndexes(gProjectFull).toRope
let code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",
"tableofcontents", "moduledesc", "date", "time",
"content", "author", "version"],
["Index".toRope, nil, nil, toRope(getDateStr()),
let code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",
"tableofcontents", "moduledesc", "date", "time",
"content", "author", "version"],
["Index".toRope, nil, nil, toRope(getDateStr()),
toRope(getClockStr()), content, nil, nil])
writeRope(code, getOutFile("theindex", HtmlExt))

View File

@@ -27,7 +27,7 @@ proc close(p: PPassContext, n: PNode): PNode =
try:
generateIndex(g.doc)
except EIO:
nil
discard
proc processNode(c: PPassContext, n: PNode): PNode =
result = n
@@ -46,4 +46,4 @@ proc myOpen(module: PSym): PPassContext =
const docgen2Pass* = makePass(open = myOpen, process = processNode, close = close)
proc finishDoc2Pass*(project: string) =
nil
discard

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -9,7 +9,7 @@
## This file implements the FFI part of the evaluator for Nimrod code.
import ast, astalgo, ropes, types, options, tables, dynlib, libffi, msgs
import ast, astalgo, ropes, types, options, tables, dynlib, libffi, msgs, os
when defined(windows):
const libcDll = "msvcrt.dll"
@@ -20,7 +20,11 @@ type
TDllCache = tables.TTable[string, TLibHandle]
var
gDllCache = initTable[string, TLibHandle]()
gExeHandle = LoadLib()
when defined(windows):
var gExeHandle = loadLib(os.getAppFilename())
else:
var gExeHandle = loadLib()
proc getDll(cache: var TDllCache; dll: string; info: TLineInfo): pointer =
result = cache[dll]
@@ -28,15 +32,17 @@ proc getDll(cache: var TDllCache; dll: string; info: TLineInfo): pointer =
var libs: seq[string] = @[]
libCandidates(dll, libs)
for c in libs:
result = LoadLib(c)
result = loadLib(c)
if not result.isNil: break
if result.isNil:
GlobalError(info, "cannot load: " & dll)
globalError(info, "cannot load: " & dll)
cache[dll] = result
const
nkPtrLit = nkIntLit # hopefully we can get rid of this hack soon
var myerrno {.importc: "errno", header: "<errno.h>".}: cint ## error variable
proc importcSymbol*(sym: PSym): PNode =
let name = ropeToStr(sym.loc.r)
@@ -47,10 +53,11 @@ proc importcSymbol*(sym: PSym): PNode =
of "stdin": result.intVal = cast[TAddress](system.stdin)
of "stdout": result.intVal = cast[TAddress](system.stdout)
of "stderr": result.intVal = cast[TAddress](system.stderr)
of "vmErrnoWrapper": result.intVal = cast[TAddress](myerrno)
else:
let lib = sym.annex
if lib != nil and lib.path.kind notin {nkStrLit..nkTripleStrLit}:
GlobalError(sym.info, "dynlib needs to be a string lit for the REPL")
globalError(sym.info, "dynlib needs to be a string lit for the REPL")
var theAddr: pointer
if lib.isNil and not gExehandle.isNil:
# first try this exe itself:
@@ -58,10 +65,12 @@ proc importcSymbol*(sym: PSym): PNode =
# then try libc:
if theAddr.isNil:
let dllhandle = gDllCache.getDll(libcDll, sym.info)
theAddr = dllhandle.checkedSymAddr(name)
else:
let dllhandle = gDllCache.getDll(lib.path.strVal, sym.info)
theAddr = dllhandle.checkedSymAddr(name)
theAddr = dllhandle.symAddr(name)
elif not lib.isNil:
let dllhandle = gDllCache.getDll(if lib.kind == libHeader: libcDll
else: lib.path.strVal, sym.info)
theAddr = dllhandle.symAddr(name)
if theAddr.isNil: globalError(sym.info, "cannot import: " & sym.name.s)
result.intVal = cast[TAddress](theAddr)
proc mapType(t: ast.PType): ptr libffi.TType =
@@ -78,7 +87,7 @@ proc mapType(t: ast.PType): ptr libffi.TType =
of tyFloat, tyFloat64: result = addr libffi.type_double
of tyFloat32: result = addr libffi.type_float
of tyVar, tyPointer, tyPtr, tyRef, tyCString, tySequence, tyString, tyExpr,
tyStmt, tyTypeDesc, tyProc, tyArray, tyArrayConstr, tyNil:
tyStmt, tyTypeDesc, tyProc, tyArray, tyArrayConstr, tyStatic, tyNil:
result = addr libffi.type_pointer
of tyDistinct:
result = mapType(t.sons[0])
@@ -93,7 +102,7 @@ proc mapCallConv(cc: TCallingConvention, info: TLineInfo): TABI =
of ccStdCall: result = when defined(windows): STDCALL else: DEFAULT_ABI
of ccCDecl: result = DEFAULT_ABI
else:
GlobalError(info, "cannot map calling convention to FFI")
globalError(info, "cannot map calling convention to FFI")
template rd(T, p: expr): expr {.immediate.} = (cast[ptr T](p))[]
template wr(T, p, v: expr) {.immediate.} = (cast[ptr T](p))[] = v
@@ -107,7 +116,7 @@ proc packSize(v: PNode, typ: PType): int =
if v.kind in {nkNilLit, nkPtrLit}:
result = sizeof(pointer)
else:
result = sizeof(pointer) + packSize(v.sons[0], typ.sons[0])
result = sizeof(pointer) + packSize(v.sons[0], typ.lastSon)
of tyDistinct, tyGenericInst:
result = packSize(v, typ.sons[0])
of tyArray, tyArrayConstr:
@@ -139,10 +148,10 @@ proc getField(n: PNode; position: int): PSym =
else: internalError(n.info, "getField(record case branch)")
of nkSym:
if n.sym.position == position: result = n.sym
else: nil
else: discard
proc packObject(x: PNode, typ: PType, res: pointer) =
InternalAssert x.kind in {nkObjConstr, nkPar}
internalAssert x.kind in {nkObjConstr, nkPar}
# compute the field's offsets:
discard typ.getSize
for i in countup(ord(x.kind == nkObjConstr), sonsLen(x) - 1):
@@ -155,7 +164,7 @@ proc packObject(x: PNode, typ: PType, res: pointer) =
let field = getField(typ.n, i)
pack(it, field.typ, res +! field.offset)
else:
GlobalError(x.info, "cannot pack unnamed tuple")
globalError(x.info, "cannot pack unnamed tuple")
const maxPackDepth = 20
var packRecCheck = 0
@@ -184,7 +193,7 @@ proc pack(v: PNode, typ: PType, res: pointer) =
of 4: awr(int32, v.intVal.int32)
of 8: awr(int64, v.intVal.int64)
else:
GlobalError(v.info, "cannot map value to FFI (tyEnum, tySet)")
globalError(v.info, "cannot map value to FFI (tyEnum, tySet)")
of tyFloat: awr(float, v.floatVal)
of tyFloat32: awr(float32, v.floatVal)
of tyFloat64: awr(float64, v.floatVal)
@@ -192,25 +201,25 @@ proc pack(v: PNode, typ: PType, res: pointer) =
of tyPointer, tyProc, tyCString, tyString:
if v.kind == nkNilLit:
# nothing to do since the memory is 0 initialized anyway
nil
discard
elif v.kind == nkPtrLit:
awr(pointer, cast[pointer](v.intVal))
elif v.kind in {nkStrLit..nkTripleStrLit}:
awr(cstring, cstring(v.strVal))
else:
GlobalError(v.info, "cannot map pointer/proc value to FFI")
globalError(v.info, "cannot map pointer/proc value to FFI")
of tyPtr, tyRef, tyVar:
if v.kind == nkNilLit:
# nothing to do since the memory is 0 initialized anyway
nil
discard
elif v.kind == nkPtrLit:
awr(pointer, cast[pointer](v.intVal))
else:
if packRecCheck > maxPackDepth:
packRecCheck = 0
GlobalError(v.info, "cannot map value to FFI " & typeToString(v.typ))
globalError(v.info, "cannot map value to FFI " & typeToString(v.typ))
inc packRecCheck
pack(v.sons[0], typ.sons[0], res +! sizeof(pointer))
pack(v.sons[0], typ.lastSon, res +! sizeof(pointer))
dec packRecCheck
awr(pointer, res +! sizeof(pointer))
of tyArray, tyArrayConstr:
@@ -220,11 +229,11 @@ proc pack(v: PNode, typ: PType, res: pointer) =
of tyObject, tyTuple:
packObject(v, typ, res)
of tyNil:
nil
discard
of tyDistinct, tyGenericInst:
pack(v, typ.sons[0], res)
else:
GlobalError(v.info, "cannot map value to FFI " & typeToString(v.typ))
globalError(v.info, "cannot map value to FFI " & typeToString(v.typ))
proc unpack(x: pointer, typ: PType, n: PNode): PNode
@@ -234,14 +243,14 @@ proc unpackObjectAdd(x: pointer, n, result: PNode) =
for i in countup(0, sonsLen(n) - 1):
unpackObjectAdd(x, n.sons[i], result)
of nkRecCase:
GlobalError(result.info, "case objects cannot be unpacked")
globalError(result.info, "case objects cannot be unpacked")
of nkSym:
var pair = newNodeI(nkExprColonExpr, result.info, 2)
pair.sons[0] = n
pair.sons[1] = unpack(x +! n.sym.offset, n.sym.typ, nil)
#echo "offset: ", n.sym.name.s, " ", n.sym.offset
result.add pair
else: nil
else: discard
proc unpackObject(x: pointer, typ: PType, n: PNode): PNode =
# compute the field's offsets:
@@ -253,14 +262,14 @@ proc unpackObject(x: pointer, typ: PType, n: PNode): PNode =
result = newNode(nkPar)
result.typ = typ
if typ.n.isNil:
InternalError("cannot unpack unnamed tuple")
internalError("cannot unpack unnamed tuple")
unpackObjectAdd(x, typ.n, result)
else:
result = n
if result.kind notin {nkObjConstr, nkPar}:
GlobalError(n.info, "cannot map value from FFI")
globalError(n.info, "cannot map value from FFI")
if typ.n.isNil:
GlobalError(n.info, "cannot unpack unnamed tuple")
globalError(n.info, "cannot unpack unnamed tuple")
for i in countup(ord(n.kind == nkObjConstr), sonsLen(n) - 1):
var it = n.sons[i]
if it.kind == nkExprColonExpr:
@@ -279,7 +288,7 @@ proc unpackArray(x: pointer, typ: PType, n: PNode): PNode =
else:
result = n
if result.kind != nkBracket:
GlobalError(n.info, "cannot map value from FFI")
globalError(n.info, "cannot map value from FFI")
let baseSize = typ.sons[1].getSize
for i in 0 .. < result.len:
result.sons[i] = unpack(x +! i * baseSize, typ.sons[1], result.sons[i])
@@ -303,7 +312,7 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
#echo "expected ", k, " but got ", result.kind
#debug result
return newNodeI(nkExceptBranch, n.info)
#GlobalError(n.info, "cannot map value from FFI")
#globalError(n.info, "cannot map value from FFI")
result.field = v
template setNil() =
@@ -328,19 +337,19 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
of tyInt16: awi(nkInt16Lit, rd(int16, x))
of tyInt32: awi(nkInt32Lit, rd(int32, x))
of tyInt64: awi(nkInt64Lit, rd(int64, x))
of tyUInt: awi(nkUIntLit, rd(uint, x).biggestInt)
of tyUInt8: awi(nkUInt8Lit, rd(uint8, x).biggestInt)
of tyUInt16: awi(nkUInt16Lit, rd(uint16, x).biggestInt)
of tyUInt32: awi(nkUInt32Lit, rd(uint32, x).biggestInt)
of tyUInt64: awi(nkUInt64Lit, rd(uint64, x).biggestInt)
of tyUInt: awi(nkUIntLit, rd(uint, x).BiggestInt)
of tyUInt8: awi(nkUInt8Lit, rd(uint8, x).BiggestInt)
of tyUInt16: awi(nkUInt16Lit, rd(uint16, x).BiggestInt)
of tyUInt32: awi(nkUInt32Lit, rd(uint32, x).BiggestInt)
of tyUInt64: awi(nkUInt64Lit, rd(uint64, x).BiggestInt)
of tyEnum:
case typ.getSize
of 1: awi(nkIntLit, rd(uint8, x).biggestInt)
of 2: awi(nkIntLit, rd(uint16, x).biggestInt)
of 4: awi(nkIntLit, rd(int32, x).biggestInt)
of 8: awi(nkIntLit, rd(int64, x).biggestInt)
of 1: awi(nkIntLit, rd(uint8, x).BiggestInt)
of 2: awi(nkIntLit, rd(uint16, x).BiggestInt)
of 4: awi(nkIntLit, rd(int32, x).BiggestInt)
of 8: awi(nkIntLit, rd(int64, x).BiggestInt)
else:
GlobalError(n.info, "cannot map value from FFI (tyEnum, tySet)")
globalError(n.info, "cannot map value from FFI (tyEnum, tySet)")
of tyFloat: awf(nkFloatLit, rd(float, x))
of tyFloat32: awf(nkFloat32Lit, rd(float32, x))
of tyFloat64: awf(nkFloat64Lit, rd(float64, x))
@@ -362,10 +371,10 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
awi(nkPtrLit, cast[TAddress](p))
elif n != nil and n.len == 1:
internalAssert n.kind == nkRefTy
n.sons[0] = unpack(p, typ.sons[0], n.sons[0])
n.sons[0] = unpack(p, typ.lastSon, n.sons[0])
result = n
else:
GlobalError(n.info, "cannot map value from FFI " & typeToString(typ))
globalError(n.info, "cannot map value from FFI " & typeToString(typ))
of tyObject, tyTuple:
result = unpackObject(x, typ, n)
of tyArray, tyArrayConstr:
@@ -382,7 +391,7 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
result = unpack(x, typ.sons[0], n)
else:
# XXX what to do with 'array' here?
GlobalError(n.info, "cannot map value from FFI " & typeToString(typ))
globalError(n.info, "cannot map value from FFI " & typeToString(typ))
proc fficast*(x: PNode, destTyp: PType): PNode =
if x.kind == nkPtrLit and x.typ.kind in {tyPtr, tyRef, tyVar, tyPointer,
@@ -405,7 +414,7 @@ proc fficast*(x: PNode, destTyp: PType): PNode =
dealloc a
proc callForeignFunction*(call: PNode): PNode =
InternalAssert call.sons[0].kind == nkPtrLit
internalAssert call.sons[0].kind == nkPtrLit
var cif: TCif
var sig: TParamList
@@ -413,12 +422,12 @@ proc callForeignFunction*(call: PNode): PNode =
for i in 1..call.len-1:
sig[i-1] = mapType(call.sons[i].typ)
if sig[i-1].isNil:
GlobalError(call.info, "cannot map FFI type")
globalError(call.info, "cannot map FFI type")
let typ = call.sons[0].typ
if prep_cif(cif, mapCallConv(typ.callConv, call.info), cuint(call.len-1),
mapType(typ.sons[0]), sig) != OK:
GlobalError(call.info, "error in FFI call")
globalError(call.info, "error in FFI call")
var args: TArgList
let fn = cast[pointer](call.sons[0].intVal)
@@ -441,3 +450,46 @@ proc callForeignFunction*(call: PNode): PNode =
for i in 1 .. call.len-1:
call.sons[i] = unpack(args[i-1], typ.sons[i], call[i])
dealloc args[i-1]
proc callForeignFunction*(fn: PNode, fntyp: PType,
args: var TNodeSeq, start, len: int,
info: TLineInfo): PNode =
internalAssert fn.kind == nkPtrLit
var cif: TCif
var sig: TParamList
for i in 0..len-1:
var aTyp = args[i+start].typ
if aTyp.isNil:
internalAssert i+1 < fntyp.len
aTyp = fntyp.sons[i+1]
args[i+start].typ = aTyp
sig[i] = mapType(aTyp)
if sig[i].isNil: globalError(info, "cannot map FFI type")
if prep_cif(cif, mapCallConv(fntyp.callConv, info), cuint(len),
mapType(fntyp.sons[0]), sig) != OK:
globalError(info, "error in FFI call")
var cargs: TArgList
let fn = cast[pointer](fn.intVal)
for i in 0 .. len-1:
let t = args[i+start].typ
cargs[i] = alloc0(packSize(args[i+start], t))
pack(args[i+start], t, cargs[i])
let retVal = if isEmptyType(fntyp.sons[0]): pointer(nil)
else: alloc(fntyp.sons[0].getSize.int)
libffi.call(cif, fn, retVal, cargs)
if retVal.isNil:
result = emptyNode
else:
result = unpack(retVal, fntyp.sons[0], nil)
result.info = info
if retVal != nil: dealloc retVal
for i in 0 .. len-1:
let t = args[i+start].typ
args[i+start] = unpack(cargs[i], t, args[i+start])
dealloc cargs[i]

View File

@@ -23,12 +23,12 @@ when hasFFI:
type
PStackFrame* = ref TStackFrame
TStackFrame*{.final.} = object
mapping*: TIdNodeTable # mapping from symbols to nodes
prc*: PSym # current prc; proc that is evaluated
call*: PNode
next*: PStackFrame # for stacking
params*: TNodeSeq # parameters passed to the proc
TStackFrame* = object
prc: PSym # current prc; proc that is evaluated
slots: TNodeSeq # parameters passed to the proc + locals;
# parameters come first
call: PNode
next: PStackFrame # for stacking
TEvalMode* = enum ## reason for evaluation
emRepl, ## evaluate because in REPL mode
@@ -53,7 +53,8 @@ type
features: TSandboxFlags
globals*: TIdNodeTable # state of global vars
getType*: proc(n: PNode): PNode {.closure.}
handleIsOperator*: proc(n: PNode): PNode {.closure.}
PEvalContext* = ref TEvalContext
TEvalFlag = enum
@@ -67,10 +68,9 @@ const
# other idea: use a timeout! -> Wether code compiles depends on the machine
# the compiler runs on then! Bad idea!
proc newStackFrame*(): PStackFrame =
proc newStackFrame*(): PStackFrame =
new(result)
initIdNodeTable(result.mapping)
result.params = @[]
result.slots = @[]
proc newEvalContext*(module: PSym, mode: TEvalMode): PEvalContext =
new(result)
@@ -91,6 +91,7 @@ proc evalMacroCall*(c: PEvalContext, n, nOrig: PNode, sym: PSym): PNode
proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode
proc raiseCannotEval(c: PEvalContext, info: TLineInfo): PNode =
if defined(debug) and gVerbosity >= 3: writeStackTrace()
result = newNodeI(nkExceptBranch, info)
# creating a nkExceptBranch without sons
# means that it could not be evaluated
@@ -111,13 +112,18 @@ proc stackTraceAux(x: PStackFrame) =
add(s, x.prc.name.s)
MsgWriteln(s)
proc stackTrace(c: PEvalContext, n: PNode, msg: TMsgKind, arg = "") =
proc stackTrace(c: PEvalContext, info: TLineInfo, msg: TMsgKind, arg = "") =
MsgWriteln("stack trace: (most recent call last)")
stackTraceAux(c.tos)
LocalError(n.info, msg, arg)
LocalError(info, msg, arg)
proc isSpecial(n: PNode): bool {.inline.} =
result = n.kind == nkExceptBranch
template isSpecial(n: PNode): bool = n.kind == nkExceptBranch
template bailout() {.dirty.} =
if isSpecial(result): return
template evalX(n, flags) {.dirty.} =
result = evalAux(c, n, flags)
bailout()
proc myreset(n: PNode) =
when defined(system.reset):
@@ -129,19 +135,17 @@ proc evalIf(c: PEvalContext, n: PNode): PNode =
var i = 0
var length = sonsLen(n)
while (i < length) and (sonsLen(n.sons[i]) >= 2):
result = evalAux(c, n.sons[i].sons[0], {})
if isSpecial(result): return
if (result.kind == nkIntLit) and (result.intVal != 0):
evalX(n.sons[i].sons[0], {})
if result.kind == nkIntLit and result.intVal != 0:
return evalAux(c, n.sons[i].sons[1], {})
inc(i)
if (i < length) and (sonsLen(n.sons[i]) < 2):
if (i < length) and (sonsLen(n.sons[i]) < 2):
result = evalAux(c, n.sons[i].sons[0], {})
else:
else:
result = emptyNode
proc evalCase(c: PEvalContext, n: PNode): PNode =
result = evalAux(c, n.sons[0], {})
if isSpecial(result): return
evalX(n.sons[0], {})
var res = result
result = emptyNode
for i in countup(1, sonsLen(n) - 1):
@@ -159,11 +163,11 @@ var
gNestedEvals: int # count the recursive calls to ``evalAux`` to prevent
# endless recursion
proc evalWhile(c: PEvalContext, n: PNode): PNode =
while true:
result = evalAux(c, n.sons[0], {})
if isSpecial(result): return
if getOrdValue(result) == 0: break
proc evalWhile(c: PEvalContext, n: PNode): PNode =
while true:
evalX(n.sons[0], {})
if getOrdValue(result) == 0:
result = emptyNode; break
result = evalAux(c, n.sons[1], {})
case result.kind
of nkBreakStmt:
@@ -178,7 +182,7 @@ proc evalWhile(c: PEvalContext, n: PNode): PNode =
if allowInfiniteLoops in c.features:
gWhileCounter = 0
else:
stackTrace(c, n, errTooManyIterations)
stackTrace(c, n.info, errTooManyIterations)
break
proc evalBlock(c: PEvalContext, n: PNode): PNode =
@@ -223,7 +227,9 @@ proc evalTry(c: PEvalContext, n: PNode): PNode =
else:
for j in countup(0, blen - 2):
assert(n.sons[i].sons[j].kind == nkType)
if exc.typ.id == n.sons[i].sons[j].typ.id:
let a = exc.typ.skipTypes(abstractPtrs)
let b = n.sons[i].sons[j].typ.skipTypes(abstractPtrs)
if a == b:
result = evalAux(c, n.sons[i].sons[blen - 1], {})
exc = result
break
@@ -240,7 +246,7 @@ proc getNullValueAux(obj: PNode, result: PNode) =
getNullValueAux(obj.sons[0], result)
for i in countup(1, sonsLen(obj) - 1):
getNullValueAux(lastSon(obj.sons[i]), result)
of nkSym:
of nkSym:
var s = obj.sym
var p = newNodeIT(nkExprColonExpr, result.info, s.typ)
addSon(p, newSymNode(s, result.info))
@@ -258,8 +264,8 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
result = newNodeIT(nkUIntLit, info, t)
of tyFloat..tyFloat128:
result = newNodeIt(nkFloatLit, info, t)
of tyVar, tyPointer, tyPtr, tyRef, tyCString, tySequence, tyString, tyExpr,
tyStmt, tyTypeDesc, tyProc:
of tyVar, tyPointer, tyPtr, tyRef, tyCString, tySequence, tyString, tyExpr,
tyStmt, tyTypeDesc, tyStatic, tyProc:
result = newNodeIT(nkNilLit, info, t)
of tyObject:
result = newNodeIT(nkPar, info, t)
@@ -287,67 +293,93 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
result = newNodeIT(nkCurly, info, t)
else: InternalError("getNullValue: " & $t.kind)
proc evalVar(c: PEvalContext, n: PNode): PNode =
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if a.kind != nkIdentDefs: return raiseCannotEval(c, n.info)
# XXX var (x, y) = z support?
proc evalVarValue(c: PEvalContext, n: PNode): PNode =
result = evalAux(c, n, {})
if result.kind in {nkType..nkNilLit}: result = result.copyNode
proc allocSlot(c: PStackFrame; sym: PSym): int =
result = sym.position + ord(sym.kind == skParam)
if result == 0 and sym.kind != skResult:
result = c.slots.len
if result == 0: result = 1
sym.position = result
setLen(c.slots, max(result+1, c.slots.len))
proc setSlot(c: PStackFrame, sym: PSym, val: PNode) =
assert sym.owner == c.prc or sfFromGeneric in sym.flags
let idx = allocSlot(c, sym)
c.slots[idx] = val
proc setVar(c: PEvalContext, v: PSym, n: PNode) =
if sfGlobal notin v.flags: setSlot(c.tos, v, n)
else: IdNodeTablePut(c.globals, v, n)
proc evalVar(c: PEvalContext, n: PNode): PNode =
for i in countup(0, sonsLen(n) - 1):
let a = n.sons[i]
if a.kind == nkCommentStmt: continue
#assert(a.sons[0].kind == nkSym) can happen for transformed vars
if a.sons[2].kind != nkEmpty:
result = evalAux(c, a.sons[2], {})
if result.kind in {nkType..nkNilLit}:
if a.kind == nkVarTuple:
result = evalVarValue(c, a.lastSon)
if result.kind in {nkType..nkNilLit}:
result = result.copyNode
if isSpecial(result): return
bailout()
if result.kind != nkPar:
return raiseCannotEval(c, n.info)
for i in 0 .. a.len-3:
var v = a.sons[i].sym
setVar(c, v, result.sons[i])
else:
result = getNullValue(a.sons[0].typ, a.sons[0].info)
if a.sons[0].kind == nkSym:
var v = a.sons[0].sym
IdNodeTablePut(c.tos.mapping, v, result)
else:
# assign to a.sons[0]:
var x = result
result = evalAux(c, a.sons[0], {})
if isSpecial(result): return
myreset(x)
x.kind = result.kind
x.typ = result.typ
case x.kind
of nkCharLit..nkInt64Lit: x.intVal = result.intVal
of nkFloatLit..nkFloat64Lit: x.floatVal = result.floatVal
of nkStrLit..nkTripleStrLit: x.strVal = result.strVal
of nkIdent: x.ident = result.ident
of nkSym: x.sym = result.sym
if a.sons[2].kind != nkEmpty:
result = evalVarValue(c, a.sons[2])
bailout()
else:
if x.kind notin {nkEmpty..nkNilLit}:
discardSons(x)
for j in countup(0, sonsLen(result) - 1): addSon(x, result.sons[j])
result = getNullValue(a.sons[0].typ, a.sons[0].info)
if a.sons[0].kind == nkSym:
var v = a.sons[0].sym
setVar(c, v, result)
else:
# assign to a.sons[0]:
var x = result
evalX(a.sons[0], {})
myreset(x)
x.kind = result.kind
x.typ = result.typ
case x.kind
of nkCharLit..nkInt64Lit: x.intVal = result.intVal
of nkFloatLit..nkFloat64Lit: x.floatVal = result.floatVal
of nkStrLit..nkTripleStrLit: x.strVal = result.strVal
of nkIdent: x.ident = result.ident
of nkSym: x.sym = result.sym
else:
if x.kind notin {nkEmpty..nkNilLit}:
discardSons(x)
for j in countup(0, sonsLen(result) - 1): addSon(x, result.sons[j])
result = emptyNode
proc aliasNeeded(n: PNode, flags: TEvalFlags): bool =
result = efLValue in flags or n.typ == nil or
n.typ.kind in {tyExpr, tyStmt, tyTypeDesc}
n.typ.kind in {tyExpr, tyStatic, tyStmt, tyTypeDesc}
proc evalVariable(c: PStackFrame, sym: PSym, flags: TEvalFlags): PNode =
proc evalVariable(c: PStackFrame, sym: PSym, flags: TEvalFlags): PNode =
# We need to return a node to the actual value,
# which can be modified.
assert sym.position != 0 or skResult == sym.kind
var x = c
while x != nil:
if sym.kind == skResult and x.params.len > 0:
result = x.params[0]
if result == nil: result = emptyNode
while x != nil:
if sym.owner == x.prc:
result = x.slots[sym.position]
assert result != nil
if not aliasNeeded(result, flags):
result = copyTree(result)
return
result = IdNodeTableGet(x.mapping, sym)
if result != nil and not aliasNeeded(result, flags):
result = copyTree(result)
if result != nil: return
x = x.next
#internalError(sym.info, "cannot eval " & sym.name.s)
#internalError(sym.info, "cannot eval " & sym.name.s & " " & $sym.position)
result = raiseCannotEval(nil, sym.info)
#result = emptyNode
proc evalGlobalVar(c: PEvalContext, s: PSym, flags: TEvalFlags): PNode =
if sfCompileTime in s.flags or c.mode == emRepl:
if sfCompileTime in s.flags or c.mode == emRepl or s.kind == skForVar:
result = IdNodeTableGet(c.globals, s)
if result != nil:
if not aliasNeeded(result, flags):
@@ -369,17 +401,19 @@ proc evalGlobalVar(c: PEvalContext, s: PSym, flags: TEvalFlags): PNode =
else:
result = raiseCannotEval(nil, s.info)
proc optBody(c: PEvalContext, s: PSym): PNode =
result = s.getBody
proc evalCall(c: PEvalContext, n: PNode): PNode =
var d = newStackFrame()
d.call = n
var prc = n.sons[0]
let isClosure = prc.kind == nkClosure
setlen(d.params, sonsLen(n) + ord(isClosure))
setlen(d.slots, sonsLen(n) + ord(isClosure))
if isClosure:
#debug prc
result = evalAux(c, prc.sons[1], {efLValue})
if isSpecial(result): return
d.params[sonsLen(n)] = result
evalX(prc.sons[1], {efLValue})
d.slots[sonsLen(n)] = result
result = evalAux(c, prc.sons[0], {})
else:
result = evalAux(c, prc, {})
@@ -395,47 +429,43 @@ proc evalCall(c: PEvalContext, n: PNode): PNode =
InternalError(n.info, "evalCall")
return
for i in countup(1, sonsLen(n) - 1):
result = evalAux(c, n.sons[i], {})
if isSpecial(result): return
d.params[i] = result
if n.typ != nil: d.params[0] = getNullValue(n.typ, n.info)
evalX(n.sons[i], {})
d.slots[i] = result
if n.typ != nil: d.slots[0] = getNullValue(n.typ, n.info)
when hasFFI:
if sfImportc in prc.sym.flags and allowFFI in c.features:
var newCall = newNodeI(nkCall, n.info, n.len)
newCall.sons[0] = evalGlobalVar(c, prc.sym, {})
for i in 1 .. <n.len:
newCall.sons[i] = d.params[i]
newCall.sons[i] = d.slots[i]
return callForeignFunction(newCall)
pushStackFrame(c, d)
result = evalAux(c, prc.sym.getBody, {})
if result.kind == nkExceptBranch: return
if n.typ != nil: result = d.params[0]
evalX(optBody(c, prc.sym), {})
if n.typ != nil: result = d.slots[0]
popStackFrame(c)
proc evalArrayAccess(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
result = evalAux(c, n.sons[0], flags)
if isSpecial(result): return
evalX(n.sons[0], flags)
var x = result
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
evalX(n.sons[1], {})
var idx = getOrdValue(result)
result = emptyNode
case x.kind
of nkPar:
of nkPar:
if (idx >= 0) and (idx < sonsLen(x)):
result = x.sons[int(idx)]
if result.kind == nkExprColonExpr: result = result.sons[1]
if not aliasNeeded(result, flags): result = copyTree(result)
else:
stackTrace(c, n, errIndexOutOfBounds)
stackTrace(c, n.info, errIndexOutOfBounds)
of nkBracket, nkMetaNode:
if (idx >= 0) and (idx < sonsLen(x)):
result = x.sons[int(idx)]
if not aliasNeeded(result, flags): result = copyTree(result)
else:
stackTrace(c, n, errIndexOutOfBounds)
stackTrace(c, n.info, errIndexOutOfBounds)
of nkStrLit..nkTripleStrLit:
if efLValue in flags: return raiseCannotEval(c, n.info)
result = newNodeIT(nkCharLit, x.info, getSysType(tyChar))
@@ -444,14 +474,13 @@ proc evalArrayAccess(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
elif idx == len(x.strVal):
nil
else:
stackTrace(c, n, errIndexOutOfBounds)
else: stackTrace(c, n, errNilAccess)
stackTrace(c, n.info, errIndexOutOfBounds)
else: stackTrace(c, n.info, errNilAccess)
proc evalFieldAccess(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
# a real field access; proc calls have already been transformed
# XXX: field checks!
result = evalAux(c, n.sons[0], flags)
if isSpecial(result): return
evalX(n.sons[0], flags)
var x = result
if x.kind != nkPar: return raiseCannotEval(c, n.info)
# this is performance critical:
@@ -459,48 +488,26 @@ proc evalFieldAccess(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
result = x.sons[field.position]
if result.kind == nkExprColonExpr: result = result.sons[1]
if not aliasNeeded(result, flags): result = copyTree(result)
when false:
var field = n.sons[1].sym
for i in countup(0, sonsLen(x) - 1):
var it = x.sons[i]
if it.kind != nkExprColonExpr:
# lookup per index:
result = x.sons[field.position]
if result.kind == nkExprColonExpr: result = result.sons[1]
if not aliasNeeded(result, flags): result = copyTree(result)
return
#InternalError(it.info, "evalFieldAccess")
if it.sons[0].sym.name.id == field.name.id:
result = x.sons[i].sons[1]
if not aliasNeeded(result, flags): result = copyTree(result)
return
stackTrace(c, n, errFieldXNotFound, field.name.s)
result = emptyNode
proc evalAsgn(c: PEvalContext, n: PNode): PNode =
proc evalAsgn(c: PEvalContext, n: PNode): PNode =
var a = n.sons[0]
if a.kind == nkBracketExpr and a.sons[0].typ.kind in {tyString, tyCString}:
result = evalAux(c, a.sons[0], {efLValue})
if isSpecial(result): return
evalX(a.sons[0], {efLValue})
var x = result
result = evalAux(c, a.sons[1], {})
if isSpecial(result): return
evalX(a.sons[1], {})
var idx = getOrdValue(result)
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
if result.kind != nkCharLit: return raiseCannotEval(c, n.info)
evalX(n.sons[1], {})
if result.kind notin {nkIntLit, nkCharLit}: return c.raiseCannotEval(n.info)
if (idx >= 0) and (idx < len(x.strVal)):
if idx >= 0 and idx < len(x.strVal):
x.strVal[int(idx)] = chr(int(result.intVal))
else:
stackTrace(c, n, errIndexOutOfBounds)
else:
stackTrace(c, n.info, errIndexOutOfBounds)
else:
result = evalAux(c, n.sons[0], {efLValue})
if isSpecial(result): return
evalX(n.sons[0], {efLValue})
var x = result
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
evalX(n.sons[1], {})
myreset(x)
x.kind = result.kind
x.typ = result.typ
@@ -518,13 +525,11 @@ proc evalAsgn(c: PEvalContext, n: PNode): PNode =
assert result.kind == nkEmpty
proc evalSwap(c: PEvalContext, n: PNode): PNode =
result = evalAux(c, n.sons[0], {efLValue})
if isSpecial(result): return
evalX(n.sons[0], {efLValue})
var x = result
result = evalAux(c, n.sons[1], {efLValue})
if isSpecial(result): return
evalX(n.sons[1], {efLValue})
if x.kind != result.kind:
stackTrace(c, n, errCannotInterpretNodeX, $n.kind)
stackTrace(c, n.info, errCannotInterpretNodeX, $n.kind)
else:
case x.kind
of nkCharLit..nkInt64Lit: swap(x.intVal, result.intVal)
@@ -553,8 +558,8 @@ proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
result = evalGlobalVar(c, s, flags)
of skParam:
# XXX what about LValue?
if s.position + 1 <% c.tos.params.len:
result = c.tos.params[s.position + 1]
if s.position + 1 <% c.tos.slots.len:
result = c.tos.slots[s.position + 1]
of skConst: result = s.ast
of skEnumField: result = newIntNodeT(s.position, n)
else: result = nil
@@ -564,11 +569,9 @@ proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
result = raiseCannotEval(c, n.info)
proc evalIncDec(c: PEvalContext, n: PNode, sign: biggestInt): PNode =
result = evalAux(c, n.sons[1], {efLValue})
if isSpecial(result): return
evalX(n.sons[1], {efLValue})
var a = result
result = evalAux(c, n.sons[2], {})
if isSpecial(result): return
evalX(n.sons[2], {})
var b = result
case a.kind
of nkCharLit..nkInt64Lit: a.intval = a.intVal + sign * getOrdValue(b)
@@ -584,64 +587,62 @@ proc getStrValue(n: PNode): string =
proc evalEcho(c: PEvalContext, n: PNode): PNode =
for i in countup(1, sonsLen(n) - 1):
result = evalAux(c, n.sons[i], {})
if isSpecial(result): return
evalX(n.sons[i], {})
Write(stdout, getStrValue(result))
writeln(stdout, "")
result = emptyNode
proc evalExit(c: PEvalContext, n: PNode): PNode =
if c.mode in {emRepl, emStatic}:
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
evalX(n.sons[1], {})
Message(n.info, hintQuitCalled)
quit(int(getOrdValue(result)))
else:
result = raiseCannotEval(c, n.info)
proc evalOr(c: PEvalContext, n: PNode): PNode =
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
if result.kind != nkIntLit: InternalError(n.info, "evalOr")
elif result.intVal == 0: result = evalAux(c, n.sons[2], {})
evalX(n.sons[1], {})
if result.intVal == 0: result = evalAux(c, n.sons[2], {})
proc evalAnd(c: PEvalContext, n: PNode): PNode =
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
if result.kind != nkIntLit: InternalError(n.info, "evalAnd")
elif result.intVal != 0: result = evalAux(c, n.sons[2], {})
evalX(n.sons[1], {})
if result.intVal != 0: result = evalAux(c, n.sons[2], {})
proc evalNew(c: PEvalContext, n: PNode): PNode =
#if c.mode == emOptimize: return raiseCannotEval(c, n.info)
# we ignore the finalizer for now and most likely forever :-)
result = evalAux(c, n.sons[1], {efLValue})
if isSpecial(result): return
evalX(n.sons[1], {efLValue})
var a = result
var t = skipTypes(n.sons[1].typ, abstractVar)
if a.kind == nkEmpty: InternalError(n.info, "first parameter is empty")
myreset(a)
a.kind = nkRefTy
a.info = n.info
let u = getNullValue(t.sons[0], n.info)
a.kind = u.kind
a.typ = t
a.sons = nil
addSon(a, getNullValue(t.sons[0], n.info))
shallowCopy(a.sons, u.sons)
result = emptyNode
when false:
a.kind = nkRefTy
a.info = n.info
a.typ = t
a.sons = nil
addSon(a, getNullValue(t.sons[0], n.info))
result = emptyNode
proc evalDeref(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
result = evalAux(c, n.sons[0], {efLValue})
if isSpecial(result): return
evalX(n.sons[0], {efLValue})
case result.kind
of nkNilLit: stackTrace(c, n, errNilAccess)
of nkNilLit: stackTrace(c, n.info, errNilAccess)
of nkRefTy:
# XXX efLValue?
result = result.sons[0]
else:
result = raiseCannotEval(c, n.info)
if skipTypes(n.sons[0].typ, abstractInst).kind != tyRef:
result = raiseCannotEval(c, n.info)
proc evalAddr(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
result = evalAux(c, n.sons[0], {efLValue})
if isSpecial(result): return
evalX(n.sons[0], {efLValue})
var a = result
var t = newType(tyPtr, c.module)
addSonSkipIntLit(t, a.typ)
@@ -680,24 +681,22 @@ proc evalUpConv(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
var dest = skipTypes(n.typ, abstractPtrs)
var src = skipTypes(result.typ, abstractPtrs)
if inheritanceDiff(src, dest) > 0:
stackTrace(c, n, errInvalidConversionFromTypeX, typeToString(src))
stackTrace(c, n.info, errInvalidConversionFromTypeX, typeToString(src))
proc evalRangeChck(c: PEvalContext, n: PNode): PNode =
result = evalAux(c, n.sons[0], {})
if isSpecial(result): return
evalX(n.sons[0], {})
var x = result
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
evalX(n.sons[1], {})
var a = result
result = evalAux(c, n.sons[2], {})
if isSpecial(result): return
evalX(n.sons[2], {})
var b = result
if leValueConv(a, x) and leValueConv(x, b):
result = x # a <= x and x <= b
result.typ = n.typ
else:
stackTrace(c, n, errGenerated, msgKindToString(errIllegalConvFromXtoY) % [
typeToString(n.sons[0].typ), typeToString(n.typ)])
stackTrace(c, n.info, errGenerated,
msgKindToString(errIllegalConvFromXtoY) % [
typeToString(n.sons[0].typ), typeToString(n.typ)])
proc evalConvStrToCStr(c: PEvalContext, n: PNode): PNode =
result = evalAux(c, n.sons[0], {})
@@ -721,7 +720,7 @@ proc evalRaise(c: PEvalContext, n: PNode): PNode =
elif c.lastException != nil:
result = c.lastException
else:
stackTrace(c, n, errExceptionAlreadyHandled)
stackTrace(c, n.info, errExceptionAlreadyHandled)
result = newNodeIT(nkExceptBranch, n.info, nil)
addSon(result, ast.emptyNode)
else:
@@ -739,10 +738,12 @@ proc evalProc(c: PEvalContext, n: PNode): PNode =
if (resultPos < sonsLen(n)) and (n.sons[resultPos].kind != nkEmpty):
var v = n.sons[resultPos].sym
result = getNullValue(v.typ, n.info)
IdNodeTablePut(c.tos.mapping, v, result)
if c.tos.slots.len == 0: setLen(c.tos.slots, 1)
c.tos.slots[0] = result
#IdNodeTablePut(c.tos.mapping, v, result)
result = evalAux(c, s.getBody, {})
if result.kind == nkReturnToken:
result = IdNodeTableGet(c.tos.mapping, v)
if result.kind == nkReturnToken:
result = c.tos.slots[0]
else:
result = evalAux(c, s.getBody, {})
if result.kind == nkReturnToken:
@@ -891,17 +892,10 @@ proc evalRepr(c: PEvalContext, n: PNode): PNode =
proc isEmpty(n: PNode): bool =
result = n != nil and n.kind == nkEmpty
# The lexer marks multi-line strings as residing at the line where they
# are closed. This function returns the line where the string begins
# Maybe the lexer should mark both the beginning and the end of expressions,
# then this function could be removed.
proc stringStartingLine(s: PNode): int =
result = s.info.line.int - countLines(s.strVal)
proc evalParseExpr(c: PEvalContext, n: PNode): PNode =
var code = evalAux(c, n.sons[1], {})
var ast = parseString(code.getStrValue, code.info.toFilename,
code.stringStartingLine)
code.info.line.int)
if sonsLen(ast) != 1:
GlobalError(code.info, errExprExpected, "multiple statements")
result = ast.sons[0]
@@ -910,51 +904,23 @@ proc evalParseExpr(c: PEvalContext, n: PNode): PNode =
proc evalParseStmt(c: PEvalContext, n: PNode): PNode =
var code = evalAux(c, n.sons[1], {})
result = parseString(code.getStrValue, code.info.toFilename,
code.stringStartingLine)
code.info.line.int)
#result.typ = newType(tyStmt, c.module)
proc evalTypeTrait*(n: PNode, context: PSym): PNode =
## XXX: This should be pretty much guaranteed to be true
# by the type traits procs' signatures, but until the
# code is more mature it doesn't hurt to be extra safe
internalAssert n.sons.len >= 2 and n.sons[1].kind == nkSym
let typ = n.sons[1].sym.typ.skipTypes({tyTypeDesc})
case n.sons[0].sym.name.s.normalize
proc evalTypeTrait*(trait, operand: PNode, context: PSym): PNode =
let typ = operand.typ.skipTypes({tyTypeDesc})
case trait.sym.name.s.normalize
of "name":
result = newStrNode(nkStrLit, typ.typeToString(preferName))
result.typ = newType(tyString, context)
result.info = n.info
result.info = trait.info
of "arity":
result = newIntNode(nkIntLit, typ.n.len-1)
result.typ = newType(tyInt, context)
result.info = trait.info
else:
internalAssert false
proc evalIsOp*(n: PNode): PNode =
InternalAssert n.sonsLen == 3 and
n[1].kind == nkSym and n[1].sym.kind == skType and
n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
let t1 = n[1].sym.typ
if n[2].kind in {nkStrLit..nkTripleStrLit}:
case n[2].strVal.normalize
of "closure":
let t = skipTypes(t1, abstractRange)
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
t.callConv == ccClosure and
tfIterator notin t.flags))
of "iterator":
let t = skipTypes(t1, abstractRange)
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
t.callConv == ccClosure and
tfIterator in t.flags))
else:
let t2 = n[2].typ
var match = if t2.kind == tyTypeClass: matchTypeClass(t2, t1)
else: sameType(t1, t2)
result = newIntNode(nkIntLit, ord(match))
result.typ = n.typ
proc expectString(n: PNode) =
if n.kind notin nkStrKinds:
GlobalError(n.info, errStringLiteralExpected)
@@ -1046,11 +1012,11 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
of mParseStmtToAst: result = evalParseStmt(c, n)
of mExpandToAst: result = evalExpandToAst(c, n)
of mTypeTrait:
n.sons[1] = evalAux(c, n.sons[1], {})
result = evalTypeTrait(n, c.module)
let operand = evalAux(c, n.sons[1], {})
result = evalTypeTrait(n[0], operand, c.module)
of mIs:
n.sons[1] = evalAux(c, n.sons[1], {})
result = evalIsOp(n)
result = c.handleIsOperator(n)
of mSlurp: result = evalSlurp(evalAux(c, n.sons[1], {}), c.module)
of mStaticExec:
let cmd = evalAux(c, n.sons[1], {})
@@ -1064,7 +1030,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
case a.kind
of nkEmpty..nkNilLit: nil
else: result.intVal = sonsLen(a)
of mNChild:
of mNChild:
result = evalAux(c, n.sons[1], {efLValue})
if isSpecial(result): return
var a = result
@@ -1075,7 +1041,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
result = a.sons[int(k)]
if result == nil: result = newNode(nkEmpty)
else:
stackTrace(c, n, errIndexOutOfBounds)
stackTrace(c, n.info, errIndexOutOfBounds)
result = emptyNode
of mNSetChild:
result = evalAux(c, n.sons[1], {efLValue})
@@ -1090,7 +1056,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
if (k >= 0) and (k < sonsLen(a)) and not (a.kind in {nkEmpty..nkNilLit}):
a.sons[int(k)] = result
else:
stackTrace(c, n, errIndexOutOfBounds)
stackTrace(c, n.info, errIndexOutOfBounds)
result = emptyNode
of mNAdd:
result = evalAux(c, n.sons[1], {efLValue})
@@ -1133,7 +1099,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
result = newNodeIT(nkIntLit, n.info, n.typ)
case a.kind
of nkCharLit..nkInt64Lit: result.intVal = a.intVal
else: stackTrace(c, n, errFieldXNotFound, "intVal")
else: stackTrace(c, n.info, errFieldXNotFound, "intVal")
of mNFloatVal:
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
@@ -1141,15 +1107,15 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
result = newNodeIT(nkFloatLit, n.info, n.typ)
case a.kind
of nkFloatLit..nkFloat64Lit: result.floatVal = a.floatVal
else: stackTrace(c, n, errFieldXNotFound, "floatVal")
else: stackTrace(c, n.info, errFieldXNotFound, "floatVal")
of mNSymbol:
result = evalAux(c, n.sons[1], {efLValue})
if isSpecial(result): return
if result.kind != nkSym: stackTrace(c, n, errFieldXNotFound, "symbol")
if result.kind != nkSym: stackTrace(c, n.info, errFieldXNotFound, "symbol")
of mNIdent:
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
if result.kind != nkIdent: stackTrace(c, n, errFieldXNotFound, "ident")
if result.kind != nkIdent: stackTrace(c, n.info, errFieldXNotFound, "ident")
of mNGetType:
var ast = evalAux(c, n.sons[1], {})
InternalAssert c.getType != nil
@@ -1161,7 +1127,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
result = newNodeIT(nkStrLit, n.info, n.typ)
case a.kind
of nkStrLit..nkTripleStrLit: result.strVal = a.strVal
else: stackTrace(c, n, errFieldXNotFound, "strVal")
else: stackTrace(c, n.info, errFieldXNotFound, "strVal")
of mNSetIntVal:
result = evalAux(c, n.sons[1], {efLValue})
if isSpecial(result): return
@@ -1172,7 +1138,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
result.kind in {nkCharLit..nkInt64Lit}:
a.intVal = result.intVal
else:
stackTrace(c, n, errFieldXNotFound, "intVal")
stackTrace(c, n.info, errFieldXNotFound, "intVal")
result = emptyNode
of mNSetFloatVal:
result = evalAux(c, n.sons[1], {efLValue})
@@ -1184,7 +1150,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
result.kind in {nkFloatLit..nkFloat64Lit}:
a.floatVal = result.floatVal
else:
stackTrace(c, n, errFieldXNotFound, "floatVal")
stackTrace(c, n.info, errFieldXNotFound, "floatVal")
result = emptyNode
of mNSetSymbol:
result = evalAux(c, n.sons[1], {efLValue})
@@ -1195,7 +1161,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
if a.kind == nkSym and result.kind == nkSym:
a.sym = result.sym
else:
stackTrace(c, n, errFieldXNotFound, "symbol")
stackTrace(c, n.info, errFieldXNotFound, "symbol")
result = emptyNode
of mNSetIdent:
result = evalAux(c, n.sons[1], {efLValue})
@@ -1206,7 +1172,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
if a.kind == nkIdent and result.kind == nkIdent:
a.ident = result.ident
else:
stackTrace(c, n, errFieldXNotFound, "ident")
stackTrace(c, n.info, errFieldXNotFound, "ident")
result = emptyNode
of mNSetType:
result = evalAux(c, n.sons[1], {efLValue})
@@ -1227,7 +1193,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
if a.kind in {nkStrLit..nkTripleStrLit} and
result.kind in {nkStrLit..nkTripleStrLit}:
a.strVal = result.strVal
else: stackTrace(c, n, errFieldXNotFound, "strVal")
else: stackTrace(c, n.info, errFieldXNotFound, "strVal")
result = emptyNode
of mNNewNimNode:
result = evalAux(c, n.sons[1], {})
@@ -1251,11 +1217,21 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
of mNBindSym:
# trivial implementation:
result = n.sons[1]
of mNGenSym:
evalX(n.sons[1], {efLValue})
let k = getOrdValue(result)
evalX(n.sons[2], {efLValue})
let b = result
let name = if b.strVal.len == 0: ":tmp" else: b.strVal
if k < 0 or k > ord(high(TSymKind)):
internalError(n.info, "request to create a symbol with invalid kind")
result = newSymNode(newSym(k.TSymKind, name.getIdent, c.module, n.info))
incl(result.sym.flags, sfGenSym)
of mStrToIdent:
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
if not (result.kind in {nkStrLit..nkTripleStrLit}):
stackTrace(c, n, errFieldXNotFound, "strVal")
stackTrace(c, n.info, errFieldXNotFound, "strVal")
return
var a = result
result = newNodeIT(nkIdent, n.info, n.typ)
@@ -1308,7 +1284,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
of mNError:
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
stackTrace(c, n, errUser, getStrValue(result))
stackTrace(c, n.info, errUser, getStrValue(result))
result = emptyNode
of mConStrStr:
result = evalConStrStr(c, n)
@@ -1328,7 +1304,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
result.strVal = newString(0)
of mNCallSite:
if c.callsite != nil: result = c.callsite
else: stackTrace(c, n, errFieldXNotFound, "callsite")
else: stackTrace(c, n.info, errFieldXNotFound, "callsite")
else:
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
@@ -1346,13 +1322,13 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
if isEmpty(a) or isEmpty(b) or isEmpty(cc): result = emptyNode
else: result = evalOp(m, n, a, b, cc)
proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
result = emptyNode
dec(gNestedEvals)
if gNestedEvals <= 0: stackTrace(c, n, errTooManyIterations)
if gNestedEvals <= 0: stackTrace(c, n.info, errTooManyIterations)
case n.kind
of nkSym: result = evalSym(c, n, flags)
of nkType..nkNilLit:
of nkType..nkNilLit, nkTypeOfExpr:
# nkStrLit is VERY common in the traces, so we should avoid
# the 'copyNode' here.
result = n #.copyNode
@@ -1420,7 +1396,7 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
of nkChckRangeF, nkChckRange64, nkChckRange: result = evalRangeChck(c, n)
of nkStringToCString: result = evalConvStrToCStr(c, n)
of nkCStringToString: result = evalConvCStrToStr(c, n)
of nkStmtListExpr, nkStmtList, nkModule:
of nkStmtListExpr, nkStmtList:
for i in countup(0, sonsLen(n) - 1):
result = evalAux(c, n.sons[i], flags)
case result.kind
@@ -1464,28 +1440,22 @@ proc eval*(c: PEvalContext, n: PNode): PNode =
result = tryEval(c, n)
if result.kind == nkExceptBranch:
if sonsLen(result) >= 1:
stackTrace(c, n, errUnhandledExceptionX, typeToString(result.typ))
stackTrace(c, n.info, errUnhandledExceptionX, typeToString(result.typ))
else:
stackTrace(c, result, errCannotInterpretNodeX, renderTree(n))
stackTrace(c, result.info, errCannotInterpretNodeX, renderTree(n))
proc evalConstExprAux(module: PSym, e: PNode, mode: TEvalMode): PNode =
var p = newEvalContext(module, mode)
proc evalConstExprAux*(p: PEvalContext, module, prc: PSym, e: PNode): PNode =
var s = newStackFrame()
s.call = e
s.prc = prc
pushStackFrame(p, s)
result = tryEval(p, e)
if result != nil and result.kind == nkExceptBranch: result = nil
popStackFrame(p)
proc evalConstExpr*(module: PSym, e: PNode): PNode =
result = evalConstExprAux(module, e, emConst)
proc evalStaticExpr*(module: PSym, e: PNode): PNode =
result = evalConstExprAux(module, e, emStatic)
proc setupMacroParam(x: PNode): PNode =
result = x
if result.kind == nkHiddenStdConv: result = result.sons[1]
if result.kind in {nkHiddenSubConv, nkHiddenStdConv}: result = result.sons[1]
proc evalMacroCall(c: PEvalContext, n, nOrig: PNode, sym: PSym): PNode =
# XXX GlobalError() is ugly here, but I don't know a better solution for now
@@ -1496,16 +1466,17 @@ proc evalMacroCall(c: PEvalContext, n, nOrig: PNode, sym: PSym): PNode =
c.callsite = nOrig
var s = newStackFrame()
s.call = n
s.prc = sym
var L = n.safeLen
if L == 0: L = 1
setlen(s.params, L)
setlen(s.slots, L)
# return value:
s.params[0] = newNodeIT(nkNilLit, n.info, sym.typ.sons[0])
s.slots[0] = newNodeIT(nkNilLit, n.info, sym.typ.sons[0])
# setup parameters:
for i in 1 .. < L: s.params[i] = setupMacroParam(n.sons[i])
for i in 1 .. < L: s.slots[i] = setupMacroParam(n.sons[i])
pushStackFrame(c, s)
discard eval(c, sym.getBody)
result = s.params[0]
discard eval(c, optBody(c, sym))
result = s.slots[0]
popStackFrame(c)
if cyclicTree(result): GlobalError(n.info, errCyclicTree)
dec(evalTemplateCounter)
@@ -1521,10 +1492,11 @@ var oldErrorCount: int
proc myProcess(c: PPassContext, n: PNode): PNode =
# don't eval errornous code:
if oldErrorCount != msgs.gErrorCounter:
oldErrorCount = msgs.gErrorCounter
return n
result = eval(PEvalContext(c), n)
if oldErrorCount == msgs.gErrorCounter:
result = eval(PEvalContext(c), n)
else:
result = n
oldErrorCount = msgs.gErrorCounter
const evalPass* = makePass(myOpen, nil, myProcess, myProcess)

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -16,9 +16,14 @@ import
type
TemplCtx {.pure, final.} = object
owner, genSymOwner: PSym
instLines: bool # use the instantiation lines numbers
mapping: TIdTable # every gensym'ed symbol needs to be mapped to some
# new symbol
proc copyNode(ctx: TemplCtx, a, b: PNode): PNode =
result = copyNode(a)
if ctx.instLines: result.info = b.info
proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
case templ.kind
of nkSym:
@@ -31,49 +36,23 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
else:
result.add copyTree(x)
else:
InternalAssert sfGenSym in s.flags
var x = PSym(IdTableGet(c.mapping, s))
internalAssert sfGenSym in s.flags
var x = PSym(idTableGet(c.mapping, s))
if x == nil:
x = copySym(s, false)
x.owner = c.genSymOwner
IdTablePut(c.mapping, s, x)
result.add newSymNode(x, templ.info)
idTablePut(c.mapping, s, x)
result.add newSymNode(x, if c.instLines: actual.info else: templ.info)
else:
result.add copyNode(templ)
result.add copyNode(c, templ, actual)
of nkNone..nkIdent, nkType..nkNilLit: # atom
result.add copyNode(templ)
result.add copyNode(c, templ, actual)
else:
var res = copyNode(templ)
var res = copyNode(c, templ, actual)
for i in countup(0, sonsLen(templ) - 1):
evalTemplateAux(templ.sons[i], actual, c, res)
result.add res
when false:
proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx): PNode =
case templ.kind
of nkSym:
var s = templ.sym
if s.owner.id == c.owner.id:
if s.kind == skParam:
result = copyTree(actual.sons[s.position])
else:
InternalAssert sfGenSym in s.flags
var x = PSym(IdTableGet(c.mapping, s))
if x == nil:
x = copySym(s, false)
x.owner = c.genSymOwner
IdTablePut(c.mapping, s, x)
result = newSymNode(x, templ.info)
else:
result = copyNode(templ)
of nkNone..nkIdent, nkType..nkNilLit: # atom
result = copyNode(templ)
else:
result = copyNode(templ)
newSons(result, sonsLen(templ))
for i in countup(0, sonsLen(templ) - 1):
result.sons[i] = evalTemplateAux(templ.sons[i], actual, c)
proc evalTemplateArgs(n: PNode, s: PSym): PNode =
# if the template has zero arguments, it can be called without ``()``
# `n` is then a nkSym or something similar
@@ -83,13 +62,13 @@ proc evalTemplateArgs(n: PNode, s: PSym): PNode =
a = sonsLen(n)
else: a = 0
var f = s.typ.sonsLen
if a > f: GlobalError(n.info, errWrongNumberOfArguments)
if a > f: globalError(n.info, errWrongNumberOfArguments)
result = newNodeI(nkArgList, n.info)
for i in countup(1, f - 1):
var arg = if i < a: n.sons[i] else: copyTree(s.typ.n.sons[i].sym.ast)
if arg == nil or arg.kind == nkEmpty:
LocalError(n.info, errWrongNumberOfArguments)
localError(n.info, errWrongNumberOfArguments)
addSon(result, arg)
var evalTemplateCounter* = 0
@@ -98,7 +77,7 @@ var evalTemplateCounter* = 0
proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym): PNode =
inc(evalTemplateCounter)
if evalTemplateCounter > 100:
GlobalError(n.info, errTemplateInstantiationTooNested)
globalError(n.info, errTemplateInstantiationTooNested)
result = n
# replace each param by the corresponding node:
@@ -114,11 +93,13 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym): PNode =
evalTemplateAux(body, args, ctx, result)
if result.len == 1: result = result.sons[0]
else:
GlobalError(result.info, errIllFormedAstX,
globalError(result.info, errIllFormedAstX,
renderTree(result, {renderNoComments}))
else:
result = copyNode(body)
#evalTemplateAux(body, args, ctx, result)
ctx.instLines = body.kind notin {nkStmtList, nkStmtListExpr,
nkBlockStmt, nkBlockExpr}
if ctx.instLines: result.info = n.info
for i in countup(0, safeLen(body) - 1):
evalTemplateAux(body.sons[i], args, ctx, result)

View File

@@ -16,13 +16,16 @@ import
type
TSystemCC* = enum
ccNone, ccGcc, ccLLVM_Gcc, ccCLang, ccLcc, ccBcc, ccDmc, ccWcc, ccVcc,
ccTcc, ccPcc, ccUcc, ccIcl, ccGpp
ccTcc, ccPcc, ccUcc, ccIcl
TInfoCCProp* = enum # properties of the C compiler:
hasSwitchRange, # CC allows ranges in switch statements (GNU C)
hasComputedGoto, # CC has computed goto (GNU C extension)
hasCpp, # CC is/contains a C++ compiler
hasAssume, # CC has __assume (Visual C extension)
hasGcGuard # CC supports GC_GUARD to keep stack roots
hasGcGuard, # CC supports GC_GUARD to keep stack roots
hasGnuAsm, # CC's asm uses the absurd GNU assembler syntax
hasNakedDeclspec, # CC has __declspec(naked)
hasNakedAttribute # CC has __attribute__((naked))
TInfoCCProps* = set[TInfoCCProp]
TInfoCC* = tuple[
name: string, # the short name of the compiler
@@ -30,11 +33,12 @@ type
optSpeed: string, # the options for optimization for speed
optSize: string, # the options for optimization for size
compilerExe: string, # the compiler's executable
cppCompiler: string, # name of the C++ compiler's executable (if supported)
compileTmpl: string, # the compile command template
buildGui: string, # command to build a GUI application
buildDll: string, # command to build a shared library
buildLib: string, # command to build a static library
linkerExe: string, # the linker's executable
linkerExe: string, # the linker's executable (if not matching compiler's)
linkTmpl: string, # command to link files to produce an exe
includeCmd: string, # command to add an include dir
linkDirCmd: string, # command to add a lib dir
@@ -43,6 +47,8 @@ type
pic: string, # command for position independent code
# used on some platforms
asmStmtFrmt: string, # format of ASM statement
structStmtFmt: string, # Format for struct statement
packedPragma: string, # Attribute/pragma to make struct packed (1-byte aligned)
props: TInfoCCProps] # properties of the C compiler
@@ -60,11 +66,12 @@ compiler gcc:
optSpeed: " -O3 -ffast-math ",
optSize: " -Os -ffast-math ",
compilerExe: "gcc",
cppCompiler: "g++",
compileTmpl: "-c $options $include -o $objfile $file",
buildGui: " -mwindows",
buildDll: " -shared",
buildLib: "ar rcs $libfile $objfiles",
linkerExe: "gcc",
linkerExe: "",
linkTmpl: "$buildgui $builddll -o $exefile $objfiles $options",
includeCmd: " -I",
linkDirCmd: " -L",
@@ -72,33 +79,25 @@ compiler gcc:
debug: "",
pic: "-fPIC",
asmStmtFrmt: "asm($1);$n",
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard})
compiler gpp:
result = gcc()
result.name = "gpp"
result.compilerExe = "g++"
result.linkerExe = "g++"
result.buildDll = " -mdll"
# XXX: Hmm, I'm keeping this from the previos version,
# but my gcc doesn't even have such an option (is this mingw?)
structStmtFmt: "$1 $3 $2 ", # struct|union [packed] $name
packedPragma: "__attribute__((__packed__))",
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm,
hasNakedAttribute})
compiler llvmGcc:
result = gcc()
result.name = "llvm_gcc"
result.compilerExe = "llvm-gcc"
result.cppCompiler = "llvm-g++"
result.buildLib = "llvm-ar rcs $libfile $objfiles"
result.linkerExe = "llvm-gcc"
compiler clang:
result = llvmGcc()
result.name = "clang"
result.compilerExe = "clang"
result.linkerExe = "clang"
result.cppCompiler = "clang++"
compiler vcc:
result = (
@@ -107,6 +106,7 @@ compiler vcc:
optSpeed: " /Ogityb2 /G7 /arch:SSE2 ",
optSize: " /O1 /G7 ",
compilerExe: "cl",
cppCompiler: "cl",
compileTmpl: "/c $options $include /Fo$objfile $file",
buildGui: " /link /SUBSYSTEM:WINDOWS ",
buildDll: " /LD",
@@ -119,7 +119,9 @@ compiler vcc:
debug: " /GZ /Zi ",
pic: "",
asmStmtFrmt: "__asm{$n$1$n}$n",
props: {hasCpp, hasAssume})
structStmtFmt: "$3$n$1 $2",
packedPragma: "#pragma pack(1)",
props: {hasCpp, hasAssume, hasNakedDeclspec})
compiler icl:
# Intel compilers try to imitate the native ones (gcc and msvc)
@@ -127,7 +129,7 @@ compiler icl:
result = vcc()
else:
result = gcc()
result.name = "icl"
result.compilerExe = "icl"
result.linkerExe = "icl"
@@ -139,6 +141,7 @@ compiler lcc:
optSpeed: " -O -p6 ",
optSize: " -O -p6 ",
compilerExe: "lcc",
cppCompiler: "",
compileTmpl: "$options $include -Fo$objfile $file",
buildGui: " -subsystem windows",
buildDll: " -dll",
@@ -151,6 +154,8 @@ compiler lcc:
debug: " -g5 ",
pic: "",
asmStmtFrmt: "_asm{$n$1$n}$n",
structStmtFmt: "$1 $2",
packedPragma: "", # XXX: not supported yet
props: {})
compiler bcc:
@@ -160,6 +165,7 @@ compiler bcc:
optSpeed: " -O2 -6 ",
optSize: " -O1 -6 ",
compilerExe: "bcc32",
cppCompiler: "",
compileTmpl: "-c $options $include -o$objfile $file",
buildGui: " -tW",
buildDll: " -tWD",
@@ -172,6 +178,8 @@ compiler bcc:
debug: "",
pic: "",
asmStmtFrmt: "__asm{$n$1$n}$n",
structStmtFmt: "$1 $2",
packedPragma: "", # XXX: not supported yet
props: {hasCpp})
compiler dmc:
@@ -181,6 +189,7 @@ compiler dmc:
optSpeed: " -ff -o -6 ",
optSize: " -ff -o -6 ",
compilerExe: "dmc",
cppCompiler: "",
compileTmpl: "-c $options $include -o$objfile $file",
buildGui: " -L/exet:nt/su:windows",
buildDll: " -WD",
@@ -193,6 +202,8 @@ compiler dmc:
debug: " -g ",
pic: "",
asmStmtFrmt: "__asm{$n$1$n}$n",
structStmtFmt: "$3$n$1 $2",
packedPragma: "#pragma pack(1)",
props: {hasCpp})
compiler wcc:
@@ -202,6 +213,7 @@ compiler wcc:
optSpeed: " -ox -on -6 -d0 -fp6 -zW ",
optSize: "",
compilerExe: "wcl386",
cppCompiler: "",
compileTmpl: "-c $options $include -fo=$objfile $file",
buildGui: " -bw",
buildDll: " -bd",
@@ -214,6 +226,8 @@ compiler wcc:
debug: " -d2 ",
pic: "",
asmStmtFrmt: "__asm{$n$1$n}$n",
structStmtFmt: "$1 $2",
packedPragma: "", # XXX: not supported yet
props: {hasCpp})
compiler tcc:
@@ -223,6 +237,7 @@ compiler tcc:
optSpeed: "",
optSize: "",
compilerExe: "tcc",
cppCompiler: "",
compileTmpl: "-c $options $include -o $objfile $file",
buildGui: "UNAVAILABLE!",
buildDll: " -shared",
@@ -235,6 +250,8 @@ compiler tcc:
debug: " -g ",
pic: "",
asmStmtFrmt: "__asm{$n$1$n}$n",
structStmtFmt: "$1 $2",
packedPragma: "", # XXX: not supported yet
props: {hasSwitchRange, hasComputedGoto})
compiler pcc:
@@ -245,6 +262,7 @@ compiler pcc:
optSpeed: " -Ox ",
optSize: " -Os ",
compilerExe: "cc",
cppCompiler: "",
compileTmpl: "-c $options $include -Fo$objfile $file",
buildGui: " -SUBSYSTEM:WINDOWS",
buildDll: " -DLL",
@@ -257,6 +275,8 @@ compiler pcc:
debug: " -Zi ",
pic: "",
asmStmtFrmt: "__asm{$n$1$n}$n",
structStmtFmt: "$1 $2",
packedPragma: "", # XXX: not supported yet
props: {})
compiler ucc:
@@ -266,6 +286,7 @@ compiler ucc:
optSpeed: " -O3 ",
optSize: " -O1 ",
compilerExe: "cc",
cppCompiler: "",
compileTmpl: "-c $options $include -o $objfile $file",
buildGui: "",
buildDll: " -shared ",
@@ -278,6 +299,8 @@ compiler ucc:
debug: "",
pic: "",
asmStmtFrmt: "__asm{$n$1$n}$n",
structStmtFmt: "$1 $2",
packedPragma: "", # XXX: not supported yet
props: {})
const
@@ -293,17 +316,16 @@ const
tcc(),
pcc(),
ucc(),
icl(),
gpp()]
icl()]
const
hExt* = "h"
hExt* = ".h"
var
cCompiler* = ccGcc # the used compiler
cExt* = "c" # extension of generated C/C++ files
# (can be changed to .cpp later)
cExt* = ".c" # extension of generated C/C++ files
# (can be changed to .cpp later)
cIncludes*: seq[string] = @[] # directories to search for included files
cLibs*: seq[string] = @[] # directories to search for lib files
@@ -320,7 +342,7 @@ var
compileOptions: string = ""
ccompilerpath: string = ""
proc NameToCC*(name: string): TSystemCC =
proc nameToCC*(name: string): TSystemCC =
for i in countup(succ(ccNone), high(TSystemCC)):
if cmpIgnoreStyle(name, CC[i].name) == 0:
return i
@@ -331,8 +353,8 @@ proc getConfigVar(c: TSystemCC, suffix: string): string =
# for niminst support
if (platform.hostOS != targetOS or platform.hostCPU != targetCPU) and
optCompileOnly notin gGlobalOptions:
let fullCCname = platform.cpu[targetCPU].name & '.' &
platform.os[targetOS].name & '.' &
let fullCCname = platform.CPU[targetCPU].name & '.' &
platform.OS[targetOS].name & '.' &
CC[c].name & suffix
result = getConfigVar(fullCCname)
if result.len == 0:
@@ -342,13 +364,13 @@ proc getConfigVar(c: TSystemCC, suffix: string): string =
result = getConfigVar(CC[c].name & suffix)
proc setCC*(ccname: string) =
ccompiler = nameToCC(ccname)
if ccompiler == ccNone: rawMessage(errUnknownCcompiler, ccname)
compileOptions = getConfigVar(ccompiler, ".options.always")
linkOptions = getConfigVar(ccompiler, ".options.linker")
ccompilerpath = getConfigVar(ccompiler, ".path")
cCompiler = nameToCC(ccname)
if cCompiler == ccNone: rawMessage(errUnknownCcompiler, ccname)
compileOptions = getConfigVar(cCompiler, ".options.always")
linkOptions = getConfigVar(cCompiler, ".options.linker")
ccompilerpath = getConfigVar(cCompiler, ".path")
for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
defineSymbol(CC[ccompiler].name)
defineSymbol(CC[cCompiler].name)
proc addOpt(dest: var string, src: string) =
if len(dest) == 0 or dest[len(dest)-1] != ' ': add(dest, " ")
@@ -364,20 +386,20 @@ proc addCompileOption*(option: string) =
proc initVars*() =
# we need to define the symbol here, because ``CC`` may have never been set!
for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
defineSymbol(CC[ccompiler].name)
defineSymbol(CC[cCompiler].name)
if gCmd == cmdCompileToCpp: cExt = ".cpp"
elif gCmd == cmdCompileToOC: cExt = ".m"
addCompileOption(getConfigVar(ccompiler, ".options.always"))
addLinkOption(getConfigVar(ccompiler, ".options.linker"))
if len(ccompilerPath) == 0:
ccompilerpath = getConfigVar(ccompiler, ".path")
addCompileOption(getConfigVar(cCompiler, ".options.always"))
addLinkOption(getConfigVar(cCompiler, ".options.linker"))
if len(ccompilerpath) == 0:
ccompilerpath = getConfigVar(cCompiler, ".path")
proc completeCFilePath*(cfile: string, createSubDir: bool = true): string =
result = completeGeneratedFilePath(cfile, createSubDir)
proc toObjFile*(filenameWithoutExt: string): string =
# Object file for compilation
result = changeFileExt(filenameWithoutExt, cc[ccompiler].objExt)
result = changeFileExt(filenameWithoutExt, CC[cCompiler].objExt)
proc addFileToCompile*(filename: string) =
appendStr(toCompile, filename)
@@ -396,28 +418,28 @@ proc addFileToLink*(filename: string) =
# BUGFIX: was ``appendStr``
proc execExternalProgram*(cmd: string) =
if optListCmd in gGlobalOptions or gVerbosity > 0: MsgWriteln(cmd)
if optListCmd in gGlobalOptions or gVerbosity > 0: msgWriteln(cmd)
if execCmd(cmd) != 0: rawMessage(errExecutionOfProgramFailed, "")
proc generateScript(projectFile: string, script: PRope) =
let (dir, name, ext) = splitFile(projectFile)
WriteRope(script, dir / addFileExt("compile_" & name,
platform.os[targetOS].scriptExt))
writeRope(script, dir / addFileExt("compile_" & name,
platform.OS[targetOS].scriptExt))
proc getOptSpeed(c: TSystemCC): string =
result = getConfigVar(c, ".options.speed")
if result == "":
result = cc[c].optSpeed # use default settings from this file
result = CC[c].optSpeed # use default settings from this file
proc getDebug(c: TSystemCC): string =
result = getConfigVar(c, ".options.debug")
if result == "":
result = cc[c].debug # use default settings from this file
result = CC[c].debug # use default settings from this file
proc getOptSize(c: TSystemCC): string =
result = getConfigVar(c, ".options.size")
if result == "":
result = cc[c].optSize # use default settings from this file
result = CC[c].optSize # use default settings from this file
proc noAbsolutePaths: bool {.inline.} =
# We used to check current OS != specified OS, but this makes no sense
@@ -432,92 +454,102 @@ const
var fileCounter: int
proc add(s: var string, many: openarray[string]) =
proc add(s: var string, many: openArray[string]) =
s.add many.join
proc CFileSpecificOptions(cfilename: string): string =
proc cFileSpecificOptions(cfilename: string): string =
result = compileOptions
var trunk = splitFile(cfilename).name
if optCDebug in gGlobalOptions:
var key = trunk & ".debug"
if existsConfigVar(key): addOpt(result, getConfigVar(key))
else: addOpt(result, getDebug(ccompiler))
else: addOpt(result, getDebug(cCompiler))
if optOptimizeSpeed in gOptions:
var key = trunk & ".speed"
if existsConfigVar(key): addOpt(result, getConfigVar(key))
else: addOpt(result, getOptSpeed(ccompiler))
else: addOpt(result, getOptSpeed(cCompiler))
elif optOptimizeSize in gOptions:
var key = trunk & ".size"
if existsConfigVar(key): addOpt(result, getConfigVar(key))
else: addOpt(result, getOptSize(ccompiler))
else: addOpt(result, getOptSize(cCompiler))
var key = trunk & ".always"
if existsConfigVar(key): addOpt(result, getConfigVar(key))
proc getCompileOptions: string =
result = CFileSpecificOptions("__dummy__")
result = cFileSpecificOptions("__dummy__")
proc getLinkOptions: string =
result = linkOptions
for linkedLib in items(cLinkedLibs):
result.add(cc[ccompiler].linkLibCmd % linkedLib.quoteIfContainsWhite)
result.add(CC[cCompiler].linkLibCmd % linkedLib.quoteShell)
for libDir in items(cLibs):
result.add([cc[ccompiler].linkDirCmd, libDir.quoteIfContainsWhite])
result.add([CC[cCompiler].linkDirCmd, libDir.quoteShell])
proc needsExeExt(): bool {.inline.} =
result = (optGenScript in gGlobalOptions and targetOS == osWindows) or
(platform.hostOS == osWindows)
proc getCompilerExe(compiler: TSystemCC): string =
result = if gCmd == cmdCompileToCpp: CC[compiler].cppCompiler
else: CC[compiler].compilerExe
if result.len == 0:
rawMessage(errCompilerDoesntSupportTarget, CC[compiler].name)
proc getLinkerExe(compiler: TSystemCC): string =
result = if CC[compiler].linkerExe.len > 0: CC[compiler].linkerExe
else: compiler.getCompilerExe
proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
var c = ccompiler
var options = CFileSpecificOptions(cfilename)
var c = cCompiler
var options = cFileSpecificOptions(cfilename)
var exe = getConfigVar(c, ".exe")
if exe.len == 0: exe = cc[c].compilerExe
if exe.len == 0: exe = c.getCompilerExe
if needsExeExt(): exe = addFileExt(exe, "exe")
if optGenDynLib in gGlobalOptions and
ospNeedsPIC in platform.OS[targetOS].props:
add(options, ' ' & cc[c].pic)
add(options, ' ' & CC[c].pic)
var includeCmd, compilePattern: string
if not noAbsolutePaths():
# compute include paths:
includeCmd = cc[c].includeCmd & quoteIfContainsWhite(libpath)
includeCmd = CC[c].includeCmd & quoteShell(libpath)
for includeDir in items(cIncludes):
includeCmd.add([cc[c].includeCmd, includeDir.quoteIfContainsWhite])
includeCmd.add([CC[c].includeCmd, includeDir.quoteShell])
compilePattern = JoinPath(ccompilerpath, exe)
compilePattern = joinPath(ccompilerpath, exe)
else:
includeCmd = ""
compilePattern = cc[c].compilerExe
compilePattern = c.getCompilerExe
var cfile = if noAbsolutePaths(): extractFileName(cfilename)
var cfile = if noAbsolutePaths(): extractFilename(cfilename)
else: cfilename
var objfile = if not isExternal or noAbsolutePaths():
toObjFile(cfile)
else:
completeCFilePath(toObjFile(cfile))
cfile = quoteIfContainsWhite(AddFileExt(cfile, cExt))
objfile = quoteIfContainsWhite(objfile)
result = quoteIfContainsWhite(compilePattern % [
cfile = quoteShell(addFileExt(cfile, cExt))
objfile = quoteShell(objfile)
result = quoteShell(compilePattern % [
"file", cfile, "objfile", objfile, "options", options,
"include", includeCmd, "nimrod", getPrefixDir(), "lib", libpath])
add(result, ' ')
addf(result, cc[c].compileTmpl, [
addf(result, CC[c].compileTmpl, [
"file", cfile, "objfile", objfile,
"options", options, "include", includeCmd,
"nimrod", quoteIfContainsWhite(getPrefixDir()),
"lib", quoteIfContainsWhite(libpath)])
"nimrod", quoteShell(getPrefixDir()),
"lib", quoteShell(libpath)])
proc footprint(filename: string): TCrc32 =
result = crcFromFile(filename) ><
platform.OS[targetOS].name ><
platform.CPU[targetCPU].name ><
extccomp.CC[extccomp.ccompiler].name ><
extccomp.CC[extccomp.cCompiler].name ><
getCompileCFileCmd(filename, true)
proc externalFileChanged(filename: string): bool =
var crcFile = toGeneratedFile(filename, "crc")
var crcFile = toGeneratedFile(filename.withPackageName, "crc")
var currentCrc = int(footprint(filename))
var f: TFile
if open(f, crcFile, fmRead):
@@ -537,7 +569,7 @@ proc addExternalFileToCompile*(filename: string) =
if optForceFullMake in gGlobalOptions or externalFileChanged(filename):
appendStr(externalToCompile, filename)
proc CompileCFile(list: TLinkedList, script: var PRope, cmds: var TStringSeq,
proc compileCFile(list: TLinkedList, script: var PRope, cmds: var TStringSeq,
isExternal: bool) =
var it = PStrEntry(list.head)
while it != nil:
@@ -550,18 +582,18 @@ proc CompileCFile(list: TLinkedList, script: var PRope, cmds: var TStringSeq,
app(script, tnl)
it = PStrEntry(it.next)
proc CallCCompiler*(projectfile: string) =
proc callCCompiler*(projectfile: string) =
var
linkCmd, buildgui, builddll: string
if gGlobalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}:
return # speed up that call if only compiling and no script shall be
# generated
fileCounter = 0
var c = ccompiler
var c = cCompiler
var script: PRope = nil
var cmds: TStringSeq = @[]
CompileCFile(toCompile, script, cmds, false)
CompileCFile(externalToCompile, script, cmds, true)
compileCFile(toCompile, script, cmds, false)
compileCFile(externalToCompile, script, cmds, true)
if optCompileOnly notin gGlobalOptions:
if gNumberOfProcessors == 0: gNumberOfProcessors = countProcessors()
var res = 0
@@ -579,63 +611,64 @@ proc CallCCompiler*(projectfile: string) =
else:
rawMessage(errGenerated, " execution of an external program failed; " &
"rerun with --parallelBuild:1 to see the error message")
if optNoLinking notin gGlobalOptions and cmds.len > 0:
if optNoLinking notin gGlobalOptions:
# call the linker:
var it = PStrEntry(toLink.head)
var objfiles = ""
while it != nil:
let objFile = if noAbsolutePaths(): it.data.extractFilename else: it.data
add(objfiles, ' ')
add(objfiles, quoteIfContainsWhite(
addFileExt(objFile, cc[ccompiler].objExt)))
add(objfiles, quoteShell(
addFileExt(objFile, CC[cCompiler].objExt)))
it = PStrEntry(it.next)
if optGenStaticLib in gGlobalOptions:
linkcmd = cc[c].buildLib % ["libfile", (libNameTmpl() % gProjectName),
linkCmd = CC[c].buildLib % ["libfile", (libNameTmpl() % gProjectName),
"objfiles", objfiles]
if optCompileOnly notin gGlobalOptions: execExternalProgram(linkCmd)
else:
var linkerExe = getConfigVar(c, ".linkerexe")
if len(linkerExe) == 0: linkerExe = cc[c].linkerExe
if len(linkerExe) == 0: linkerExe = c.getLinkerExe
if needsExeExt(): linkerExe = addFileExt(linkerExe, "exe")
if noAbsolutePaths(): linkCmd = quoteIfContainsWhite(linkerExe)
else: linkCmd = quoteIfContainsWhite(JoinPath(ccompilerpath, linkerExe))
if optGenGuiApp in gGlobalOptions: buildGui = cc[c].buildGui
else: buildGui = ""
if noAbsolutePaths(): linkCmd = quoteShell(linkerExe)
else: linkCmd = quoteShell(joinPath(ccompilerpath, linkerExe))
if optGenGuiApp in gGlobalOptions: buildgui = CC[c].buildGui
else: buildgui = ""
var exefile: string
if options.outFile.len > 0:
exefile = options.outFile
elif optGenDynLib in gGlobalOptions:
exefile = platform.os[targetOS].dllFrmt % splitFile(projectFile).name
buildDll = cc[c].buildDll
if optGenDynLib in gGlobalOptions:
exefile = platform.OS[targetOS].dllFrmt % splitFile(projectfile).name
builddll = CC[c].buildDll
else:
exefile = splitFile(projectFile).name & platform.os[targetOS].exeExt
buildDll = ""
exefile = splitFile(projectfile).name & platform.OS[targetOS].exeExt
builddll = ""
if options.outFile.len > 0:
exefile = options.outFile.expandTilde
if not noAbsolutePaths():
exefile = joinPath(splitFile(projectFile).dir, exefile)
exefile = quoteIfContainsWhite(exefile)
if not exefile.isAbsolute():
exefile = joinPath(splitFile(projectfile).dir, exefile)
exefile = quoteShell(exefile)
let linkOptions = getLinkOptions()
linkCmd = quoteIfContainsWhite(linkCmd % ["builddll", builddll,
linkCmd = quoteShell(linkCmd % ["builddll", builddll,
"buildgui", buildgui, "options", linkOptions, "objfiles", objfiles,
"exefile", exefile, "nimrod", getPrefixDir(), "lib", libpath])
linkCmd.add ' '
addf(linkCmd, cc[c].linkTmpl, ["builddll", builddll,
addf(linkCmd, CC[c].linkTmpl, ["builddll", builddll,
"buildgui", buildgui, "options", linkOptions,
"objfiles", objfiles, "exefile", exefile,
"nimrod", quoteIfContainsWhite(getPrefixDir()),
"lib", quoteIfContainsWhite(libpath)])
"nimrod", quoteShell(getPrefixDir()),
"lib", quoteShell(libpath)])
if optCompileOnly notin gGlobalOptions: execExternalProgram(linkCmd)
else:
linkCmd = ""
if optGenScript in gGlobalOptions:
app(script, linkCmd)
app(script, tnl)
generateScript(projectFile, script)
generateScript(projectfile, script)
proc genMappingFiles(list: TLinkedList): PRope =
var it = PStrEntry(list.head)
while it != nil:
appf(result, "--file:r\"$1\"$N", [toRope(AddFileExt(it.data, cExt))])
appf(result, "--file:r\"$1\"$N", [toRope(addFileExt(it.data, cExt))])
it = PStrEntry(it.next)
proc writeMapping*(gSymbolMapping: PRope) =
@@ -653,5 +686,5 @@ proc writeMapping*(gSymbolMapping: PRope) =
app(code, strutils.escape(libpath))
appf(code, "\n[Symbols]$n$1", [gSymbolMapping])
WriteRope(code, joinPath(gProjectPath, "mapping.txt"))
writeRope(code, joinPath(gProjectPath, "mapping.txt"))

View File

@@ -27,7 +27,7 @@ type
indent, emitPar: int
x: string # the current input line
outp: PLLStream # the ouput will be parsed by pnimsyn
subsChar, NimDirective: Char
subsChar, nimDirective: char
emit, conc, toStr: string
curly, bracket, par: int
pendingExprLine: bool
@@ -37,11 +37,11 @@ const
PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '.', '_'}
proc newLine(p: var TTmplParser) =
LLStreamWrite(p.outp, repeatChar(p.emitPar, ')'))
llStreamWrite(p.outp, repeatChar(p.emitPar, ')'))
p.emitPar = 0
if p.info.line > int16(1): LLStreamWrite(p.outp, "\n")
if p.info.line > int16(1): llStreamWrite(p.outp, "\n")
if p.pendingExprLine:
LLStreamWrite(p.outp, repeatChar(2))
llStreamWrite(p.outp, repeatChar(2))
p.pendingExprLine = false
proc scanPar(p: var TTmplParser, d: int) =
@@ -55,7 +55,7 @@ proc scanPar(p: var TTmplParser, d: int) =
of ']': dec(p.bracket)
of '{': inc(p.curly)
of '}': dec(p.curly)
else: nil
else: discard
inc(i)
proc withInExpr(p: TTmplParser): bool {.inline.} =
@@ -67,9 +67,9 @@ proc parseLine(p: var TTmplParser) =
keyw: string
j = 0
while p.x[j] == ' ': inc(j)
if (p.x[0] == p.NimDirective) and (p.x[0 + 1] == '!'):
if (p.x[0] == p.nimDirective) and (p.x[0 + 1] == '!'):
newLine(p)
elif (p.x[j] == p.NimDirective):
elif (p.x[j] == p.nimDirective):
newLine(p)
inc(j)
while p.x[j] == ' ': inc(j)
@@ -87,26 +87,26 @@ proc parseLine(p: var TTmplParser) =
dec(p.indent, 2)
else:
p.info.col = int16(j)
LocalError(p.info, errXNotAllowedHere, "end")
LLStreamWrite(p.outp, repeatChar(p.indent))
LLStreamWrite(p.outp, "#end")
localError(p.info, errXNotAllowedHere, "end")
llStreamWrite(p.outp, repeatChar(p.indent))
llStreamWrite(p.outp, "#end")
of wIf, wWhen, wTry, wWhile, wFor, wBlock, wCase, wProc, wIterator,
wConverter, wMacro, wTemplate, wMethod:
LLStreamWrite(p.outp, repeatChar(p.indent))
LLStreamWrite(p.outp, substr(p.x, d))
llStreamWrite(p.outp, repeatChar(p.indent))
llStreamWrite(p.outp, substr(p.x, d))
inc(p.indent, 2)
of wElif, wOf, wElse, wExcept, wFinally:
LLStreamWrite(p.outp, repeatChar(p.indent - 2))
LLStreamWrite(p.outp, substr(p.x, d))
llStreamWrite(p.outp, repeatChar(p.indent - 2))
llStreamWrite(p.outp, substr(p.x, d))
of wLet, wVar, wConst, wType:
LLStreamWrite(p.outp, repeatChar(p.indent))
LLStreamWrite(p.outp, substr(p.x, d))
llStreamWrite(p.outp, repeatChar(p.indent))
llStreamWrite(p.outp, substr(p.x, d))
if not p.x.contains({':', '='}):
# no inline element --> treat as block:
inc(p.indent, 2)
else:
LLStreamWrite(p.outp, repeatChar(p.indent))
LLStreamWrite(p.outp, substr(p.x, d))
llStreamWrite(p.outp, repeatChar(p.indent))
llStreamWrite(p.outp, substr(p.x, d))
p.state = psDirective
else:
# data line
@@ -118,15 +118,15 @@ proc parseLine(p: var TTmplParser) =
case p.state
of psTempl:
# next line of string literal:
LLStreamWrite(p.outp, p.conc)
LLStreamWrite(p.outp, "\n")
LLStreamWrite(p.outp, repeatChar(p.indent + 2))
LLStreamWrite(p.outp, "\"")
llStreamWrite(p.outp, p.conc)
llStreamWrite(p.outp, "\n")
llStreamWrite(p.outp, repeatChar(p.indent + 2))
llStreamWrite(p.outp, "\"")
of psDirective:
newLine(p)
LLStreamWrite(p.outp, repeatChar(p.indent))
LLStreamWrite(p.outp, p.emit)
LLStreamWrite(p.outp, "(\"")
llStreamWrite(p.outp, repeatChar(p.indent))
llStreamWrite(p.outp, p.emit)
llStreamWrite(p.outp, "(\"")
inc(p.emitPar)
p.state = psTempl
while true:
@@ -134,17 +134,17 @@ proc parseLine(p: var TTmplParser) =
of '\0':
break
of '\x01'..'\x1F', '\x80'..'\xFF':
LLStreamWrite(p.outp, "\\x")
LLStreamWrite(p.outp, toHex(ord(p.x[j]), 2))
llStreamWrite(p.outp, "\\x")
llStreamWrite(p.outp, toHex(ord(p.x[j]), 2))
inc(j)
of '\\':
LLStreamWrite(p.outp, "\\\\")
llStreamWrite(p.outp, "\\\\")
inc(j)
of '\'':
LLStreamWrite(p.outp, "\\\'")
llStreamWrite(p.outp, "\\\'")
inc(j)
of '\"':
LLStreamWrite(p.outp, "\\\"")
llStreamWrite(p.outp, "\\\"")
inc(j)
else:
if p.x[j] == p.subsChar:
@@ -153,59 +153,59 @@ proc parseLine(p: var TTmplParser) =
case p.x[j]
of '{':
p.info.col = int16(j)
LLStreamWrite(p.outp, '\"')
LLStreamWrite(p.outp, p.conc)
LLStreamWrite(p.outp, p.toStr)
LLStreamWrite(p.outp, '(')
llStreamWrite(p.outp, '\"')
llStreamWrite(p.outp, p.conc)
llStreamWrite(p.outp, p.toStr)
llStreamWrite(p.outp, '(')
inc(j)
curly = 0
while true:
case p.x[j]
of '\0':
LocalError(p.info, errXExpected, "}")
localError(p.info, errXExpected, "}")
break
of '{':
inc(j)
inc(curly)
LLStreamWrite(p.outp, '{')
llStreamWrite(p.outp, '{')
of '}':
inc(j)
if curly == 0: break
if curly > 0: dec(curly)
LLStreamWrite(p.outp, '}')
llStreamWrite(p.outp, '}')
else:
LLStreamWrite(p.outp, p.x[j])
llStreamWrite(p.outp, p.x[j])
inc(j)
LLStreamWrite(p.outp, ')')
LLStreamWrite(p.outp, p.conc)
LLStreamWrite(p.outp, '\"')
llStreamWrite(p.outp, ')')
llStreamWrite(p.outp, p.conc)
llStreamWrite(p.outp, '\"')
of 'a'..'z', 'A'..'Z', '\x80'..'\xFF':
LLStreamWrite(p.outp, '\"')
LLStreamWrite(p.outp, p.conc)
LLStreamWrite(p.outp, p.toStr)
LLStreamWrite(p.outp, '(')
llStreamWrite(p.outp, '\"')
llStreamWrite(p.outp, p.conc)
llStreamWrite(p.outp, p.toStr)
llStreamWrite(p.outp, '(')
while p.x[j] in PatternChars:
LLStreamWrite(p.outp, p.x[j])
llStreamWrite(p.outp, p.x[j])
inc(j)
LLStreamWrite(p.outp, ')')
LLStreamWrite(p.outp, p.conc)
LLStreamWrite(p.outp, '\"')
llStreamWrite(p.outp, ')')
llStreamWrite(p.outp, p.conc)
llStreamWrite(p.outp, '\"')
else:
if p.x[j] == p.subsChar:
LLStreamWrite(p.outp, p.subsChar)
llStreamWrite(p.outp, p.subsChar)
inc(j)
else:
p.info.col = int16(j)
LocalError(p.info, errInvalidExpression, "$")
localError(p.info, errInvalidExpression, "$")
else:
LLStreamWrite(p.outp, p.x[j])
llStreamWrite(p.outp, p.x[j])
inc(j)
LLStreamWrite(p.outp, "\\n\"")
llStreamWrite(p.outp, "\\n\"")
proc filterTmpl(stdin: PLLStream, filename: string, call: PNode): PLLStream =
var p: TTmplParser
p.info = newLineInfo(filename, 0, 0)
p.outp = LLStreamOpen("")
p.outp = llStreamOpen("")
p.inp = stdin
p.subsChar = charArg(call, "subschar", 1, '$')
p.nimDirective = charArg(call, "metachar", 2, '#')
@@ -213,9 +213,9 @@ proc filterTmpl(stdin: PLLStream, filename: string, call: PNode): PLLStream =
p.conc = strArg(call, "conc", 4, " & ")
p.toStr = strArg(call, "tostring", 5, "$")
p.x = newStringOfCap(120)
while LLStreamReadLine(p.inp, p.x):
while llStreamReadLine(p.inp, p.x):
p.info.line = p.info.line + int16(1)
parseLine(p)
newLine(p)
result = p.outp
LLStreamClose(p.inp)
llStreamClose(p.inp)

View File

@@ -16,13 +16,13 @@ import
proc filterReplace*(stdin: PLLStream, filename: string, call: PNode): PLLStream
proc filterStrip*(stdin: PLLStream, filename: string, call: PNode): PLLStream
# helpers to retrieve arguments:
proc charArg*(n: PNode, name: string, pos: int, default: Char): Char
proc charArg*(n: PNode, name: string, pos: int, default: char): char
proc strArg*(n: PNode, name: string, pos: int, default: string): string
proc boolArg*(n: PNode, name: string, pos: int, default: bool): bool
# implementation
proc invalidPragma(n: PNode) =
LocalError(n.info, errXNotAllowedHere, renderTree(n, {renderNoComments}))
localError(n.info, errXNotAllowedHere, renderTree(n, {renderNoComments}))
proc getArg(n: PNode, name: string, pos: int): PNode =
result = nil
@@ -30,12 +30,12 @@ proc getArg(n: PNode, name: string, pos: int): PNode =
for i in countup(1, sonsLen(n) - 1):
if n.sons[i].kind == nkExprEqExpr:
if n.sons[i].sons[0].kind != nkIdent: invalidPragma(n)
if IdentEq(n.sons[i].sons[0].ident, name):
if identEq(n.sons[i].sons[0].ident, name):
return n.sons[i].sons[1]
elif i == pos:
return n.sons[i]
proc charArg(n: PNode, name: string, pos: int, default: Char): Char =
proc charArg(n: PNode, name: string, pos: int, default: char): char =
var x = getArg(n, name, pos)
if x == nil: result = default
elif x.kind == nkCharLit: result = chr(int(x.intVal))
@@ -50,30 +50,30 @@ proc strArg(n: PNode, name: string, pos: int, default: string): string =
proc boolArg(n: PNode, name: string, pos: int, default: bool): bool =
var x = getArg(n, name, pos)
if x == nil: result = default
elif (x.kind == nkIdent) and IdentEq(x.ident, "true"): result = true
elif (x.kind == nkIdent) and IdentEq(x.ident, "false"): result = false
elif (x.kind == nkIdent) and identEq(x.ident, "true"): result = true
elif (x.kind == nkIdent) and identEq(x.ident, "false"): result = false
else: invalidPragma(n)
proc filterStrip(stdin: PLLStream, filename: string, call: PNode): PLLStream =
var pattern = strArg(call, "startswith", 1, "")
var leading = boolArg(call, "leading", 2, true)
var trailing = boolArg(call, "trailing", 3, true)
result = LLStreamOpen("")
result = llStreamOpen("")
var line = newStringOfCap(80)
while LLStreamReadLine(stdin, line):
while llStreamReadLine(stdin, line):
var stripped = strip(line, leading, trailing)
if (len(pattern) == 0) or startsWith(stripped, pattern):
LLStreamWriteln(result, stripped)
llStreamWriteln(result, stripped)
else:
LLStreamWriteln(result, line)
LLStreamClose(stdin)
llStreamWriteln(result, line)
llStreamClose(stdin)
proc filterReplace(stdin: PLLStream, filename: string, call: PNode): PLLStream =
var sub = strArg(call, "sub", 1, "")
if len(sub) == 0: invalidPragma(call)
var by = strArg(call, "by", 2, "")
result = LLStreamOpen("")
result = llStreamOpen("")
var line = newStringOfCap(80)
while LLStreamReadLine(stdin, line):
LLStreamWriteln(result, replace(line, sub, by))
LLStreamClose(stdin)
while llStreamReadLine(stdin, line):
llStreamWriteln(result, replace(line, sub, by))
llStreamClose(stdin)

588
compiler/guards.nim Normal file
View File

@@ -0,0 +1,588 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements the 'implies' relation for guards.
import ast, astalgo, msgs, magicsys, nimsets, trees, types, renderer, idents
const
someEq = {mEqI, mEqI64, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc,
mEqUntracedRef, mEqStr, mEqSet, mEqCString}
# set excluded here as the semantics are vastly different:
someLe = {mLeI, mLeI64, mLeF64, mLeU, mLeU64, mLeEnum,
mLeCh, mLeB, mLePtr, mLeStr}
someLt = {mLtI, mLtI64, mLtF64, mLtU, mLtU64, mLtEnum,
mLtCh, mLtB, mLtPtr, mLtStr}
someLen = {mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq}
someIn = {mInRange, mInSet}
proc isValue(n: PNode): bool = n.kind in {nkCharLit..nkNilLit}
proc isLocation(n: PNode): bool = not n.isValue
proc isLet(n: PNode): bool =
if n.kind == nkSym:
if n.sym.kind in {skLet, skTemp, skForVar}:
result = true
elif n.sym.kind == skParam and skipTypes(n.sym.typ,
abstractInst).kind != tyVar:
result = true
proc isVar(n: PNode): bool =
n.kind == nkSym and n.sym.kind in {skResult, skVar} and
{sfGlobal, sfAddrTaken} * n.sym.flags == {}
proc isLetLocation(m: PNode, isApprox: bool): bool =
# consider: 'n[].kind' --> we really need to support 1 deref op even if this
# is technically wrong due to aliasing :-( We could introduce "soft" facts
# for this; this would still be very useful for warnings and also nicely
# solves the 'var' problems. For now we fix this by requiring much more
# restrictive expressions for the 'not nil' checking.
var n = m
var derefs = 0
while true:
case n.kind
of nkDotExpr, nkCheckedFieldExpr, nkObjUpConv, nkObjDownConv:
n = n.sons[0]
of nkDerefExpr, nkHiddenDeref:
n = n.sons[0]
inc derefs
of nkBracketExpr:
if isConstExpr(n.sons[1]) or isLet(n.sons[1]):
n = n.sons[0]
else: return
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
n = n.sons[1]
else:
break
result = n.isLet and derefs <= ord(isApprox)
if not result and isApprox:
result = isVar(n)
proc interestingCaseExpr*(m: PNode): bool = isLetLocation(m, true)
proc getMagicOp(name: string, m: TMagic): PSym =
result = newSym(skProc, getIdent(name), nil, unknownLineInfo())
result.magic = m
let
opLe = getMagicOp("<=", mLeI)
opLt = getMagicOp("<", mLtI)
opAnd = getMagicOp("and", mAnd)
opOr = getMagicOp("or", mOr)
opNot = getMagicOp("not", mNot)
opIsNil = getMagicOp("isnil", mIsNil)
opContains = getMagicOp("contains", mInSet)
opEq = getMagicOp("==", mEqI)
proc swapArgs(fact: PNode, newOp: PSym): PNode =
result = newNodeI(nkCall, fact.info, 3)
result.sons[0] = newSymNode(newOp)
result.sons[1] = fact.sons[2]
result.sons[2] = fact.sons[1]
proc neg(n: PNode): PNode =
if n == nil: return nil
case n.getMagic
of mNot:
result = n.sons[1]
of someLt:
# not (a < b) == a >= b == b <= a
result = swapArgs(n, opLe)
of someLe:
result = swapArgs(n, opLt)
of mInSet:
if n.sons[1].kind != nkCurly: return nil
let t = n.sons[2].typ.skipTypes(abstractInst)
result = newNodeI(nkCall, n.info, 3)
result.sons[0] = n.sons[0]
result.sons[2] = n.sons[2]
if t.kind == tyEnum:
var s = newNodeIT(nkCurly, n.info, n.sons[1].typ)
for e in t.n:
let eAsNode = newIntNode(nkIntLit, e.sym.position)
if not inSet(n.sons[1], eAsNode): s.add eAsNode
result.sons[1] = s
elif lengthOrd(t) < 1000:
result.sons[1] = complement(n.sons[1])
else:
# not ({2, 3, 4}.contains(x)) x != 2 and x != 3 and x != 4
# XXX todo
result = nil
of mOr:
# not (a or b) --> not a and not b
let
a = n.sons[1].neg
b = n.sons[2].neg
if a != nil and b != nil:
result = newNodeI(nkCall, n.info, 3)
result.sons[0] = newSymNode(opAnd)
result.sons[1] = a
result.sons[2] = b
elif a != nil:
result = a
elif b != nil:
result = b
else:
# leave not (a == 4) as it is
result = newNodeI(nkCall, n.info, 2)
result.sons[0] = newSymNode(opNot)
result.sons[1] = n
proc buildIsNil(arg: PNode): PNode =
result = newNodeI(nkCall, arg.info, 2)
result.sons[0] = newSymNode(opIsNil)
result.sons[1] = arg
proc usefulFact(n: PNode): PNode =
case n.getMagic
of someEq:
if skipConv(n.sons[2]).kind == nkNilLit and (
isLetLocation(n.sons[1], false) or isVar(n.sons[1])):
result = buildIsNil(n.sons[1])
else:
if isLetLocation(n.sons[1], true) or isLetLocation(n.sons[2], true):
# XXX algebraic simplifications! 'i-1 < a.len' --> 'i < a.len+1'
result = n
of someLe+someLt:
if isLetLocation(n.sons[1], true) or isLetLocation(n.sons[2], true):
# XXX algebraic simplifications! 'i-1 < a.len' --> 'i < a.len+1'
result = n
of mIsNil:
if isLetLocation(n.sons[1], false) or isVar(n.sons[1]):
result = n
of someIn:
if isLetLocation(n.sons[1], true):
result = n
of mAnd:
let
a = usefulFact(n.sons[1])
b = usefulFact(n.sons[2])
if a != nil and b != nil:
result = newNodeI(nkCall, n.info, 3)
result.sons[0] = newSymNode(opAnd)
result.sons[1] = a
result.sons[2] = b
elif a != nil:
result = a
elif b != nil:
result = b
of mNot:
let a = usefulFact(n.sons[1])
if a != nil:
result = a.neg
of mOr:
# 'or' sucks! (p.isNil or q.isNil) --> hard to do anything
# with that knowledge...
# DeMorgan helps a little though:
# not a or not b --> not (a and b)
# (x == 3) or (y == 2) ---> not ( not (x==3) and not (y == 2))
# not (x != 3 and y != 2)
let
a = usefulFact(n.sons[1]).neg
b = usefulFact(n.sons[2]).neg
if a != nil and b != nil:
result = newNodeI(nkCall, n.info, 3)
result.sons[0] = newSymNode(opAnd)
result.sons[1] = a
result.sons[2] = b
result = result.neg
elif n.kind == nkSym and n.sym.kind == skLet:
# consider:
# let a = 2 < x
# if a:
# ...
# We make can easily replace 'a' by '2 < x' here:
if n.sym.ast != nil:
result = usefulFact(n.sym.ast)
elif n.kind == nkStmtListExpr:
result = usefulFact(n.lastSon)
type
TModel* = seq[PNode] # the "knowledge base"
proc addFact*(m: var TModel, n: PNode) =
let n = usefulFact(n)
if n != nil: m.add n
proc addFactNeg*(m: var TModel, n: PNode) =
let n = n.neg
if n != nil: addFact(m, n)
proc sameTree(a, b: PNode): bool =
result = false
if a == b:
result = true
elif (a != nil) and (b != nil) and (a.kind == b.kind):
case a.kind
of nkSym: result = a.sym == b.sym
of nkIdent: result = a.ident.id == b.ident.id
of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal
of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
of nkType: result = a.typ == b.typ
of nkEmpty, nkNilLit: result = true
else:
if sonsLen(a) == sonsLen(b):
for i in countup(0, sonsLen(a) - 1):
if not sameTree(a.sons[i], b.sons[i]): return
result = true
proc hasSubTree(n, x: PNode): bool =
if n.sameTree(x): result = true
else:
for i in 0..safeLen(n)-1:
if hasSubTree(n.sons[i], x): return true
proc invalidateFacts*(m: var TModel, n: PNode) =
# We are able to guard local vars (as opposed to 'let' variables)!
# 'while p != nil: f(p); p = p.next'
# This is actually quite easy to do:
# Re-assignments (incl. pass to a 'var' param) trigger an invalidation
# of every fact that contains 'v'.
#
# if x < 4:
# if y < 5
# x = unknown()
# # we invalidate 'x' here but it's known that x >= 4
# # for the else anyway
# else:
# echo x
#
# The same mechanism could be used for more complex data stored on the heap;
# procs that 'write: []' cannot invalidate 'n.kind' for instance. In fact, we
# could CSE these expressions then and help C's optimizer.
for i in 0..high(m):
if m[i] != nil and m[i].hasSubTree(n): m[i] = nil
proc valuesUnequal(a, b: PNode): bool =
if a.isValue and b.isValue:
result = not sameValue(a, b)
proc pred(n: PNode): PNode =
if n.kind in {nkCharLit..nkUInt64Lit} and n.intVal != low(BiggestInt):
result = copyNode(n)
dec result.intVal
else:
result = n
proc impliesEq(fact, eq: PNode): TImplication =
let (loc, val) = if isLocation(eq.sons[1]): (1, 2) else: (2, 1)
case fact.sons[0].sym.magic
of someEq:
if sameTree(fact.sons[1], eq.sons[loc]):
# this is not correct; consider: a == b; a == 1 --> unknown!
if sameTree(fact.sons[2], eq.sons[val]): result = impYes
elif valuesUnequal(fact.sons[2], eq.sons[val]): result = impNo
elif sameTree(fact.sons[2], eq.sons[loc]):
if sameTree(fact.sons[1], eq.sons[val]): result = impYes
elif valuesUnequal(fact.sons[1], eq.sons[val]): result = impNo
of mInSet:
# remember: mInSet is 'contains' so the set comes first!
if sameTree(fact.sons[2], eq.sons[loc]) and isValue(eq.sons[val]):
if inSet(fact.sons[1], eq.sons[val]): result = impYes
else: result = impNo
of mNot, mOr, mAnd: internalError(eq.info, "impliesEq")
else: discard
proc leImpliesIn(x, c, aSet: PNode): TImplication =
if c.kind in {nkCharLit..nkUInt64Lit}:
# fact: x <= 4; question x in {56}?
# --> true if every value <= 4 is in the set {56}
#
var value = newIntNode(c.kind, firstOrd(x.typ))
# don't iterate too often:
if c.intVal - value.intVal < 1000:
var i, pos, neg: int
while value.intVal <= c.intVal:
if inSet(aSet, value): inc pos
else: inc neg
inc i; inc value.intVal
if pos == i: result = impYes
elif neg == i: result = impNo
proc geImpliesIn(x, c, aSet: PNode): TImplication =
if c.kind in {nkCharLit..nkUInt64Lit}:
# fact: x >= 4; question x in {56}?
# --> true iff every value >= 4 is in the set {56}
#
var value = newIntNode(c.kind, c.intVal)
let max = lastOrd(x.typ)
# don't iterate too often:
if max - value.intVal < 1000:
var i, pos, neg: int
while value.intVal <= max:
if inSet(aSet, value): inc pos
else: inc neg
inc i; inc value.intVal
if pos == i: result = impYes
elif neg == i: result = impNo
proc compareSets(a, b: PNode): TImplication =
if equalSets(a, b): result = impYes
elif intersectSets(a, b).len == 0: result = impNo
proc impliesIn(fact, loc, aSet: PNode): TImplication =
case fact.sons[0].sym.magic
of someEq:
if sameTree(fact.sons[1], loc):
if inSet(aSet, fact.sons[2]): result = impYes
else: result = impNo
elif sameTree(fact.sons[2], loc):
if inSet(aSet, fact.sons[1]): result = impYes
else: result = impNo
of mInSet:
if sameTree(fact.sons[2], loc):
result = compareSets(fact.sons[1], aSet)
of someLe:
if sameTree(fact.sons[1], loc):
result = leImpliesIn(fact.sons[1], fact.sons[2], aSet)
elif sameTree(fact.sons[2], loc):
result = geImpliesIn(fact.sons[2], fact.sons[1], aSet)
of someLt:
if sameTree(fact.sons[1], loc):
result = leImpliesIn(fact.sons[1], fact.sons[2].pred, aSet)
elif sameTree(fact.sons[2], loc):
# 4 < x --> 3 <= x
result = geImpliesIn(fact.sons[2], fact.sons[1].pred, aSet)
of mNot, mOr, mAnd: internalError(loc.info, "impliesIn")
else: discard
proc valueIsNil(n: PNode): TImplication =
if n.kind == nkNilLit: impYes
elif n.kind in {nkStrLit..nkTripleStrLit, nkBracket, nkObjConstr}: impNo
else: impUnknown
proc impliesIsNil(fact, eq: PNode): TImplication =
case fact.sons[0].sym.magic
of mIsNil:
if sameTree(fact.sons[1], eq.sons[1]):
result = impYes
of someEq:
if sameTree(fact.sons[1], eq.sons[1]):
result = valueIsNil(fact.sons[2].skipConv)
elif sameTree(fact.sons[2], eq.sons[1]):
result = valueIsNil(fact.sons[1].skipConv)
of mNot, mOr, mAnd: internalError(eq.info, "impliesIsNil")
else: discard
proc impliesGe(fact, x, c: PNode): TImplication =
internalAssert isLocation(x)
case fact.sons[0].sym.magic
of someEq:
if sameTree(fact.sons[1], x):
if isValue(fact.sons[2]) and isValue(c):
# fact: x = 4; question x >= 56? --> true iff 4 >= 56
if leValue(c, fact.sons[2]): result = impYes
else: result = impNo
elif sameTree(fact.sons[2], x):
if isValue(fact.sons[1]) and isValue(c):
if leValue(c, fact.sons[1]): result = impYes
else: result = impNo
of someLt:
if sameTree(fact.sons[1], x):
if isValue(fact.sons[2]) and isValue(c):
# fact: x < 4; question N <= x? --> false iff N <= 4
if leValue(fact.sons[2], c): result = impNo
# fact: x < 4; question 2 <= x? --> we don't know
elif sameTree(fact.sons[2], x):
# fact: 3 < x; question: N-1 < x ? --> true iff N-1 <= 3
if isValue(fact.sons[1]) and isValue(c):
if leValue(c.pred, fact.sons[1]): result = impYes
of someLe:
if sameTree(fact.sons[1], x):
if isValue(fact.sons[2]) and isValue(c):
# fact: x <= 4; question x >= 56? --> false iff 4 <= 56
if leValue(fact.sons[2], c): result = impNo
# fact: x <= 4; question x >= 2? --> we don't know
elif sameTree(fact.sons[2], x):
# fact: 3 <= x; question: x >= 2 ? --> true iff 2 <= 3
if isValue(fact.sons[1]) and isValue(c):
if leValue(c, fact.sons[1]): result = impYes
of mNot, mOr, mAnd: internalError(x.info, "impliesGe")
else: discard
proc impliesLe(fact, x, c: PNode): TImplication =
if not isLocation(x):
return impliesGe(fact, c, x)
case fact.sons[0].sym.magic
of someEq:
if sameTree(fact.sons[1], x):
if isValue(fact.sons[2]) and isValue(c):
# fact: x = 4; question x <= 56? --> true iff 4 <= 56
if leValue(fact.sons[2], c): result = impYes
else: result = impNo
elif sameTree(fact.sons[2], x):
if isValue(fact.sons[1]) and isValue(c):
if leValue(fact.sons[1], c): result = impYes
else: result = impNo
of someLt:
if sameTree(fact.sons[1], x):
if isValue(fact.sons[2]) and isValue(c):
# fact: x < 4; question x <= N? --> true iff N-1 <= 4
if leValue(fact.sons[2], c.pred): result = impYes
# fact: x < 4; question x <= 2? --> we don't know
elif sameTree(fact.sons[2], x):
# fact: 3 < x; question: x <= 1 ? --> false iff 1 <= 3
if isValue(fact.sons[1]) and isValue(c):
if leValue(c, fact.sons[1]): result = impNo
of someLe:
if sameTree(fact.sons[1], x):
if isValue(fact.sons[2]) and isValue(c):
# fact: x <= 4; question x <= 56? --> true iff 4 <= 56
if leValue(fact.sons[2], c): result = impYes
# fact: x <= 4; question x <= 2? --> we don't know
elif sameTree(fact.sons[2], x):
# fact: 3 <= x; question: x <= 2 ? --> false iff 2 < 3
if isValue(fact.sons[1]) and isValue(c):
if leValue(c, fact.sons[1].pred): result = impNo
of mNot, mOr, mAnd: internalError(x.info, "impliesLe")
else: discard
proc impliesLt(fact, x, c: PNode): TImplication =
# x < 3 same as x <= 2:
let p = c.pred
if p != c:
result = impliesLe(fact, x, p)
else:
# 4 < x same as 3 <= x
let q = x.pred
if q != x:
result = impliesLe(fact, q, c)
proc `~`(x: TImplication): TImplication =
case x
of impUnknown: impUnknown
of impNo: impYes
of impYes: impNo
proc factImplies(fact, prop: PNode): TImplication =
case fact.getMagic
of mNot:
# Consider:
# enum nkBinary, nkTernary, nkStr
# fact: not (k <= nkBinary)
# question: k in {nkStr}
# --> 'not' for facts is entirely different than 'not' for questions!
# it's provably wrong if every value > 4 is in the set {56}
# That's because we compute the implication and 'a -> not b' cannot
# be treated the same as 'not a -> b'
# (not a) -> b compute as not (a -> b) ???
# == not a or not b == not (a and b)
let arg = fact.sons[1]
case arg.getMagic
of mIsNil:
return ~factImplies(arg, prop)
of mAnd:
# not (a and b) means not a or not b:
# a or b --> both need to imply 'prop'
let a = factImplies(arg.sons[1], prop)
let b = factImplies(arg.sons[2], prop)
if a == b: return ~a
return impUnknown
else:
internalError(fact.info, "invalid fact")
of mAnd:
result = factImplies(fact.sons[1], prop)
if result != impUnknown: return result
return factImplies(fact.sons[2], prop)
else: discard
case prop.sons[0].sym.magic
of mNot: result = ~fact.factImplies(prop.sons[1])
of mIsNil: result = impliesIsNil(fact, prop)
of someEq: result = impliesEq(fact, prop)
of someLe: result = impliesLe(fact, prop.sons[1], prop.sons[2])
of someLt: result = impliesLt(fact, prop.sons[1], prop.sons[2])
of mInSet: result = impliesIn(fact, prop.sons[2], prop.sons[1])
else: internalError(prop.info, "invalid proposition")
proc doesImply*(facts: TModel, prop: PNode): TImplication =
assert prop.kind in nkCallKinds
for f in facts:
# facts can be invalidated, in which case they are 'nil':
if not f.isNil:
result = f.factImplies(prop)
if result != impUnknown: return
proc impliesNotNil*(facts: TModel, arg: PNode): TImplication =
result = doesImply(facts, buildIsNil(arg).neg)
proc settype(n: PNode): PType =
result = newType(tySet, n.typ.owner)
addSonSkipIntLit(result, n.typ)
proc buildOf(it, loc: PNode): PNode =
var s = newNodeI(nkCurly, it.info, it.len-1)
s.typ = settype(loc)
for i in 0..it.len-2: s.sons[i] = it.sons[i]
result = newNodeI(nkCall, it.info, 3)
result.sons[0] = newSymNode(opContains)
result.sons[1] = s
result.sons[2] = loc
proc buildElse(n: PNode): PNode =
var s = newNodeIT(nkCurly, n.info, settype(n.sons[0]))
for i in 1..n.len-2:
let branch = n.sons[i]
assert branch.kind == nkOfBranch
for j in 0..branch.len-2:
s.add(branch.sons[j])
result = newNodeI(nkCall, n.info, 3)
result.sons[0] = newSymNode(opContains)
result.sons[1] = s
result.sons[2] = n.sons[0]
proc addDiscriminantFact*(m: var TModel, n: PNode) =
var fact = newNodeI(nkCall, n.info, 3)
fact.sons[0] = newSymNode(opEq)
fact.sons[1] = n.sons[0]
fact.sons[2] = n.sons[1]
m.add fact
proc addAsgnFact*(m: var TModel, key, value: PNode) =
var fact = newNodeI(nkCall, key.info, 3)
fact.sons[0] = newSymNode(opEq)
fact.sons[1] = key
fact.sons[2] = value
m.add fact
proc addCaseBranchFacts*(m: var TModel, n: PNode, i: int) =
let branch = n.sons[i]
if branch.kind == nkOfBranch:
m.add buildOf(branch, n.sons[0])
else:
m.add n.buildElse.neg
proc buildProperFieldCheck(access, check: PNode): PNode =
if check.sons[1].kind == nkCurly:
result = copyTree(check)
if access.kind == nkDotExpr:
var a = copyTree(access)
a.sons[1] = check.sons[2]
result.sons[2] = a
# 'access.kind != nkDotExpr' can happen for object constructors
# which we don't check yet
else:
# it is some 'not'
assert check.getMagic == mNot
result = buildProperFieldCheck(access, check.sons[1]).neg
proc checkFieldAccess*(m: TModel, n: PNode) =
for i in 1..n.len-1:
let check = buildProperFieldCheck(n.sons[0], n.sons[i])
if m.doesImply(check) != impYes:
message(n.info, warnProveField, renderTree(n.sons[0])); break

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -12,7 +12,7 @@
proc hlo(c: PContext, n: PNode): PNode
proc evalPattern(c: PContext, n, orig: PNode): PNode =
InternalAssert n.kind == nkCall and n.sons[0].kind == nkSym
internalAssert n.kind == nkCall and n.sons[0].kind == nkSym
# we need to ensure that the resulting AST is semchecked. However, it's
# aweful to semcheck before macro invocation, so we don't and treat
# templates and macros as immediate in this context.
@@ -28,10 +28,8 @@ proc evalPattern(c: PContext, n, orig: PNode): PNode =
else:
result = semDirectOp(c, n, {})
if optHints in gOptions and hintPattern in gNotes:
Message(orig.info, hintPattern, rule & " --> '" &
message(orig.info, hintPattern, rule & " --> '" &
renderTree(result, {renderNoComments}) & "'")
# check the resulting AST for optimization rules again:
result = hlo(c, result)
proc applyPatterns(c: PContext, n: PNode): PNode =
result = n
@@ -44,9 +42,10 @@ proc applyPatterns(c: PContext, n: PNode): PNode =
let x = applyRule(c, pattern, result)
if not isNil(x):
assert x.kind in {nkStmtList, nkCall}
# better be safe than sorry, so check evalTemplateCounter too:
inc(evalTemplateCounter)
if evalTemplateCounter > 100:
GlobalError(n.info, errTemplateInstantiationTooNested)
globalError(n.info, errTemplateInstantiationTooNested)
# deactivate this pattern:
c.patterns[i] = nil
if x.kind == nkStmtList:
@@ -60,11 +59,19 @@ proc applyPatterns(c: PContext, n: PNode): PNode =
c.patterns[i] = pattern
proc hlo(c: PContext, n: PNode): PNode =
inc(c.hloLoopDetector)
# simply stop and do not perform any further transformations:
if c.hloLoopDetector > 300: return n
case n.kind
of nkMacroDef, nkTemplateDef, procDefs:
# already processed (special cases in semstmts.nim)
result = n
else:
if n.kind in {nkFastAsgn, nkAsgn, nkIdentDefs, nkVarTuple} and
n.sons[0].kind == nkSym and
{sfGlobal, sfPure} * n.sons[0].sym.flags == {sfGlobal, sfPure}:
# do not optimize 'var g {.global} = re(...)' again!
return n
result = applyPatterns(c, n)
if result == n:
# no optimization applied, try subtrees:
@@ -74,18 +81,23 @@ proc hlo(c: PContext, n: PNode): PNode =
if h != a: result.sons[i] = h
else:
# perform type checking, so that the replacement still fits:
if n.typ == nil and (result.typ == nil or
result.typ.kind in {tyStmt, tyEmpty}):
nil
if isEmptyType(n.typ) and isEmptyType(result.typ):
discard
else:
result = fitNode(c, n.typ, result)
# optimization has been applied so check again:
result = commonOptimizations(c.module, result)
result = hlo(c, result)
result = commonOptimizations(c.module, result)
proc hloBody(c: PContext, n: PNode): PNode =
# fast exit:
if c.patterns.len == 0 or optPatterns notin gOptions: return n
c.hloLoopDetector = 0
result = hlo(c, n)
proc hloStmt(c: PContext, n: PNode): PNode =
# fast exit:
if c.patterns.len == 0 or optPatterns notin gOptions: return n
c.hloLoopDetector = 0
result = hlo(c, n)

View File

@@ -24,10 +24,13 @@ type
s*: string
next*: PIdent # for hash-table chaining
h*: THash # hash value of s
var firstCharIsCS*: bool
var buckets*: array[0..4096 * 2 - 1, PIdent]
proc cmpIgnoreStyle(a, b: cstring, blen: int): int =
if firstCharIsCS:
if a[0] != b[0]: return 1
var i = 0
var j = 0
result = 1
@@ -99,8 +102,9 @@ proc getIdent*(identifier: string): PIdent =
proc getIdent*(identifier: string, h: THash): PIdent =
result = getIdent(cstring(identifier), len(identifier), h)
proc IdentEq*(id: PIdent, name: string): bool =
proc identEq*(id: PIdent, name: string): bool =
result = id.id == getIdent(name).id
var idAnon* = getIdent":anonymous"
let idDelegator* = getIdent":delegator"

View File

@@ -19,12 +19,12 @@ const
when debugIds:
import intsets
var usedIds = InitIntSet()
var usedIds = initIntSet()
proc registerID*(id: PIdObj) =
when debugIDs:
if id.id == -1 or ContainsOrIncl(usedIds, id.id):
InternalError("ID already used: " & $id.id)
when debugIds:
if id.id == -1 or containsOrIncl(usedIds, id.id):
internalError("ID already used: " & $id.id)
proc getID*(): int {.inline.} =
result = gFrontEndId
@@ -37,8 +37,8 @@ proc backendId*(): int {.inline.} =
proc setId*(id: int) {.inline.} =
gFrontEndId = max(gFrontEndId, id + 1)
proc IDsynchronizationPoint*(idRange: int) =
gFrontEndId = (gFrontEndId div IdRange + 1) * IdRange + 1
proc idSynchronizationPoint*(idRange: int) =
gFrontEndId = (gFrontEndId div idRange + 1) * idRange + 1
proc toGid(f: string): string =
# we used to use ``f.addFileExt("gid")`` (aka ``$project.gid``), but this
@@ -49,7 +49,7 @@ proc toGid(f: string): string =
proc saveMaxIds*(project: string) =
var f = open(project.toGid, fmWrite)
f.writeln($gFrontEndId)
f.writeln($gBackEndId)
f.writeln($gBackendId)
f.close()
proc loadMaxIds*(project: string) =
@@ -61,5 +61,5 @@ proc loadMaxIds*(project: string) =
if f.readLine(line):
var backEndId = parseInt(line)
gFrontEndId = max(gFrontEndId, frontEndId)
gBackEndId = max(gBackEndId, backEndId)
gBackendId = max(gBackendId, backEndId)
f.close()

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -22,24 +22,35 @@ proc getModuleName*(n: PNode): string =
# The proc won't perform any checks that the path is actually valid
case n.kind
of nkStrLit, nkRStrLit, nkTripleStrLit:
result = UnixToNativePath(n.strVal)
result = unixToNativePath(n.strVal)
of nkIdent:
result = n.ident.s
of nkSym:
result = n.sym.name.s
else:
of nkInfix:
if n.sons[0].kind == nkIdent and n.sons[0].ident.id == getIdent("as").id:
# XXX hack ahead:
n.kind = nkImportAs
n.sons[0] = n.sons[1]
n.sons[1] = n.sons[2]
n.sons.setLen(2)
return getModuleName(n.sons[0])
# hacky way to implement 'x / y /../ z':
result = renderTree(n, {renderNoComments}).replace(" ")
#localError(n.info, errGenerated,
# "invalide module name: '$1'" % renderTree(n))
#result = ""
of nkDotExpr:
result = renderTree(n, {renderNoComments}).replace(".", "/")
of nkImportAs:
result = getModuleName(n.sons[0])
else:
localError(n.info, errGenerated, "invalid module name: '$1'" % n.renderTree)
result = ""
proc checkModuleName*(n: PNode): int32 =
# This returns the full canonical path for a given module import
let modulename = n.getModuleName
let fullPath = findModule(modulename)
let fullPath = findModule(modulename, n.info.toFullPath)
if fullPath.len == 0:
LocalError(n.info, errCannotOpenFile, modulename)
localError(n.info, errCannotOpenFile, modulename)
result = InvalidFileIDX
else:
result = fullPath.fileInfoIdx
@@ -48,32 +59,32 @@ proc rawImportSymbol(c: PContext, s: PSym) =
# This does not handle stubs, because otherwise loading on demand would be
# pointless in practice. So importing stubs is fine here!
# check if we have already a symbol of the same name:
var check = StrTableGet(c.importTable.symbols, s.name)
var check = strTableGet(c.importTable.symbols, s.name)
if check != nil and check.id != s.id:
if s.kind notin OverloadableSyms:
# s and check need to be qualified:
Incl(c.AmbiguousSymbols, s.id)
Incl(c.AmbiguousSymbols, check.id)
incl(c.ambiguousSymbols, s.id)
incl(c.ambiguousSymbols, check.id)
# thanks to 'export' feature, it could be we import the same symbol from
# multiple sources, so we need to call 'StrTableAdd' here:
StrTableAdd(c.importTable.symbols, s)
strTableAdd(c.importTable.symbols, s)
if s.kind == skType:
var etyp = s.typ
if etyp.kind in {tyBool, tyEnum} and sfPure notin s.flags:
for j in countup(0, sonsLen(etyp.n) - 1):
var e = etyp.n.sons[j].sym
if e.Kind != skEnumField:
InternalError(s.info, "rawImportSymbol")
if e.kind != skEnumField:
internalError(s.info, "rawImportSymbol")
# BUGFIX: because of aliases for enums the symbol may already
# have been put into the symbol table
# BUGFIX: but only iff they are the same symbols!
var it: TIdentIter
check = InitIdentIter(it, c.importTable.symbols, e.name)
check = initIdentIter(it, c.importTable.symbols, e.name)
while check != nil:
if check.id == e.id:
e = nil
break
check = NextIdentIter(it, c.importTable.symbols)
check = nextIdentIter(it, c.importTable.symbols)
if e != nil:
rawImportSymbol(c, e)
else:
@@ -83,36 +94,36 @@ proc rawImportSymbol(c: PContext, s: PSym) =
proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
let ident = lookups.considerAcc(n)
let s = StrTableGet(fromMod.tab, ident)
let s = strTableGet(fromMod.tab, ident)
if s == nil:
LocalError(n.info, errUndeclaredIdentifier, ident.s)
localError(n.info, errUndeclaredIdentifier, ident.s)
else:
if s.kind == skStub: loadStub(s)
if s.Kind notin ExportableSymKinds:
InternalError(n.info, "importSymbol: 2")
if s.kind notin ExportableSymKinds:
internalError(n.info, "importSymbol: 2")
# for an enumeration we have to add all identifiers
case s.Kind
of skProc, skMethod, skIterator, skMacro, skTemplate, skConverter:
case s.kind
of skProcKinds:
# for a overloadable syms add all overloaded routines
var it: TIdentIter
var e = InitIdentIter(it, fromMod.tab, s.name)
var e = initIdentIter(it, fromMod.tab, s.name)
while e != nil:
if e.name.id != s.Name.id: InternalError(n.info, "importSymbol: 3")
if e.name.id != s.name.id: internalError(n.info, "importSymbol: 3")
rawImportSymbol(c, e)
e = NextIdentIter(it, fromMod.tab)
e = nextIdentIter(it, fromMod.tab)
else: rawImportSymbol(c, s)
proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: TIntSet) =
var i: TTabIter
var s = InitTabIter(i, fromMod.tab)
var s = initTabIter(i, fromMod.tab)
while s != nil:
if s.kind != skModule:
if s.kind != skEnumField:
if s.Kind notin ExportableSymKinds:
InternalError(s.info, "importAllSymbols: " & $s.kind)
if s.kind notin ExportableSymKinds:
internalError(s.info, "importAllSymbols: " & $s.kind)
if exceptSet.empty or s.name.id notin exceptSet:
rawImportSymbol(c, s)
s = NextIter(i, fromMod.tab)
s = nextIter(i, fromMod.tab)
proc importAllSymbols*(c: PContext, fromMod: PSym) =
var exceptSet: TIntSet
@@ -135,15 +146,28 @@ proc importForwarded(c: PContext, n: PNode, exceptSet: TIntSet) =
for i in 0 ..safeLen(n)-1:
importForwarded(c, n.sons[i], exceptSet)
proc importModuleAs(n: PNode, realModule: PSym): PSym =
result = realModule
if n.kind != nkImportAs: discard
elif n.len != 2 or n.sons[1].kind != nkIdent:
localError(n.info, errGenerated, "module alias must be an identifier")
elif n.sons[1].ident.id != realModule.name.id:
# some misguided guy will write 'import abc.foo as foo' ...
result = createModuleAlias(realModule, n.sons[1].ident, n.sons[1].info)
proc myImportModule(c: PContext, n: PNode): PSym =
var f = checkModuleName(n)
if f != InvalidFileIDX:
result = importModuleAs(n, gImportModule(c.module, f))
if sfDeprecated in result.flags:
message(n.info, warnDeprecated, result.name.s)
proc evalImport(c: PContext, n: PNode): PNode =
result = n
var emptySet: TIntSet
for i in countup(0, sonsLen(n) - 1):
var f = checkModuleName(n.sons[i])
if f != InvalidFileIDX:
var m = gImportModule(c.module, f)
if sfDeprecated in m.flags:
Message(n.sons[i].info, warnDeprecated, m.name.s)
var m = myImportModule(c, n.sons[i])
if m != nil:
# ``addDecl`` needs to be done before ``importAllSymbols``!
addDecl(c, m) # add symbol to symbol table of module
importAllSymbolsExcept(c, m, emptySet)
@@ -152,21 +176,19 @@ proc evalImport(c: PContext, n: PNode): PNode =
proc evalFrom(c: PContext, n: PNode): PNode =
result = n
checkMinSonsLen(n, 2)
var f = checkModuleName(n.sons[0])
if f != InvalidFileIDX:
var m = gImportModule(c.module, f)
var m = myImportModule(c, n.sons[0])
if m != nil:
n.sons[0] = newSymNode(m)
addDecl(c, m) # add symbol to symbol table of module
for i in countup(1, sonsLen(n) - 1):
for i in countup(1, sonsLen(n) - 1):
if n.sons[i].kind != nkNilLit:
importSymbol(c, n.sons[i], m)
proc evalImportExcept*(c: PContext, n: PNode): PNode =
result = n
checkMinSonsLen(n, 2)
var f = checkModuleName(n.sons[0])
if f != InvalidFileIDX:
var m = gImportModule(c.module, f)
var m = myImportModule(c, n.sons[0])
if m != nil:
n.sons[0] = newSymNode(m)
addDecl(c, m) # add symbol to symbol table of module
var exceptSet = initIntSet()

File diff suppressed because it is too large Load Diff

View File

@@ -37,7 +37,7 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): PRope =
[mangleName(field), s, makeJSString(field.name.s)])
of nkRecCase:
length = sonsLen(n)
if (n.sons[0].kind != nkSym): InternalError(n.info, "genObjectFields")
if (n.sons[0].kind != nkSym): internalError(n.info, "genObjectFields")
field = n.sons[0].sym
s = genTypeInfo(p, field.typ)
for i in countup(1, length - 1):
@@ -98,7 +98,7 @@ proc genEnumInfo(p: PProc, typ: PType, name: PRope) =
let length = sonsLen(typ.n)
var s: PRope = nil
for i in countup(0, length - 1):
if (typ.n.sons[i].kind != nkSym): InternalError(typ.n.info, "genEnumInfo")
if (typ.n.sons[i].kind != nkSym): internalError(typ.n.info, "genEnumInfo")
let field = typ.n.sons[i].sym
if i > 0: app(s, ", " & tnl)
let extName = if field.ast == nil: field.name.s else: field.ast.strVal
@@ -119,7 +119,7 @@ proc genTypeInfo(p: PProc, typ: PType): PRope =
var t = typ
if t.kind == tyGenericInst: t = lastSon(t)
result = ropef("NTI$1", [toRope(t.id)])
if ContainsOrIncl(p.g.TypeInfoGenerated, t.id): return
if containsOrIncl(p.g.typeInfoGenerated, t.id): return
case t.kind
of tyDistinct:
result = genTypeInfo(p, typ.sons[0])
@@ -134,7 +134,7 @@ proc genTypeInfo(p: PProc, typ: PType): PRope =
[result, toRope(ord(t.kind))])
prepend(p.g.typeInfo, s)
appf(p.g.typeInfo, "$1.base = $2;$n",
[result, genTypeInfo(p, typ.sons[0])])
[result, genTypeInfo(p, typ.lastSon)])
of tyArrayConstr, tyArray:
var s = ropef(
"var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n",
@@ -145,4 +145,4 @@ proc genTypeInfo(p: PProc, typ: PType): PRope =
of tyEnum: genEnumInfo(p, t, result)
of tyObject: genObjectInfo(p, t, result)
of tyTuple: genTupleInfo(p, t, result)
else: InternalError("genTypeInfo(" & $t.kind & ')')
else: internalError("genTypeInfo(" & $t.kind & ')')

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2013 Andreas Rumpf
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -11,7 +11,7 @@
import
intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os,
idents, renderer, types, magicsys, rodread
idents, renderer, types, magicsys, rodread, lowerings
discard """
The basic approach is that captured vars need to be put on the heap and
@@ -116,98 +116,58 @@ type
TDep = tuple[e: PEnv, field: PSym]
TEnv {.final.} = object of TObject
attachedNode: PNode
closure: PSym # if != nil it is a used environment
createdVar: PSym # if != nil it is a used environment
createdVarComesFromIter: bool
capturedVars: seq[PSym] # captured variables in this environment
deps: seq[TDep] # dependencies
deps: seq[TDep] # dependencies
up: PEnv
tup: PType
obj: PType
TInnerContext {.final.} = object
TInnerContext = object
fn: PSym
closureParam: PSym
localsToAccess: TIdNodeTable
TOuterContext {.final.} = object
TOuterContext = object
fn: PSym # may also be a module!
currentEnv: PEnv
isIter: bool # first class iterator?
capturedVars, processed: TIntSet
localsToEnv: TIdTable # PSym->PEnv mapping
localsToAccess: TIdNodeTable
lambdasToEnv: TIdTable # PSym->PEnv mapping
up: POuterContext
proc newOuterContext(fn: PSym, up: POuterContext = nil): POuterContext =
new(result)
result.fn = fn
result.capturedVars = initIntSet()
result.processed = initIntSet()
initIdNodeTable(result.localsToAccess)
initIdTable(result.localsToEnv)
initIdTable(result.lambdasToEnv)
proc newInnerContext(fn: PSym): PInnerContext =
new(result)
result.fn = fn
initIdNodeTable(result.localsToAccess)
proc newEnv(outerProc: PSym, up: PEnv, n: PNode): PEnv =
new(result)
result.deps = @[]
result.capturedVars = @[]
result.tup = newType(tyTuple, outerProc)
result.tup.n = newNodeI(nkRecList, outerProc.info)
result.up = up
result.attachedNode = n
closureParam, state, resultSym: PSym # only if isIter
obj: PType # only if isIter
proc addField(tup: PType, s: PSym) =
var field = newSym(skField, s.name, s.owner, s.info)
let t = skipIntLit(s.typ)
field.typ = t
field.position = sonsLen(tup)
addSon(tup.n, newSymNode(field))
rawAddSon(tup, t)
proc addCapturedVar(e: PEnv, v: PSym) =
for x in e.capturedVars:
if x == v: return
e.capturedVars.add(v)
addField(e.tup, v)
proc addDep(e, d: PEnv, owner: PSym): PSym =
for x, field in items(e.deps):
if x == d: return field
var pos = sonsLen(e.tup)
result = newSym(skField, getIdent(upName & $pos), owner, owner.info)
result.typ = newType(tyRef, owner)
result.position = pos
assert d.tup != nil
rawAddSon(result.typ, d.tup)
addField(e.tup, result)
e.deps.add((d, result))
proc indirectAccess(a: PNode, b: PSym, info: TLineInfo): PNode =
# returns a[].b as a node
var deref = newNodeI(nkHiddenDeref, info)
deref.typ = a.typ.sons[0]
let field = getSymFromList(deref.typ.n, b.name)
assert field != nil, b.name.s
addSon(deref, a)
result = newNodeI(nkDotExpr, info)
addSon(result, deref)
addSon(result, newSymNode(field))
result.typ = field.typ
proc getStateType(iter: PSym): PType =
var n = newNodeI(nkRange, iter.info)
addSon(n, newIntNode(nkIntLit, -1))
addSon(n, newIntNode(nkIntLit, 0))
result = newType(tyRange, iter)
result.n = n
rawAddSon(result, getSysType(tyInt))
proc indirectAccess(a, b: PSym, info: TLineInfo): PNode =
result = indirectAccess(newSymNode(a), b, info)
proc createStateField(iter: PSym): PSym =
result = newSym(skField, getIdent(":state"), iter, iter.info)
result.typ = getStateType(iter)
proc newCall(a, b: PSym): PNode =
result = newNodeI(nkCall, a.info)
result.add newSymNode(a)
result.add newSymNode(b)
proc newIterResult(iter: PSym): PSym =
if resultPos < iter.ast.len:
result = iter.ast.sons[resultPos].sym
else:
# XXX a bit hacky:
result = newSym(skResult, getIdent":result", iter, iter.info)
result.typ = iter.typ.sons[0]
incl(result.flags, sfUsed)
iter.ast.add newSymNode(result)
proc addHiddenParam(routine: PSym, param: PSym) =
var params = routine.ast.sons[paramsPos]
param.position = params.len
# -1 is correct here as param.position is 0 based but we have at position 0
# some nkEffect node:
param.position = params.len-1
addSon(params, newSymNode(param))
incl(routine.typ.flags, tfCapturesEnv)
#echo "produced environment: ", param.id, " for ", routine.name.s
@@ -218,24 +178,115 @@ proc getHiddenParam(routine: PSym): PSym =
assert hidden.kind == nkSym
result = hidden.sym
proc getEnvParam(routine: PSym): PSym =
let params = routine.ast.sons[paramsPos]
let hidden = lastSon(params)
if hidden.kind == nkSym and hidden.sym.name.s == paramName:
result = hidden.sym
proc initIterContext(c: POuterContext, iter: PSym) =
c.fn = iter
c.capturedVars = initIntSet()
var cp = getEnvParam(iter)
if cp == nil:
c.obj = createObj(iter, iter.info)
cp = newSym(skParam, getIdent(paramName), iter, iter.info)
incl(cp.flags, sfFromGeneric)
cp.typ = newType(tyRef, iter)
rawAddSon(cp.typ, c.obj)
addHiddenParam(iter, cp)
c.state = createStateField(iter)
addField(c.obj, c.state)
else:
c.obj = cp.typ.sons[0]
assert c.obj.kind == tyObject
if c.obj.n.len > 0:
c.state = c.obj.n[0].sym
else:
c.state = createStateField(iter)
addField(c.obj, c.state)
c.closureParam = cp
if iter.typ.sons[0] != nil:
c.resultSym = newIterResult(iter)
#iter.ast.add(newSymNode(c.resultSym))
proc newOuterContext(fn: PSym, up: POuterContext = nil): POuterContext =
new(result)
result.fn = fn
result.capturedVars = initIntSet()
result.processed = initIntSet()
initIdNodeTable(result.localsToAccess)
initIdTable(result.localsToEnv)
initIdTable(result.lambdasToEnv)
result.isIter = fn.kind == skClosureIterator
if result.isIter: initIterContext(result, fn)
proc newInnerContext(fn: PSym): PInnerContext =
new(result)
result.fn = fn
initIdNodeTable(result.localsToAccess)
proc newEnv(outerProc: PSym, up: PEnv, n: PNode): PEnv =
new(result)
result.deps = @[]
result.capturedVars = @[]
result.obj = createObj(outerProc, outerProc.info)
result.up = up
result.attachedNode = n
proc addCapturedVar(e: PEnv, v: PSym) =
for x in e.capturedVars:
if x == v: return
# XXX meh, just add the state field for every closure for now, it's too
# hard to figure out if it comes from a closure iterator:
if e.obj.n.len == 0: addField(e.obj, createStateField(v.owner))
e.capturedVars.add(v)
addField(e.obj, v)
proc addDep(e, d: PEnv, owner: PSym): PSym =
for x, field in items(e.deps):
if x == d: return field
var pos = sonsLen(e.obj.n)
result = newSym(skField, getIdent(upName & $pos), owner, owner.info)
result.typ = newType(tyRef, owner)
result.position = pos
assert d.obj != nil
rawAddSon(result.typ, d.obj)
addField(e.obj, result)
e.deps.add((d, result))
proc newCall(a, b: PSym): PNode =
result = newNodeI(nkCall, a.info)
result.add newSymNode(a)
result.add newSymNode(b)
proc isInnerProc(s, outerProc: PSym): bool {.inline.} =
result = s.kind in {skProc, skMethod, skConverter} and
s.owner == outerProc and not isGenericRoutine(s)
result = s.kind in {skProc, skMethod, skConverter, skClosureIterator} and
s.skipGenericOwner == outerProc
#s.typ.callConv == ccClosure
proc addClosureParam(i: PInnerContext, e: PEnv) =
var cp = newSym(skParam, getIdent(paramname), i.fn, i.fn.info)
incl(cp.flags, sfFromGeneric)
cp.typ = newType(tyRef, i.fn)
rawAddSon(cp.typ, e.tup)
var cp = getEnvParam(i.fn)
if cp == nil:
cp = newSym(skParam, getIdent(paramName), i.fn, i.fn.info)
incl(cp.flags, sfFromGeneric)
cp.typ = newType(tyRef, i.fn)
rawAddSon(cp.typ, e.obj)
addHiddenParam(i.fn, cp)
else:
e.obj = cp.typ.sons[0]
assert e.obj.kind == tyObject
i.closureParam = cp
addHiddenParam(i.fn, i.closureParam)
#echo "closure param added for ", i.fn.name.s, " ", i.fn.id
proc dummyClosureParam(o: POuterContext, i: PInnerContext) =
var e = o.currentEnv
if IdTableGet(o.lambdasToEnv, i.fn) == nil:
IdTablePut(o.lambdasToEnv, i.fn, e)
if idTableGet(o.lambdasToEnv, i.fn) == nil:
idTablePut(o.lambdasToEnv, i.fn, e)
if i.closureParam == nil: addClosureParam(i, e)
proc illegalCapture(s: PSym): bool {.inline.} =
@@ -247,13 +298,13 @@ proc captureVar(o: POuterContext, i: PInnerContext, local: PSym,
info: TLineInfo) =
# for inlined variables the owner is still wrong, so it can happen that it's
# not a captured variable at all ... *sigh*
var it = PEnv(IdTableGet(o.localsToEnv, local))
var it = PEnv(idTableGet(o.localsToEnv, local))
if it == nil: return
if illegalCapture(local) or o.fn.id != local.owner.id or
i.fn.typ.callConv notin {ccClosure, ccDefault}:
# Currently captures are restricted to a single level of nesting:
LocalError(info, errIllegalCaptureX, local.name.s)
localError(info, errIllegalCaptureX, local.name.s)
i.fn.typ.callConv = ccClosure
#echo "captureVar ", i.fn.name.s, i.fn.id, " ", local.name.s, local.id
@@ -261,11 +312,11 @@ proc captureVar(o: POuterContext, i: PInnerContext, local: PSym,
# we need to remember which inner most closure belongs to this lambda:
var e = o.currentEnv
if IdTableGet(o.lambdasToEnv, i.fn) == nil:
IdTablePut(o.lambdasToEnv, i.fn, e)
if idTableGet(o.lambdasToEnv, i.fn) == nil:
idTablePut(o.lambdasToEnv, i.fn, e)
# variable already captured:
if IdNodeTableGet(i.localsToAccess, local) != nil: return
if idNodeTableGet(i.localsToAccess, local) != nil: return
if i.closureParam == nil: addClosureParam(i, e)
# check which environment `local` belongs to:
@@ -273,13 +324,16 @@ proc captureVar(o: POuterContext, i: PInnerContext, local: PSym,
addCapturedVar(it, local)
if it == e:
# common case: local directly in current environment:
nil
discard
else:
# it's in some upper environment:
access = indirectAccess(access, addDep(e, it, i.fn), info)
access = indirectAccess(access, local, info)
incl(o.capturedVars, local.id)
IdNodeTablePut(i.localsToAccess, local, access)
if o.isIter:
if not containsOrIncl(o.capturedVars, local.id): addField(o.obj, local)
else:
incl(o.capturedVars, local.id)
idNodeTablePut(i.localsToAccess, local, access)
proc interestingVar(s: PSym): bool {.inline.} =
result = s.kind in {skVar, skLet, skTemp, skForVar, skParam, skResult} and
@@ -288,6 +342,9 @@ proc interestingVar(s: PSym): bool {.inline.} =
proc semCaptureSym*(s, owner: PSym) =
if interestingVar(s) and owner.id != s.owner.id and s.kind != skResult:
if owner.typ != nil and not isGenericRoutine(owner):
# XXX: is this really safe?
# if we capture a var from another generic routine,
# it won't be consider captured.
owner.typ.callConv = ccClosure
#echo "semCaptureSym ", owner.name.s, owner.id, " ", s.name.s, s.id
# since the analysis is not entirely correct, we don't set 'tfCapturesEnv'
@@ -301,15 +358,17 @@ proc gatherVars(o: POuterContext, i: PInnerContext, n: PNode) =
var s = n.sym
if interestingVar(s) and i.fn.id != s.owner.id:
captureVar(o, i, s, n.info)
elif isInnerProc(s, o.fn) and tfCapturesEnv in s.typ.flags and s != i.fn:
elif s.kind in {skProc, skMethod, skConverter} and
s.skipGenericOwner == o.fn and
tfCapturesEnv in s.typ.flags and s != i.fn:
# call to some other inner proc; we need to track the dependencies for
# this:
let env = PEnv(IdTableGet(o.lambdasToEnv, i.fn))
if env == nil: InternalError(n.info, "no environment computed")
let env = PEnv(idTableGet(o.lambdasToEnv, i.fn))
if env == nil: internalError(n.info, "no environment computed")
if o.currentEnv != env:
discard addDep(o.currentEnv, env, i.fn)
InternalError(n.info, "too complex environment handling required")
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: nil
internalError(n.info, "too complex environment handling required")
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkClosure: discard
else:
for k in countup(0, sonsLen(n) - 1):
gatherVars(o, i, n.sons[k])
@@ -346,7 +405,7 @@ proc makeClosure(prc, env: PSym, info: TLineInfo): PNode =
proc transformInnerProc(o: POuterContext, i: PInnerContext, n: PNode): PNode =
case n.kind
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: nil
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: discard
of nkSym:
let s = n.sym
if s == i.fn:
@@ -360,13 +419,14 @@ proc transformInnerProc(o: POuterContext, i: PInnerContext, n: PNode): PNode =
result = makeClosure(s, i.closureParam, n.info)
else:
# captured symbol?
result = IdNodeTableGet(i.localsToAccess, n.sym)
of nkLambdaKinds:
result = transformInnerProc(o, i, n.sons[namePos])
result = idNodeTableGet(i.localsToAccess, n.sym)
of nkLambdaKinds, nkIteratorDef:
if n.typ != nil:
result = transformInnerProc(o, i, n.sons[namePos])
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
nkIteratorDef:
nkClosure:
# don't recurse here:
nil
discard
else:
for j in countup(0, sonsLen(n) - 1):
let x = transformInnerProc(o, i, n.sons[j])
@@ -381,7 +441,7 @@ proc searchForInnerProcs(o: POuterContext, n: PNode) =
if n == nil: return
case n.kind
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
nil
discard
of nkSym:
if isInnerProc(n.sym, o.fn) and not containsOrIncl(o.processed, n.sym.id):
var inner = newInnerContext(n.sym)
@@ -395,8 +455,9 @@ proc searchForInnerProcs(o: POuterContext, n: PNode) =
if inner.closureParam != nil:
let ti = transformInnerProc(o, inner, body)
if ti != nil: n.sym.ast.sons[bodyPos] = ti
of nkLambdaKinds:
searchForInnerProcs(o, n.sons[namePos])
of nkLambdaKinds, nkIteratorDef:
if n.typ != nil:
searchForInnerProcs(o, n.sons[namePos])
of nkWhileStmt, nkForStmt, nkParForStmt, nkBlockStmt:
# some nodes open a new scope, so they are candidates for the insertion
# of closure creation; however for simplicity we merge closures between
@@ -417,26 +478,26 @@ proc searchForInnerProcs(o: POuterContext, n: PNode) =
# counts, not the block where it is captured!
for i in countup(0, sonsLen(n) - 1):
var it = n.sons[i]
if it.kind == nkCommentStmt: nil
if it.kind == nkCommentStmt: discard
elif it.kind == nkIdentDefs:
var L = sonsLen(it)
if it.sons[0].kind != nkSym: InternalError(it.info, "transformOuter")
if it.sons[0].kind != nkSym: internalError(it.info, "transformOuter")
#echo "set: ", it.sons[0].sym.name.s, " ", o.currentBlock == nil
IdTablePut(o.localsToEnv, it.sons[0].sym, o.currentEnv)
idTablePut(o.localsToEnv, it.sons[0].sym, o.currentEnv)
searchForInnerProcs(o, it.sons[L-1])
elif it.kind == nkVarTuple:
var L = sonsLen(it)
for j in countup(0, L-3):
#echo "set: ", it.sons[j].sym.name.s, " ", o.currentBlock == nil
IdTablePut(o.localsToEnv, it.sons[j].sym, o.currentEnv)
idTablePut(o.localsToEnv, it.sons[j].sym, o.currentEnv)
searchForInnerProcs(o, it.sons[L-1])
else:
InternalError(it.info, "transformOuter")
internalError(it.info, "transformOuter")
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
nkIteratorDef:
nkClosure, nkTypeSection:
# don't recurse here:
# XXX recurse here and setup 'up' pointers
nil
discard
else:
for i in countup(0, sonsLen(n) - 1):
searchForInnerProcs(o, n.sons[i])
@@ -451,26 +512,20 @@ proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode =
result.sons[0] = le
result.sons[1] = ri
proc addVar*(father, v: PNode) =
var vpart = newNodeI(nkIdentDefs, v.info)
addSon(vpart, v)
addSon(vpart, ast.emptyNode)
addSon(vpart, ast.emptyNode)
addSon(father, vpart)
proc newClosureCreationVar(o: POuterContext; e: PEnv): PSym =
result = newSym(skVar, getIdent(envName), o.fn, e.attachedNode.info)
incl(result.flags, sfShadowed)
result.typ = newType(tyRef, o.fn)
result.typ.rawAddSon(e.obj)
proc getClosureVar(o: POuterContext, e: PEnv): PSym =
if e.closure == nil:
result = newSym(skVar, getIdent(envName), o.fn, e.attachedNode.info)
incl(result.flags, sfShadowed)
result.typ = newType(tyRef, o.fn)
result.typ.rawAddSon(e.tup)
e.closure = result
proc getClosureVar(o: POuterContext; e: PEnv): PSym =
if e.createdVar == nil:
result = newClosureCreationVar(o, e)
e.createdVar = result
else:
result = e.closure
proc generateClosureCreation(o: POuterContext, scope: PEnv): PNode =
var env = getClosureVar(o, scope)
result = e.createdVar
proc rawClosureCreation(o: POuterContext, scope: PEnv; env: PSym): PNode =
result = newNodeI(nkStmtList, env.info)
var v = newNodeI(nkVarSection, env.info)
addVar(v, newSymNode(env))
@@ -485,23 +540,130 @@ proc generateClosureCreation(o: POuterContext, scope: PEnv): PNode =
# maybe later: (sfByCopy in local.flags)
# add ``env.param = param``
result.add(newAsgnStmt(fieldAccess, newSymNode(local), env.info))
IdNodeTablePut(o.localsToAccess, local, fieldAccess)
# it can happen that we already captured 'local' in some other environment
# then we capture by copy for now. This is not entirely correct but better
# than nothing:
let existing = idNodeTableGet(o.localsToAccess, local)
if existing.isNil:
idNodeTablePut(o.localsToAccess, local, fieldAccess)
else:
result.add(newAsgnStmt(fieldAccess, existing, env.info))
# add support for 'up' references:
for e, field in items(scope.deps):
# add ``env.up = env2``
result.add(newAsgnStmt(indirectAccess(env, field, env.info),
newSymNode(getClosureVar(o, e)), env.info))
proc generateClosureCreation(o: POuterContext, scope: PEnv): PNode =
var env = getClosureVar(o, scope)
result = rawClosureCreation(o, scope, env)
proc generateIterClosureCreation(o: POuterContext; env: PEnv;
scope: PNode): PSym =
if env.createdVarComesFromIter or env.createdVar.isNil:
# we have to create a new closure:
result = newClosureCreationVar(o, env)
let cc = rawClosureCreation(o, env, result)
var insertPoint = scope.sons[0]
if insertPoint.kind == nkEmpty: scope.sons[0] = cc
else:
assert cc.kind == nkStmtList and insertPoint.kind == nkStmtList
for x in cc: insertPoint.add(x)
if env.createdVar == nil: env.createdVar = result
else:
result = env.createdVar
env.createdVarComesFromIter = true
proc interestingIterVar(s: PSym): bool {.inline.} =
result = s.kind in {skVar, skLet, skTemp, skForVar} and sfGlobal notin s.flags
proc transformOuterProc(o: POuterContext, n: PNode): PNode
proc transformYield(c: POuterContext, n: PNode): PNode =
inc c.state.typ.n.sons[1].intVal
let stateNo = c.state.typ.n.sons[1].intVal
var stateAsgnStmt = newNodeI(nkAsgn, n.info)
stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),c.state,n.info))
stateAsgnStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
var retStmt = newNodeI(nkReturnStmt, n.info)
if n.sons[0].kind != nkEmpty:
var a = newNodeI(nkAsgn, n.sons[0].info)
var retVal = transformOuterProc(c, n.sons[0])
addSon(a, newSymNode(c.resultSym))
addSon(a, if retVal.isNil: n.sons[0] else: retVal)
retStmt.add(a)
else:
retStmt.add(emptyNode)
var stateLabelStmt = newNodeI(nkState, n.info)
stateLabelStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
result = newNodeI(nkStmtList, n.info)
result.add(stateAsgnStmt)
result.add(retStmt)
result.add(stateLabelStmt)
proc transformReturn(c: POuterContext, n: PNode): PNode =
result = newNodeI(nkStmtList, n.info)
var stateAsgnStmt = newNodeI(nkAsgn, n.info)
stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),c.state,n.info))
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
result.add(stateAsgnStmt)
result.add(n)
proc outerProcSons(o: POuterContext, n: PNode) =
for i in countup(0, sonsLen(n) - 1):
let x = transformOuterProc(o, n.sons[i])
if x != nil: n.sons[i] = x
proc liftIterSym*(n: PNode): PNode =
# transforms (iter) to (let env = newClosure[iter](); (iter, env))
let iter = n.sym
assert iter.kind == skClosureIterator
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
var env = copySym(getHiddenParam(iter))
env.kind = skLet
var v = newNodeI(nkVarSection, n.info)
addVar(v, newSymNode(env))
result.add(v)
# add 'new' statement:
result.add(newCall(getSysSym"internalNew", env))
result.add makeClosure(iter, env, n.info)
proc transformOuterProc(o: POuterContext, n: PNode): PNode =
if n == nil: return nil
case n.kind
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: nil
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: discard
of nkSym:
var local = n.sym
var closure = PEnv(IdTableGet(o.lambdasToEnv, local))
if o.isIter and interestingIterVar(local) and o.fn.id == local.owner.id:
if not containsOrIncl(o.capturedVars, local.id): addField(o.obj, local)
return indirectAccess(newSymNode(o.closureParam), local, n.info)
var closure = PEnv(idTableGet(o.lambdasToEnv, local))
if local.kind == skClosureIterator:
# consider: [i1, i2, i1] Since we merged the iterator's closure
# with the captured owning variables, we need to generate the
# closure generation code again:
if local == o.fn: message(n.info, errRecursiveDependencyX, local.name.s)
# XXX why doesn't this work?
if closure.isNil:
return liftIterSym(n)
else:
let createdVar = generateIterClosureCreation(o, closure,
closure.attachedNode)
return makeClosure(local, createdVar, n.info)
if closure != nil:
# we need to replace the lambda with '(lambda, env)':
let a = closure.closure
# we need to replace the lambda with '(lambda, env)':
let a = closure.createdVar
if a != nil:
return makeClosure(local, a, n.info)
else:
@@ -511,12 +673,12 @@ proc transformOuterProc(o: POuterContext, n: PNode): PNode =
if scope.sons[0].kind == nkEmpty:
# change the empty node to contain the closure construction:
scope.sons[0] = generateClosureCreation(o, closure)
let x = closure.closure
let x = closure.createdVar
assert x != nil
return makeClosure(local, x, n.info)
if not contains(o.capturedVars, local.id): return
var env = PEnv(IdTableGet(o.localsToEnv, local))
var env = PEnv(idTableGet(o.localsToEnv, local))
if env == nil: return
var scope = env.attachedNode
assert scope.kind == nkStmtList
@@ -526,26 +688,55 @@ proc transformOuterProc(o: POuterContext, n: PNode): PNode =
# change 'local' to 'closure.local', unless it's a 'byCopy' variable:
# if sfByCopy notin local.flags:
result = IdNodeTableGet(o.localsToAccess, local)
result = idNodeTableGet(o.localsToAccess, local)
assert result != nil, "cannot find: " & local.name.s
# else it is captured by copy and this means that 'outer' should continue
# to access the local as a local.
of nkLambdaKinds:
result = transformOuterProc(o, n.sons[namePos])
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
nkIteratorDef:
of nkLambdaKinds, nkIteratorDef:
if n.typ != nil:
result = transformOuterProc(o, n.sons[namePos])
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
nkClosure:
# don't recurse here:
nil
discard
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
let x = transformOuterProc(o, n.sons[1])
if x != nil: n.sons[1] = x
result = transformOuterConv(n)
of nkYieldStmt:
if o.isIter: result = transformYield(o, n)
else: outerProcSons(o, n)
of nkReturnStmt:
if o.isIter: result = transformReturn(o, n)
else: outerProcSons(o, n)
else:
for i in countup(0, sonsLen(n) - 1):
let x = transformOuterProc(o, n.sons[i])
if x != nil: n.sons[i] = x
outerProcSons(o, n)
proc liftIterator(c: POuterContext, body: PNode): PNode =
let iter = c.fn
result = newNodeI(nkStmtList, iter.info)
var gs = newNodeI(nkGotoState, iter.info)
gs.add(indirectAccess(newSymNode(c.closureParam), c.state, iter.info))
result.add(gs)
var state0 = newNodeI(nkState, iter.info)
state0.add(newIntNode(nkIntLit, 0))
result.add(state0)
let newBody = transformOuterProc(c, body)
if newBody != nil:
result.add(newBody)
else:
result.add(body)
var stateAsgnStmt = newNodeI(nkAsgn, iter.info)
stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),
c.state,iter.info))
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
result.add(stateAsgnStmt)
proc liftLambdas*(fn: PSym, body: PNode): PNode =
# XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs
# the transformation even when compiling to JS ...
if body.kind == nkEmpty or gCmd == cmdCompileToJS:
# ignore forward declaration:
result = body
@@ -557,16 +748,19 @@ proc liftLambdas*(fn: PSym, body: PNode): PNode =
let params = fn.typ.n
for i in 1.. <params.len:
if params.sons[i].kind != nkSym:
InternalError(params.info, "liftLambdas: strange params")
internalError(params.info, "liftLambdas: strange params")
let param = params.sons[i].sym
IdTablePut(o.localsToEnv, param, o.currentEnv)
idTablePut(o.localsToEnv, param, o.currentEnv)
# put the 'result' into the environment so it can be captured:
let ast = fn.ast
if resultPos < sonsLen(ast) and ast.sons[resultPos].kind == nkSym:
IdTablePut(o.localsToEnv, ast.sons[resultPos].sym, o.currentEnv)
idTablePut(o.localsToEnv, ast.sons[resultPos].sym, o.currentEnv)
searchForInnerProcs(o, body)
discard transformOuterProc(o, body)
result = ex
if o.isIter:
result = liftIterator(o, ex)
else:
discard transformOuterProc(o, body)
result = ex
proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode =
if body.kind == nkEmpty or gCmd == cmdCompileToJS:
@@ -581,147 +775,6 @@ proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode =
# ------------------- iterator transformation --------------------------------
discard """
iterator chain[S, T](a, b: *S->T, args: *S): T =
for x in a(args): yield x
for x in b(args): yield x
let c = chain(f, g)
for x in c: echo x
# translated to:
let c = chain( (f, newClosure(f)), (g, newClosure(g)), newClosure(chain))
"""
type
TIterContext {.final, pure.} = object
iter, closureParam, state, resultSym: PSym
capturedVars: TIntSet
tup: PType
proc newIterResult(iter: PSym): PSym =
result = iter.ast.sons[resultPos].sym
when false:
result = newSym(skResult, getIdent":result", iter, iter.info)
result.typ = iter.typ.sons[0]
incl(result.flags, sfUsed)
proc interestingIterVar(s: PSym): bool {.inline.} =
result = s.kind in {skVar, skLet, skTemp, skForVar} and sfGlobal notin s.flags
proc transfIterBody(c: var TIterContext, n: PNode): PNode =
# gather used vars for closure generation
if n == nil: return nil
case n.kind
of nkSym:
var s = n.sym
if interestingIterVar(s) and c.iter.id == s.owner.id:
if not containsOrIncl(c.capturedVars, s.id): addField(c.tup, s)
result = indirectAccess(newSymNode(c.closureParam), s, n.info)
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: nil
of nkYieldStmt:
inc c.state.typ.n.sons[1].intVal
let stateNo = c.state.typ.n.sons[1].intVal
var stateAsgnStmt = newNodeI(nkAsgn, n.info)
stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),c.state,n.info))
stateAsgnStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
var retStmt = newNodeI(nkReturnStmt, n.info)
if n.sons[0].kind != nkEmpty:
var a = newNodeI(nkAsgn, n.sons[0].info)
var retVal = transfIterBody(c, n.sons[0])
addSon(a, newSymNode(c.resultSym))
addSon(a, if retVal.isNil: n.sons[0] else: retVal)
retStmt.add(a)
else:
retStmt.add(emptyNode)
var stateLabelStmt = newNodeI(nkState, n.info)
stateLabelStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
result = newNodeI(nkStmtList, n.info)
result.add(stateAsgnStmt)
result.add(retStmt)
result.add(stateLabelStmt)
of nkReturnStmt:
result = newNodeI(nkStmtList, n.info)
var stateAsgnStmt = newNodeI(nkAsgn, n.info)
stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),c.state,n.info))
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
result.add(stateAsgnStmt)
result.add(n)
else:
for i in countup(0, sonsLen(n)-1):
let x = transfIterBody(c, n.sons[i])
if x != nil: n.sons[i] = x
proc getStateType(iter: PSym): PType =
var n = newNodeI(nkRange, iter.info)
addSon(n, newIntNode(nkIntLit, -1))
addSon(n, newIntNode(nkIntLit, 0))
result = newType(tyRange, iter)
result.n = n
rawAddSon(result, getSysType(tyInt))
proc liftIterator*(iter: PSym, body: PNode): PNode =
var c: TIterContext
c.iter = iter
c.capturedVars = initIntSet()
c.tup = newType(tyTuple, iter)
c.tup.n = newNodeI(nkRecList, iter.info)
var cp = newSym(skParam, getIdent(paramname), iter, iter.info)
incl(cp.flags, sfFromGeneric)
cp.typ = newType(tyRef, iter)
rawAddSon(cp.typ, c.tup)
c.closureParam = cp
addHiddenParam(iter, cp)
c.state = newSym(skField, getIdent(":state"), iter, iter.info)
c.state.typ = getStateType(iter)
addField(c.tup, c.state)
if iter.typ.sons[0] != nil:
c.resultSym = newIterResult(iter)
iter.ast.add(newSymNode(c.resultSym))
result = newNodeI(nkStmtList, iter.info)
var gs = newNodeI(nkGotoState, iter.info)
gs.add(indirectAccess(newSymNode(c.closureParam), c.state, iter.info))
result.add(gs)
var state0 = newNodeI(nkState, iter.info)
state0.add(newIntNode(nkIntLit, 0))
result.add(state0)
let newBody = transfIterBody(c, body)
if newBody != nil:
result.add(newBody)
else:
result.add(body)
var stateAsgnStmt = newNodeI(nkAsgn, iter.info)
stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),
c.state,iter.info))
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
result.add(stateAsgnStmt)
proc liftIterSym*(n: PNode): PNode =
# transforms (iter) to (let env = newClosure[iter](); (iter, env))
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
let iter = n.sym
assert iter.kind == skIterator
var env = copySym(getHiddenParam(iter))
env.kind = skLet
var v = newNodeI(nkVarSection, n.info)
addVar(v, newSymNode(env))
result.add(v)
# add 'new' statement:
result.add(newCall(getSysSym"internalNew", env))
result.add makeClosure(iter, env, n.info)
proc liftForLoop*(body: PNode): PNode =
# problem ahead: the iterator could be invoked indirectly, but then
# we don't know what environment to create here:
@@ -751,17 +804,17 @@ proc liftForLoop*(body: PNode): PNode =
...
"""
var L = body.len
InternalAssert body.kind == nkForStmt and body[L-2].kind in nkCallKinds
internalAssert body.kind == nkForStmt and body[L-2].kind in nkCallKinds
var call = body[L-2]
result = newNodeI(nkStmtList, body.info)
# static binding?
var env: PSym
if call[0].kind == nkSym and call[0].sym.kind == skIterator:
# createClose()
if call[0].kind == nkSym and call[0].sym.kind == skClosureIterator:
# createClosure()
let iter = call[0].sym
assert iter.kind == skIterator
assert iter.kind == skClosureIterator
env = copySym(getHiddenParam(iter))
var v = newNodeI(nkVarSection, body.info)
@@ -786,7 +839,7 @@ proc liftForLoop*(body: PNode): PNode =
addSon(vpart, body[i])
addSon(vpart, ast.emptyNode) # no explicit type
if not env.isnil:
if not env.isNil:
call.sons[0] = makeClosure(call.sons[0].sym, env, body.info)
addSon(vpart, call)
addSon(v2, vpart)

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2013 Andreas Rumpf
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -43,9 +43,10 @@ type
tkLambda, tkLet,
tkMacro, tkMethod, tkMixin, tkMod, tkNil, tkNot, tkNotin,
tkObject, tkOf, tkOr, tkOut,
tkProc, tkPtr, tkRaise, tkRef, tkReturn, tkShared, tkShl, tkShr, tkStatic,
tkProc, tkPtr, tkRaise, tkRef, tkReturn, tkShl, tkShr, tkStatic,
tkTemplate,
tkTry, tkTuple, tkType, tkVar, tkWhen, tkWhile, tkWith, tkWithout, tkXor,
tkTry, tkTuple, tkType, tkUsing,
tkVar, tkWhen, tkWhile, tkWith, tkWithout, tkXor,
tkYield, # end of keywords
tkIntLit, tkInt8Lit, tkInt16Lit, tkInt32Lit, tkInt64Lit,
tkUIntLit, tkUInt8Lit, tkUInt16Lit, tkUInt32Lit, tkUInt64Lit,
@@ -78,9 +79,10 @@ const
"macro", "method", "mixin", "mod",
"nil", "not", "notin", "object", "of", "or",
"out", "proc", "ptr", "raise", "ref", "return",
"shared", "shl", "shr", "static",
"shl", "shr", "static",
"template",
"try", "tuple", "type", "var", "when", "while", "with", "without", "xor",
"try", "tuple", "type", "using",
"var", "when", "while", "with", "without", "xor",
"yield",
"tkIntLit", "tkInt8Lit", "tkInt16Lit", "tkInt32Lit", "tkInt64Lit",
"tkUIntLit", "tkUInt8Lit", "tkUInt16Lit", "tkUInt32Lit", "tkUInt64Lit",
@@ -99,6 +101,7 @@ type
base10, # base10 is listed as the first element,
# so that it is the correct default value
base2, base8, base16
TToken* = object # a Nimrod token
tokType*: TTokType # the type of the token
indent*: int # the indentation; != -1 if the token has been
@@ -108,15 +111,20 @@ type
fNumber*: BiggestFloat # the parsed floating point literal
base*: TNumericalBase # the numerical base; only valid for int
# or float literals
strongSpaceA*: int8 # leading spaces of an operator
strongSpaceB*: int8 # trailing spaces of an operator
literal*: string # the parsed (string) literal; and
# documentation comments are here too
line*, col*: int
TLexer* = object of TBaseLexer
fileIdx*: int32
indentAhead*: int # if > 0 an indendation has already been read
# this is needed because scanning comments
# needs so much look-ahead
currLineIndent*: int
strongSpaces*: bool
var gLinesCompiled*: int # all lines that have been compiled
@@ -124,14 +132,16 @@ proc isKeyword*(kind: TTokType): bool
proc openLexer*(lex: var TLexer, fileidx: int32, inputstream: PLLStream)
proc rawGetTok*(L: var TLexer, tok: var TToken)
# reads in the next token into tok and skips it
proc getColumn*(L: TLexer): int
proc getLineInfo*(L: TLexer): TLineInfo
proc getLineInfo*(L: TLexer, tok: TToken): TLineInfo {.inline.} =
newLineInfo(L.fileIdx, tok.line, tok.col)
proc closeLexer*(lex: var TLexer)
proc PrintTok*(tok: TToken)
proc printTok*(tok: TToken)
proc tokToStr*(tok: TToken): string
proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream) =
OpenLexer(lex, filename.fileInfoIdx, inputStream)
openLexer(lex, filename.fileInfoIdx, inputstream)
proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "")
@@ -155,19 +165,20 @@ proc tokToStr*(tok: TToken): string =
of tkFloatLit..tkFloat64Lit: result = $tok.fNumber
of tkInvalid, tkStrLit..tkCharLit, tkComment: result = tok.literal
of tkParLe..tkColon, tkEof, tkAccent:
result = tokTypeToStr[tok.tokType]
result = TokTypeToStr[tok.tokType]
else:
if tok.ident != nil:
result = tok.ident.s
else:
InternalError("tokToStr")
internalError("tokToStr")
result = ""
proc prettyTok*(tok: TToken): string =
if IsKeyword(tok.tokType): result = "keyword " & tok.ident.s
if isKeyword(tok.tokType): result = "keyword " & tok.ident.s
else: result = tokToStr(tok)
proc PrintTok*(tok: TToken) =
proc printTok*(tok: TToken) =
write(stdout, tok.line, ":", tok.col, "\t")
write(stdout, TokTypeToStr[tok.tokType])
write(stdout, " ")
writeln(stdout, tokToStr(tok))
@@ -175,18 +186,20 @@ proc PrintTok*(tok: TToken) =
var dummyIdent: PIdent
proc initToken*(L: var TToken) =
L.TokType = tkInvalid
L.tokType = tkInvalid
L.iNumber = 0
L.Indent = 0
L.indent = 0
L.strongSpaceA = 0
L.literal = ""
L.fNumber = 0.0
L.base = base10
L.ident = dummyIdent
proc fillToken(L: var TToken) =
L.TokType = tkInvalid
L.tokType = tkInvalid
L.iNumber = 0
L.Indent = 0
L.indent = 0
L.strongSpaceA = 0
setLen(L.literal, 0)
L.fNumber = 0.0
L.base = base10
@@ -194,26 +207,27 @@ proc fillToken(L: var TToken) =
proc openLexer(lex: var TLexer, fileIdx: int32, inputstream: PLLStream) =
openBaseLexer(lex, inputstream)
lex.fileIdx = fileIdx
lex.fileIdx = fileidx
lex.indentAhead = - 1
inc(lex.Linenumber, inputstream.lineOffset)
lex.currLineIndent = 0
inc(lex.lineNumber, inputstream.lineOffset)
proc closeLexer(lex: var TLexer) =
inc(gLinesCompiled, lex.LineNumber)
inc(gLinesCompiled, lex.lineNumber)
closeBaseLexer(lex)
proc getColumn(L: TLexer): int =
result = getColNumber(L, L.bufPos)
result = getColNumber(L, L.bufpos)
proc getLineInfo(L: TLexer): TLineInfo =
result = newLineInfo(L.fileIdx, L.linenumber, getColNumber(L, L.bufpos))
result = newLineInfo(L.fileIdx, L.lineNumber, getColNumber(L, L.bufpos))
proc lexMessage(L: TLexer, msg: TMsgKind, arg = "") =
msgs.Message(getLineInfo(L), msg, arg)
msgs.message(getLineInfo(L), msg, arg)
proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
var info = newLineInfo(L.fileIdx, L.linenumber, pos - L.lineStart)
msgs.Message(info, msg, arg)
var info = newLineInfo(L.fileIdx, L.lineNumber, pos - L.lineStart)
msgs.message(info, msg, arg)
proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
var pos = L.bufpos # use registers for pos, buf
@@ -221,7 +235,7 @@ proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
while true:
if buf[pos] in chars:
add(tok.literal, buf[pos])
Inc(pos)
inc(pos)
else:
break
if buf[pos] == '_':
@@ -229,46 +243,47 @@ proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
lexMessage(L, errInvalidToken, "_")
break
add(tok.literal, '_')
Inc(pos)
L.bufPos = pos
inc(pos)
L.bufpos = pos
proc matchTwoChars(L: TLexer, first: Char, second: TCharSet): bool =
result = (L.buf[L.bufpos] == first) and (L.buf[L.bufpos + 1] in Second)
proc matchTwoChars(L: TLexer, first: char, second: TCharSet): bool =
result = (L.buf[L.bufpos] == first) and (L.buf[L.bufpos + 1] in second)
proc isFloatLiteral(s: string): bool =
for i in countup(0, len(s) + 0 - 1):
if s[i] in {'.', 'e', 'E'}:
proc isFloatLiteral(s: string): bool =
for i in countup(0, len(s) - 1):
if s[i] in {'.', 'e', 'E'}:
return true
result = false
proc GetNumber(L: var TLexer): TToken =
proc getNumber(L: var TLexer): TToken =
var
pos, endpos: int
xi: biggestInt
xi: BiggestInt
# get the base:
result.tokType = tkIntLit # int literal until we know better
result.literal = ""
result.base = base10 # BUGFIX
pos = L.bufpos # make sure the literal is correct for error messages:
var eallowed = false
if L.buf[pos] == '0' and L.buf[pos+1] in {'X', 'x'}:
matchUnderscoreChars(L, result, {'A'..'F', 'a'..'f', '0'..'9', 'X', 'x'})
else:
matchUnderscoreChars(L, result, {'0'..'9', 'b', 'B', 'o', 'c', 'C'})
eallowed = true
if (L.buf[L.bufpos] == '.') and (L.buf[L.bufpos + 1] in {'0'..'9'}):
add(result.literal, '.')
inc(L.bufpos)
#matchUnderscoreChars(L, result, ['A'..'Z', 'a'..'z', '0'..'9'])
inc(L.bufpos)
matchUnderscoreChars(L, result, {'0'..'9'})
if L.buf[L.bufpos] in {'e', 'E'}:
add(result.literal, 'e')
eallowed = true
if eallowed and L.buf[L.bufpos] in {'e', 'E'}:
add(result.literal, 'e')
inc(L.bufpos)
if L.buf[L.bufpos] in {'+', '-'}:
add(result.literal, L.buf[L.bufpos])
inc(L.bufpos)
if L.buf[L.bufpos] in {'+', '-'}:
add(result.literal, L.buf[L.bufpos])
inc(L.bufpos)
matchUnderscoreChars(L, result, {'0'..'9'})
matchUnderscoreChars(L, result, {'0'..'9'})
endpos = L.bufpos
if L.buf[endpos] in {'\'', 'f', 'F', 'i', 'I', 'u', 'U'}:
#matchUnderscoreChars(L, result, ['''', 'f', 'F', 'i', 'I', '0'..'9']);
if L.buf[endpos] == '\'': inc(endpos)
L.bufpos = pos # restore position
case L.buf[endpos]
@@ -384,32 +399,32 @@ proc GetNumber(L: var TLexer): TToken =
xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('A') + 10)
inc(pos)
else: break
else: InternalError(getLineInfo(L), "getNumber")
else: internalError(getLineInfo(L), "getNumber")
case result.tokType
of tkIntLit, tkInt64Lit: result.iNumber = xi
of tkInt8Lit: result.iNumber = biggestInt(int8(toU8(int(xi))))
of tkInt16Lit: result.iNumber = biggestInt(toU16(int(xi)))
of tkInt32Lit: result.iNumber = biggestInt(toU32(xi))
of tkInt8Lit: result.iNumber = BiggestInt(int8(toU8(int(xi))))
of tkInt16Lit: result.iNumber = BiggestInt(toU16(int(xi)))
of tkInt32Lit: result.iNumber = BiggestInt(toU32(xi))
of tkUIntLit, tkUInt64Lit: result.iNumber = xi
of tkUInt8Lit: result.iNumber = biggestInt(int8(toU8(int(xi))))
of tkUInt16Lit: result.iNumber = biggestInt(toU16(int(xi)))
of tkUInt32Lit: result.iNumber = biggestInt(toU32(xi))
of tkUInt8Lit: result.iNumber = BiggestInt(int8(toU8(int(xi))))
of tkUInt16Lit: result.iNumber = BiggestInt(toU16(int(xi)))
of tkUInt32Lit: result.iNumber = BiggestInt(toU32(xi))
of tkFloat32Lit:
result.fNumber = (cast[PFloat32](addr(xi)))[]
# note: this code is endian neutral!
# XXX: Test this on big endian machine!
of tkFloat64Lit: result.fNumber = (cast[PFloat64](addr(xi)))[]
else: InternalError(getLineInfo(L), "getNumber")
else: internalError(getLineInfo(L), "getNumber")
elif isFloatLiteral(result.literal) or (result.tokType == tkFloat32Lit) or
(result.tokType == tkFloat64Lit):
result.fnumber = parseFloat(result.literal)
result.fNumber = parseFloat(result.literal)
if result.tokType == tkIntLit: result.tokType = tkFloatLit
else:
result.iNumber = ParseBiggestInt(result.literal)
if (result.iNumber < low(int32)) or (result.iNumber > high(int32)):
if result.tokType == tkIntLit:
else:
result.iNumber = parseBiggestInt(result.literal)
if (result.iNumber < low(int32)) or (result.iNumber > high(int32)):
if result.tokType == tkIntLit:
result.tokType = tkInt64Lit
elif result.tokType != tkInt64Lit:
elif result.tokType in {tkInt8Lit, tkInt16Lit}:
lexMessage(L, errInvalidNumber, result.literal)
except EInvalidValue:
lexMessage(L, errInvalidNumber, result.literal)
@@ -428,7 +443,7 @@ proc handleHexChar(L: var TLexer, xi: var int) =
of 'A'..'F':
xi = (xi shl 4) or (ord(L.buf[L.bufpos]) - ord('A') + 10)
inc(L.bufpos)
else: nil
else: discard
proc handleDecChars(L: var TLexer, xi: var int) =
while L.buf[L.bufpos] in {'0'..'9'}:
@@ -439,51 +454,51 @@ proc getEscapedChar(L: var TLexer, tok: var TToken) =
inc(L.bufpos) # skip '\'
case L.buf[L.bufpos]
of 'n', 'N':
if tok.toktype == tkCharLit: lexMessage(L, errNnotAllowedInCharacter)
if tok.tokType == tkCharLit: lexMessage(L, errNnotAllowedInCharacter)
add(tok.literal, tnl)
Inc(L.bufpos)
inc(L.bufpos)
of 'r', 'R', 'c', 'C':
add(tok.literal, CR)
Inc(L.bufpos)
inc(L.bufpos)
of 'l', 'L':
add(tok.literal, LF)
Inc(L.bufpos)
inc(L.bufpos)
of 'f', 'F':
add(tok.literal, FF)
inc(L.bufpos)
of 'e', 'E':
add(tok.literal, ESC)
Inc(L.bufpos)
inc(L.bufpos)
of 'a', 'A':
add(tok.literal, BEL)
Inc(L.bufpos)
inc(L.bufpos)
of 'b', 'B':
add(tok.literal, BACKSPACE)
Inc(L.bufpos)
inc(L.bufpos)
of 'v', 'V':
add(tok.literal, VT)
Inc(L.bufpos)
inc(L.bufpos)
of 't', 'T':
add(tok.literal, Tabulator)
Inc(L.bufpos)
inc(L.bufpos)
of '\'', '\"':
add(tok.literal, L.buf[L.bufpos])
Inc(L.bufpos)
inc(L.bufpos)
of '\\':
add(tok.literal, '\\')
Inc(L.bufpos)
inc(L.bufpos)
of 'x', 'X':
inc(L.bufpos)
var xi = 0
handleHexChar(L, xi)
handleHexChar(L, xi)
add(tok.literal, Chr(xi))
add(tok.literal, chr(xi))
of '0'..'9':
if matchTwoChars(L, '0', {'0'..'9'}):
lexMessage(L, warnOctalEscape)
var xi = 0
handleDecChars(L, xi)
if (xi <= 255): add(tok.literal, Chr(xi))
if (xi <= 255): add(tok.literal, chr(xi))
else: lexMessage(L, errInvalidCharacterConstant)
else: lexMessage(L, errInvalidCharacterConstant)
@@ -493,7 +508,7 @@ proc newString(s: cstring, len: int): string =
for i in 0 .. <len:
result[i] = s[i]
proc HandleCRLF(L: var TLexer, pos: int): int =
proc handleCRLF(L: var TLexer, pos: int): int =
template registerLine =
let col = L.getColNumber(pos)
@@ -508,21 +523,21 @@ proc HandleCRLF(L: var TLexer, pos: int): int =
case L.buf[pos]
of CR:
registerLine()
result = nimlexbase.HandleCR(L, pos)
result = nimlexbase.handleCR(L, pos)
of LF:
registerLine()
result = nimlexbase.HandleLF(L, pos)
result = nimlexbase.handleLF(L, pos)
else: result = pos
proc getString(L: var TLexer, tok: var TToken, rawMode: bool) =
var pos = L.bufPos + 1 # skip "
var pos = L.bufpos + 1 # skip "
var buf = L.buf # put `buf` in a register
var line = L.linenumber # save linenumber for better error message
var line = L.lineNumber # save linenumber for better error message
if buf[pos] == '\"' and buf[pos+1] == '\"':
tok.tokType = tkTripleStrLit # long string literal:
inc(pos, 2) # skip ""
# skip leading newline:
pos = HandleCRLF(L, pos)
pos = handleCRLF(L, pos)
buf = L.buf
while true:
case buf[pos]
@@ -532,20 +547,20 @@ proc getString(L: var TLexer, tok: var TToken, rawMode: bool) =
L.bufpos = pos + 3 # skip the three """
break
add(tok.literal, '\"')
Inc(pos)
inc(pos)
of CR, LF:
pos = HandleCRLF(L, pos)
pos = handleCRLF(L, pos)
buf = L.buf
add(tok.literal, tnl)
of nimlexbase.EndOfFile:
var line2 = L.linenumber
L.LineNumber = line
var line2 = L.lineNumber
L.lineNumber = line
lexMessagePos(L, errClosingTripleQuoteExpected, L.lineStart)
L.LineNumber = line2
L.lineNumber = line2
break
else:
add(tok.literal, buf[pos])
Inc(pos)
inc(pos)
else:
# ordinary string literal
if rawMode: tok.tokType = tkRStrLit
@@ -563,23 +578,23 @@ proc getString(L: var TLexer, tok: var TToken, rawMode: bool) =
lexMessage(L, errClosingQuoteExpected)
break
elif (c == '\\') and not rawMode:
L.bufPos = pos
L.bufpos = pos
getEscapedChar(L, tok)
pos = L.bufPos
pos = L.bufpos
else:
add(tok.literal, c)
Inc(pos)
inc(pos)
L.bufpos = pos
proc getCharacter(L: var TLexer, tok: var TToken) =
Inc(L.bufpos) # skip '
inc(L.bufpos) # skip '
var c = L.buf[L.bufpos]
case c
of '\0'..Pred(' '), '\'': lexMessage(L, errInvalidCharacterConstant)
of '\0'..pred(' '), '\'': lexMessage(L, errInvalidCharacterConstant)
of '\\': getEscapedChar(L, tok)
else:
tok.literal = $c
Inc(L.bufpos)
inc(L.bufpos)
if L.buf[L.bufpos] != '\'': lexMessage(L, errMissingFinalQuote)
inc(L.bufpos) # skip '
@@ -600,7 +615,7 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
lexMessage(L, errInvalidToken, "_")
break
else: break
Inc(pos)
inc(pos)
h = !$h
tok.ident = getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h)
L.bufpos = pos
@@ -625,9 +640,17 @@ proc getOperator(L: var TLexer, tok: var TToken) =
while true:
var c = buf[pos]
if c notin OpChars: break
h = h !& Ord(c)
Inc(pos)
h = h !& ord(c)
inc(pos)
endOperator(L, tok, pos, h)
# advance pos but don't store it in L.bufpos so the next token (which might
# be an operator too) gets the preceeding spaces:
tok.strongSpaceB = 0
while buf[pos] == ' ':
inc pos
inc tok.strongSpaceB
if buf[pos] in {CR, LF, nimlexbase.EndOfFile}:
tok.strongSpaceB = -1
proc scanComment(L: var TLexer, tok: var TToken) =
var pos = L.bufpos
@@ -671,22 +694,26 @@ proc scanComment(L: var TLexer, tok: var TToken) =
proc skip(L: var TLexer, tok: var TToken) =
var pos = L.bufpos
var buf = L.buf
tok.strongSpaceA = 0
while true:
case buf[pos]
of ' ':
Inc(pos)
inc(pos)
inc(tok.strongSpaceA)
of Tabulator:
lexMessagePos(L, errTabulatorsAreNotAllowed, pos)
inc(pos)
of CR, LF:
pos = HandleCRLF(L, pos)
pos = handleCRLF(L, pos)
buf = L.buf
var indent = 0
while buf[pos] == ' ':
Inc(pos)
Inc(indent)
inc(pos)
inc(indent)
tok.strongSpaceA = 0
if buf[pos] > ' ':
tok.indent = indent
L.currLineIndent = indent
break
else:
break # EndOfFile also leaves the loop
@@ -696,11 +723,14 @@ proc rawGetTok(L: var TLexer, tok: var TToken) =
fillToken(tok)
if L.indentAhead >= 0:
tok.indent = L.indentAhead
L.currLineIndent = L.indentAhead
L.indentAhead = -1
else:
tok.indent = -1
skip(L, tok)
var c = L.buf[L.bufpos]
tok.line = L.lineNumber
tok.col = getColNumber(L, L.bufpos)
if c in SymStartChars - {'r', 'R', 'l'}:
getSymbol(L, tok)
else:
@@ -716,8 +746,8 @@ proc rawGetTok(L: var TLexer, tok: var TToken) =
else:
getOperator(L, tok)
of ',':
tok.toktype = tkComma
Inc(L.bufpos)
tok.tokType = tkComma
inc(L.bufpos)
of 'l':
# if we parsed exactly one character and its a small L (l), this
# is treated as a warning because it may be confused with the number 1
@@ -725,59 +755,59 @@ proc rawGetTok(L: var TLexer, tok: var TToken) =
lexMessage(L, warnSmallLshouldNotBeUsed)
getSymbol(L, tok)
of 'r', 'R':
if L.buf[L.bufPos + 1] == '\"':
Inc(L.bufPos)
if L.buf[L.bufpos + 1] == '\"':
inc(L.bufpos)
getString(L, tok, true)
else:
getSymbol(L, tok)
of '(':
Inc(L.bufpos)
if L.buf[L.bufPos] == '.' and L.buf[L.bufPos+1] != '.':
tok.toktype = tkParDotLe
Inc(L.bufpos)
inc(L.bufpos)
if L.buf[L.bufpos] == '.' and L.buf[L.bufpos+1] != '.':
tok.tokType = tkParDotLe
inc(L.bufpos)
else:
tok.toktype = tkParLe
tok.tokType = tkParLe
of ')':
tok.toktype = tkParRi
Inc(L.bufpos)
tok.tokType = tkParRi
inc(L.bufpos)
of '[':
Inc(L.bufpos)
if L.buf[L.bufPos] == '.' and L.buf[L.bufPos+1] != '.':
tok.toktype = tkBracketDotLe
Inc(L.bufpos)
inc(L.bufpos)
if L.buf[L.bufpos] == '.' and L.buf[L.bufpos+1] != '.':
tok.tokType = tkBracketDotLe
inc(L.bufpos)
else:
tok.toktype = tkBracketLe
tok.tokType = tkBracketLe
of ']':
tok.toktype = tkBracketRi
Inc(L.bufpos)
tok.tokType = tkBracketRi
inc(L.bufpos)
of '.':
if L.buf[L.bufPos+1] == ']':
if L.buf[L.bufpos+1] == ']':
tok.tokType = tkBracketDotRi
Inc(L.bufpos, 2)
elif L.buf[L.bufPos+1] == '}':
inc(L.bufpos, 2)
elif L.buf[L.bufpos+1] == '}':
tok.tokType = tkCurlyDotRi
Inc(L.bufpos, 2)
elif L.buf[L.bufPos+1] == ')':
inc(L.bufpos, 2)
elif L.buf[L.bufpos+1] == ')':
tok.tokType = tkParDotRi
Inc(L.bufpos, 2)
inc(L.bufpos, 2)
else:
getOperator(L, tok)
of '{':
Inc(L.bufpos)
if L.buf[L.bufPos] == '.' and L.buf[L.bufPos+1] != '.':
tok.toktype = tkCurlyDotLe
Inc(L.bufpos)
inc(L.bufpos)
if L.buf[L.bufpos] == '.' and L.buf[L.bufpos+1] != '.':
tok.tokType = tkCurlyDotLe
inc(L.bufpos)
else:
tok.toktype = tkCurlyLe
tok.tokType = tkCurlyLe
of '}':
tok.toktype = tkCurlyRi
Inc(L.bufpos)
tok.tokType = tkCurlyRi
inc(L.bufpos)
of ';':
tok.toktype = tkSemiColon
Inc(L.bufpos)
tok.tokType = tkSemiColon
inc(L.bufpos)
of '`':
tok.tokType = tkAccent
Inc(L.bufpos)
inc(L.bufpos)
of '\"':
# check for extended raw string literal:
var rawMode = L.bufpos > 0 and L.buf[L.bufpos-1] in SymChars
@@ -796,12 +826,12 @@ proc rawGetTok(L: var TLexer, tok: var TToken) =
if c in OpChars:
getOperator(L, tok)
elif c == nimlexbase.EndOfFile:
tok.toktype = tkEof
tok.tokType = tkEof
tok.indent = 0
else:
tok.literal = $c
tok.tokType = tkInvalid
lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
Inc(L.bufpos)
inc(L.bufpos)
dummyIdent = getIdent("")

View File

@@ -20,17 +20,17 @@ type
PStrEntry* = ref TStrEntry
TLinkedList* = object # for the "find" operation:
head*, tail*: PListEntry
Counter*: int
counter*: int
TCompareProc* = proc (entry: PListEntry, closure: Pointer): bool {.nimcall.}
TCompareProc* = proc (entry: PListEntry, closure: pointer): bool {.nimcall.}
proc InitLinkedList*(list: var TLinkedList) =
list.Counter = 0
proc initLinkedList*(list: var TLinkedList) =
list.counter = 0
list.head = nil
list.tail = nil
proc Append*(list: var TLinkedList, entry: PListEntry) =
Inc(list.counter)
proc append*(list: var TLinkedList, entry: PListEntry) =
inc(list.counter)
entry.next = nil
entry.prev = list.tail
if list.tail != nil:
@@ -39,7 +39,7 @@ proc Append*(list: var TLinkedList, entry: PListEntry) =
list.tail = entry
if list.head == nil: list.head = entry
proc Contains*(list: TLinkedList, data: string): bool =
proc contains*(list: TLinkedList, data: string): bool =
var it = list.head
while it != nil:
if PStrEntry(it).data == data:
@@ -50,15 +50,15 @@ proc newStrEntry(data: string): PStrEntry =
new(result)
result.data = data
proc AppendStr*(list: var TLinkedList, data: string) =
proc appendStr*(list: var TLinkedList, data: string) =
append(list, newStrEntry(data))
proc IncludeStr*(list: var TLinkedList, data: string): bool =
if Contains(list, data): return true
AppendStr(list, data) # else: add to list
proc includeStr*(list: var TLinkedList, data: string): bool =
if contains(list, data): return true
appendStr(list, data) # else: add to list
proc Prepend*(list: var TLinkedList, entry: PListEntry) =
Inc(list.counter)
proc prepend*(list: var TLinkedList, entry: PListEntry) =
inc(list.counter)
entry.prev = nil
entry.next = list.head
if list.head != nil:
@@ -67,22 +67,22 @@ proc Prepend*(list: var TLinkedList, entry: PListEntry) =
list.head = entry
if list.tail == nil: list.tail = entry
proc PrependStr*(list: var TLinkedList, data: string) =
proc prependStr*(list: var TLinkedList, data: string) =
prepend(list, newStrEntry(data))
proc InsertBefore*(list: var TLinkedList, pos, entry: PListEntry) =
proc insertBefore*(list: var TLinkedList, pos, entry: PListEntry) =
assert(pos != nil)
if pos == list.head:
prepend(list, entry)
else:
Inc(list.counter)
inc(list.counter)
entry.next = pos
entry.prev = pos.prev
if pos.prev != nil: pos.prev.next = entry
pos.prev = entry
proc Remove*(list: var TLinkedList, entry: PListEntry) =
Dec(list.counter)
proc remove*(list: var TLinkedList, entry: PListEntry) =
dec(list.counter)
if entry == list.tail:
list.tail = entry.prev
if entry == list.head:
@@ -91,22 +91,26 @@ proc Remove*(list: var TLinkedList, entry: PListEntry) =
if entry.prev != nil: entry.prev.next = entry.next
proc bringToFront*(list: var TLinkedList, entry: PListEntry) =
if entry == list.head: return
if entry == list.tail: list.tail = entry.prev
if entry.next != nil: entry.next.prev = entry.prev
if entry.prev != nil: entry.prev.next = entry.next
entry.prev = nil
entry.next = list.head
list.head = entry
when true:
list.remove entry
list.prepend entry
else:
if entry == list.head: return
if entry == list.tail: list.tail = entry.prev
if entry.next != nil: entry.next.prev = entry.prev
if entry.prev != nil: entry.prev.next = entry.next
entry.prev = nil
entry.next = list.head
list.head = entry
proc ExcludeStr*(list: var TLinkedList, data: string) =
proc excludeStr*(list: var TLinkedList, data: string) =
var it = list.head
while it != nil:
let nxt = it.next
if PStrEntry(it).data == data: remove(list, it)
it = nxt
proc Find*(list: TLinkedList, fn: TCompareProc, closure: Pointer): PListEntry =
proc find*(list: TLinkedList, fn: TCompareProc, closure: pointer): PListEntry =
result = list.head
while result != nil:
if fn(result, closure): return

View File

@@ -23,63 +23,63 @@ type
llsStdIn # stream encapsulates stdin
TLLStream* = object of TObject
kind*: TLLStreamKind # accessible for low-level access (lexbase uses this)
f*: tfile
f*: TFile
s*: string
rd*, wr*: int # for string streams
lineOffset*: int # for fake stdin line numbers
PLLStream* = ref TLLStream
proc LLStreamOpen*(data: string): PLLStream
proc LLStreamOpen*(f: var tfile): PLLStream
proc LLStreamOpen*(filename: string, mode: TFileMode): PLLStream
proc LLStreamOpen*(): PLLStream
proc LLStreamOpenStdIn*(): PLLStream
proc LLStreamClose*(s: PLLStream)
proc LLStreamRead*(s: PLLStream, buf: pointer, bufLen: int): int
proc LLStreamReadLine*(s: PLLStream, line: var string): bool
proc LLStreamReadAll*(s: PLLStream): string
proc LLStreamWrite*(s: PLLStream, data: string)
proc LLStreamWrite*(s: PLLStream, data: Char)
proc LLStreamWrite*(s: PLLStream, buf: pointer, buflen: int)
proc LLStreamWriteln*(s: PLLStream, data: string)
proc llStreamOpen*(data: string): PLLStream
proc llStreamOpen*(f: var TFile): PLLStream
proc llStreamOpen*(filename: string, mode: TFileMode): PLLStream
proc llStreamOpen*(): PLLStream
proc llStreamOpenStdIn*(): PLLStream
proc llStreamClose*(s: PLLStream)
proc llStreamRead*(s: PLLStream, buf: pointer, bufLen: int): int
proc llStreamReadLine*(s: PLLStream, line: var string): bool
proc llStreamReadAll*(s: PLLStream): string
proc llStreamWrite*(s: PLLStream, data: string)
proc llStreamWrite*(s: PLLStream, data: char)
proc llStreamWrite*(s: PLLStream, buf: pointer, buflen: int)
proc llStreamWriteln*(s: PLLStream, data: string)
# implementation
proc LLStreamOpen(data: string): PLLStream =
proc llStreamOpen(data: string): PLLStream =
new(result)
result.s = data
result.kind = llsString
proc LLStreamOpen(f: var tfile): PLLStream =
proc llStreamOpen(f: var TFile): PLLStream =
new(result)
result.f = f
result.kind = llsFile
proc LLStreamOpen(filename: string, mode: TFileMode): PLLStream =
proc llStreamOpen(filename: string, mode: TFileMode): PLLStream =
new(result)
result.kind = llsFile
if not open(result.f, filename, mode): result = nil
proc LLStreamOpen(): PLLStream =
proc llStreamOpen(): PLLStream =
new(result)
result.kind = llsNone
proc LLStreamOpenStdIn(): PLLStream =
proc llStreamOpenStdIn(): PLLStream =
new(result)
result.kind = llsStdIn
result.s = ""
result.lineOffset = -1
proc LLStreamClose(s: PLLStream) =
proc llStreamClose(s: PLLStream) =
case s.kind
of llsNone, llsString, llsStdIn:
nil
discard
of llsFile:
close(s.f)
when not defined(ReadLineFromStdin):
when not defined(readLineFromStdin):
# fallback implementation:
proc ReadLineFromStdin(prompt: string, line: var string): bool =
proc readLineFromStdin(prompt: string, line: var string): bool =
stdout.write(prompt)
result = readLine(stdin, line)
@@ -99,7 +99,7 @@ proc endsWithOpr*(x: string): bool =
result = x.endsWith(LineContinuationOprs)
proc continueLine(line: string, inTripleString: bool): bool {.inline.} =
result = inTriplestring or
result = inTripleString or
line[0] == ' ' or
line.endsWith(LineContinuationOprs+AdditionalLineContinuationOprs)
@@ -111,12 +111,12 @@ proc countTriples(s: string): int =
inc i, 2
inc i
proc LLreadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int =
proc llReadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int =
s.s = ""
s.rd = 0
var line = newStringOfCap(120)
var triples = 0
while ReadLineFromStdin(if s.s.len == 0: ">>> " else: "... ", line):
while readLineFromStdin(if s.s.len == 0: ">>> " else: "... ", line):
add(s.s, line)
add(s.s, "\n")
inc triples, countTriples(line)
@@ -127,7 +127,7 @@ proc LLreadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int =
copyMem(buf, addr(s.s[s.rd]), result)
inc(s.rd, result)
proc LLStreamRead(s: PLLStream, buf: pointer, bufLen: int): int =
proc llStreamRead(s: PLLStream, buf: pointer, bufLen: int): int =
case s.kind
of llsNone:
result = 0
@@ -139,9 +139,9 @@ proc LLStreamRead(s: PLLStream, buf: pointer, bufLen: int): int =
of llsFile:
result = readBuffer(s.f, buf, bufLen)
of llsStdIn:
result = LLreadFromStdin(s, buf, bufLen)
result = llReadFromStdin(s, buf, bufLen)
proc LLStreamReadLine(s: PLLStream, line: var string): bool =
proc llStreamReadLine(s: PLLStream, line: var string): bool =
setLen(line, 0)
case s.kind
of llsNone:
@@ -165,25 +165,25 @@ proc LLStreamReadLine(s: PLLStream, line: var string): bool =
of llsStdIn:
result = readLine(stdin, line)
proc LLStreamWrite(s: PLLStream, data: string) =
proc llStreamWrite(s: PLLStream, data: string) =
case s.kind
of llsNone, llsStdIn:
nil
discard
of llsString:
add(s.s, data)
inc(s.wr, len(data))
of llsFile:
write(s.f, data)
proc LLStreamWriteln(s: PLLStream, data: string) =
LLStreamWrite(s, data)
LLStreamWrite(s, "\n")
proc llStreamWriteln(s: PLLStream, data: string) =
llStreamWrite(s, data)
llStreamWrite(s, "\n")
proc LLStreamWrite(s: PLLStream, data: Char) =
proc llStreamWrite(s: PLLStream, data: char) =
var c: char
case s.kind
of llsNone, llsStdIn:
nil
discard
of llsString:
add(s.s, data)
inc(s.wr)
@@ -191,22 +191,21 @@ proc LLStreamWrite(s: PLLStream, data: Char) =
c = data
discard writeBuffer(s.f, addr(c), sizeof(c))
proc LLStreamWrite(s: PLLStream, buf: pointer, buflen: int) =
proc llStreamWrite(s: PLLStream, buf: pointer, buflen: int) =
case s.kind
of llsNone, llsStdIn:
nil
discard
of llsString:
if bufLen > 0:
setlen(s.s, len(s.s) + bufLen)
copyMem(addr(s.s[0 + s.wr]), buf, bufLen)
inc(s.wr, bufLen)
if buflen > 0:
setLen(s.s, len(s.s) + buflen)
copyMem(addr(s.s[0 + s.wr]), buf, buflen)
inc(s.wr, buflen)
of llsFile:
discard writeBuffer(s.f, buf, bufLen)
discard writeBuffer(s.f, buf, buflen)
proc LLStreamReadAll(s: PLLStream): string =
proc llStreamReadAll(s: PLLStream): string =
const
bufSize = 2048
var bytes, i: int
case s.kind
of llsNone, llsStdIn:
result = ""
@@ -216,10 +215,10 @@ proc LLStreamReadAll(s: PLLStream): string =
s.rd = len(s.s)
of llsFile:
result = newString(bufSize)
bytes = readBuffer(s.f, addr(result[0]), bufSize)
i = bytes
var bytes = readBuffer(s.f, addr(result[0]), bufSize)
var i = bytes
while bytes == bufSize:
setlen(result, i + bufSize)
setLen(result, i + bufSize)
bytes = readBuffer(s.f, addr(result[i + 0]), bufSize)
inc(i, bytes)
setlen(result, i)
setLen(result, i)

View File

@@ -21,7 +21,7 @@ proc considerAcc*(n: PNode): PIdent =
of nkSym: result = n.sym.name
of nkAccQuoted:
case n.len
of 0: GlobalError(n.info, errIdentifierExpected, renderTree(n))
of 0: globalError(n.info, errIdentifierExpected, renderTree(n))
of 1: result = considerAcc(n.sons[0])
else:
var id = ""
@@ -30,16 +30,17 @@ proc considerAcc*(n: PNode): PIdent =
case x.kind
of nkIdent: id.add(x.ident.s)
of nkSym: id.add(x.sym.name.s)
else: GlobalError(n.info, errIdentifierExpected, renderTree(n))
else: globalError(n.info, errIdentifierExpected, renderTree(n))
result = getIdent(id)
of nkOpenSymChoice, nkClosedSymChoice: result = n.sons[0].sym.name
else:
GlobalError(n.info, errIdentifierExpected, renderTree(n))
globalError(n.info, errIdentifierExpected, renderTree(n))
template addSym*(scope: PScope, s: PSym) =
StrTableAdd(scope.symbols, s)
strTableAdd(scope.symbols, s)
proc addUniqueSym*(scope: PScope, s: PSym): TResult =
if StrTableIncl(scope.symbols, s):
if strTableIncl(scope.symbols, s):
result = Failure
else:
result = Success
@@ -64,17 +65,17 @@ iterator walkScopes*(scope: PScope): PScope =
current = current.parent
proc localSearchInScope*(c: PContext, s: PIdent): PSym =
result = StrTableGet(c.currentScope.symbols, s)
result = strTableGet(c.currentScope.symbols, s)
proc searchInScopes*(c: PContext, s: PIdent): PSym =
for scope in walkScopes(c.currentScope):
result = StrTableGet(scope.symbols, s)
result = strTableGet(scope.symbols, s)
if result != nil: return
result = nil
proc searchInScopes*(c: PContext, s: PIdent, filter: TSymKinds): PSym =
for scope in walkScopes(c.currentScope):
result = StrTableGet(scope.symbols, s)
result = strTableGet(scope.symbols, s)
if result != nil and result.kind in filter: return
result = nil
@@ -91,7 +92,8 @@ proc errorSym*(c: PContext, n: PNode): PSym =
result.typ = errorType(c)
incl(result.flags, sfDiscardable)
# pretend it's imported from some unknown module to prevent cascading errors:
c.importTable.addSym(result)
if gCmd != cmdInteractive and c.inCompilesContext == 0:
c.importTable.addSym(result)
type
TOverloadIterMode* = enum
@@ -107,71 +109,74 @@ type
proc getSymRepr*(s: PSym): string =
case s.kind
of skProc, skMethod, skConverter, skIterator: result = getProcHeader(s)
of skProc, skMethod, skConverter, skIterators: result = getProcHeader(s)
else: result = s.name.s
proc ensureNoMissingOrUnusedSymbols(scope: PScope) =
# check if all symbols have been used and defined:
var it: TTabIter
var s = InitTabIter(it, scope.symbols)
var s = initTabIter(it, scope.symbols)
var missingImpls = 0
while s != nil:
if sfForward in s.flags:
# too many 'implementation of X' errors are annoying
# and slow 'suggest' down:
if missingImpls == 0:
LocalError(s.info, errImplOfXexpected, getSymRepr(s))
localError(s.info, errImplOfXexpected, getSymRepr(s))
inc missingImpls
elif {sfUsed, sfExported} * s.flags == {} and optHints in s.options:
# BUGFIX: check options in s!
if s.kind notin {skForVar, skParam, skMethod, skUnknown, skGenericParam}:
Message(s.info, hintXDeclaredButNotUsed, getSymRepr(s))
s = NextIter(it, scope.symbols)
# XXX: implicit type params are currently skTypes
# maybe they can be made skGenericParam as well.
if s.typ != nil and tfImplicitTypeParam notin s.typ.flags:
message(s.info, hintXDeclaredButNotUsed, getSymRepr(s))
s = nextIter(it, scope.symbols)
proc WrongRedefinition*(info: TLineInfo, s: string) =
proc wrongRedefinition*(info: TLineInfo, s: string) =
if gCmd != cmdInteractive:
localError(info, errAttemptToRedefine, s)
proc addDecl*(c: PContext, sym: PSym) =
if c.currentScope.addUniqueSym(sym) == Failure:
WrongRedefinition(sym.info, sym.Name.s)
wrongRedefinition(sym.info, sym.name.s)
proc addPrelimDecl*(c: PContext, sym: PSym) =
discard c.currentScope.addUniqueSym(sym)
proc addDeclAt*(scope: PScope, sym: PSym) =
if scope.addUniqueSym(sym) == Failure:
WrongRedefinition(sym.info, sym.Name.s)
wrongRedefinition(sym.info, sym.name.s)
proc AddInterfaceDeclAux(c: PContext, sym: PSym) =
proc addInterfaceDeclAux(c: PContext, sym: PSym) =
if sfExported in sym.flags:
# add to interface:
if c.module != nil: StrTableAdd(c.module.tab, sym)
else: InternalError(sym.info, "AddInterfaceDeclAux")
if c.module != nil: strTableAdd(c.module.tab, sym)
else: internalError(sym.info, "AddInterfaceDeclAux")
proc addInterfaceDeclAt*(c: PContext, scope: PScope, sym: PSym) =
addDeclAt(scope, sym)
AddInterfaceDeclAux(c, sym)
addInterfaceDeclAux(c, sym)
proc addOverloadableSymAt*(scope: PScope, fn: PSym) =
if fn.kind notin OverloadableSyms:
InternalError(fn.info, "addOverloadableSymAt")
internalError(fn.info, "addOverloadableSymAt")
return
var check = StrTableGet(scope.symbols, fn.name)
if check != nil and check.Kind notin OverloadableSyms:
WrongRedefinition(fn.info, fn.Name.s)
var check = strTableGet(scope.symbols, fn.name)
if check != nil and check.kind notin OverloadableSyms:
wrongRedefinition(fn.info, fn.name.s)
else:
scope.addSym(fn)
proc addInterfaceDecl*(c: PContext, sym: PSym) =
# it adds the symbol to the interface if appropriate
addDecl(c, sym)
AddInterfaceDeclAux(c, sym)
addInterfaceDeclAux(c, sym)
proc addInterfaceOverloadableSymAt*(c: PContext, scope: PScope, sym: PSym) =
# it adds the symbol to the interface if appropriate
addOverloadableSymAt(scope, sym)
AddInterfaceDeclAux(c, sym)
addInterfaceDeclAux(c, sym)
proc lookUp*(c: PContext, n: PNode): PSym =
# Looks up a symbol. Generates an error in case of nil.
@@ -179,7 +184,7 @@ proc lookUp*(c: PContext, n: PNode): PSym =
of nkIdent:
result = searchInScopes(c, n.ident)
if result == nil:
LocalError(n.info, errUndeclaredIdentifier, n.ident.s)
localError(n.info, errUndeclaredIdentifier, n.ident.s)
result = errorSym(c, n)
of nkSym:
result = n.sym
@@ -187,34 +192,34 @@ proc lookUp*(c: PContext, n: PNode): PSym =
var ident = considerAcc(n)
result = searchInScopes(c, ident)
if result == nil:
LocalError(n.info, errUndeclaredIdentifier, ident.s)
localError(n.info, errUndeclaredIdentifier, ident.s)
result = errorSym(c, n)
else:
InternalError(n.info, "lookUp")
internalError(n.info, "lookUp")
return
if Contains(c.AmbiguousSymbols, result.id):
LocalError(n.info, errUseQualifier, result.name.s)
if contains(c.ambiguousSymbols, result.id):
localError(n.info, errUseQualifier, result.name.s)
if result.kind == skStub: loadStub(result)
type
TLookupFlag* = enum
checkAmbiguity, checkUndeclared
proc QualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
proc qualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
case n.kind
of nkIdent, nkAccQuoted:
var ident = considerAcc(n)
result = searchInScopes(c, ident)
if result == nil and checkUndeclared in flags:
LocalError(n.info, errUndeclaredIdentifier, ident.s)
localError(n.info, errUndeclaredIdentifier, ident.s)
result = errorSym(c, n)
elif checkAmbiguity in flags and result != nil and
Contains(c.AmbiguousSymbols, result.id):
LocalError(n.info, errUseQualifier, ident.s)
contains(c.ambiguousSymbols, result.id):
localError(n.info, errUseQualifier, ident.s)
of nkSym:
result = n.sym
if checkAmbiguity in flags and Contains(c.AmbiguousSymbols, result.id):
LocalError(n.info, errUseQualifier, n.sym.name.s)
if checkAmbiguity in flags and contains(c.ambiguousSymbols, result.id):
localError(n.info, errUseQualifier, n.sym.name.s)
of nkDotExpr:
result = nil
var m = qualifiedLookUp(c, n.sons[0], flags*{checkUndeclared})
@@ -226,28 +231,31 @@ proc QualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
ident = considerAcc(n.sons[1])
if ident != nil:
if m == c.module:
result = StrTableGet(c.topLevelScope.symbols, ident)
result = strTableGet(c.topLevelScope.symbols, ident)
else:
result = StrTableGet(m.tab, ident)
result = strTableGet(m.tab, ident)
if result == nil and checkUndeclared in flags:
LocalError(n.sons[1].info, errUndeclaredIdentifier, ident.s)
localError(n.sons[1].info, errUndeclaredIdentifier, ident.s)
result = errorSym(c, n.sons[1])
elif checkUndeclared in flags:
LocalError(n.sons[1].info, errIdentifierExpected,
elif n.sons[1].kind == nkSym:
result = n.sons[1].sym
elif checkUndeclared in flags and
n.sons[1].kind notin {nkOpenSymChoice, nkClosedSymChoice}:
localError(n.sons[1].info, errIdentifierExpected,
renderTree(n.sons[1]))
result = errorSym(c, n.sons[1])
else:
result = nil
if result != nil and result.kind == skStub: loadStub(result)
proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
case n.kind
of nkIdent, nkAccQuoted:
var ident = considerAcc(n)
o.scope = c.currentScope
o.mode = oimNoQualifier
while true:
result = InitIdentIter(o.it, o.scope.symbols, ident)
result = initIdentIter(o.it, o.scope.symbols, ident)
if result != nil:
break
else:
@@ -268,12 +276,12 @@ proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
if ident != nil:
if o.m == c.module:
# a module may access its private members:
result = InitIdentIter(o.it, c.topLevelScope.symbols, ident)
result = initIdentIter(o.it, c.topLevelScope.symbols, ident)
o.mode = oimSelfModule
else:
result = InitIdentIter(o.it, o.m.tab, ident)
result = initIdentIter(o.it, o.m.tab, ident)
else:
LocalError(n.sons[1].info, errIdentifierExpected,
localError(n.sons[1].info, errIdentifierExpected,
renderTree(n.sons[1]))
result = errorSym(c, n.sons[1])
of nkClosedSymChoice, nkOpenSymChoice:
@@ -281,8 +289,8 @@ proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
result = n.sons[0].sym
o.symChoiceIndex = 1
o.inSymChoice = initIntSet()
Incl(o.inSymChoice, result.id)
else: nil
incl(o.inSymChoice, result.id)
else: discard
if result != nil and result.kind == skStub: loadStub(result)
proc lastOverloadScope*(o: TOverloadIter): int =
@@ -302,7 +310,7 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
while result == nil:
o.scope = o.scope.parent
if o.scope == nil: break
result = InitIdentIter(o.it, o.scope.symbols, o.it.name)
result = initIdentIter(o.it, o.scope.symbols, o.it.name)
# BUGFIX: o.it.name <-> n.ident
else:
result = nil
@@ -313,26 +321,38 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
of oimSymChoice:
if o.symChoiceIndex < sonsLen(n):
result = n.sons[o.symChoiceIndex].sym
Incl(o.inSymChoice, result.id)
incl(o.inSymChoice, result.id)
inc o.symChoiceIndex
elif n.kind == nkOpenSymChoice:
# try 'local' symbols too for Koenig's lookup:
o.mode = oimSymChoiceLocalLookup
o.scope = c.currentScope
result = FirstIdentExcluding(o.it, o.scope.symbols,
result = firstIdentExcluding(o.it, o.scope.symbols,
n.sons[0].sym.name, o.inSymChoice)
while result == nil:
o.scope = o.scope.parent
if o.scope == nil: break
result = FirstIdentExcluding(o.it, o.scope.symbols,
result = firstIdentExcluding(o.it, o.scope.symbols,
n.sons[0].sym.name, o.inSymChoice)
of oimSymChoiceLocalLookup:
result = nextIdentExcluding(o.it, o.scope.symbols, o.inSymChoice)
while result == nil:
o.scope = o.scope.parent
if o.scope == nil: break
result = FirstIdentExcluding(o.it, o.scope.symbols,
result = firstIdentExcluding(o.it, o.scope.symbols,
n.sons[0].sym.name, o.inSymChoice)
if result != nil and result.kind == skStub: loadStub(result)
when false:
proc qualifiedLookUpPreferImmediate*(c: PContext, n: PNode,
flags = {checkUndeclared}): PSym =
var o: TOverloadIter
result = initOverloadIter(o, c, n)
var a = result
while a != nil:
if sfImmediate in a.flags: return a
a = nextOverloadIter(o, c, n)
if result == nil and checkUndeclared in flags:
localError(n.info, errUndeclaredIdentifier, n.considerAcc.s)
result = errorSym(c, n)

228
compiler/lowerings.nim Normal file
View File

@@ -0,0 +1,228 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements common simple lowerings.
const
genPrefix* = ":tmp" # prefix for generated names
import ast, astalgo, types, idents, magicsys, msgs, options
proc newTupleAccess*(tup: PNode, i: int): PNode =
result = newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes(
abstractInst).sons[i])
addSon(result, copyTree(tup))
var lit = newNodeIT(nkIntLit, tup.info, getSysType(tyInt))
lit.intVal = i
addSon(result, lit)
proc addVar*(father, v: PNode) =
var vpart = newNodeI(nkIdentDefs, v.info, 3)
vpart.sons[0] = v
vpart.sons[1] = ast.emptyNode
vpart.sons[2] = ast.emptyNode
addSon(father, vpart)
proc newAsgnStmt(le, ri: PNode): PNode =
result = newNodeI(nkAsgn, le.info, 2)
result.sons[0] = le
result.sons[1] = ri
proc newFastAsgnStmt(le, ri: PNode): PNode =
result = newNodeI(nkFastAsgn, le.info, 2)
result.sons[0] = le
result.sons[1] = ri
proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode =
assert n.kind == nkVarTuple
let value = n.lastSon
result = newNodeI(nkStmtList, n.info)
var temp = newSym(skTemp, getIdent(genPrefix), owner, value.info)
temp.typ = skipTypes(value.typ, abstractInst)
incl(temp.flags, sfFromGeneric)
var v = newNodeI(nkVarSection, value.info)
v.addVar(newSymNode(temp))
result.add(v)
result.add newAsgnStmt(newSymNode(temp), value)
for i in 0 .. n.len-3:
result.add newAsgnStmt(n.sons[i], newTupleAccess(value, i))
proc createObj*(owner: PSym, info: TLineInfo): PType =
result = newType(tyObject, owner)
rawAddSon(result, nil)
incl result.flags, tfFinal
result.n = newNodeI(nkRecList, info)
proc addField*(obj: PType; s: PSym) =
# because of 'gensym' support, we have to mangle the name with its ID.
# This is hacky but the clean solution is much more complex than it looks.
var field = newSym(skField, getIdent(s.name.s & $s.id), s.owner, s.info)
let t = skipIntLit(s.typ)
field.typ = t
field.position = sonsLen(obj.n)
addSon(obj.n, newSymNode(field))
proc newDotExpr(obj, b: PSym): PNode =
result = newNodeI(nkDotExpr, obj.info)
let field = getSymFromList(obj.typ.n, getIdent(b.name.s & $b.id))
assert field != nil, b.name.s
addSon(result, newSymNode(obj))
addSon(result, newSymNode(field))
result.typ = field.typ
proc indirectAccess*(a: PNode, b: PSym, info: TLineInfo): PNode =
# returns a[].b as a node
var deref = newNodeI(nkHiddenDeref, info)
deref.typ = a.typ.sons[0]
assert deref.typ.kind == tyObject
let field = getSymFromList(deref.typ.n, getIdent(b.name.s & $b.id))
assert field != nil, b.name.s
addSon(deref, a)
result = newNodeI(nkDotExpr, info)
addSon(result, deref)
addSon(result, newSymNode(field))
result.typ = field.typ
proc indirectAccess*(a, b: PSym, info: TLineInfo): PNode =
result = indirectAccess(newSymNode(a), b, info)
proc genAddrOf*(n: PNode): PNode =
result = newNodeI(nkAddr, n.info, 1)
result.sons[0] = n
result.typ = newType(tyPtr, n.typ.owner)
result.typ.rawAddSon(n.typ)
proc callCodegenProc*(name: string, arg1: PNode;
arg2, arg3: PNode = nil): PNode =
result = newNodeI(nkCall, arg1.info)
let sym = magicsys.getCompilerProc(name)
if sym == nil:
localError(arg1.info, errSystemNeeds, name)
else:
result.add newSymNode(sym)
result.add arg1
if arg2 != nil: result.add arg2
if arg3 != nil: result.add arg3
proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
varSection, call: PNode): PSym =
var body = newNodeI(nkStmtList, f.info)
body.add varSection
body.add callCodeGenProc("nimArgsPassingDone", newSymNode(threadParam))
body.add call
var params = newNodeI(nkFormalParams, f.info)
params.add emptyNode
params.add threadParam.newSymNode
params.add argsParam.newSymNode
var t = newType(tyProc, threadParam.owner)
t.rawAddSon nil
t.rawAddSon threadParam.typ
t.rawAddSon argsParam.typ
t.n = newNodeI(nkFormalParams, f.info)
t.n.add newNodeI(nkEffectList, f.info)
t.n.add threadParam.newSymNode
t.n.add argsParam.newSymNode
let name = (if f.kind == nkSym: f.sym.name.s else: genPrefix) & "Wrapper"
result = newSym(skProc, getIdent(name), argsParam.owner, f.info)
result.ast = newProcNode(nkProcDef, f.info, body, params, newSymNode(result))
result.typ = t
proc createCastExpr(argsParam: PSym; objType: PType): PNode =
result = newNodeI(nkCast, argsParam.info)
result.add emptyNode
result.add newSymNode(argsParam)
result.typ = newType(tyPtr, objType.owner)
result.typ.rawAddSon(objType)
proc wrapProcForSpawn*(owner: PSym; n: PNode): PNode =
result = newNodeI(nkStmtList, n.info)
if n.kind notin nkCallKinds or not n.typ.isEmptyType:
localError(n.info, "'spawn' takes a call expression of type void")
return
if optThreadAnalysis in gGlobalOptions:
if {tfThread, tfNoSideEffect} * n[0].typ.flags == {}:
localError(n.info, "'spawn' takes a GC safe call expression")
var
threadParam = newSym(skParam, getIdent"thread", owner, n.info)
argsParam = newSym(skParam, getIdent"args", owner, n.info)
block:
let ptrType = getSysType(tyPointer)
threadParam.typ = ptrType
argsParam.typ = ptrType
argsParam.position = 1
var objType = createObj(owner, n.info)
incl(objType.flags, tfFinal)
let castExpr = createCastExpr(argsParam, objType)
var scratchObj = newSym(skVar, getIdent"scratch", owner, n.info)
block:
scratchObj.typ = objType
incl(scratchObj.flags, sfFromGeneric)
var varSectionB = newNodeI(nkVarSection, n.info)
varSectionB.addVar(scratchObj.newSymNode)
result.add varSectionB
var call = newNodeI(nkCall, n.info)
var fn = n.sons[0]
# templates and macros are in fact valid here due to the nature of
# the transformation:
if not (fn.kind == nkSym and fn.sym.kind in {skProc, skTemplate, skMacro,
skMethod, skConverter}):
# for indirect calls we pass the function pointer in the scratchObj
var argType = n[0].typ.skipTypes(abstractInst)
var field = newSym(skField, getIdent"fn", owner, n.info)
field.typ = argType
objType.addField(field)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[0])
fn = indirectAccess(castExpr, field, n.info)
elif fn.kind == nkSym and fn.sym.kind in {skClosureIterator, skIterator}:
localError(n.info, "iterator in spawn environment is not allowed")
elif fn.typ.callConv == ccClosure:
localError(n.info, "closure in spawn environment is not allowed")
call.add(fn)
var varSection = newNodeI(nkVarSection, n.info)
let formals = n[0].typ.n
let tmpName = getIdent(genPrefix)
for i in 1 .. <n.len:
# we pick n's type here, which hopefully is 'tyArray' and not
# 'tyOpenArray':
var argType = n[i].typ.skipTypes(abstractInst)
if i < formals.len and formals[i].typ.kind == tyVar:
localError(n[i].info, "'spawn'ed function cannot have a 'var' parameter")
elif containsTyRef(argType):
localError(n[i].info, "'spawn'ed function cannot refer to 'ref'/closure")
let fieldname = if i < formals.len: formals[i].sym.name else: tmpName
var field = newSym(skField, fieldname, owner, n.info)
field.typ = argType
objType.addField(field)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[i])
var temp = newSym(skTemp, tmpName, owner, n.info)
temp.typ = argType
incl(temp.flags, sfFromGeneric)
var vpart = newNodeI(nkIdentDefs, n.info, 3)
vpart.sons[0] = newSymNode(temp)
vpart.sons[1] = ast.emptyNode
vpart.sons[2] = indirectAccess(castExpr, field, n.info)
varSection.add vpart
call.add(newSymNode(temp))
let wrapper = createWrapperProc(fn, threadParam, argsParam, varSection, call)
result.add callCodeGenProc("nimSpawn", wrapper.newSymNode,
genAddrOf(scratchObj.newSymNode))

View File

@@ -12,14 +12,14 @@
import
ast, astalgo, hashes, msgs, platform, nversion, times, idents, rodread
var SystemModule*: PSym
var systemModule*: PSym
proc registerSysType*(t: PType)
# magic symbols in the system module:
proc getSysType*(kind: TTypeKind): PType
proc getCompilerProc*(name: string): PSym
proc registerCompilerProc*(s: PSym)
proc FinishSystem*(tab: TStrTable)
proc finishSystem*(tab: TStrTable)
proc getSysSym*(name: string): PSym
# implementation
@@ -36,13 +36,25 @@ proc newSysType(kind: TTypeKind, size: int): PType =
result.align = size
proc getSysSym(name: string): PSym =
result = StrTableGet(systemModule.tab, getIdent(name))
result = strTableGet(systemModule.tab, getIdent(name))
if result == nil:
rawMessage(errSystemNeeds, name)
result = newSym(skError, getIdent(name), systemModule, systemModule.info)
result.typ = newType(tyError, systemModule)
if result.kind == skStub: loadStub(result)
proc getSysMagic*(name: string, m: TMagic): PSym =
var ti: TIdentIter
let id = getIdent(name)
result = initIdentIter(ti, systemModule.tab, id)
while result != nil:
if result.kind == skStub: loadStub(result)
if result.magic == m: return result
result = nextIdentIter(ti, systemModule.tab)
rawMessage(errSystemNeeds, name)
result = newSym(skError, id, systemModule, systemModule.info)
result.typ = newType(tyError, systemModule)
proc sysTypeFromName*(name: string): PType =
result = getSysSym(name).typ
@@ -62,19 +74,19 @@ proc getSysType(kind: TTypeKind): PType =
of tyUInt64: result = sysTypeFromName("uint64")
of tyFloat: result = sysTypeFromName("float")
of tyFloat32: result = sysTypeFromName("float32")
of tyFloat64: result = sysTypeFromName("float64")
of tyFloat64: return sysTypeFromName("float64")
of tyFloat128: result = sysTypeFromName("float128")
of tyBool: result = sysTypeFromName("bool")
of tyChar: result = sysTypeFromName("char")
of tyString: result = sysTypeFromName("string")
of tyCstring: result = sysTypeFromName("cstring")
of tyCString: result = sysTypeFromName("cstring")
of tyPointer: result = sysTypeFromName("pointer")
of tyNil: result = newSysType(tyNil, ptrSize)
else: InternalError("request for typekind: " & $kind)
else: internalError("request for typekind: " & $kind)
gSysTypes[kind] = result
if result.kind != kind:
InternalError("wanted: " & $kind & " got: " & $result.kind)
if result == nil: InternalError("type not found: " & $kind)
internalError("wanted: " & $kind & " got: " & $result.kind)
if result == nil: internalError("type not found: " & $kind)
var
intTypeCache: array[-5..64, PType]
@@ -103,19 +115,26 @@ proc getIntLitType*(literal: PNode): PType =
result = copyType(ti, ti.owner, false)
result.n = literal
proc skipIntLit*(t: PType): PType {.inline.} =
if t.kind == tyInt and t.n != nil:
result = getSysType(tyInt)
else:
result = t
proc getFloatLitType*(literal: PNode): PType =
# for now we do not cache these:
result = newSysType(tyFloat, size=8)
result.n = literal
proc AddSonSkipIntLit*(father, son: PType) =
proc skipIntLit*(t: PType): PType {.inline.} =
if t.n != nil:
if t.kind in {tyInt, tyFloat}:
return getSysType(t.kind)
result = t
proc addSonSkipIntLit*(father, son: PType) =
if isNil(father.sons): father.sons = @[]
add(father.sons, son.skipIntLit)
let s = son.skipIntLit
add(father.sons, s)
propagateToOwner(father, s)
proc setIntLitType*(result: PNode) =
let i = result.intVal
case platform.IntSize
case platform.intSize
of 8: result.typ = getIntLitType(result)
of 4:
if i >= low(int32) and i <= high(int32):
@@ -139,13 +158,13 @@ proc setIntLitType*(result: PNode) =
result.typ = getSysType(tyInt32)
else:
result.typ = getSysType(tyInt64)
else: InternalError(result.info, "invalid int size")
else: internalError(result.info, "invalid int size")
proc getCompilerProc(name: string): PSym =
var ident = getIdent(name, hashIgnoreStyle(name))
result = StrTableGet(compilerprocs, ident)
result = strTableGet(compilerprocs, ident)
if result == nil:
result = StrTableGet(rodCompilerProcs, ident)
result = strTableGet(rodCompilerprocs, ident)
if result != nil:
strTableAdd(compilerprocs, result)
if result.kind == skStub: loadStub(result)
@@ -153,7 +172,6 @@ proc getCompilerProc(name: string): PSym =
proc registerCompilerProc(s: PSym) =
strTableAdd(compilerprocs, s)
proc FinishSystem(tab: TStrTable) = nil
initStrTable(compilerprocs)
proc finishSystem(tab: TStrTable) = discard
initStrTable(compilerprocs)

View File

@@ -1,214 +1,31 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2013 Andreas Rumpf
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# implements the command dispatcher and several commands as well as the
# module handling
# implements the command dispatcher and several commands
import
llstream, strutils, ast, astalgo, lexer, syntaxes, renderer, options, msgs,
os, lists, condsyms, rodread, rodwrite, ropes, trees, times,
import
llstream, strutils, ast, astalgo, lexer, syntaxes, renderer, options, msgs,
os, condsyms, rodread, rodwrite, times,
wordrecg, sem, semdata, idents, passes, docgen, extccomp,
cgen, jsgen, cgendata, json, nversion,
platform, nimconf, importer, passaux, depends, evals, types, idgen,
tables, docgen2, service, magicsys, parser, crc, ccgutils, sigmatch
cgen, jsgen, json, nversion,
platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen,
tables, docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists,
pretty
from magicsys import systemModule, resetSysTypes
const
has_LLVM_Backend = false
hasLLVM_Backend = false
when has_LLVM_Backend:
when hasLLVM_Backend:
import llvmgen
proc MainCommand*()
# ------------------ module handling -----------------------------------------
type
TNeedRecompile = enum Maybe, No, Yes, Probing, Recompiled
TCrcStatus = enum crcNotTaken, crcCached, crcHasChanged, crcNotChanged
TModuleInMemory = object
compiledAt: float
crc: TCrc32
deps: seq[int32] ## XXX: slurped files are not currently tracked
needsRecompile: TNeedRecompile
crcStatus: TCrcStatus
var
gCompiledModules: seq[PSym] = @[]
gMemCacheData: seq[TModuleInMemory] = @[]
## XXX: we should implement recycling of file IDs
## if the user keeps renaming modules, the file IDs will keep growing
proc getModule(fileIdx: int32): PSym =
if fileIdx >= 0 and fileIdx < gCompiledModules.len:
result = gCompiledModules[fileIdx]
else:
result = nil
template compiledAt(x: PSym): expr =
gMemCacheData[x.position].compiledAt
template crc(x: PSym): expr =
gMemCacheData[x.position].crc
proc crcChanged(fileIdx: int32): bool =
InternalAssert fileIdx >= 0 and fileIdx < gMemCacheData.len
template updateStatus =
gMemCacheData[fileIdx].crcStatus = if result: crcHasChanged
else: crcNotChanged
# echo "TESTING CRC: ", fileIdx.toFilename, " ", result
case gMemCacheData[fileIdx].crcStatus:
of crcHasChanged:
result = true
of crcNotChanged:
result = false
of crcCached:
let newCrc = crcFromFile(fileIdx.toFilename)
result = newCrc != gMemCacheData[fileIdx].crc
gMemCacheData[fileIdx].crc = newCrc
updateStatus()
of crcNotTaken:
gMemCacheData[fileIdx].crc = crcFromFile(fileIdx.toFilename)
result = true
updateStatus()
proc doCRC(fileIdx: int32) =
if gMemCacheData[fileIdx].crcStatus == crcNotTaken:
# echo "FIRST CRC: ", fileIdx.ToFilename
gMemCacheData[fileIdx].crc = crcFromFile(fileIdx.toFilename)
proc addDep(x: Psym, dep: int32) =
growCache gMemCacheData, dep
gMemCacheData[x.position].deps.safeAdd(dep)
proc resetModule(fileIdx: int32) =
# echo "HARD RESETTING ", fileIdx.toFilename
gMemCacheData[fileIdx].needsRecompile = Yes
gCompiledModules[fileIdx] = nil
cgendata.gModules[fileIdx] = nil
resetSourceMap(fileIdx)
proc resetAllModules =
for i in 0..gCompiledModules.high:
if gCompiledModules[i] != nil:
resetModule(i.int32)
# for m in cgenModules(): echo "CGEN MODULE FOUND"
proc checkDepMem(fileIdx: int32): TNeedRecompile =
template markDirty =
resetModule(fileIdx)
return Yes
if gMemCacheData[fileIdx].needsRecompile != Maybe:
return gMemCacheData[fileIdx].needsRecompile
if optForceFullMake in gGlobalOptions or
crcChanged(fileIdx):
markDirty
if gMemCacheData[fileIdx].deps != nil:
gMemCacheData[fileIdx].needsRecompile = Probing
for dep in gMemCacheData[fileIdx].deps:
let d = checkDepMem(dep)
if d in { Yes, Recompiled }:
# echo fileIdx.toFilename, " depends on ", dep.toFilename, " ", d
markDirty
gMemCacheData[fileIdx].needsRecompile = No
return No
proc newModule(fileIdx: int32): PSym =
# We cannot call ``newSym`` here, because we have to circumvent the ID
# mechanism, which we do in order to assign each module a persistent ID.
new(result)
result.id = - 1 # for better error checking
result.kind = skModule
let filename = fileIdx.toFilename
result.name = getIdent(splitFile(filename).name)
if not isNimrodIdentifier(result.name.s):
rawMessage(errInvalidModuleName, result.name.s)
result.owner = result # a module belongs to itself
result.info = newLineInfo(fileIdx, 1, 1)
result.position = fileIdx
growCache gMemCacheData, fileIdx
growCache gCompiledModules, fileIdx
gCompiledModules[result.position] = result
incl(result.flags, sfUsed)
initStrTable(result.tab)
StrTableAdd(result.tab, result) # a module knows itself
proc compileModule(fileIdx: int32, flags: TSymFlags): PSym =
result = getModule(fileIdx)
if result == nil:
growCache gMemCacheData, fileIdx
gMemCacheData[fileIdx].needsRecompile = Probing
result = newModule(fileIdx)
#var rd = handleSymbolFile(result)
var rd: PRodReader
result.flags = result.flags + flags
if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}:
rd = handleSymbolFile(result)
if result.id < 0:
InternalError("handleSymbolFile should have set the module\'s ID")
return
else:
result.id = getID()
processModule(result, nil, rd)
if optCaasEnabled in gGlobalOptions:
gMemCacheData[fileIdx].compiledAt = gLastCmdTime
gMemCacheData[fileIdx].needsRecompile = Recompiled
doCRC fileIdx
else:
if checkDepMem(fileIdx) == Yes:
result = CompileModule(fileIdx, flags)
else:
result = gCompiledModules[fileIdx]
proc importModule(s: PSym, fileIdx: int32): PSym =
# this is called by the semantic checking phase
result = compileModule(fileIdx, {})
if optCaasEnabled in gGlobalOptions: addDep(s, fileIdx)
if sfSystemModule in result.flags:
LocalError(result.info, errAttemptToRedefine, result.Name.s)
proc includeModule(s: PSym, fileIdx: int32): PNode =
result = syntaxes.parseFile(fileIdx)
if optCaasEnabled in gGlobalOptions:
growCache gMemCacheData, fileIdx
addDep(s, fileIdx)
doCrc(fileIdx)
proc `==^`(a, b: string): bool =
try:
result = sameFile(a, b)
except EOS:
result = false
proc compileSystemModule =
if magicsys.SystemModule == nil:
SystemFileIdx = fileInfoIdx(options.libpath/"system.nim")
discard CompileModule(SystemFileIdx, {sfSystemModule})
proc CompileProject(projectFile = gProjectMainIdx) =
let systemFileIdx = fileInfoIdx(options.libpath / "system.nim")
if projectFile == SystemFileIdx:
discard CompileModule(projectFile, {sfMainModule, sfSystemModule})
else:
compileSystemModule()
discard CompileModule(projectFile, {sfMainModule})
proc rodPass =
if optSymbolFiles in gGlobalOptions:
registerPass(rodwritePass)
@@ -220,22 +37,22 @@ proc semanticPasses =
registerPass verbosePass
registerPass semPass
proc CommandGenDepend =
proc commandGenDepend =
semanticPasses()
registerPass(genDependPass)
registerPass(gendependPass)
registerPass(cleanupPass)
compileProject()
generateDot(gProjectFull)
execExternalProgram("dot -Tpng -o" & changeFileExt(gProjectFull, "png") &
' ' & changeFileExt(gProjectFull, "dot"))
proc CommandCheck =
proc commandCheck =
msgs.gErrorMax = high(int) # do not stop after first error
semanticPasses() # use an empty backend for semantic checking only
rodPass()
compileProject()
proc CommandDoc2 =
proc commandDoc2 =
msgs.gErrorMax = high(int) # do not stop after first error
semanticPasses()
registerPass(docgen2Pass)
@@ -243,7 +60,7 @@ proc CommandDoc2 =
compileProject()
finishDoc2Pass(gProjectName)
proc CommandCompileToC =
proc commandCompileToC =
semanticPasses()
registerPass(cgenPass)
rodPass()
@@ -256,7 +73,7 @@ proc CommandCompileToC =
compileProject()
cgenWriteModules()
if gCmd != cmdRun:
extccomp.CallCCompiler(changeFileExt(gProjectFull, ""))
extccomp.callCCompiler(changeFileExt(gProjectFull, ""))
if isServing:
# caas will keep track only of the compilation commands
@@ -281,7 +98,7 @@ proc CommandCompileToC =
# rodread.rodcompilerProcs
# rodread.gTypeTable
# rodread.gMods
# !! ropes.cache
# semthreads.computed?
#
@@ -294,52 +111,45 @@ proc CommandCompileToC =
ccgutils.resetCaches()
GC_fullCollect()
when has_LLVM_Backend:
proc CommandCompileToLLVM =
when hasLLVM_Backend:
proc commandCompileToLLVM =
semanticPasses()
registerPass(llvmgen.llvmgenPass())
rodPass()
#registerPass(cleanupPass())
compileProject()
proc CommandCompileToJS =
proc commandCompileToJS =
#incl(gGlobalOptions, optSafeCode)
setTarget(osJS, cpuJS)
#initDefines()
DefineSymbol("nimrod") # 'nimrod' is always defined
DefineSymbol("ecmascript") # For backward compatibility
DefineSymbol("js")
defineSymbol("nimrod") # 'nimrod' is always defined
defineSymbol("ecmascript") # For backward compatibility
defineSymbol("js")
semanticPasses()
registerPass(jsgenPass)
registerPass(JSgenPass)
compileProject()
proc InteractivePasses =
proc interactivePasses =
#incl(gGlobalOptions, optSafeCode)
#setTarget(osNimrodVM, cpuNimrodVM)
initDefines()
DefineSymbol("nimrodvm")
when hasFFI: DefineSymbol("nimffi")
defineSymbol("nimrodvm")
when hasFFI: defineSymbol("nimffi")
registerPass(verbosePass)
registerPass(semPass)
registerPass(evalPass)
var stdinModule: PSym
proc makeStdinModule: PSym =
if stdinModule == nil:
stdinModule = newModule(fileInfoIdx"stdin")
stdinModule.id = getID()
result = stdinModule
proc CommandInteractive =
proc commandInteractive =
msgs.gErrorMax = high(int) # do not stop after first error
InteractivePasses()
interactivePasses()
compileSystemModule()
if commandArgs.len > 0:
discard CompileModule(fileInfoIdx(gProjectFull), {})
discard compileModule(fileInfoIdx(gProjectFull), {})
else:
var m = makeStdinModule()
incl(m.flags, sfMainModule)
processModule(m, LLStreamOpenStdIn(), nil)
processModule(m, llStreamOpenStdIn(), nil)
const evalPasses = [verbosePass, semPass, evalPass]
@@ -347,43 +157,50 @@ proc evalNim(nodes: PNode, module: PSym) =
carryPasses(nodes, module, evalPasses)
proc commandEval(exp: string) =
if SystemModule == nil:
InteractivePasses()
if systemModule == nil:
interactivePasses()
compileSystemModule()
var echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")"
evalNim(echoExp.parseString, makeStdinModule())
proc CommandPretty =
proc commandPrettyOld =
var projectFile = addFileExt(mainCommandArg(), NimExt)
var module = parseFile(projectFile.fileInfoIdx)
if module != nil:
if module != nil:
renderModule(module, getOutFile(mainCommandArg(), "pretty." & NimExt))
proc CommandScan =
var f = addFileExt(mainCommandArg(), nimExt)
var stream = LLStreamOpen(f, fmRead)
if stream != nil:
var
proc commandPretty =
msgs.gErrorMax = high(int) # do not stop after first error
semanticPasses()
registerPass(prettyPass)
compileProject()
pretty.overwriteFiles()
proc commandScan =
var f = addFileExt(mainCommandArg(), NimExt)
var stream = llStreamOpen(f, fmRead)
if stream != nil:
var
L: TLexer
tok: TToken
initToken(tok)
openLexer(L, f, stream)
while true:
while true:
rawGetTok(L, tok)
PrintTok(tok)
if tok.tokType == tkEof: break
CloseLexer(L)
else:
printTok(tok)
if tok.tokType == tkEof: break
closeLexer(L)
else:
rawMessage(errCannotOpenFile, f)
proc CommandSuggest =
proc commandSuggest =
if isServing:
# XXX: hacky work-around ahead
# Currently, it's possible to issue a idetools command, before
# issuing the first compile command. This will leave the compiler
# cache in a state where "no recompilation is necessary", but the
# cgen pass was never executed at all.
CommandCompileToC()
commandCompileToC()
if gDirtyBufferIdx != 0:
discard compileModule(gDirtyBufferIdx, {sfDirty})
resetModule(gDirtyBufferIdx)
@@ -393,26 +210,30 @@ proc CommandSuggest =
msgs.gErrorMax = high(int) # do not stop after first error
semanticPasses()
rodPass()
compileProject()
# XXX: this handles the case when the dirty buffer is the main file,
# but doesn't handle the case when it's imported module
var projFile = if gProjectMainIdx == gDirtyOriginalIdx: gDirtyBufferIdx
else: gProjectMainIdx
compileProject(projFile)
proc wantMainModule =
if gProjectFull.len == 0:
if optMainModule.len == 0:
Fatal(gCmdLineInfo, errCommandExpectsFilename)
fatal(gCmdLineInfo, errCommandExpectsFilename)
else:
gProjectName = optMainModule
gProjectFull = gProjectPath / gProjectName
gProjectMainIdx = addFileExt(gProjectFull, nimExt).fileInfoIdx
gProjectMainIdx = addFileExt(gProjectFull, NimExt).fileInfoIdx
proc requireMainModuleOption =
if optMainModule.len == 0:
Fatal(gCmdLineInfo, errMainModuleMustBeSpecified)
fatal(gCmdLineInfo, errMainModuleMustBeSpecified)
else:
gProjectName = optMainModule
gProjectFull = gProjectPath / gProjectName
gProjectMainIdx = addFileExt(gProjectFull, nimExt).fileInfoIdx
gProjectMainIdx = addFileExt(gProjectFull, NimExt).fileInfoIdx
proc resetMemory =
resetCompilationLists()
@@ -425,7 +246,7 @@ proc resetMemory =
for i in low(buckets)..high(buckets):
buckets[i] = nil
idAnon = nil
# XXX: clean these global vars
# ccgstmts.gBreakpoints
# ccgthreadvars.nimtv
@@ -441,7 +262,7 @@ proc resetMemory =
# rodread.rodcompilerProcs
# rodread.gTypeTable
# rodread.gMods
# !! ropes.cache
# semthreads.computed?
#
@@ -465,10 +286,10 @@ const
SimiluateCaasMemReset = false
PrintRopeCacheStats = false
proc MainCommand =
proc mainCommand* =
when SimiluateCaasMemReset:
gGlobalOptions.incl(optCaasEnabled)
# In "nimrod serve" scenario, each command must reset the registered passes
clearPasses()
gLastCmdTime = epochTime()
@@ -476,90 +297,96 @@ proc MainCommand =
if gProjectFull.len != 0:
# current path is always looked first for modules
prependStr(searchPaths, gProjectPath)
setID(100)
setId(100)
passes.gIncludeFile = includeModule
passes.gImportModule = importModule
case command.normalize
of "c", "cc", "compile", "compiletoc":
of "c", "cc", "compile", "compiletoc":
# compile means compileToC currently
gCmd = cmdCompileToC
wantMainModule()
CommandCompileToC()
commandCompileToC()
of "cpp", "compiletocpp":
extccomp.cExt = ".cpp"
gCmd = cmdCompileToCpp
if cCompiler == ccGcc: setCC("gpp")
wantMainModule()
DefineSymbol("cpp")
CommandCompileToC()
defineSymbol("cpp")
commandCompileToC()
of "objc", "compiletooc":
extccomp.cExt = ".m"
gCmd = cmdCompileToOC
wantMainModule()
DefineSymbol("objc")
CommandCompileToC()
defineSymbol("objc")
commandCompileToC()
of "run":
gCmd = cmdRun
wantMainModule()
when hasTinyCBackend:
extccomp.setCC("tcc")
CommandCompileToC()
else:
commandCompileToC()
else:
rawMessage(errInvalidCommandX, command)
of "js", "compiletojs":
of "js", "compiletojs":
gCmd = cmdCompileToJS
wantMainModule()
CommandCompileToJS()
of "compiletollvm":
commandCompileToJS()
of "compiletollvm":
gCmd = cmdCompileToLLVM
wantMainModule()
when has_LLVM_Backend:
when hasLLVM_Backend:
CommandCompileToLLVM()
else:
rawMessage(errInvalidCommandX, command)
of "pretty":
gCmd = cmdPretty
wantMainModule()
CommandPretty()
commandPretty()
of "doc":
gCmd = cmdDoc
LoadConfigs(DocConfig)
loadConfigs(DocConfig)
wantMainModule()
CommandDoc()
commandDoc()
of "doc2":
gCmd = cmdDoc
LoadConfigs(DocConfig)
loadConfigs(DocConfig)
wantMainModule()
DefineSymbol("nimdoc")
CommandDoc2()
of "rst2html":
defineSymbol("nimdoc")
commandDoc2()
of "rst2html":
gCmd = cmdRst2html
LoadConfigs(DocConfig)
loadConfigs(DocConfig)
wantMainModule()
CommandRst2Html()
of "rst2tex":
commandRst2Html()
of "rst2tex":
gCmd = cmdRst2tex
LoadConfigs(DocTexConfig)
loadConfigs(DocTexConfig)
wantMainModule()
CommandRst2TeX()
commandRst2TeX()
of "jsondoc":
gCmd = cmdDoc
loadConfigs(DocConfig)
wantMainModule()
defineSymbol("nimdoc")
commandJSON()
of "buildindex":
gCmd = cmdDoc
LoadConfigs(DocConfig)
CommandBuildIndex()
of "gendepend":
loadConfigs(DocConfig)
commandBuildIndex()
of "gendepend":
gCmd = cmdGenDepend
wantMainModule()
CommandGenDepend()
commandGenDepend()
of "dump":
gcmd = cmdDump
if getconfigvar("dump.format") == "json":
gCmd = cmdDump
if getConfigVar("dump.format") == "json":
requireMainModuleOption()
var definedSymbols = newJArray()
for s in definedSymbolNames(): definedSymbols.elems.add(%s)
var libpaths = newJArray()
for dir in itersearchpath(searchpaths): libpaths.elems.add(%dir)
for dir in iterSearchPath(searchPaths): libpaths.elems.add(%dir)
var dumpdata = % [
(key: "version", val: %VersionAsString),
@@ -568,29 +395,29 @@ proc MainCommand =
(key: "lib_paths", val: libpaths)
]
outWriteLn($dumpdata)
outWriteln($dumpdata)
else:
outWriteLn("-- list of currently defined symbols --")
for s in definedSymbolNames(): outWriteLn(s)
outWriteLn("-- end of list --")
outWriteln("-- list of currently defined symbols --")
for s in definedSymbolNames(): outWriteln(s)
outWriteln("-- end of list --")
for it in iterSearchPath(searchpaths): msgWriteLn(it)
for it in iterSearchPath(searchPaths): msgWriteln(it)
of "check":
gCmd = cmdCheck
wantMainModule()
CommandCheck()
of "parse":
commandCheck()
of "parse":
gCmd = cmdParse
wantMainModule()
discard parseFile(gProjectMainIdx)
of "scan":
of "scan":
gCmd = cmdScan
wantMainModule()
CommandScan()
MsgWriteln("Beware: Indentation tokens depend on the parser\'s state!")
of "i":
commandScan()
msgWriteln("Beware: Indentation tokens depend on the parser\'s state!")
of "i":
gCmd = cmdInteractive
CommandInteractive()
commandInteractive()
of "e":
# XXX: temporary command for easier testing
commandEval(mainCommandArg())
@@ -602,16 +429,18 @@ proc MainCommand =
commandEval(gEvalExpr)
else:
wantMainModule()
CommandSuggest()
commandSuggest()
of "serve":
isServing = true
gGlobalOptions.incl(optCaasEnabled)
msgs.gErrorMax = high(int) # do not stop after first error
serve(MainCommand)
msgs.gErrorMax = high(int) # do not stop after first error
serve(mainCommand)
else:
rawMessage(errInvalidCommandX, command)
if msgs.gErrorCounter == 0 and gCmd notin {cmdInterpret, cmdRun, cmdDump}:
if (msgs.gErrorCounter == 0 and
gCmd notin {cmdInterpret, cmdRun, cmdDump} and
gVerbosity > 0):
rawMessage(hintSuccessX, [$gLinesCompiled,
formatFloat(epochTime() - gLastCmdTime, ffDecimal, 3),
formatSize(getTotalMem())])
@@ -621,7 +450,8 @@ proc MainCommand =
echo " tries : ", gCacheTries
echo " misses: ", gCacheMisses
echo " int tries: ", gCacheIntTries
echo " efficiency: ", formatFloat(1-(gCacheMisses.float/gCacheTries.float), ffDecimal, 3)
echo " efficiency: ", formatFloat(1-(gCacheMisses.float/gCacheTries.float),
ffDecimal, 3)
when SimiluateCaasMemReset:
resetMemory()

201
compiler/modules.nim Normal file
View File

@@ -0,0 +1,201 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## implements the module handling
import
ast, astalgo, magicsys, crc, rodread, msgs, cgendata, sigmatch, options,
idents, os, lexer, idgen, passes, syntaxes
type
TNeedRecompile* = enum Maybe, No, Yes, Probing, Recompiled
TCrcStatus* = enum crcNotTaken, crcCached, crcHasChanged, crcNotChanged
TModuleInMemory* = object
compiledAt*: float
crc*: TCrc32
deps*: seq[int32] ## XXX: slurped files are currently not tracked
needsRecompile*: TNeedRecompile
crcStatus*: TCrcStatus
var
gCompiledModules: seq[PSym] = @[]
gMemCacheData*: seq[TModuleInMemory] = @[]
## XXX: we should implement recycling of file IDs
## if the user keeps renaming modules, the file IDs will keep growing
proc getModule(fileIdx: int32): PSym =
if fileIdx >= 0 and fileIdx < gCompiledModules.len:
result = gCompiledModules[fileIdx]
template compiledAt(x: PSym): expr =
gMemCacheData[x.position].compiledAt
template crc(x: PSym): expr =
gMemCacheData[x.position].crc
proc crcChanged(fileIdx: int32): bool =
internalAssert fileIdx >= 0 and fileIdx < gMemCacheData.len
template updateStatus =
gMemCacheData[fileIdx].crcStatus = if result: crcHasChanged
else: crcNotChanged
# echo "TESTING CRC: ", fileIdx.toFilename, " ", result
case gMemCacheData[fileIdx].crcStatus:
of crcHasChanged:
result = true
of crcNotChanged:
result = false
of crcCached:
let newCrc = crcFromFile(fileIdx.toFilename)
result = newCrc != gMemCacheData[fileIdx].crc
gMemCacheData[fileIdx].crc = newCrc
updateStatus()
of crcNotTaken:
gMemCacheData[fileIdx].crc = crcFromFile(fileIdx.toFilename)
result = true
updateStatus()
proc doCRC(fileIdx: int32) =
if gMemCacheData[fileIdx].crcStatus == crcNotTaken:
# echo "FIRST CRC: ", fileIdx.ToFilename
gMemCacheData[fileIdx].crc = crcFromFile(fileIdx.toFilename)
proc addDep(x: PSym, dep: int32) =
growCache gMemCacheData, dep
gMemCacheData[x.position].deps.safeAdd(dep)
proc resetModule*(fileIdx: int32) =
# echo "HARD RESETTING ", fileIdx.toFilename
gMemCacheData[fileIdx].needsRecompile = Yes
gCompiledModules[fileIdx] = nil
cgendata.gModules[fileIdx] = nil
resetSourceMap(fileIdx)
proc resetAllModules* =
for i in 0..gCompiledModules.high:
if gCompiledModules[i] != nil:
resetModule(i.int32)
resetPackageCache()
# for m in cgenModules(): echo "CGEN MODULE FOUND"
proc checkDepMem(fileIdx: int32): TNeedRecompile =
template markDirty =
resetModule(fileIdx)
return Yes
if gMemCacheData[fileIdx].needsRecompile != Maybe:
return gMemCacheData[fileIdx].needsRecompile
if optForceFullMake in gGlobalOptions or
crcChanged(fileIdx):
markDirty
if gMemCacheData[fileIdx].deps != nil:
gMemCacheData[fileIdx].needsRecompile = Probing
for dep in gMemCacheData[fileIdx].deps:
let d = checkDepMem(dep)
if d in {Yes, Recompiled}:
# echo fileIdx.toFilename, " depends on ", dep.toFilename, " ", d
markDirty
gMemCacheData[fileIdx].needsRecompile = No
return No
proc newModule(fileIdx: int32): PSym =
# We cannot call ``newSym`` here, because we have to circumvent the ID
# mechanism, which we do in order to assign each module a persistent ID.
new(result)
result.id = - 1 # for better error checking
result.kind = skModule
let filename = fileIdx.toFilename
result.name = getIdent(splitFile(filename).name)
if not isNimrodIdentifier(result.name.s):
rawMessage(errInvalidModuleName, result.name.s)
result.info = newLineInfo(fileIdx, 1, 1)
result.owner = newSym(skPackage, getIdent(getPackageName(filename)), nil,
result.info)
result.position = fileIdx
growCache gMemCacheData, fileIdx
growCache gCompiledModules, fileIdx
gCompiledModules[result.position] = result
incl(result.flags, sfUsed)
initStrTable(result.tab)
strTableAdd(result.tab, result) # a module knows itself
proc compileModule*(fileIdx: int32, flags: TSymFlags): PSym =
result = getModule(fileIdx)
if result == nil:
growCache gMemCacheData, fileIdx
gMemCacheData[fileIdx].needsRecompile = Probing
result = newModule(fileIdx)
#var rd = handleSymbolFile(result)
var rd: PRodReader
result.flags = result.flags + flags
if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}:
rd = handleSymbolFile(result)
if result.id < 0:
internalError("handleSymbolFile should have set the module\'s ID")
return
else:
result.id = getID()
processModule(result, nil, rd)
if optCaasEnabled in gGlobalOptions:
gMemCacheData[fileIdx].compiledAt = gLastCmdTime
gMemCacheData[fileIdx].needsRecompile = Recompiled
doCRC fileIdx
else:
if checkDepMem(fileIdx) == Yes:
result = compileModule(fileIdx, flags)
else:
result = gCompiledModules[fileIdx]
proc importModule*(s: PSym, fileIdx: int32): PSym {.procvar.} =
# this is called by the semantic checking phase
result = compileModule(fileIdx, {})
if optCaasEnabled in gGlobalOptions: addDep(s, fileIdx)
if sfSystemModule in result.flags:
localError(result.info, errAttemptToRedefine, result.name.s)
proc includeModule*(s: PSym, fileIdx: int32): PNode {.procvar.} =
result = syntaxes.parseFile(fileIdx)
if optCaasEnabled in gGlobalOptions:
growCache gMemCacheData, fileIdx
addDep(s, fileIdx)
doCRC(fileIdx)
proc `==^`(a, b: string): bool =
try:
result = sameFile(a, b)
except EOS:
result = false
proc compileSystemModule* =
if magicsys.systemModule == nil:
systemFileIdx = fileInfoIdx(options.libpath/"system.nim")
discard compileModule(systemFileIdx, {sfSystemModule})
proc compileProject*(projectFile = gProjectMainIdx) =
let systemFileIdx = fileInfoIdx(options.libpath / "system.nim")
if projectFile == systemFileIdx:
discard compileModule(projectFile, {sfMainModule, sfSystemModule})
else:
compileSystemModule()
discard compileModule(projectFile, {sfMainModule})
var stdinModule: PSym
proc makeStdinModule*(): PSym =
if stdinModule == nil:
stdinModule = newModule(fileInfoIdx"stdin")
stdinModule.id = getID()
result = stdinModule

View File

@@ -8,7 +8,10 @@
#
import
options, strutils, os, tables, sockets, ropes, platform
options, strutils, os, tables, ropes, platform
when useCaas:
import sockets
type
TMsgKind* = enum
@@ -64,7 +67,7 @@ type
errAmbiguousCallXYZ, errWrongNumberOfArguments,
errXCannotBePassedToProcVar,
errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProc, errImplOfXNotAllowed,
errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValue,
errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX,
errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice,
errInvalidOrderInArrayConstructor,
errInvalidOrderInEnumX, errEnumXHasHoles, errExceptExpected, errInvalidTry,
@@ -85,12 +88,16 @@ type
errTemplateInstantiationTooNested, errInstantiationFrom,
errInvalidIndexValueForTuple, errCommandExpectsFilename,
errMainModuleMustBeSpecified,
errXExpected,
errXExpected,
errTIsNotAConcreteType,
errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError,
errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile,
errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitely,
errXExpectsTwoArguments,
errOnlyACallOpCanBeDelegator, errUsingNoSymbol,
errMacroBodyDependsOnGenericTypes,
errDestructorNotGenericEnough,
errInlineIteratorsAsProcParams,
errXExpectsTwoArguments,
errXExpectsObjectTypes, errXcanNeverBeOfThisSubtype, errTooManyIterations,
errCannotInterpretNodeX, errFieldXNotFound, errInvalidConversionFromTypeX,
errAssertionFailed, errCannotGenerateCodeForX, errXRequiresOneArgument,
@@ -98,6 +105,10 @@ type
errXhasSideEffects, errIteratorExpected, errLetNeedsInit,
errThreadvarCannotInit, errWrongSymbolX, errIllegalCaptureX,
errXCannotBeClosure, errXMustBeCompileTime,
errCannotInferTypeOfTheLiteral,
errCannotInferReturnType,
errGenericLambdaNotAllowed,
errCompilerDoesntSupportTarget,
errUser,
warnCannotOpenFile,
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
@@ -106,11 +117,13 @@ type
warnUnknownSubstitutionX, warnLanguageXNotSupported, warnCommentXIgnored,
warnNilStatement, warnAnalysisLoophole,
warnDifferentHeaps, warnWriteToForeignHeap, warnImplicitClosure,
warnEachIdentIsTuple, warnShadowIdent, warnUser,
hintSuccess, hintSuccessX,
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
warnEachIdentIsTuple, warnShadowIdent,
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
warnUninit, warnGcMem, warnUser,
hintSuccess, hintSuccessX,
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
hintConditionAlwaysTrue, hintPattern,
hintUser
@@ -157,7 +170,7 @@ const
errInvalidNumberOfYieldExpr: "invalid number of \'yield\' expressions",
errCannotReturnExpr: "current routine cannot return an expression",
errAttemptToRedefine: "redefinition of \'$1\'",
errStmtInvalidAfterReturn: "statement not allowed after \'return\', \'break\' or \'raise\'",
errStmtInvalidAfterReturn: "statement not allowed after \'return\', \'break\', \'raise\' or \'continue'",
errStmtExpected: "statement expected",
errInvalidLabel: "\'$1\' is no label",
errInvalidCmdLineOption: "invalid command line option: \'$1\'",
@@ -189,7 +202,7 @@ const
errXExpectsArrayType: "\'$1\' expects an array type",
errIteratorCannotBeInstantiated: "'$1' cannot be instantiated because its body has not been compiled yet",
errExprXAmbiguous: "expression '$1' ambiguous in this context",
errConstantDivisionByZero: "constant division by zero",
errConstantDivisionByZero: "division by zero",
errOrdinalTypeExpected: "ordinal type expected",
errOrdinalOrFloatTypeExpected: "ordinal or float type expected",
errOverOrUnderflow: "over- or underflow",
@@ -256,7 +269,7 @@ const
errImplOfXNotAllowed: "implementation of \'$1\' is not allowed",
errImplOfXexpected: "implementation of \'$1\' expected",
errNoSymbolToBorrowFromFound: "no symbol to borrow from found",
errDiscardValue: "value returned by statement has to be discarded",
errDiscardValueX: "value of type '$1' has to be discarded",
errInvalidDiscard: "statement returns no value that can be discarded",
errIllegalConvFromXtoY: "conversion from $1 to $2 is invalid",
errCannotBindXTwice: "cannot bind parameter \'$1\' twice",
@@ -305,6 +318,7 @@ const
errCommandExpectsFilename: "command expects a filename argument",
errMainModuleMustBeSpecified: "please, specify a main module in the project configuration file",
errXExpected: "\'$1\' expected",
errTIsNotAConcreteType: "\'$1\' is not a concrete type.",
errInvalidSectionStart: "invalid section start",
errGridTableNotImplemented: "grid table is not implemented",
errGeneralParseError: "general parse error",
@@ -314,6 +328,14 @@ const
errCannotRenderX: "cannot render reStructuredText element \'$1\'",
errVarVarTypeNotAllowed: "type \'var var\' is not allowed",
errInstantiateXExplicitely: "instantiate '$1' explicitely",
errOnlyACallOpCanBeDelegator: "only a call operator can be a delegator",
errUsingNoSymbol: "'$1' is not a variable, constant or a proc name",
errMacroBodyDependsOnGenericTypes: "the macro body cannot be compiled, " &
"because the parameter '$1' has a generic type",
errDestructorNotGenericEnough: "Destructor signarue is too specific. " &
"A destructor must be associated will all instantiations of a generic type",
errInlineIteratorsAsProcParams: "inline iterators can be used as parameters only for " &
"templates, macros and other inline iterators",
errXExpectsTwoArguments: "\'$1\' expects two arguments",
errXExpectsObjectTypes: "\'$1\' expects object types",
errXcanNeverBeOfThisSubtype: "\'$1\' can never be of this subtype",
@@ -335,6 +357,12 @@ const
errIllegalCaptureX: "illegal capture '$1'",
errXCannotBeClosure: "'$1' cannot have 'closure' calling convention",
errXMustBeCompileTime: "'$1' can only be used in compile-time context",
errCannotInferTypeOfTheLiteral: "cannot infer the type of the $1",
errCannotInferReturnType: "cannot infer the return type of the proc",
errGenericLambdaNotAllowed: "A nested proc can have generic parameters only when " &
"it is used as an operand to another routine and the types " &
"of the generic paramers can be infered from the expected signature.",
errCompilerDoesntSupportTarget: "The current compiler \'$1\' doesn't support the requested compilation target",
errUser: "$1",
warnCannotOpenFile: "cannot open \'$1\' [CannotOpenFile]",
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored [OctalEscape]",
@@ -355,6 +383,13 @@ const
warnImplicitClosure: "implicit closure convention: '$1' [ImplicitClosure]",
warnEachIdentIsTuple: "each identifier is a tuple [EachIdentIsTuple]",
warnShadowIdent: "shadowed identifier: '$1' [ShadowIdent]",
warnProveInit: "Cannot prove that '$1' is initialized. This will become a compile time error in the future. [ProveInit]",
warnProveField: "cannot prove that field '$1' is accessible [ProveField]",
warnProveIndex: "cannot prove index '$1' is valid [ProveIndex]",
warnGcUnsafe: "not GC-safe: '$1' [GcUnsafe]",
warnGcUnsafe2: "cannot prove '$1' is GC-safe. This will become a compile time error in the future.",
warnUninit: "'$1' might not have been initialized [Uninit]",
warnGcMem: "'$1' uses GC'ed memory [GcMem]",
warnUser: "$1 [User]",
hintSuccess: "operation successful [Success]",
hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#) [SuccessX]",
@@ -374,14 +409,16 @@ const
hintUser: "$1 [User]"]
const
WarningsToStr*: array[0..19, string] = ["CannotOpenFile", "OctalEscape",
WarningsToStr*: array[0..26, string] = ["CannotOpenFile", "OctalEscape",
"XIsNeverRead", "XmightNotBeenInit",
"Deprecated", "ConfigDeprecated",
"SmallLshouldNotBeUsed", "UnknownMagic",
"RedefinitionOfLabel", "UnknownSubstitutionX", "LanguageXNotSupported",
"CommentXIgnored", "NilStmt",
"AnalysisLoophole", "DifferentHeaps", "WriteToForeignHeap",
"ImplicitClosure", "EachIdentIsTuple", "ShadowIdent", "User"]
"ImplicitClosure", "EachIdentIsTuple", "ShadowIdent",
"ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
"GcMem", "User"]
HintsToStr*: array[0..15, string] = ["Success", "SuccessX", "LineTooLong",
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
@@ -406,7 +443,7 @@ type
TFileInfo*{.final.} = object
fullPath*: string # This is a canonical full filesystem path
projPath*: string # This is relative to the project's root
shortName*: string # short name of the module
quotedName*: PRope # cached quoted short name for codegen
# purpoes
@@ -423,9 +460,16 @@ type
# only 8 bytes.
line*, col*: int16
fileIndex*: int32
TErrorOutput* = enum
eStdOut
eStdErr
eInMemory
TErrorOutputs* = set[TErrorOutput]
ERecoverableError* = object of EInvalidValue
ESuggestDone* = object of EBase
ESuggestDone* = object of E_Base
const
InvalidFileIDX* = int32(-1)
@@ -433,9 +477,9 @@ const
var
filenameToIndexTbl = initTable[string, int32]()
fileInfos*: seq[TFileInfo] = @[]
SystemFileIdx*: int32
systemFileIdx*: int32
proc toCChar*(c: Char): string =
proc toCChar*(c: char): string =
case c
of '\0'..'\x1F', '\x80'..'\xFF': result = '\\' & toOctal(c)
of '\'', '\"', '\\': result = '\\' & c
@@ -454,7 +498,7 @@ proc makeCString*(s: string): PRope =
add(res, '\"')
add(res, tnl)
app(result, toRope(res)) # reset:
setlen(res, 1)
setLen(res, 1)
res[0] = '\"'
add(res, toCChar(s[i]))
add(res, '\"')
@@ -466,7 +510,9 @@ proc newFileInfo(fullPath, projPath: string): TFileInfo =
#shallow(result.fullPath)
result.projPath = projPath
#shallow(result.projPath)
result.quotedName = projPath.extractFilename.makeCString
let fileName = projPath.extractFilename
result.shortName = fileName.changeFileExt("")
result.quotedName = fileName.makeCString
if optEmbedOrigSrc in gGlobalOptions or true:
result.lines = @[]
@@ -512,22 +558,46 @@ proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} =
proc sourceLine*(i: TLineInfo): PRope
var
gNotes*: TNoteKinds = {low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent}
gNotes*: TNoteKinds = {low(TNoteKind)..high(TNoteKind)} -
{warnShadowIdent, warnUninit,
warnProveField, warnProveIndex, warnGcUnsafe}
gErrorCounter*: int = 0 # counts the number of errors
gHintCounter*: int = 0
gWarnCounter*: int = 0
gErrorMax*: int = 1 # stop after gErrorMax errors
gSilence*: int # == 0 if we produce any output at all
stdoutSocket*: TSocket
proc SuggestWriteln*(s: string) =
if gSilence == 0:
if isNil(stdoutSocket): Writeln(stdout, s)
else:
Writeln(stdout, s)
stdoutSocket.send(s & "\c\L")
when useCaas:
var stdoutSocket*: TSocket
proc SuggestQuit*() =
proc unknownLineInfo*(): TLineInfo =
result.line = int16(-1)
result.col = int16(-1)
result.fileIndex = -1
var
msgContext: seq[TLineInfo] = @[]
lastError = unknownLineInfo()
bufferedMsgs*: seq[string]
errorOutputs* = {eStdOut, eStdErr}
proc clearBufferedMsgs* =
bufferedMsgs = nil
proc suggestWriteln*(s: string) =
if eStdOut in errorOutputs:
when useCaas:
if isNil(stdoutSocket): writeln(stdout, s)
else:
writeln(stdout, s)
stdoutSocket.send(s & "\c\L")
else:
writeln(stdout, s)
if eInMemory in errorOutputs:
bufferedMsgs.safeAdd(s)
proc suggestQuit*() =
if not isServing:
quit(0)
elif isWorkingWithDirtyBuffer:
@@ -548,14 +618,6 @@ const
RawWarningFormat* = "Warning: $1"
RawHintFormat* = "Hint: $1"
proc UnknownLineInfo*(): TLineInfo =
result.line = int16(-1)
result.col = int16(-1)
result.fileIndex = -1
var
msgContext: seq[TLineInfo] = @[]
proc getInfoContextLen*(): int = return msgContext.len
proc setInfoContextLen*(L: int) = setLen(msgContext, L)
@@ -563,12 +625,12 @@ proc pushInfoContext*(info: TLineInfo) =
msgContext.add(info)
proc popInfoContext*() =
setlen(msgContext, len(msgContext) - 1)
setLen(msgContext, len(msgContext) - 1)
proc getInfoContext*(index: int): TLineInfo =
let L = msgContext.len
let i = if index < 0: L + index else: index
if i >=% L: result = UnknownLineInfo()
if i >=% L: result = unknownLineInfo()
else: result = msgContext[i]
proc toFilename*(fileIdx: int32): string =
@@ -605,6 +667,8 @@ proc toFileLine*(info: TLineInfo): string {.inline.} =
proc toFileLineCol*(info: TLineInfo): string {.inline.} =
result = info.toFilename & "(" & $info.line & "," & $info.col & ")"
template `$`*(info: TLineInfo): expr = toFileLineCol(info)
proc `??`* (info: TLineInfo, filename: string): bool =
# only for debugging purposes
result = filename in info.toFilename
@@ -618,24 +682,28 @@ proc addCheckpoint*(info: TLineInfo) =
proc addCheckpoint*(filename: string, line: int) =
addCheckpoint(newLineInfo(filename, line, - 1))
proc OutWriteln*(s: string) =
proc outWriteln*(s: string) =
## Writes to stdout. Always.
if gSilence == 0: Writeln(stdout, s)
if eStdOut in errorOutputs: writeln(stdout, s)
proc MsgWriteln*(s: string) =
proc msgWriteln*(s: string) =
## Writes to stdout. If --stdout option is given, writes to stderr instead.
if gSilence == 0:
if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
if optStdout in gGlobalOptions: Writeln(stderr, s)
else: Writeln(stdout, s)
if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
if optStdout in gGlobalOptions:
if eStdErr in errorOutputs: writeln(stderr, s)
else:
if eStdOut in errorOutputs: writeln(stdout, s)
if eInMemory in errorOutputs: bufferedMsgs.safeAdd(s)
proc coordToStr(coord: int): string =
if coord == -1: result = "???"
else: result = $coord
proc MsgKindToString*(kind: TMsgKind): string =
proc msgKindToString*(kind: TMsgKind): string =
# later versions may provide translated error messages
result = msgKindToStr[kind]
result = MsgKindToStr[kind]
proc getMessageStr(msg: TMsgKind, arg: string): string =
result = msgKindToString(msg) % [arg]
@@ -657,70 +725,64 @@ type
TErrorHandling = enum doNothing, doAbort, doRaise
proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
template maybeTrace =
if defined(debug) or gVerbosity >= 3:
template quit =
if defined(debug) or gVerbosity >= 3 or msg == errInternal:
writeStackTrace()
quit 1
if msg == errInternal:
writeStackTrace() # we always want a stack trace here
if msg >= fatalMin and msg <= fatalMax:
maybeTrace()
quit(1)
if msg >= errMin and msg <= errMax:
maybeTrace()
if msg >= fatalMin and msg <= fatalMax:
quit()
if msg >= errMin and msg <= errMax:
inc(gErrorCounter)
options.gExitcode = 1'i8
if gErrorCounter >= gErrorMax:
quit(1)
if gErrorCounter >= gErrorMax:
quit()
elif eh == doAbort and gCmd != cmdIdeTools:
quit(1)
quit()
elif eh == doRaise:
raiseRecoverableError(s)
proc `==`*(a, b: TLineInfo): bool =
proc `==`*(a, b: TLineInfo): bool =
result = a.line == b.line and a.fileIndex == b.fileIndex
proc writeContext(lastinfo: TLineInfo) =
var info = lastInfo
var info = lastinfo
for i in countup(0, len(msgContext) - 1):
if msgContext[i] != lastInfo and msgContext[i] != info:
MsgWriteln(posContextFormat % [toMsgFilename(msgContext[i]),
if msgContext[i] != lastinfo and msgContext[i] != info:
msgWriteln(PosContextFormat % [toMsgFilename(msgContext[i]),
coordToStr(msgContext[i].line),
coordToStr(msgContext[i].col),
getMessageStr(errInstantiationFrom, "")])
info = msgContext[i]
proc rawMessage*(msg: TMsgKind, args: openarray[string]) =
proc rawMessage*(msg: TMsgKind, args: openArray[string]) =
var frmt: string
case msg
of errMin..errMax:
writeContext(unknownLineInfo())
frmt = rawErrorFormat
frmt = RawErrorFormat
of warnMin..warnMax:
if optWarns notin gOptions: return
if msg notin gNotes: return
writeContext(unknownLineInfo())
frmt = rawWarningFormat
frmt = RawWarningFormat
inc(gWarnCounter)
of hintMin..hintMax:
if optHints notin gOptions: return
if msg notin gNotes: return
frmt = rawHintFormat
frmt = RawHintFormat
inc(gHintCounter)
let s = `%`(frmt, `%`(msgKindToString(msg), args))
MsgWriteln(s)
msgWriteln(s)
handleError(msg, doAbort, s)
proc rawMessage*(msg: TMsgKind, arg: string) =
rawMessage(msg, [arg])
var
lastError = UnknownLineInfo()
proc writeSurroundingSrc(info: TLineInfo) =
const indent = " "
MsgWriteln(indent & info.sourceLine.ropeToStr)
MsgWriteln(indent & repeatChar(info.col, ' ') & '^')
msgWriteln(indent & info.sourceLine.ropeToStr)
msgWriteln(indent & repeatChar(info.col, ' ') & '^')
proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
eh: TErrorHandling) =
@@ -729,7 +791,7 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
case msg
of errMin..errMax:
writeContext(info)
frmt = posErrorFormat
frmt = PosErrorFormat
# we try to filter error messages so that not two error message
# in the same file and line are produced:
#ignoreMsg = lastError == info and eh != doAbort
@@ -737,51 +799,54 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
of warnMin..warnMax:
ignoreMsg = optWarns notin gOptions or msg notin gNotes
if not ignoreMsg: writeContext(info)
frmt = posWarningFormat
frmt = PosWarningFormat
inc(gWarnCounter)
of hintMin..hintMax:
ignoreMsg = optHints notin gOptions or msg notin gNotes
frmt = posHintFormat
frmt = PosHintFormat
inc(gHintCounter)
let s = frmt % [toMsgFilename(info), coordToStr(info.line),
coordToStr(info.col), getMessageStr(msg, arg)]
if not ignoreMsg:
MsgWriteln(s)
msgWriteln(s)
if optPrintSurroundingSrc and msg in errMin..errMax:
info.writeSurroundingSrc
handleError(msg, eh, s)
proc Fatal*(info: TLineInfo, msg: TMsgKind, arg = "") =
proc fatal*(info: TLineInfo, msg: TMsgKind, arg = "") =
liMessage(info, msg, arg, doAbort)
proc GlobalError*(info: TLineInfo, msg: TMsgKind, arg = "") =
proc globalError*(info: TLineInfo, msg: TMsgKind, arg = "") =
liMessage(info, msg, arg, doRaise)
proc GlobalError*(info: TLineInfo, arg: string) =
proc globalError*(info: TLineInfo, arg: string) =
liMessage(info, errGenerated, arg, doRaise)
proc LocalError*(info: TLineInfo, msg: TMsgKind, arg = "") =
proc localError*(info: TLineInfo, msg: TMsgKind, arg = "") =
liMessage(info, msg, arg, doNothing)
proc Message*(info: TLineInfo, msg: TMsgKind, arg = "") =
proc localError*(info: TLineInfo, arg: string) =
liMessage(info, errGenerated, arg, doNothing)
proc message*(info: TLineInfo, msg: TMsgKind, arg = "") =
liMessage(info, msg, arg, doNothing)
proc InternalError*(info: TLineInfo, errMsg: string) =
proc internalError*(info: TLineInfo, errMsg: string) =
if gCmd == cmdIdeTools: return
writeContext(info)
liMessage(info, errInternal, errMsg, doAbort)
proc InternalError*(errMsg: string) =
proc internalError*(errMsg: string) =
if gCmd == cmdIdeTools: return
writeContext(UnknownLineInfo())
writeContext(unknownLineInfo())
rawMessage(errInternal, errMsg)
template AssertNotNil*(e: expr): expr =
if e == nil: InternalError($InstantiationInfo())
template assertNotNil*(e: expr): expr =
if e == nil: internalError($instantiationInfo())
e
template InternalAssert*(e: bool): stmt =
if not e: InternalError($InstantiationInfo())
template internalAssert*(e: bool): stmt =
if not e: internalError($instantiationInfo())
proc addSourceLine*(fileIdx: int32, line: string) =
fileInfos[fileIdx].lines.add line.toRope
@@ -789,28 +854,28 @@ proc addSourceLine*(fileIdx: int32, line: string) =
proc sourceLine*(i: TLineInfo): PRope =
if i.fileIndex < 0: return nil
if not optPreserveOrigSource and
fileInfos[i.fileIndex].lines.len == 0:
for line in lines(i.toFullPath):
addSourceLine i.fileIndex, line.string
InternalAssert i.fileIndex < fileInfos.len
if not optPreserveOrigSource and fileInfos[i.fileIndex].lines.len == 0:
try:
for line in lines(i.toFullPath):
addSourceLine i.fileIndex, line.string
except EIO:
discard
internalAssert i.fileIndex < fileInfos.len
# can happen if the error points to EOF:
if i.line > fileInfos[i.fileIndex].lines.len: return nil
result = fileInfos[i.fileIndex].lines[i.line-1]
proc quotedFilename*(i: TLineInfo): PRope =
InternalAssert i.fileIndex >= 0
internalAssert i.fileIndex >= 0
result = fileInfos[i.fileIndex].quotedName
ropes.ErrorHandler = proc (err: TRopesError, msg: string, useWarning: bool) =
ropes.errorHandler = proc (err: TRopesError, msg: string, useWarning: bool) =
case err
of rInvalidFormatStr:
internalError("ropes: invalid format string: " & msg)
of rTokenTooLong:
internalError("ropes: token too long: " & msg)
of rCannotOpenFile:
rawMessage(if useWarning: warnCannotOpenFile else: errCannotOpenFile,
msg)
rawMessage(if useWarning: warnCannotOpenFile else: errCannotOpenFile, msg)

View File

@@ -49,7 +49,7 @@ proc parseExpr(L: var TLexer, tok: var TToken): bool =
var b = parseAndExpr(L, tok)
result = result or b
proc EvalppIf(L: var TLexer, tok: var TToken): bool =
proc evalppIf(L: var TLexer, tok: var TToken): bool =
ppGetTok(L, tok) # skip 'if' or 'elif'
result = parseExpr(L, tok)
if tok.tokType == tkColon: ppGetTok(L, tok)
@@ -60,7 +60,7 @@ var condStack: seq[bool] = @[]
proc doEnd(L: var TLexer, tok: var TToken) =
if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
ppGetTok(L, tok) # skip 'end'
setlen(condStack, high(condStack))
setLen(condStack, high(condStack))
type
TJumpDest = enum
@@ -75,18 +75,18 @@ proc doElse(L: var TLexer, tok: var TToken) =
proc doElif(L: var TLexer, tok: var TToken) =
if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
var res = EvalppIf(L, tok)
var res = evalppIf(L, tok)
if condStack[high(condStack)] or not res: jumpToDirective(L, tok, jdElseEndif)
else: condStack[high(condStack)] = true
proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) =
var nestedIfs = 0
while True:
while true:
if (tok.ident != nil) and (tok.ident.s == "@"):
ppGetTok(L, tok)
case whichKeyword(tok.ident)
of wIf:
Inc(nestedIfs)
inc(nestedIfs)
of wElse:
if (dest == jdElseEndif) and (nestedIfs == 0):
doElse(L, tok)
@@ -99,21 +99,21 @@ proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) =
if nestedIfs == 0:
doEnd(L, tok)
break
if nestedIfs > 0: Dec(nestedIfs)
if nestedIfs > 0: dec(nestedIfs)
else:
nil
discard
ppGetTok(L, tok)
elif tok.tokType == tkEof:
elif tok.tokType == tkEof:
lexMessage(L, errTokenExpected, "@end")
else:
else:
ppGetTok(L, tok)
proc parseDirective(L: var TLexer, tok: var TToken) =
ppGetTok(L, tok) # skip @
case whichKeyword(tok.ident)
of wIf:
setlen(condStack, len(condStack) + 1)
var res = EvalppIf(L, tok)
setLen(condStack, len(condStack) + 1)
var res = evalppIf(L, tok)
condStack[high(condStack)] = res
if not res: jumpToDirective(L, tok, jdElseEndif)
of wElif: doElif(L, tok)
@@ -121,7 +121,7 @@ proc parseDirective(L: var TLexer, tok: var TToken) =
of wEnd: doEnd(L, tok)
of wWrite:
ppGetTok(L, tok)
msgs.MsgWriteln(tokToStr(tok))
msgs.msgWriteln(tokToStr(tok))
ppGetTok(L, tok)
else:
case tok.ident.s.normalize
@@ -135,13 +135,13 @@ proc parseDirective(L: var TLexer, tok: var TToken) =
ppGetTok(L, tok)
var key = tokToStr(tok)
ppGetTok(L, tok)
os.putEnv(key, tokToStr(tok) & os.getenv(key))
os.putEnv(key, tokToStr(tok) & os.getEnv(key))
ppGetTok(L, tok)
of "appendenv":
ppGetTok(L, tok)
var key = tokToStr(tok)
ppGetTok(L, tok)
os.putEnv(key, os.getenv(key) & tokToStr(tok))
os.putEnv(key, os.getEnv(key) & tokToStr(tok))
ppGetTok(L, tok)
else: lexMessage(L, errInvalidDirectiveX, tokToStr(tok))
@@ -157,7 +157,7 @@ proc checkSymbol(L: TLexer, tok: TToken) =
proc parseAssignment(L: var TLexer, tok: var TToken) =
if tok.ident.id == getIdent("-").id or tok.ident.id == getIdent("--").id:
confTok(L, tok) # skip unnecessary prefix
var info = getLineInfo(L) # safe for later in case of an error
var info = getLineInfo(L, tok) # safe for later in case of an error
checkSymbol(L, tok)
var s = tokToStr(tok)
confTok(L, tok) # skip symbol
@@ -176,7 +176,7 @@ proc parseAssignment(L: var TLexer, tok: var TToken) =
add(val, tokToStr(tok))
confTok(L, tok)
if tok.tokType == tkBracketRi: confTok(L, tok)
else: lexMessage(L, errTokenExpected, "\']\'")
else: lexMessage(L, errTokenExpected, "']'")
add(val, ']')
if tok.tokType in {tkColon, tkEquals}:
if len(val) > 0: add(val, ':')
@@ -196,7 +196,7 @@ proc readConfigFile(filename: string) =
L: TLexer
tok: TToken
stream: PLLStream
stream = LLStreamOpen(filename, fmRead)
stream = llStreamOpen(filename, fmRead)
if stream != nil:
initToken(tok)
openLexer(L, filename, stream)
@@ -213,10 +213,13 @@ proc getUserConfigPath(filename: string): string =
proc getSystemConfigPath(filename: string): string =
# try standard configuration file (installation did not distribute files
# the UNIX way)
result = joinPath([getPrefixDir(), "config", filename])
if not ExistsFile(result): result = "/etc/" & filename
let p = getPrefixDir()
result = joinPath([p, "config", filename])
when defined(unix):
if not existsFile(result): result = joinPath([p, "etc", filename])
if not existsFile(result): result = "/etc/" & filename
proc LoadConfigs*(cfg: string) =
proc loadConfigs*(cfg: string) =
# set default value (can be overwritten):
if libpath == "":
# choose default libpath:
@@ -240,11 +243,6 @@ proc LoadConfigs*(cfg: string) =
readConfigFile(pd / cfg)
if gProjectName.len != 0:
var conffile = changeFileExt(gProjectFull, "cfg")
if conffile != pd / cfg and existsFile(conffile):
readConfigFile(conffile)
rawMessage(warnConfigDeprecated, conffile)
# new project wide config file:
readConfigFile(changeFileExt(gProjectFull, "nimrod.cfg"))

33
compiler/nimeval.nim Normal file
View File

@@ -0,0 +1,33 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## exposes the Nimrod VM to clients.
import
ast, modules, passes, passaux, condsyms,
options, nimconf, lists, sem, semdata, llstream, vm
proc execute*(program: string) =
passes.gIncludeFile = includeModule
passes.gImportModule = importModule
initDefines()
loadConfigs(DefaultConfig)
initDefines()
defineSymbol("nimrodvm")
when hasFFI: defineSymbol("nimffi")
registerPass(verbosePass)
registerPass(semPass)
registerPass(vmPass)
appendStr(searchPaths, options.libpath)
compileSystemModule()
var m = makeStdinModule()
incl(m.flags, sfMainModule)
processModule(m, llStreamOpen(program), nil)

View File

@@ -42,7 +42,7 @@ type
buf*: cstring
bufLen*: int # length of buffer in characters
stream*: PLLStream # we read from this stream
LineNumber*: int # the current line number
lineNumber*: int # the current line number
# private data:
sentinel*: int
lineStart*: int # index of last line start in buffer
@@ -54,11 +54,11 @@ proc openBaseLexer*(L: var TBaseLexer, inputstream: PLLStream,
proc closeBaseLexer*(L: var TBaseLexer)
proc getCurrentLine*(L: TBaseLexer, marker: bool = true): string
proc getColNumber*(L: TBaseLexer, pos: int): int
proc HandleCR*(L: var TBaseLexer, pos: int): int
proc handleCR*(L: var TBaseLexer, pos: int): int
# Call this if you scanned over CR in the buffer; it returns the
# position to continue the scanning from. `pos` must be the position
# of the CR.
proc HandleLF*(L: var TBaseLexer, pos: int): int
proc handleLF*(L: var TBaseLexer, pos: int): int
# Call this if you scanned over LF in the buffer; it returns the the
# position to continue the scanning from. `pos` must be the position
# of the LF.
@@ -69,9 +69,9 @@ const
proc closeBaseLexer(L: var TBaseLexer) =
dealloc(L.buf)
LLStreamClose(L.stream)
llStreamClose(L.stream)
proc FillBuffer(L: var TBaseLexer) =
proc fillBuffer(L: var TBaseLexer) =
var
charsRead, toCopy, s: int # all are in characters,
# not bytes (in case this
@@ -80,12 +80,12 @@ proc FillBuffer(L: var TBaseLexer) =
# we know here that pos == L.sentinel, but not if this proc
# is called the first time by initBaseLexer()
assert(L.sentinel < L.bufLen)
toCopy = L.BufLen - L.sentinel - 1
toCopy = L.bufLen - L.sentinel - 1
assert(toCopy >= 0)
if toCopy > 0:
MoveMem(L.buf, addr(L.buf[L.sentinel + 1]), toCopy * chrSize)
moveMem(L.buf, addr(L.buf[L.sentinel + 1]), toCopy * chrSize)
# "moveMem" handles overlapping regions
charsRead = LLStreamRead(L.stream, addr(L.buf[toCopy]),
charsRead = llStreamRead(L.stream, addr(L.buf[toCopy]),
(L.sentinel + 1) * chrSize) div chrSize
s = toCopy + charsRead
if charsRead < L.sentinel + 1:
@@ -96,7 +96,7 @@ proc FillBuffer(L: var TBaseLexer) =
dec(s) # BUGFIX (valgrind)
while true:
assert(s < L.bufLen)
while (s >= 0) and not (L.buf[s] in NewLines): Dec(s)
while (s >= 0) and not (L.buf[s] in NewLines): dec(s)
if s >= 0:
# we found an appropriate character for a sentinel:
L.sentinel = s
@@ -104,11 +104,11 @@ proc FillBuffer(L: var TBaseLexer) =
else:
# rather than to give up here because the line is too long,
# double the buffer's size and try again:
oldBufLen = L.BufLen
L.bufLen = L.BufLen * 2
oldBufLen = L.bufLen
L.bufLen = L.bufLen * 2
L.buf = cast[cstring](realloc(L.buf, L.bufLen * chrSize))
assert(L.bufLen - oldBuflen == oldBufLen)
charsRead = LLStreamRead(L.stream, addr(L.buf[oldBufLen]),
assert(L.bufLen - oldBufLen == oldBufLen)
charsRead = llStreamRead(L.stream, addr(L.buf[oldBufLen]),
oldBufLen * chrSize) div chrSize
if charsRead < oldBufLen:
L.buf[oldBufLen + charsRead] = EndOfFile
@@ -126,20 +126,20 @@ proc fillBaseLexer(L: var TBaseLexer, pos: int): int =
result = 0
L.lineStart = result
proc HandleCR(L: var TBaseLexer, pos: int): int =
proc handleCR(L: var TBaseLexer, pos: int): int =
assert(L.buf[pos] == CR)
inc(L.linenumber)
inc(L.lineNumber)
result = fillBaseLexer(L, pos)
if L.buf[result] == LF:
result = fillBaseLexer(L, result)
proc HandleLF(L: var TBaseLexer, pos: int): int =
proc handleLF(L: var TBaseLexer, pos: int): int =
assert(L.buf[pos] == LF)
inc(L.linenumber)
inc(L.lineNumber)
result = fillBaseLexer(L, pos) #L.lastNL := result-1; // BUGFIX: was: result;
proc skip_UTF_8_BOM(L: var TBaseLexer) =
if (L.buf[0] == '\xEF') and (L.buf[1] == '\xBB') and (L.buf[2] == '\xBF'):
proc skipUTF8BOM(L: var TBaseLexer) =
if L.buf[0] == '\xEF' and L.buf[1] == '\xBB' and L.buf[2] == '\xBF':
inc(L.bufpos, 3)
inc(L.lineStart, 3)
@@ -150,10 +150,10 @@ proc openBaseLexer(L: var TBaseLexer, inputstream: PLLStream, bufLen = 8192) =
L.buf = cast[cstring](alloc(bufLen * chrSize))
L.sentinel = bufLen - 1
L.lineStart = 0
L.linenumber = 1 # lines start at 1
L.lineNumber = 1 # lines start at 1
L.stream = inputstream
fillBuffer(L)
skip_UTF_8_BOM(L)
skipUTF8BOM(L)
proc getColNumber(L: TBaseLexer, pos: int): int =
result = abs(pos - L.lineStart)
@@ -166,5 +166,4 @@ proc getCurrentLine(L: TBaseLexer, marker: bool = true): string =
inc(i)
result.add("\n")
if marker:
result.add(RepeatChar(getColNumber(L, L.bufpos)) & '^' & "\n")
result.add(repeatChar(getColNumber(L, L.bufpos)) & '^' & "\n")

View File

@@ -1,591 +0,0 @@
digraph nimrod {
times -> strutils;
os -> strutils;
os -> times;
posix -> times;
os -> posix;
nhashes -> strutils;
nstrtabs -> os;
nstrtabs -> nhashes;
nstrtabs -> strutils;
options -> os;
options -> lists;
options -> strutils;
options -> nstrtabs;
msgs -> options;
msgs -> strutils;
msgs -> os;
crc -> strutils;
platform -> strutils;
ropes -> msgs;
ropes -> strutils;
ropes -> platform;
ropes -> nhashes;
ropes -> crc;
idents -> nhashes;
idents -> strutils;
ast -> msgs;
ast -> nhashes;
ast -> nversion;
ast -> options;
ast -> strutils;
ast -> crc;
ast -> ropes;
ast -> idents;
ast -> lists;
astalgo -> ast;
astalgo -> nhashes;
astalgo -> strutils;
astalgo -> options;
astalgo -> msgs;
astalgo -> ropes;
astalgo -> idents;
condsyms -> ast;
condsyms -> astalgo;
condsyms -> msgs;
condsyms -> nhashes;
condsyms -> platform;
condsyms -> strutils;
condsyms -> idents;
hashes -> strutils;
strtabs -> os;
strtabs -> hashes;
strtabs -> strutils;
osproc -> strutils;
osproc -> os;
osproc -> strtabs;
osproc -> streams;
osproc -> posix;
extccomp -> lists;
extccomp -> ropes;
extccomp -> os;
extccomp -> strutils;
extccomp -> osproc;
extccomp -> platform;
extccomp -> condsyms;
extccomp -> options;
extccomp -> msgs;
wordrecg -> nhashes;
wordrecg -> strutils;
wordrecg -> idents;
commands -> os;
commands -> msgs;
commands -> options;
commands -> nversion;
commands -> condsyms;
commands -> strutils;
commands -> extccomp;
commands -> platform;
commands -> lists;
commands -> wordrecg;
llstream -> strutils;
lexbase -> llstream;
lexbase -> strutils;
scanner -> nhashes;
scanner -> options;
scanner -> msgs;
scanner -> strutils;
scanner -> platform;
scanner -> idents;
scanner -> lexbase;
scanner -> llstream;
scanner -> wordrecg;
nimconf -> llstream;
nimconf -> nversion;
nimconf -> commands;
nimconf -> os;
nimconf -> strutils;
nimconf -> msgs;
nimconf -> platform;
nimconf -> condsyms;
nimconf -> scanner;
nimconf -> options;
nimconf -> idents;
nimconf -> wordrecg;
pnimsyn -> llstream;
pnimsyn -> scanner;
pnimsyn -> idents;
pnimsyn -> strutils;
pnimsyn -> ast;
pnimsyn -> msgs;
pbraces -> llstream;
pbraces -> scanner;
pbraces -> idents;
pbraces -> strutils;
pbraces -> ast;
pbraces -> msgs;
pbraces -> pnimsyn;
rnimsyn -> scanner;
rnimsyn -> options;
rnimsyn -> idents;
rnimsyn -> strutils;
rnimsyn -> ast;
rnimsyn -> msgs;
rnimsyn -> lists;
filters -> llstream;
filters -> os;
filters -> wordrecg;
filters -> idents;
filters -> strutils;
filters -> ast;
filters -> astalgo;
filters -> msgs;
filters -> options;
filters -> rnimsyn;
ptmplsyn -> llstream;
ptmplsyn -> os;
ptmplsyn -> wordrecg;
ptmplsyn -> idents;
ptmplsyn -> strutils;
ptmplsyn -> ast;
ptmplsyn -> astalgo;
ptmplsyn -> msgs;
ptmplsyn -> options;
ptmplsyn -> rnimsyn;
ptmplsyn -> filters;
syntaxes -> strutils;
syntaxes -> llstream;
syntaxes -> ast;
syntaxes -> astalgo;
syntaxes -> idents;
syntaxes -> scanner;
syntaxes -> options;
syntaxes -> msgs;
syntaxes -> pnimsyn;
syntaxes -> pbraces;
syntaxes -> ptmplsyn;
syntaxes -> filters;
syntaxes -> rnimsyn;
paslex -> nhashes;
paslex -> options;
paslex -> msgs;
paslex -> strutils;
paslex -> platform;
paslex -> idents;
paslex -> lexbase;
paslex -> wordrecg;
paslex -> scanner;
pasparse -> os;
pasparse -> llstream;
pasparse -> scanner;
pasparse -> paslex;
pasparse -> idents;
pasparse -> wordrecg;
pasparse -> strutils;
pasparse -> ast;
pasparse -> astalgo;
pasparse -> msgs;
pasparse -> options;
rodread -> os;
rodread -> options;
rodread -> strutils;
rodread -> nversion;
rodread -> ast;
rodread -> astalgo;
rodread -> msgs;
rodread -> platform;
rodread -> condsyms;
rodread -> ropes;
rodread -> idents;
rodread -> crc;
trees -> ast;
trees -> astalgo;
trees -> scanner;
trees -> msgs;
trees -> strutils;
types -> ast;
types -> astalgo;
types -> trees;
types -> msgs;
types -> strutils;
types -> platform;
magicsys -> ast;
magicsys -> astalgo;
magicsys -> nhashes;
magicsys -> msgs;
magicsys -> platform;
magicsys -> nversion;
magicsys -> times;
magicsys -> idents;
magicsys -> rodread;
nimsets -> ast;
nimsets -> astalgo;
nimsets -> trees;
nimsets -> nversion;
nimsets -> msgs;
nimsets -> platform;
nimsets -> bitsets;
nimsets -> types;
nimsets -> rnimsyn;
passes -> strutils;
passes -> lists;
passes -> options;
passes -> ast;
passes -> astalgo;
passes -> llstream;
passes -> msgs;
passes -> platform;
passes -> os;
passes -> condsyms;
passes -> idents;
passes -> rnimsyn;
passes -> types;
passes -> extccomp;
passes -> math;
passes -> magicsys;
passes -> nversion;
passes -> nimsets;
passes -> syntaxes;
passes -> times;
passes -> rodread;
treetab -> nhashes;
treetab -> ast;
treetab -> astalgo;
treetab -> types;
semdata -> strutils;
semdata -> lists;
semdata -> options;
semdata -> scanner;
semdata -> ast;
semdata -> astalgo;
semdata -> trees;
semdata -> treetab;
semdata -> wordrecg;
semdata -> ropes;
semdata -> msgs;
semdata -> platform;
semdata -> os;
semdata -> condsyms;
semdata -> idents;
semdata -> rnimsyn;
semdata -> types;
semdata -> extccomp;
semdata -> math;
semdata -> magicsys;
semdata -> nversion;
semdata -> nimsets;
semdata -> pnimsyn;
semdata -> times;
semdata -> passes;
semdata -> rodread;
lookups -> ast;
lookups -> astalgo;
lookups -> idents;
lookups -> semdata;
lookups -> types;
lookups -> msgs;
lookups -> options;
lookups -> rodread;
lookups -> rnimsyn;
importer -> strutils;
importer -> os;
importer -> ast;
importer -> astalgo;
importer -> msgs;
importer -> options;
importer -> idents;
importer -> rodread;
importer -> lookups;
importer -> semdata;
importer -> passes;
rodwrite -> os;
rodwrite -> options;
rodwrite -> strutils;
rodwrite -> nversion;
rodwrite -> ast;
rodwrite -> astalgo;
rodwrite -> msgs;
rodwrite -> platform;
rodwrite -> condsyms;
rodwrite -> ropes;
rodwrite -> idents;
rodwrite -> crc;
rodwrite -> rodread;
rodwrite -> passes;
rodwrite -> importer;
semfold -> strutils;
semfold -> lists;
semfold -> options;
semfold -> ast;
semfold -> astalgo;
semfold -> trees;
semfold -> treetab;
semfold -> nimsets;
semfold -> times;
semfold -> nversion;
semfold -> platform;
semfold -> math;
semfold -> msgs;
semfold -> os;
semfold -> condsyms;
semfold -> idents;
semfold -> rnimsyn;
semfold -> types;
evals -> strutils;
evals -> magicsys;
evals -> lists;
evals -> options;
evals -> ast;
evals -> astalgo;
evals -> trees;
evals -> treetab;
evals -> nimsets;
evals -> msgs;
evals -> os;
evals -> condsyms;
evals -> idents;
evals -> rnimsyn;
evals -> types;
evals -> passes;
evals -> semfold;
procfind -> ast;
procfind -> astalgo;
procfind -> msgs;
procfind -> semdata;
procfind -> types;
procfind -> trees;
pragmas -> os;
pragmas -> platform;
pragmas -> condsyms;
pragmas -> ast;
pragmas -> astalgo;
pragmas -> idents;
pragmas -> semdata;
pragmas -> msgs;
pragmas -> rnimsyn;
pragmas -> wordrecg;
pragmas -> ropes;
pragmas -> options;
pragmas -> strutils;
pragmas -> lists;
pragmas -> extccomp;
pragmas -> math;
pragmas -> magicsys;
pragmas -> trees;
sem -> strutils;
sem -> nhashes;
sem -> lists;
sem -> options;
sem -> scanner;
sem -> ast;
sem -> astalgo;
sem -> trees;
sem -> treetab;
sem -> wordrecg;
sem -> ropes;
sem -> msgs;
sem -> os;
sem -> condsyms;
sem -> idents;
sem -> rnimsyn;
sem -> types;
sem -> platform;
sem -> math;
sem -> magicsys;
sem -> pnimsyn;
sem -> nversion;
sem -> nimsets;
sem -> semdata;
sem -> evals;
sem -> semfold;
sem -> importer;
sem -> procfind;
sem -> lookups;
sem -> rodread;
sem -> pragmas;
sem -> passes;
rst -> os;
rst -> msgs;
rst -> strutils;
rst -> platform;
rst -> nhashes;
rst -> ropes;
rst -> options;
highlite -> nhashes;
highlite -> options;
highlite -> msgs;
highlite -> strutils;
highlite -> platform;
highlite -> idents;
highlite -> lexbase;
highlite -> wordrecg;
highlite -> scanner;
docgen -> ast;
docgen -> astalgo;
docgen -> strutils;
docgen -> nhashes;
docgen -> options;
docgen -> nversion;
docgen -> msgs;
docgen -> os;
docgen -> ropes;
docgen -> idents;
docgen -> wordrecg;
docgen -> math;
docgen -> syntaxes;
docgen -> rnimsyn;
docgen -> scanner;
docgen -> rst;
docgen -> times;
docgen -> highlite;
ccgutils -> ast;
ccgutils -> astalgo;
ccgutils -> ropes;
ccgutils -> lists;
ccgutils -> nhashes;
ccgutils -> strutils;
ccgutils -> types;
ccgutils -> msgs;
cgmeth -> options;
cgmeth -> ast;
cgmeth -> astalgo;
cgmeth -> msgs;
cgmeth -> idents;
cgmeth -> rnimsyn;
cgmeth -> types;
cgmeth -> magicsys;
cgen -> ast;
cgen -> astalgo;
cgen -> strutils;
cgen -> nhashes;
cgen -> trees;
cgen -> platform;
cgen -> magicsys;
cgen -> extccomp;
cgen -> options;
cgen -> nversion;
cgen -> nimsets;
cgen -> msgs;
cgen -> crc;
cgen -> bitsets;
cgen -> idents;
cgen -> lists;
cgen -> types;
cgen -> ccgutils;
cgen -> os;
cgen -> times;
cgen -> ropes;
cgen -> math;
cgen -> passes;
cgen -> rodread;
cgen -> wordrecg;
cgen -> rnimsyn;
cgen -> treetab;
cgen -> cgmeth;
jsgen -> ast;
jsgen -> astalgo;
jsgen -> strutils;
jsgen -> nhashes;
jsgen -> trees;
jsgen -> platform;
jsgen -> magicsys;
jsgen -> extccomp;
jsgen -> options;
jsgen -> nversion;
jsgen -> nimsets;
jsgen -> msgs;
jsgen -> crc;
jsgen -> bitsets;
jsgen -> idents;
jsgen -> lists;
jsgen -> types;
jsgen -> os;
jsgen -> times;
jsgen -> ropes;
jsgen -> math;
jsgen -> passes;
jsgen -> ccgutils;
jsgen -> wordrecg;
jsgen -> rnimsyn;
jsgen -> rodread;
interact -> llstream;
interact -> strutils;
interact -> ropes;
interact -> nstrtabs;
interact -> msgs;
passaux -> strutils;
passaux -> ast;
passaux -> astalgo;
passaux -> passes;
passaux -> msgs;
passaux -> options;
depends -> os;
depends -> options;
depends -> ast;
depends -> astalgo;
depends -> msgs;
depends -> ropes;
depends -> idents;
depends -> passes;
depends -> importer;
transf -> strutils;
transf -> lists;
transf -> options;
transf -> ast;
transf -> astalgo;
transf -> trees;
transf -> treetab;
transf -> evals;
transf -> msgs;
transf -> os;
transf -> idents;
transf -> rnimsyn;
transf -> types;
transf -> passes;
transf -> semfold;
transf -> magicsys;
transf -> cgmeth;
main -> llstream;
main -> strutils;
main -> ast;
main -> astalgo;
main -> scanner;
main -> syntaxes;
main -> rnimsyn;
main -> options;
main -> msgs;
main -> os;
main -> lists;
main -> condsyms;
main -> paslex;
main -> pasparse;
main -> rodread;
main -> rodwrite;
main -> ropes;
main -> trees;
main -> wordrecg;
main -> sem;
main -> semdata;
main -> idents;
main -> passes;
main -> docgen;
main -> extccomp;
main -> cgen;
main -> jsgen;
main -> platform;
main -> interact;
main -> nimconf;
main -> importer;
main -> passaux;
main -> depends;
main -> transf;
main -> evals;
main -> types;
parseopt -> os;
parseopt -> strutils;
nimrod -> times;
nimrod -> commands;
nimrod -> scanner;
nimrod -> condsyms;
nimrod -> options;
nimrod -> msgs;
nimrod -> nversion;
nimrod -> nimconf;
nimrod -> ropes;
nimrod -> extccomp;
nimrod -> strutils;
nimrod -> os;
nimrod -> platform;
nimrod -> main;
nimrod -> parseopt;
}

View File

@@ -1,9 +1,17 @@
[Project]
Name: "Nimrod"
Version: "$version"
; Windows and i386 must be first!
OS: "windows;linux;macosx;solaris;freebsd;netbsd;openbsd"
CPU: "i386;amd64;powerpc64;arm" # ;sparc
Platforms: """
windows: i386;amd64
linux: i386;amd64;powerpc64;arm;sparc;mips
macosx: i386;amd64;powerpc64
solaris: i386;amd64;sparc
freebsd: i386;amd64
netbsd: i386;amd64
openbsd: i386;amd64
haiku: i386;amd64
"""
Authors: "Andreas Rumpf"
Description: """This is the Nimrod Compiler. Nimrod is a new statically typed,
imperative programming language, that supports procedural, functional, object
@@ -35,9 +43,8 @@ Start: "doc/overview.html"
[Other]
Files: "readme.txt;install.txt;contributors.txt"
Files: "readme.txt;install.txt;contributors.txt;copying.txt"
Files: "configure;makefile"
Files: "gpl.html"
Files: "*.ini"
Files: "koch.nim"
@@ -54,6 +61,11 @@ Files: "compiler/readme.txt"
Files: "compiler/nimrod.ini"
Files: "compiler/nimrod.cfg"
Files: "compiler/*.nim"
Files: "compiler/c2nim/*.nim"
Files: "compiler/c2nim/*.cfg"
Files: "compiler/pas2nim/*.nim"
Files: "compiler/pas2nim/*.cfg"
Files: "build/empty.txt"
Files: "bin/empty.txt"
@@ -137,5 +149,5 @@ flags = "-w"
buildDepends: "gcc (>= 4:4.3.2)"
pkgDepends: "gcc (>= 4:4.3.2)"
shortDesc: "The Nimrod Compiler"
licenses: "bin/nimrod,gpl2;lib/*,lgpl;"
licenses: "bin/nimrod,MIT;lib/*,MIT;"

View File

@@ -13,9 +13,9 @@ when defined(gcc) and defined(windows):
else:
{.link: "icons/nimrod_icon.o".}
import
commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,
extccomp, strutils, os, platform, main, parseopt, service
import
commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,
extccomp, strutils, os, osproc, platform, main, parseopt, service
when hasTinyCBackend:
import tccgen
@@ -23,7 +23,7 @@ when hasTinyCBackend:
when defined(profiler) or defined(memProfiler):
{.hint: "Profiling support is turned on!".}
import nimprof
proc prependCurDir(f: string): string =
when defined(unix):
if os.isAbsolute(f): result = f
@@ -31,12 +31,12 @@ proc prependCurDir(f: string): string =
else:
result = f
proc HandleCmdLine() =
proc handleCmdLine() =
if paramCount() == 0:
writeCommandLineUsage()
else:
# Process command line arguments:
ProcessCmdLine(passCmd1, "")
processCmdLine(passCmd1, "")
if gProjectName != "":
try:
gProjectFull = canonicalizePath(gProjectName)
@@ -47,12 +47,12 @@ proc HandleCmdLine() =
gProjectName = p.name
else:
gProjectPath = getCurrentDir()
LoadConfigs(DefaultConfig) # load all config files
loadConfigs(DefaultConfig) # load all config files
# now process command line arguments again, because some options in the
# command line can overwite the config file's settings
extccomp.initVars()
ProcessCmdLine(passCmd2, "")
MainCommand()
processCmdLine(passCmd2, "")
mainCommand()
if gVerbosity >= 2: echo(GC_getStatistics())
#echo(GC_getStatistics())
if msgs.gErrorCounter == 0:
@@ -61,12 +61,22 @@ proc HandleCmdLine() =
tccgen.run()
if optRun in gGlobalOptions:
if gCmd == cmdCompileToJS:
var ex = quoteIfContainsWhite(
completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir))
var ex: string
if options.outFile.len > 0:
ex = options.outFile.prependCurDir.quoteShell
else:
ex = quoteShell(
completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir))
execExternalProgram("node " & ex & ' ' & service.arguments)
else:
var ex = quoteIfContainsWhite(
changeFileExt(gProjectFull, exeExt).prependCurDir)
var binPath: string
if options.outFile.len > 0:
# If the user specified an outFile path, use that directly.
binPath = options.outFile.prependCurDir
else:
# Figure out ourselves a valid binary name.
binPath = changeFileExt(gProjectFull, ExeExt).prependCurDir
var ex = quoteShell(binPath)
execExternalProgram(ex & ' ' & service.arguments)
when defined(GC_setMaxPause):
@@ -75,6 +85,8 @@ when defined(GC_setMaxPause):
when compileOption("gc", "v2") or compileOption("gc", "refc"):
# the new correct mark&sweet collector is too slow :-/
GC_disableMarkAndSweep()
condsyms.InitDefines()
HandleCmdLine()
quit(int8(msgs.gErrorCounter > 0))
condsyms.initDefines()
when not defined(selftest):
handleCmdLine()
quit(int8(msgs.gErrorCounter > 0))

View File

@@ -2,6 +2,8 @@
mainModule:"nimrod.nim"
# gc:markAndSweep
hint[XDeclaredButNotUsed]:off
path:"llvm"
path:"$projectPath/.."
@@ -9,4 +11,13 @@ path:"$projectPath/.."
path:"$lib/packages/docutils"
define:booting
import:testability
@if windows:
cincludes: "$lib/wrappers/libffi/common"
@end
define:useStdoutAsStdmsg
cs:partial
#define:useNodeIds

View File

@@ -18,7 +18,7 @@ proc overlap*(a, b: PNode): bool
proc inSet*(s: PNode, elem: PNode): bool
proc someInSet*(s: PNode, a, b: PNode): bool
proc emptyRange*(a, b: PNode): bool
proc SetHasRange*(s: PNode): bool
proc setHasRange*(s: PNode): bool
# returns true if set contains a range (needed by the code generator)
# these are used for constant folding:
proc unionSets*(a, b: PNode): PNode
@@ -32,7 +32,7 @@ proc cardSet*(s: PNode): BiggestInt
proc inSet(s: PNode, elem: PNode): bool =
if s.kind != nkCurly:
InternalError(s.info, "inSet")
internalError(s.info, "inSet")
return false
for i in countup(0, sonsLen(s) - 1):
if s.sons[i].kind == nkRange:
@@ -58,10 +58,10 @@ proc overlap(a, b: PNode): bool =
else:
result = sameValue(a, b)
proc SomeInSet(s: PNode, a, b: PNode): bool =
proc someInSet(s: PNode, a, b: PNode): bool =
# checks if some element of a..b is in the set s
if s.kind != nkCurly:
InternalError(s.info, "SomeInSet")
internalError(s.info, "SomeInSet")
return false
for i in countup(0, sonsLen(s) - 1):
if s.sons[i].kind == nkRange:
@@ -82,12 +82,12 @@ proc toBitSet(s: PNode, b: var TBitSet) =
if s.sons[i].kind == nkRange:
j = getOrdValue(s.sons[i].sons[0])
while j <= getOrdValue(s.sons[i].sons[1]):
BitSetIncl(b, j - first)
bitSetIncl(b, j - first)
inc(j)
else:
BitSetIncl(b, getOrdValue(s.sons[i]) - first)
bitSetIncl(b, getOrdValue(s.sons[i]) - first)
proc ToTreeSet(s: TBitSet, settype: PType, info: TLineInfo): PNode =
proc toTreeSet(s: TBitSet, settype: PType, info: TLineInfo): PNode =
var
a, b, e, first: BiggestInt # a, b are interval borders
elemType: PType
@@ -98,14 +98,14 @@ proc ToTreeSet(s: TBitSet, settype: PType, info: TLineInfo): PNode =
result.typ = settype
result.info = info
e = 0
while e < len(s) * elemSize:
while e < len(s) * ElemSize:
if bitSetIn(s, e):
a = e
b = e
while true:
Inc(b)
if (b >= len(s) * elemSize) or not bitSetIn(s, b): break
Dec(b)
inc(b)
if (b >= len(s) * ElemSize) or not bitSetIn(s, b): break
dec(b)
if a == b:
addSon(result, newIntTypeNode(nkIntLit, a + first, elemType))
else:
@@ -115,34 +115,19 @@ proc ToTreeSet(s: TBitSet, settype: PType, info: TLineInfo): PNode =
addSon(n, newIntTypeNode(nkIntLit, b + first, elemType))
addSon(result, n)
e = b
Inc(e)
inc(e)
type
TSetOP = enum
soUnion, soDiff, soSymDiff, soIntersect
proc nodeSetOp(a, b: PNode, op: TSetOp): PNode =
template nodeSetOp(a, b: PNode, op: expr) {.dirty.} =
var x, y: TBitSet
toBitSet(a, x)
toBitSet(b, y)
case op
of soUnion: BitSetUnion(x, y)
of soDiff: BitSetDiff(x, y)
of soSymDiff: BitSetSymDiff(x, y)
of soIntersect: BitSetIntersect(x, y)
op(x, y)
result = toTreeSet(x, a.typ, a.info)
proc unionSets(a, b: PNode): PNode =
result = nodeSetOp(a, b, soUnion)
proc diffSets(a, b: PNode): PNode =
result = nodeSetOp(a, b, soDiff)
proc intersectSets(a, b: PNode): PNode =
result = nodeSetOp(a, b, soIntersect)
proc symdiffSets(a, b: PNode): PNode =
result = nodeSetOp(a, b, soSymDiff)
proc unionSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetUnion)
proc diffSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetDiff)
proc intersectSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetIntersect)
proc symdiffSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetSymDiff)
proc containsSets(a, b: PNode): bool =
var x, y: TBitSet
@@ -156,6 +141,12 @@ proc equalSets(a, b: PNode): bool =
toBitSet(b, y)
result = bitSetEquals(x, y)
proc complement*(a: PNode): PNode =
var x: TBitSet
toBitSet(a, x)
for i in countup(0, high(x)): x[i] = not x[i]
result = toTreeSet(x, a.typ, a.info)
proc cardSet(s: PNode): BiggestInt =
# here we can do better than converting it into a compact set
# we just count the elements directly
@@ -165,11 +156,11 @@ proc cardSet(s: PNode): BiggestInt =
result = result + getOrdValue(s.sons[i].sons[1]) -
getOrdValue(s.sons[i].sons[0]) + 1
else:
Inc(result)
inc(result)
proc SetHasRange(s: PNode): bool =
proc setHasRange(s: PNode): bool =
if s.kind != nkCurly:
InternalError(s.info, "SetHasRange")
internalError(s.info, "SetHasRange")
return false
for i in countup(0, sonsLen(s) - 1):
if s.sons[i].kind == nkRange:

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -15,8 +15,8 @@ const
defaultAsmMarkerSymbol* = '!'
VersionMajor* = 0
VersionMinor* = 9
VersionPatch* = 2
VersionPatch* = 4
VersionAsString* = $VersionMajor & "." & $VersionMinor & "." & $VersionPatch
RodFileVersion* = "1212" # modify this if the rod-format changes!
RodFileVersion* = "1215" # modify this if the rod-format changes!

View File

@@ -8,13 +8,15 @@
#
import
os, lists, strutils, strtabs
os, lists, strutils, strtabs, osproc, sets
const
hasTinyCBackend* = defined(tinyc)
useEffectSystem* = true
hasFFI* = defined(useFFI)
newScopeForIf* = false # XXX activate for 0.9.4
newScopeForIf* = true
useCaas* = not defined(noCaas)
noTimeMachine = defined(avoidTimeMachine) and defined(macosx)
type # please make sure we have under 32 options
# (improves code efficiency a lot!)
@@ -92,13 +94,15 @@ var
gOptions*: TOptions = {optObjCheck, optFieldCheck, optRangeCheck,
optBoundsCheck, optOverflowCheck, optAssert, optWarns,
optHints, optStackTrace, optLineTrace,
optPatterns}
gGlobalOptions*: TGlobalOptions = {optThreadAnalysis}
optPatterns, optNilCheck}
gGlobalOptions*: TGlobalOptions = {}
gExitcode*: int8
gCmd*: TCommands = cmdNone # the command
gSelectedGC* = gcRefc # the selected GC
searchPaths*, lazyPaths*: TLinkedList
outFile*: string = ""
docSeeSrcUrl*: string = "" # if empty, no seeSrc will be generated. \
# The string uses the formatting variables `path` and `line`.
headerFile*: string = ""
gVerbosity* = 1 # how verbose the compiler is
gNumberOfProcessors*: int # number of processors
@@ -110,6 +114,7 @@ var
gDirtyBufferIdx* = 0'i32 # indicates the fileIdx of the dirty version of
# the tracked source X, saved by the CAAS client.
gDirtyOriginalIdx* = 0'i32 # the original source file of the dirtified buffer.
gNoBabelPath* = false
proc importantComments*(): bool {.inline.} = gCmd in {cmdDoc, cmdIdeTools}
proc usesNativeGC*(): bool {.inline.} = gSelectedGC >= gcRefc
@@ -131,6 +136,7 @@ const
NimExt* = "nim"
RodExt* = "rod"
HtmlExt* = "html"
JsonExt* = "json"
TexExt* = "tex"
IniExt* = "ini"
DefaultConfig* = "nimrod.cfg"
@@ -140,7 +146,7 @@ const
# additional configuration variables:
var
gConfigVars* = newStringTable(modeStyleInsensitive)
gDllOverrides = newStringtable(modeCaseInsensitive)
gDllOverrides = newStringTable(modeCaseInsensitive)
libpath* = ""
gProjectName* = "" # holds a name like 'nimrod'
gProjectPath* = "" # holds a path like /home/alice/projects/nimrod/compiler/
@@ -180,7 +186,7 @@ proc getOutFile*(filename, ext: string): string =
proc getPrefixDir*(): string =
## gets the application directory
result = SplitPath(getAppDir()).head
result = splitPath(getAppDir()).head
proc canonicalizePath*(path: string): string =
result = path.expandFilename
@@ -188,16 +194,16 @@ proc canonicalizePath*(path: string): string =
proc shortenDir*(dir: string): string =
## returns the interesting part of a dir
var prefix = getPrefixDir() & dirSep
var prefix = getPrefixDir() & DirSep
if startsWith(dir, prefix):
return substr(dir, len(prefix))
prefix = gProjectPath & dirSep
prefix = gProjectPath & DirSep
if startsWith(dir, prefix):
return substr(dir, len(prefix))
result = dir
proc removeTrailingDirSep*(path: string): string =
if (len(path) > 0) and (path[len(path) - 1] == dirSep):
if (len(path) > 0) and (path[len(path) - 1] == DirSep):
result = substr(path, 0, len(path) - 2)
else:
result = path
@@ -205,7 +211,52 @@ proc removeTrailingDirSep*(path: string): string =
proc getGeneratedPath: string =
result = if nimcacheDir.len > 0: nimcacheDir else: gProjectPath.shortenDir /
genSubDir
template newPackageCache(): expr =
newStringTable(when FileSystemCaseSensitive:
modeCaseInsensitive
else:
modeCaseSensitive)
var packageCache = newPackageCache()
proc resetPackageCache*() = packageCache = newPackageCache()
iterator myParentDirs(p: string): string =
# XXX os's parentDirs is stupid (multiple yields) and triggers an old bug...
var current = p
while true:
current = current.parentDir
if current.len == 0: break
yield current
proc getPackageName*(path: string): string =
var parents = 0
block packageSearch:
for d in myParentDirs(path):
if packageCache.hasKey(d):
#echo "from cache ", d, " |", packageCache[d], "|", path.splitFile.name
return packageCache[d]
inc parents
for file in walkFiles(d / "*.babel"):
result = file.splitFile.name
break packageSearch
# we also store if we didn't find anything:
if result.isNil: result = ""
for d in myParentDirs(path):
#echo "set cache ", d, " |", result, "|", parents
packageCache[d] = result
dec parents
if parents <= 0: break
proc withPackageName*(path: string): string =
let x = path.getPackageName
if x.len == 0:
result = path
else:
let (p, file, ext) = path.splitFile
result = (p / (x & '_' & file)) & ext
proc toGeneratedFile*(path, ext: string): string =
## converts "/home/a/mymodule.nim", "rod" to "/home/a/nimcache/mymodule.rod"
var (head, tail) = splitPath(path)
@@ -213,6 +264,28 @@ proc toGeneratedFile*(path, ext: string): string =
result = joinPath([getGeneratedPath(), changeFileExt(tail, ext)])
#echo "toGeneratedFile(", path, ", ", ext, ") = ", result
when noTimeMachine:
var alreadyExcludedDirs = initSet[string]()
proc excludeDirFromTimeMachine(dir: string) {.raises: [].} =
## Calls a macosx command on the directory to exclude it from backups.
##
## The macosx tmutil command is invoked to mark the specified path as an
## item to be excluded from time machine backups. If a path already exists
## with files before excluding it, newer files won't be added to the
## directory, but previous files won't be removed from the backup until the
## user deletes that directory.
##
## The whole proc is optional and will ignore all kinds of errors. The only
## way to be sure that it works is to call ``tmutil isexcluded path``.
if alreadyExcludedDirs.contains(dir): return
alreadyExcludedDirs.incl(dir)
try:
var p = startProcess("/usr/bin/tmutil", args = ["addexclusion", dir])
discard p.waitForExit
p.close
except E_Base, EOS:
discard
proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string =
var (head, tail) = splitPath(f)
#if len(head) > 0: head = removeTrailingDirSep(shortenDir(head & dirSep))
@@ -220,21 +293,23 @@ proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string =
if createSubDir:
try:
createDir(subdir)
when noTimeMachine:
excludeDirFromTimeMachine(subdir)
except EOS:
writeln(stdout, "cannot create directory: " & subdir)
quit(1)
result = joinPath(subdir, tail)
#echo "completeGeneratedFilePath(", f, ") = ", result
iterator iterSearchPath*(SearchPaths: TLinkedList): string =
var it = PStrEntry(SearchPaths.head)
iterator iterSearchPath*(searchPaths: TLinkedList): string =
var it = PStrEntry(searchPaths.head)
while it != nil:
yield it.data
it = PStrEntry(it.Next)
it = PStrEntry(it.next)
proc rawFindFile(f: string): string =
for it in iterSearchPath(SearchPaths):
result = JoinPath(it, f)
for it in iterSearchPath(searchPaths):
result = joinPath(it, f)
if existsFile(result):
return result.canonicalizePath
result = ""
@@ -242,14 +317,14 @@ proc rawFindFile(f: string): string =
proc rawFindFile2(f: string): string =
var it = PStrEntry(lazyPaths.head)
while it != nil:
result = JoinPath(it.data, f)
result = joinPath(it.data, f)
if existsFile(result):
bringToFront(lazyPaths, it)
return result.canonicalizePath
it = PStrEntry(it.Next)
it = PStrEntry(it.next)
result = ""
proc FindFile*(f: string): string {.procvar.} =
proc findFile*(f: string): string {.procvar.} =
result = f.rawFindFile
if result.len == 0:
result = f.toLower.rawFindFile
@@ -258,9 +333,13 @@ proc FindFile*(f: string): string {.procvar.} =
if result.len == 0:
result = f.toLower.rawFindFile2
proc findModule*(modulename: string): string {.inline.} =
proc findModule*(modulename, currentModule: string): string =
# returns path to module
result = FindFile(AddFileExt(modulename, nimExt))
let m = addFileExt(modulename, NimExt)
let currentPath = currentModule.splitFile.dir
result = currentPath / m
if not existsFile(result):
result = findFile(m)
proc libCandidates*(s: string, dest: var seq[string]) =
var le = strutils.find(s, '(')
@@ -287,7 +366,7 @@ proc inclDynlibOverride*(lib: string) =
proc isDynlibOverride*(lib: string): bool =
result = gDllOverrides.hasKey(lib.canonDynlibName)
proc binaryStrSearch*(x: openarray[string], y: string): int =
proc binaryStrSearch*(x: openArray[string], y: string): int =
var a = 0
var b = len(x) - 1
while a <= b:

View File

@@ -42,7 +42,7 @@ const
MaxStackSize* = 64 ## max required stack size by the VM
proc patternError(n: PNode) =
LocalError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
localError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
proc add(code: var TPatternCode, op: TOpcode) {.inline.} =
add(code, chr(ord(op)))
@@ -50,6 +50,8 @@ proc add(code: var TPatternCode, op: TOpcode) {.inline.} =
proc whichAlias*(p: PSym): TAliasRequest =
if p.constraint != nil:
result = TAliasRequest(p.constraint.strVal[0].ord)
else:
result = aqNone
proc compileConstraints(p: PNode, result: var TPatternCode) =
case p.kind
@@ -95,14 +97,14 @@ proc compileConstraints(p: PNode, result: var TPatternCode) =
of "nosideeffect": result.add(ppNoSideEffect)
else:
# check all symkinds:
InternalAssert int(high(TSymKind)) < 255
internalAssert int(high(TSymKind)) < 255
for i in low(TSymKind)..high(TSymKind):
if cmpIgnoreStyle(($i).substr(2), spec) == 0:
result.add(ppSymKind)
result.add(chr(i.ord))
return
# check all nodekinds:
InternalAssert int(high(TNodeKind)) < 255
internalAssert int(high(TNodeKind)) < 255
for i in low(TNodeKind)..high(TNodeKind):
if cmpIgnoreStyle($i, spec) == 0:
result.add(ppNodeKind)
@@ -122,8 +124,8 @@ proc semNodeKindConstraints*(p: PNode): PNode =
if p.len >= 2:
for i in 1.. <p.len:
compileConstraints(p.sons[i], result.strVal)
if result.strVal.len > maxStackSize-1:
InternalError(p.info, "parameter pattern too complex")
if result.strVal.len > MaxStackSize-1:
internalError(p.info, "parameter pattern too complex")
else:
patternError(p)
result.strVal.add(ppEof)
@@ -214,12 +216,12 @@ proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
result = isAssignable(owner, n.sons[0])
else:
nil
discard
proc matchNodeKinds*(p, n: PNode): bool =
# matches the parameter constraint 'p' against the concrete AST 'n'.
# Efficiency matters here.
var stack {.noinit.}: array[0..maxStackSize, bool]
var stack {.noinit.}: array[0..MaxStackSize, bool]
# empty patterns are true:
stack[0] = true
var sp = 1

View File

@@ -1,346 +0,0 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# A HIGH-PERFORMANCE configuration file parser;
# the Nimrod version of this file is part of the
# standard library.
import
llstream, nhashes, strutils, nimlexbase
type
TCfgEventKind* = enum
cfgEof, # end of file reached
cfgSectionStart, # a ``[section]`` has been parsed
cfgKeyValuePair, # a ``key=value`` pair has been detected
cfgOption, # a ``--key=value`` command line option
cfgError # an error ocurred during parsing; msg contains the
# error message
TCfgEvent* = object of TObject
case kind*: TCfgEventKind
of cfgEof:
nil
of cfgSectionStart:
section*: string
of cfgKeyValuePair, cfgOption:
key*, value*: string
of cfgError:
msg*: string
TTokKind* = enum
tkInvalid, tkEof, # order is important here!
tkSymbol, tkEquals, tkColon, tkBracketLe, tkBracketRi, tkDashDash
TToken*{.final.} = object # a token
kind*: TTokKind # the type of the token
literal*: string # the parsed (string) literal
TParserState* = enum
startState, commaState
TCfgParser* = object of TBaseLexer
tok*: TToken
state*: TParserState
filename*: string
proc Open*(c: var TCfgParser, filename: string, inputStream: PLLStream)
proc Close*(c: var TCfgParser)
proc next*(c: var TCfgParser): TCfgEvent
proc getColumn*(c: TCfgParser): int
proc getLine*(c: TCfgParser): int
proc getFilename*(c: TCfgParser): string
proc errorStr*(c: TCfgParser, msg: string): string
# implementation
const
SymChars: TCharSet = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\x80'..'\xFF'} #
# ----------------------------------------------------------------------------
proc rawGetTok(c: var TCfgParser, tok: var TToken)
proc open(c: var TCfgParser, filename: string, inputStream: PLLStream) =
openBaseLexer(c, inputStream)
c.filename = filename
c.state = startState
c.tok.kind = tkInvalid
c.tok.literal = ""
rawGetTok(c, c.tok)
proc close(c: var TCfgParser) =
closeBaseLexer(c)
proc getColumn(c: TCfgParser): int =
result = getColNumber(c, c.bufPos)
proc getLine(c: TCfgParser): int =
result = c.linenumber
proc getFilename(c: TCfgParser): string =
result = c.filename
proc handleHexChar(c: var TCfgParser, xi: var int) =
case c.buf[c.bufpos]
of '0'..'9':
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('0'))
inc(c.bufpos)
of 'a'..'f':
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('a') + 10)
inc(c.bufpos)
of 'A'..'F':
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10)
inc(c.bufpos)
else:
nil
proc handleDecChars(c: var TCfgParser, xi: var int) =
while c.buf[c.bufpos] in {'0'..'9'}:
xi = (xi * 10) + (ord(c.buf[c.bufpos]) - ord('0'))
inc(c.bufpos)
proc getEscapedChar(c: var TCfgParser, tok: var TToken) =
var xi: int
inc(c.bufpos) # skip '\'
case c.buf[c.bufpos]
of 'n', 'N':
tok.literal = tok.literal & "\n"
Inc(c.bufpos)
of 'r', 'R', 'c', 'C':
add(tok.literal, CR)
Inc(c.bufpos)
of 'l', 'L':
add(tok.literal, LF)
Inc(c.bufpos)
of 'f', 'F':
add(tok.literal, FF)
inc(c.bufpos)
of 'e', 'E':
add(tok.literal, ESC)
Inc(c.bufpos)
of 'a', 'A':
add(tok.literal, BEL)
Inc(c.bufpos)
of 'b', 'B':
add(tok.literal, BACKSPACE)
Inc(c.bufpos)
of 'v', 'V':
add(tok.literal, VT)
Inc(c.bufpos)
of 't', 'T':
add(tok.literal, Tabulator)
Inc(c.bufpos)
of '\'', '\"':
add(tok.literal, c.buf[c.bufpos])
Inc(c.bufpos)
of '\\':
add(tok.literal, '\\')
Inc(c.bufpos)
of 'x', 'X':
inc(c.bufpos)
xi = 0
handleHexChar(c, xi)
handleHexChar(c, xi)
add(tok.literal, Chr(xi))
of '0'..'9':
xi = 0
handleDecChars(c, xi)
if (xi <= 255): add(tok.literal, Chr(xi))
else: tok.kind = tkInvalid
else: tok.kind = tkInvalid
proc HandleCRLF(c: var TCfgParser, pos: int): int =
case c.buf[pos]
of CR: result = lexbase.HandleCR(c, pos)
of LF: result = lexbase.HandleLF(c, pos)
else: result = pos
proc getString(c: var TCfgParser, tok: var TToken, rawMode: bool) =
var
pos: int
ch: Char
buf: cstring
pos = c.bufPos + 1 # skip "
buf = c.buf # put `buf` in a register
tok.kind = tkSymbol
if (buf[pos] == '\"') and (buf[pos + 1] == '\"'):
# long string literal:
inc(pos, 2) # skip ""
# skip leading newline:
pos = HandleCRLF(c, pos)
buf = c.buf
while true:
case buf[pos]
of '\"':
if (buf[pos + 1] == '\"') and (buf[pos + 2] == '\"'): break
add(tok.literal, '\"')
Inc(pos)
of CR, LF:
pos = HandleCRLF(c, pos)
buf = c.buf
tok.literal = tok.literal & "\n"
of lexbase.EndOfFile:
tok.kind = tkInvalid
break
else:
add(tok.literal, buf[pos])
Inc(pos)
c.bufpos = pos +
3 # skip the three """
else:
# ordinary string literal
while true:
ch = buf[pos]
if ch == '\"':
inc(pos) # skip '"'
break
if ch in {CR, LF, lexbase.EndOfFile}:
tok.kind = tkInvalid
break
if (ch == '\\') and not rawMode:
c.bufPos = pos
getEscapedChar(c, tok)
pos = c.bufPos
else:
add(tok.literal, ch)
Inc(pos)
c.bufpos = pos
proc getSymbol(c: var TCfgParser, tok: var TToken) =
var
pos: int
buf: cstring
pos = c.bufpos
buf = c.buf
while true:
add(tok.literal, buf[pos])
Inc(pos)
if not (buf[pos] in SymChars): break
c.bufpos = pos
tok.kind = tkSymbol
proc skip(c: var TCfgParser) =
var
buf: cstring
pos: int
pos = c.bufpos
buf = c.buf
while true:
case buf[pos]
of ' ':
Inc(pos)
of Tabulator:
inc(pos)
of '#', ';':
while not (buf[pos] in {CR, LF, lexbase.EndOfFile}): inc(pos)
of CR, LF:
pos = HandleCRLF(c, pos)
buf = c.buf
else:
break # EndOfFile also leaves the loop
c.bufpos = pos
proc rawGetTok(c: var TCfgParser, tok: var TToken) =
tok.kind = tkInvalid
setlen(tok.literal, 0)
skip(c)
case c.buf[c.bufpos]
of '=':
tok.kind = tkEquals
inc(c.bufpos)
tok.literal = "="
of '-':
inc(c.bufPos)
if c.buf[c.bufPos] == '-': inc(c.bufPos)
tok.kind = tkDashDash
tok.literal = "--"
of ':':
tok.kind = tkColon
inc(c.bufpos)
tok.literal = ":"
of 'r', 'R':
if c.buf[c.bufPos + 1] == '\"':
Inc(c.bufPos)
getString(c, tok, true)
else:
getSymbol(c, tok)
of '[':
tok.kind = tkBracketLe
inc(c.bufpos)
tok.literal = "["
of ']':
tok.kind = tkBracketRi
Inc(c.bufpos)
tok.literal = "]"
of '\"':
getString(c, tok, false)
of lexbase.EndOfFile:
tok.kind = tkEof
else: getSymbol(c, tok)
proc errorStr(c: TCfgParser, msg: string): string =
result = `%`("$1($2, $3) Error: $4",
[c.filename, $(getLine(c)), $(getColumn(c)), msg])
proc getKeyValPair(c: var TCfgParser, kind: TCfgEventKind): TCfgEvent =
if c.tok.kind == tkSymbol:
result.kind = kind
result.key = c.tok.literal
result.value = ""
rawGetTok(c, c.tok)
while c.tok.literal == ".":
add(result.key, '.')
rawGetTok(c, c.tok)
if c.tok.kind == tkSymbol:
add(result.key, c.tok.literal)
rawGetTok(c, c.tok)
else:
result.kind = cfgError
result.msg = errorStr(c, "symbol expected, but found: " & c.tok.literal)
break
if c.tok.kind in {tkEquals, tkColon}:
rawGetTok(c, c.tok)
if c.tok.kind == tkSymbol:
result.value = c.tok.literal
else:
result.kind = cfgError
result.msg = errorStr(c, "symbol expected, but found: " & c.tok.literal)
rawGetTok(c, c.tok)
else:
result.kind = cfgError
result.msg = errorStr(c, "symbol expected, but found: " & c.tok.literal)
rawGetTok(c, c.tok)
proc next(c: var TCfgParser): TCfgEvent =
case c.tok.kind
of tkEof:
result.kind = cfgEof
of tkDashDash:
rawGetTok(c, c.tok)
result = getKeyValPair(c, cfgOption)
of tkSymbol:
result = getKeyValPair(c, cfgKeyValuePair)
of tkBracketLe:
rawGetTok(c, c.tok)
if c.tok.kind == tkSymbol:
result.kind = cfgSectionStart
result.section = c.tok.literal
else:
result.kind = cfgError
result.msg = errorStr(c, "symbol expected, but found: " & c.tok.literal)
rawGetTok(c, c.tok)
if c.tok.kind == tkBracketRi:
rawGetTok(c, c.tok)
else:
result.kind = cfgError
result.msg = errorStr(c, "\']\' expected, but found: " & c.tok.literal)
of tkInvalid, tkBracketRi, tkEquals, tkColon:
result.kind = cfgError
result.msg = errorStr(c, "invalid token: " & c.tok.literal)
rawGetTok(c, c.tok)

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2013 Andreas Rumpf
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -18,10 +18,10 @@
# In fact the grammar is generated from this file:
when isMainModule:
import pegs
var outp = open("compiler/grammar.txt", fmWrite)
var outp = open("doc/grammar.txt", fmWrite)
for line in lines("compiler/parser.nim"):
if line =~ peg" \s* '#| ' {.*}":
outp.writeln matches[0]
outp.write matches[0], "\L"
outp.close
import
@@ -31,12 +31,13 @@ type
TParser*{.final.} = object # a TParser object represents a module that
# is being parsed
currInd: int # current indentation
firstTok: bool
firstTok, strongSpaces: bool
lex*: TLexer # the lexer that is used for parsing
tok*: TToken # the current token
inPragma: int
inSemiStmtList: int
proc ParseAll*(p: var TParser): PNode
proc openParser*(p: var TParser, filename: string, inputstream: PLLStream)
proc parseAll*(p: var TParser): PNode
proc closeParser*(p: var TParser)
proc parseTopLevelStmt*(p: var TParser): PNode
# implements an iterator. Returns the next top-level statement or
@@ -48,7 +49,6 @@ proc parseString*(s: string, filename: string = "", line: int = 0): PNode
# correct error messages referring to the original source.
# helpers for the other parsers
proc getPrecedence*(tok: TToken): int
proc isOperator*(tok: TToken): bool
proc getTok*(p: var TParser)
proc parMessage*(p: TParser, msg: TMsgKind, arg: string = "")
@@ -59,15 +59,15 @@ proc newFloatNodeP*(kind: TNodeKind, floatVal: BiggestFloat, p: TParser): PNode
proc newStrNodeP*(kind: TNodeKind, strVal: string, p: TParser): PNode
proc newIdentNodeP*(ident: PIdent, p: TParser): PNode
proc expectIdentOrKeyw*(p: TParser)
proc ExpectIdent*(p: TParser)
proc expectIdent*(p: TParser)
proc parLineInfo*(p: TParser): TLineInfo
proc Eat*(p: var TParser, TokType: TTokType)
proc eat*(p: var TParser, tokType: TTokType)
proc skipInd*(p: var TParser)
proc optPar*(p: var TParser)
proc optInd*(p: var TParser, n: PNode)
proc indAndComment*(p: var TParser, n: PNode)
proc setBaseFlags*(n: PNode, base: TNumericalBase)
proc parseSymbol*(p: var TParser): PNode
proc parseSymbol*(p: var TParser, allowNil = false): PNode
proc parseTry(p: var TParser): PNode
proc parseCase(p: var TParser): PNode
# implementation
@@ -75,17 +75,20 @@ proc parseCase(p: var TParser): PNode
proc getTok(p: var TParser) =
rawGetTok(p.lex, p.tok)
proc OpenParser*(p: var TParser, fileIdx: int32, inputStream: PLLStream) =
proc openParser*(p: var TParser, fileIdx: int32, inputStream: PLLStream,
strongSpaces=false) =
initToken(p.tok)
OpenLexer(p.lex, fileIdx, inputstream)
openLexer(p.lex, fileIdx, inputStream)
getTok(p) # read the first token
p.firstTok = true
p.strongSpaces = strongSpaces
proc OpenParser*(p: var TParser, filename: string, inputStream: PLLStream) =
openParser(p, filename.fileInfoIdx, inputStream)
proc openParser*(p: var TParser, filename: string, inputStream: PLLStream,
strongSpaces=false) =
openParser(p, filename.fileInfoIdx, inputstream, strongSpaces)
proc CloseParser(p: var TParser) =
CloseLexer(p.lex)
proc closeParser(p: var TParser) =
closeLexer(p.lex)
proc parMessage(p: TParser, msg: TMsgKind, arg: string = "") =
lexMessage(p.lex, msg, arg)
@@ -135,16 +138,16 @@ proc expectIdentOrKeyw(p: TParser) =
if p.tok.tokType != tkSymbol and not isKeyword(p.tok.tokType):
lexMessage(p.lex, errIdentifierExpected, prettyTok(p.tok))
proc ExpectIdent(p: TParser) =
proc expectIdent(p: TParser) =
if p.tok.tokType != tkSymbol:
lexMessage(p.lex, errIdentifierExpected, prettyTok(p.tok))
proc Eat(p: var TParser, TokType: TTokType) =
if p.tok.TokType == TokType: getTok(p)
proc eat(p: var TParser, tokType: TTokType) =
if p.tok.tokType == tokType: getTok(p)
else: lexMessage(p.lex, errTokenExpected, TokTypeToStr[tokType])
proc parLineInfo(p: TParser): TLineInfo =
result = getLineInfo(p.lex)
result = getLineInfo(p.lex, p.tok)
proc indAndComment(p: var TParser, n: PNode) =
if p.tok.indent > p.currInd:
@@ -154,7 +157,7 @@ proc indAndComment(p: var TParser, n: PNode) =
skipComment(p, n)
proc newNodeP(kind: TNodeKind, p: TParser): PNode =
result = newNodeI(kind, getLineInfo(p.lex))
result = newNodeI(kind, parLineInfo(p))
proc newIntNodeP(kind: TNodeKind, intVal: BiggestInt, p: TParser): PNode =
result = newNodeP(kind, p)
@@ -185,40 +188,58 @@ proc relevantOprChar(ident: PIdent): char {.inline.} =
if result == '\\' and L > 1:
result = ident.s[1]
proc IsSigilLike(tok: TToken): bool {.inline.} =
proc isSigilLike(tok: TToken): bool {.inline.} =
result = tok.tokType == tkOpr and relevantOprChar(tok.ident) == '@'
proc IsLeftAssociative(tok: TToken): bool {.inline.} =
proc isLeftAssociative(tok: TToken): bool {.inline.} =
result = tok.tokType != tkOpr or relevantOprChar(tok.ident) != '^'
proc getPrecedence(tok: TToken): int =
proc getPrecedence(tok: TToken, strongSpaces: bool): int =
template considerStrongSpaces(x): expr =
x + (if strongSpaces: 100 - tok.strongSpaceA.int*10 else: 0)
case tok.tokType
of tkOpr:
let L = tok.ident.s.len
let relevantChar = relevantOprChar(tok.ident)
template considerAsgn(value: expr) =
result = if tok.ident.s[L-1] == '=': 1 else: value
template considerAsgn(value: expr) =
result = if tok.ident.s[L-1] == '=': 1 else: considerStrongSpaces(value)
case relevantChar
of '$', '^': considerAsgn(10)
of '*', '%', '/', '\\': considerAsgn(9)
of '~': result = 8
of '~': result = considerStrongSpaces(8)
of '+', '-', '|': considerAsgn(8)
of '&': considerAsgn(7)
of '=', '<', '>', '!': result = 5
of '=', '<', '>', '!': result = considerStrongSpaces(5)
of '.': considerAsgn(6)
of '?': result = 2
of '?': result = considerStrongSpaces(2)
else: considerAsgn(2)
of tkDiv, tkMod, tkShl, tkShr: result = 9
of tkIn, tkNotIn, tkIs, tkIsNot, tkNot, tkOf, tkAs: result = 5
of tkDotDot: result = 6
of tkIn, tkNotin, tkIs, tkIsnot, tkNot, tkOf, tkAs: result = 5
of tkDotDot: result = considerStrongSpaces(6)
of tkAnd: result = 4
of tkOr, tkXor: result = 3
else: result = - 10
proc isOperator(tok: TToken): bool =
result = getPrecedence(tok) >= 0
of tkOr, tkXor, tkPtr, tkRef: result = 3
else: result = -10
proc isOperator(tok: TToken): bool =
tok.tokType in {tkOpr, tkDiv, tkMod, tkShl, tkShr, tkIn, tkNotin, tkIs,
tkIsnot, tkNot, tkOf, tkAs, tkDotDot, tkAnd, tkOr, tkXor}
proc isUnary(p: TParser): bool =
p.strongSpaces and p.tok.tokType in {tkOpr, tkDotDot} and
p.tok.strongSpaceB == 0 and
p.tok.strongSpaceA > 0
proc checkBinary(p: TParser) {.inline.} =
# we don't check '..' here as that's too annoying
if p.strongSpaces and p.tok.tokType == tkOpr:
if p.tok.strongSpaceB > 0 and p.tok.strongSpaceA != p.tok.strongSpaceB:
parMessage(p, errGenerated, "number of spaces around '$#' not consistent"%
prettyTok(p.tok))
elif p.tok.strongSpaceA notin {0,1,2,4,8}:
parMessage(p, errGenerated, "number of spaces must be 0,1,2,4 or 8")
#| module = stmt ^* (';' / IND{=})
#|
@@ -252,7 +273,7 @@ proc colcom(p: var TParser, n: PNode) =
eat(p, tkColon)
skipComment(p, n)
proc parseSymbol(p: var TParser): PNode =
proc parseSymbol(p: var TParser, allowNil = false): PNode =
#| symbol = '`' (KEYW|IDENT|operator|'(' ')'|'[' ']'|'{' '}'|'='|literal)+ '`'
#| | IDENT
case p.tok.tokType
@@ -279,7 +300,7 @@ proc parseSymbol(p: var TParser): PNode =
add(result, newIdentNodeP(getIdent"{}", p))
getTok(p)
eat(p, tkCurlyRi)
of tokKeywordLow..tokKeywordHigh, tkSymbol, tkOpr, tkDotDot:
of tokKeywordLow..tokKeywordHigh, tkSymbol, tkOpr, tkDot, tkDotDot:
add(result, newIdentNodeP(p.tok.ident, p))
getTok(p)
of tkIntLit..tkCharLit:
@@ -291,9 +312,13 @@ proc parseSymbol(p: var TParser): PNode =
break
eat(p, tkAccent)
else:
parMessage(p, errIdentifierExpected, p.tok)
getTok(p) # BUGFIX: We must consume a token here to prevent endless loops!
result = ast.emptyNode
if allowNil and p.tok.tokType == tkNil:
result = newNodeP(nkNilLit, p)
getTok(p)
else:
parMessage(p, errIdentifierExpected, p.tok)
getTok(p) # BUGFIX: We must consume a token here to prevent endless loops!
result = ast.emptyNode
proc indexExpr(p: var TParser): PNode =
#| indexExpr = expr
@@ -350,7 +375,7 @@ proc exprList(p: var TParser, endTok: TTokType, result: PNode) =
proc dotExpr(p: var TParser, a: PNode): PNode =
#| dotExpr = expr '.' optInd ('type' | 'addr' | symbol)
var info = p.lex.getlineInfo
var info = p.parLineInfo
getTok(p)
optInd(p, a)
case p.tok.tokType
@@ -427,7 +452,7 @@ proc parseCast(p: var TParser): PNode =
proc setBaseFlags(n: PNode, base: TNumericalBase) =
case base
of base10: nil
of base10: discard
of base2: incl(n.flags, nfBase2)
of base8: incl(n.flags, nfBase8)
of base16: incl(n.flags, nfBase16)
@@ -454,11 +479,13 @@ proc complexOrSimpleStmt(p: var TParser): PNode
proc simpleExpr(p: var TParser, mode = pmNormal): PNode
proc semiStmtList(p: var TParser, result: PNode) =
inc p.inSemiStmtList
result.add(complexOrSimpleStmt(p))
while p.tok.tokType == tkSemicolon:
while p.tok.tokType == tkSemiColon:
getTok(p)
optInd(p, result)
result.add(complexOrSimpleStmt(p))
dec p.inSemiStmtList
result.kind = nkStmtListExpr
proc parsePar(p: var TParser): PNode =
@@ -482,7 +509,7 @@ proc parsePar(p: var TParser): PNode =
# XXX 'bind' used to be an expression, so we exclude it here;
# tests/reject/tbind2 fails otherwise.
semiStmtList(p, result)
elif p.tok.tokType == tkSemicolon:
elif p.tok.tokType == tkSemiColon:
# '(;' enforces 'stmt' context:
getTok(p)
optInd(p, result)
@@ -498,7 +525,9 @@ proc parsePar(p: var TParser): PNode =
asgn.sons[0] = a
asgn.sons[1] = b
result.add(asgn)
elif p.tok.tokType == tkSemicolon:
if p.tok.tokType == tkSemiColon:
semiStmtList(p, result)
elif p.tok.tokType == tkSemiColon:
# stmt context:
result.add(a)
semiStmtList(p, result)
@@ -518,14 +547,14 @@ proc parsePar(p: var TParser): PNode =
eat(p, tkParRi)
proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode =
#| literal = | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
#| | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT
#| | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
#| | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
#| | CHAR_LIT
#| | NIL
#| generalizedLit = GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT
#| identOrLiteral = generalizedLit | symbol
#| | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
#| | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT
#| | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
#| | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
#| | CHAR_LIT
#| | NIL
#| identOrLiteral = generalizedLit | symbol | literal
#| | par | arrayConstr | setOrTableConstr
#| | castExpr
#| tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
@@ -627,20 +656,28 @@ proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode =
getTok(p) # we must consume a token here to prevend endless loops!
result = ast.emptyNode
proc primarySuffix(p: var TParser, r: PNode): PNode =
proc namedParams(p: var TParser, callee: PNode,
kind: TNodeKind, endTok: TTokType): PNode =
let a = callee
result = newNodeP(kind, p)
addSon(result, a)
exprColonEqExprListAux(p, endTok, result)
proc parseMacroColon(p: var TParser, x: PNode): PNode
proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
#| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
#| | doBlocks
#| | '.' optInd ('type' | 'addr' | symbol) generalizedLit?
#| | '[' optInd indexExprList optPar ']'
#| | '{' optInd indexExprList optPar '}'
#| | &( '`'|IDENT|literal|'cast') expr # command syntax
result = r
while p.tok.indent < 0:
while p.tok.indent < 0 or
(p.tok.tokType == tkDot and p.tok.indent >= baseIndent):
case p.tok.tokType
of tkParLe:
var a = result
result = newNodeP(nkCall, p)
addSon(result, a)
exprColonEqExprListAux(p, tkParRi, result)
of tkParLe:
if p.strongSpaces and p.tok.strongSpaceA > 0: break
result = namedParams(p, result, nkCall, tkParRi)
if result.len > 1 and result.sons[1].kind == nkExprColonExpr:
result.kind = nkObjConstr
else:
@@ -653,22 +690,48 @@ proc primarySuffix(p: var TParser, r: PNode): PNode =
of tkDot:
result = dotExpr(p, result)
result = parseGStrLit(p, result)
of tkBracketLe:
result = indexExprList(p, result, nkBracketExpr, tkBracketRi)
of tkBracketLe:
if p.strongSpaces and p.tok.strongSpaceA > 0: break
result = namedParams(p, result, nkBracketExpr, tkBracketRi)
of tkCurlyLe:
result = indexExprList(p, result, nkCurlyExpr, tkCurlyRi)
else: break
if p.strongSpaces and p.tok.strongSpaceA > 0: break
result = namedParams(p, result, nkCurlyExpr, tkCurlyRi)
of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast:
if p.inPragma == 0:
# actually parsing {.push hints:off.} as {.push(hints:off).} is a sweet
# solution, but pragmas.nim can't handle that
let a = result
result = newNodeP(nkCommand, p)
addSon(result, a)
addSon result, parseExpr(p)
when false:
while p.tok.tokType != tkEof:
let a = parseExpr(p)
addSon(result, a)
if p.tok.tokType != tkComma: break
getTok(p)
optInd(p, a)
if p.tok.tokType == tkDo:
parseDoBlocks(p, result)
else:
result = parseMacroColon(p, result)
break
else:
break
proc primary(p: var TParser, mode: TPrimaryMode): PNode
proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode
proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode =
result = primary(p, mode)
proc parseOperators(p: var TParser, headNode: PNode,
limit: int, mode: TPrimaryMode): PNode =
result = headNode
# expand while operators have priorities higher than 'limit'
var opPrec = getPrecedence(p.tok)
var opPrec = getPrecedence(p.tok, p.strongSpaces)
let modeB = if mode == pmTypeDef: pmTypeDesc else: mode
# the operator itself must not start on a new line:
while opPrec >= limit and p.tok.indent < 0:
var leftAssoc = ord(IsLeftAssociative(p.tok))
while opPrec >= limit and p.tok.indent < 0 and not isUnary(p):
checkBinary(p)
var leftAssoc = ord(isLeftAssociative(p.tok))
var a = newNodeP(nkInfix, p)
var opNode = newIdentNodeP(p.tok.ident, p) # skip operator:
getTok(p)
@@ -679,7 +742,11 @@ proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode =
addSon(a, result)
addSon(a, b)
result = a
opPrec = getPrecedence(p.tok)
opPrec = getPrecedence(p.tok, p.strongSpaces)
proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode =
result = primary(p, mode)
result = parseOperators(p, result, limit, mode)
proc simpleExpr(p: var TParser, mode = pmNormal): PNode =
result = simpleExprAux(p, -1, mode)
@@ -709,6 +776,7 @@ proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode =
proc parsePragma(p: var TParser): PNode =
#| pragma = '{.' optInd (exprColonExpr comma?)* optPar ('.}' | '}')
result = newNodeP(nkPragma, p)
inc p.inPragma
getTok(p)
optInd(p, result)
while p.tok.tokType notin {tkCurlyDotRi, tkCurlyRi, tkEof}:
@@ -720,6 +788,7 @@ proc parsePragma(p: var TParser): PNode =
optPar(p)
if p.tok.tokType in {tkCurlyDotRi, tkCurlyRi}: getTok(p)
else: parMessage(p, errTokenExpected, ".}")
dec p.inPragma
proc identVis(p: var TParser): PNode =
#| identVis = symbol opr? # postfix position
@@ -794,7 +863,7 @@ proc parseTuple(p: var TParser, indentAllowed = false): PNode =
while p.tok.tokType in {tkSymbol, tkAccent}:
var a = parseIdentColonEquals(p, {})
addSon(result, a)
if p.tok.tokType notin {tkComma, tkSemicolon}: break
if p.tok.tokType notin {tkComma, tkSemiColon}: break
getTok(p)
skipComment(p, a)
optPar(p)
@@ -836,13 +905,13 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
parMessage(p, errTokenExpected, ")")
break
addSon(result, a)
if p.tok.tokType notin {tkComma, tkSemicolon}: break
if p.tok.tokType notin {tkComma, tkSemiColon}: break
getTok(p)
skipComment(p, a)
optPar(p)
eat(p, tkParRi)
let hasRet = if retColon: p.tok.tokType == tkColon
else: p.tok.tokType == tkOpr and IdentEq(p.tok.ident, "->")
else: p.tok.tokType == tkOpr and identEq(p.tok.ident, "->")
if hasRet and p.tok.indent < 0:
getTok(p)
optInd(p, result)
@@ -898,17 +967,33 @@ proc isExprStart(p: TParser): bool =
of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf,
tkProc, tkIterator, tkBind, tkAddr,
tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, tkVar, tkRef, tkPtr,
tkTuple, tkObject, tkType, tkWhen, tkCase, tkShared:
tkTuple, tkObject, tkType, tkWhen, tkCase:
result = true
else: result = false
proc parseTypeDescKAux(p: var TParser, kind: TNodeKind,
mode: TPrimaryMode): PNode =
proc parseSymbolList(p: var TParser, result: PNode, allowNil = false) =
while true:
var s = parseSymbol(p, allowNil)
if s.kind == nkEmpty: break
addSon(result, s)
if p.tok.tokType != tkComma: break
getTok(p)
optInd(p, s)
proc parseTypeDescKAux(p: var TParser, kind: TNodeKind,
mode: TPrimaryMode): PNode =
result = newNodeP(kind, p)
getTok(p)
optInd(p, result)
if not isOperator(p.tok) and isExprStart(p):
addSon(result, primary(p, mode))
if kind == nkDistinctTy and p.tok.tokType in {tkWith, tkWithout}:
let nodeKind = if p.tok.tokType == tkWith: nkWith
else: nkWithout
getTok(p)
let list = newNodeP(nodeKind, p)
result.addSon list
parseSymbolList(p, list, allowNil = true)
proc parseExpr(p: var TParser): PNode =
#| expr = (ifExpr
@@ -923,9 +1008,9 @@ proc parseExpr(p: var TParser): PNode =
of tkTry: result = parseTry(p)
else: result = simpleExpr(p)
proc parseObject(p: var TParser): PNode
proc parseDistinct(p: var TParser): PNode
proc parseEnum(p: var TParser): PNode
proc parseObject(p: var TParser): PNode
proc parseTypeClass(p: var TParser): PNode
proc primary(p: var TParser, mode: TPrimaryMode): PNode =
#| typeKeyw = 'var' | 'ref' | 'ptr' | 'shared' | 'type' | 'tuple'
@@ -936,7 +1021,7 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
#| / 'static' primary
#| / 'bind' primary
if isOperator(p.tok):
let isSigil = IsSigilLike(p.tok)
let isSigil = isSigilLike(p.tok)
result = newNodeP(nkPrefix, p)
var a = newIdentNodeP(p.tok.ident, p)
addSon(result, a)
@@ -944,8 +1029,9 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
optInd(p, a)
if isSigil:
#XXX prefix operators
let baseInd = p.lex.currLineIndent
addSon(result, primary(p, pmSkipSuffix))
result = primarySuffix(p, result)
result = primarySuffix(p, result, baseInd)
else:
addSon(result, primary(p, pmNormal))
return
@@ -954,19 +1040,24 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
of tkVar: result = parseTypeDescKAux(p, nkVarTy, mode)
of tkRef: result = parseTypeDescKAux(p, nkRefTy, mode)
of tkPtr: result = parseTypeDescKAux(p, nkPtrTy, mode)
of tkShared: result = parseTypeDescKAux(p, nkSharedTy, mode)
of tkDistinct: result = parseTypeDescKAux(p, nkDistinctTy, mode)
of tkType: result = parseTypeDescKAux(p, nkTypeOfExpr, mode)
of tkTuple: result = parseTuple(p, mode == pmTypeDef)
of tkProc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
of tkIterator:
if mode in {pmTypeDesc, pmTypeDef}:
result = parseProcExpr(p, false)
result.kind = nkIteratorTy
when false:
if mode in {pmTypeDesc, pmTypeDef}:
result = parseProcExpr(p, false)
result.kind = nkIteratorTy
else:
# no anon iterators for now:
parMessage(p, errExprExpected, p.tok)
getTok(p) # we must consume a token here to prevend endless loops!
result = ast.emptyNode
else:
# no anon iterators for now:
parMessage(p, errExprExpected, p.tok)
getTok(p) # we must consume a token here to prevend endless loops!
result = ast.emptyNode
result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
if result.kind == nkLambda: result.kind = nkIteratorDef
else: result.kind = nkIteratorTy
of tkEnum:
if mode == pmTypeDef:
result = parseEnum(p)
@@ -979,29 +1070,33 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
else:
result = newNodeP(nkObjectTy, p)
getTok(p)
of tkDistinct:
of tkGeneric:
if mode == pmTypeDef:
result = parseDistinct(p)
result = parseTypeClass(p)
else:
result = newNodeP(nkDistinctTy, p)
getTok(p)
parMessage(p, errInvalidToken, p.tok)
of tkAddr:
result = newNodeP(nkAddr, p)
getTokNoInd(p)
addSon(result, primary(p, pmNormal))
of tkStatic:
result = newNodeP(nkStaticExpr, p)
let info = parLineInfo(p)
getTokNoInd(p)
addSon(result, primary(p, pmNormal))
let next = primary(p, pmNormal)
if next.kind == nkBracket and next.sonsLen == 1:
result = newNode(nkStaticTy, info, @[next.sons[0]])
else:
result = newNode(nkStaticExpr, info, @[next])
of tkBind:
result = newNodeP(nkBind, p)
getTok(p)
optInd(p, result)
addSon(result, primary(p, pmNormal))
else:
let baseInd = p.lex.currLineIndent
result = identOrLiteral(p, mode)
if mode != pmSkipSuffix:
result = primarySuffix(p, result)
result = primarySuffix(p, result, baseInd)
proc parseTypeDesc(p: var TParser): PNode =
#| typeDesc = simpleExpr
@@ -1009,6 +1104,7 @@ proc parseTypeDesc(p: var TParser): PNode =
proc parseTypeDefAux(p: var TParser): PNode =
#| typeDefAux = simpleExpr
#| | 'generic' typeClass
result = simpleExpr(p, pmTypeDef)
proc makeCall(n: PNode): PNode =
@@ -1018,17 +1114,54 @@ proc makeCall(n: PNode): PNode =
result = newNodeI(nkCall, n.info)
result.add n
proc parseMacroColon(p: var TParser, x: PNode): PNode =
#| macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt
#| | IND{=} 'elif' expr ':' stmt
#| | IND{=} 'except' exprList ':' stmt
#| | IND{=} 'else' ':' stmt )*
result = x
if p.tok.tokType == tkColon and p.tok.indent < 0:
result = makeCall(result)
getTok(p)
skipComment(p, result)
if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}:
let body = parseStmt(p)
addSon(result, newProcNode(nkDo, body.info, body))
while sameInd(p):
var b: PNode
case p.tok.tokType
of tkOf:
b = newNodeP(nkOfBranch, p)
exprList(p, tkColon, b)
of tkElif:
b = newNodeP(nkElifBranch, p)
getTok(p)
optInd(p, b)
addSon(b, parseExpr(p))
eat(p, tkColon)
of tkExcept:
b = newNodeP(nkExceptBranch, p)
exprList(p, tkColon, b)
skipComment(p, b)
of tkElse:
b = newNodeP(nkElse, p)
getTok(p)
eat(p, tkColon)
else: break
addSon(b, parseStmt(p))
addSon(result, b)
if b.kind == nkElse: break
proc parseExprStmt(p: var TParser): PNode =
#| exprStmt = simpleExpr
#| (( '=' optInd expr )
#| / ( expr ^+ comma
#| doBlocks
#| / ':' stmt? ( IND{=} 'of' exprList ':' stmt
#| | IND{=} 'elif' expr ':' stmt
#| | IND{=} 'except' exprList ':' stmt
#| | IND{=} 'else' ':' stmt )*
#| / macroColon
#| ))?
inc p.inPragma
var a = simpleExpr(p)
dec p.inPragma
if p.tok.tokType == tkEquals:
getTok(p)
optInd(p, result)
@@ -1051,37 +1184,18 @@ proc parseExprStmt(p: var TParser): PNode =
result = makeCall(result)
parseDoBlocks(p, result)
return result
if p.tok.tokType == tkColon and p.tok.indent < 0:
result = makeCall(result)
result = parseMacroColon(p, result)
proc parseModuleName(p: var TParser, kind: TNodeKind): PNode =
result = parseExpr(p)
when false:
# parseExpr already handles 'as' syntax ...
if p.tok.tokType == tkAs and kind == nkImportStmt:
let a = result
result = newNodeP(nkImportAs, p)
getTok(p)
skipComment(p, result)
if p.tok.TokType notin {tkOf, tkElif, tkElse, tkExcept}:
let body = parseStmt(p)
addSon(result, newProcNode(nkDo, body.info, body))
while sameInd(p):
var b: PNode
case p.tok.tokType
of tkOf:
b = newNodeP(nkOfBranch, p)
exprList(p, tkColon, b)
of tkElif:
b = newNodeP(nkElifBranch, p)
getTok(p)
optInd(p, b)
addSon(b, parseExpr(p))
eat(p, tkColon)
of tkExcept:
b = newNodeP(nkExceptBranch, p)
exprList(p, tkColon, b)
skipComment(p, b)
of tkElse:
b = newNodeP(nkElse, p)
getTok(p)
eat(p, tkColon)
else: break
addSon(b, parseStmt(p))
addSon(result, b)
if b.kind == nkElse: break
result.add(a)
result.add(parseExpr(p))
proc parseImport(p: var TParser, kind: TNodeKind): PNode =
#| importStmt = 'import' optInd expr
@@ -1090,7 +1204,7 @@ proc parseImport(p: var TParser, kind: TNodeKind): PNode =
result = newNodeP(kind, p)
getTok(p) # skip `import` or `export`
optInd(p, result)
var a = parseExpr(p)
var a = parseModuleName(p, kind)
addSon(result, a)
if p.tok.tokType in {tkComma, tkExcept}:
if p.tok.tokType == tkExcept:
@@ -1099,10 +1213,10 @@ proc parseImport(p: var TParser, kind: TNodeKind): PNode =
optInd(p, result)
while true:
# was: while p.tok.tokType notin {tkEof, tkSad, tkDed}:
a = parseExpr(p)
if a.kind == nkEmpty: break
a = parseModuleName(p, kind)
if a.kind == nkEmpty: break
addSon(result, a)
if p.tok.tokType != tkComma: break
if p.tok.tokType != tkComma: break
getTok(p)
optInd(p, a)
#expectNl(p)
@@ -1123,11 +1237,11 @@ proc parseIncludeStmt(p: var TParser): PNode =
#expectNl(p)
proc parseFromStmt(p: var TParser): PNode =
#| fromStmt = 'from' expr 'import' optInd expr (comma expr)*
#| fromStmt = 'from' moduleName 'import' optInd expr (comma expr)*
result = newNodeP(nkFromStmt, p)
getTok(p) # skip `from`
optInd(p, result)
var a = parseExpr(p)
var a = parseModuleName(p, nkImportStmt)
addSon(result, a) #optInd(p, a);
eat(p, tkImport)
optInd(p, result)
@@ -1153,8 +1267,7 @@ proc parseReturnOrRaise(p: var TParser, kind: TNodeKind): PNode =
if p.tok.tokType == tkComment:
skipComment(p, result)
addSon(result, ast.emptyNode)
elif p.tok.indent >= 0 and p.tok.indent <= p.currInd or
p.tok.tokType == tkEof:
elif p.tok.indent >= 0 and p.tok.indent <= p.currInd or not isExprStart(p):
# NL terminates:
addSon(result, ast.emptyNode)
else:
@@ -1362,7 +1475,7 @@ proc parseGenericParamList(p: var TParser): PNode =
while p.tok.tokType in {tkSymbol, tkAccent}:
var a = parseGenericParam(p)
addSon(result, a)
if p.tok.tokType notin {tkComma, tkSemicolon}: break
if p.tok.tokType notin {tkComma, tkSemiColon}: break
getTok(p)
skipComment(p, a)
optPar(p)
@@ -1407,7 +1520,6 @@ proc parseRoutine(p: var TParser, kind: TNodeKind): PNode =
proc newCommentStmt(p: var TParser): PNode =
#| commentStmt = COMMENT
result = newNodeP(nkCommentStmt, p)
result.info.line = result.info.line - int16(1) - int16(p.tok.iNumber)
result.comment = p.tok.literal
getTok(p)
@@ -1418,14 +1530,14 @@ proc parseSection(p: var TParser, kind: TNodeKind,
defparser: TDefParser): PNode =
#| section(p) = COMMENT? p / (IND{>} (p / COMMENT)^+IND{=} DED)
result = newNodeP(kind, p)
getTok(p)
if kind != nkTypeSection: getTok(p)
skipComment(p, result)
if realInd(p):
withInd(p):
skipComment(p, result)
while sameInd(p):
case p.tok.tokType
of tkSymbol, tkAccent:
of tkSymbol, tkAccent, tkParLe:
var a = defparser(p)
skipComment(p, a)
addSon(result, a)
@@ -1609,12 +1721,47 @@ proc parseObject(p: var TParser): PNode =
return
addSon(result, parseObjectPart(p))
proc parseDistinct(p: var TParser): PNode =
#| distinct = 'distinct' optInd typeDesc
result = newNodeP(nkDistinctTy, p)
proc parseTypeClassParam(p: var TParser): PNode =
if p.tok.tokType == tkVar:
getTok(p)
result = newNode(nkVarTy)
result.addSon(p.parseSymbol)
else:
result = p.parseSymbol
proc parseTypeClass(p: var TParser): PNode =
#| typeClassParam = ('var')? symbol
#| typeClass = typeClassParam ^* ',' (pragma)? ('of' typeDesc ^* ',')?
#| &IND{>} stmt
result = newNodeP(nkTypeClassTy, p)
getTok(p)
optInd(p, result)
addSon(result, parseTypeDesc(p))
var args = newNode(nkArgList)
addSon(result, args)
addSon(args, p.parseTypeClassParam)
while p.tok.tokType == tkComma:
getTok(p)
addSon(args, p.parseTypeClassParam)
if p.tok.tokType == tkCurlyDotLe and p.validInd:
addSon(result, parsePragma(p))
else:
addSon(result, ast.emptyNode)
if p.tok.tokType == tkOf and p.tok.indent < 0:
var a = newNodeP(nkOfInherit, p)
getTok(p)
while true:
addSon(a, parseTypeDesc(p))
if p.tok.tokType != tkComma: break
getTok(p)
addSon(result, a)
else:
addSon(result, ast.emptyNode)
if p.tok.tokType == tkComment:
skipComment(p, result)
# an initial IND{>} HAS to follow:
if not realInd(p):
addSon(result, emptyNode)
else:
addSon(result, parseStmt(p))
proc parseTypeDef(p: var TParser): PNode =
#| typeDef = identWithPragma genericParamList? '=' optInd typeDefAux
@@ -1737,31 +1884,43 @@ proc complexOrSimpleStmt(p: var TParser): PNode =
of tkMacro: result = parseRoutine(p, nkMacroDef)
of tkTemplate: result = parseRoutine(p, nkTemplateDef)
of tkConverter: result = parseRoutine(p, nkConverterDef)
of tkType: result = parseSection(p, nkTypeSection, parseTypeDef)
of tkType:
getTok(p)
if p.tok.tokType == tkParLe:
getTok(p)
result = newNodeP(nkTypeOfExpr, p)
result.addSon(primary(p, pmTypeDesc))
eat(p, tkParRi)
result = parseOperators(p, result, -1, pmNormal)
else:
result = parseSection(p, nkTypeSection, parseTypeDef)
of tkConst: result = parseSection(p, nkConstSection, parseConstant)
of tkLet: result = parseSection(p, nkLetSection, parseVariable)
of tkWhen: result = parseIfOrWhen(p, nkWhenStmt)
of tkVar: result = parseSection(p, nkVarSection, parseVariable)
of tkBind: result = parseBind(p, nkBindStmt)
of tkMixin: result = parseBind(p, nkMixinStmt)
of tkUsing: result = parseBind(p, nkUsingStmt)
else: result = simpleStmt(p)
proc parseStmt(p: var TParser): PNode =
#| stmt = (IND{>} complexOrSimpleStmt^+(IND{=} / ';') DED)
#| / simpleStmt
#| / simpleStmt ^+ ';'
if p.tok.indent > p.currInd:
result = newNodeP(nkStmtList, p)
withInd(p):
while true:
if p.tok.indent == p.currInd:
nil
elif p.tok.tokType == tkSemicolon:
while p.tok.tokType == tkSemicolon: getTok(p)
discard
elif p.tok.tokType == tkSemiColon:
getTok(p)
if p.tok.indent < 0 or p.tok.indent == p.currInd: discard
else: break
else:
if p.tok.indent > p.currInd:
if p.tok.indent > p.currInd and p.tok.tokType != tkDot:
parMessage(p, errInvalidIndentation)
break
if p.tok.toktype in {tkCurlyRi, tkParRi, tkCurlyDotRi, tkBracketRi}:
if p.tok.tokType in {tkCurlyRi, tkParRi, tkCurlyDotRi, tkBracketRi}:
# XXX this ensures tnamedparamanonproc still compiles;
# deprecate this syntax later
break
@@ -1779,10 +1938,19 @@ proc parseStmt(p: var TParser): PNode =
parMessage(p, errComplexStmtRequiresInd)
result = ast.emptyNode
else:
if p.tok.indent >= 0: parMessage(p, errInvalidIndentation)
result = simpleStmt(p)
if result.kind == nkEmpty: parMessage(p, errExprExpected, p.tok)
#while p.tok.tokType == tkSemicolon: getTok(p)
if p.inSemiStmtList > 0:
result = simpleStmt(p)
if result.kind == nkEmpty: parMessage(p, errExprExpected, p.tok)
else:
result = newNodeP(nkStmtList, p)
while true:
if p.tok.indent >= 0:
parMessage(p, errInvalidIndentation)
let a = simpleStmt(p)
if a.kind == nkEmpty: parMessage(p, errExprExpected, p.tok)
result.add(a)
if p.tok.tokType != tkSemiColon: break
getTok(p)
proc parseAll(p: var TParser): PNode =
result = newNodeP(nkStmtList, p)
@@ -1801,11 +1969,14 @@ proc parseTopLevelStmt(p: var TParser): PNode =
result = ast.emptyNode
while true:
if p.tok.indent != 0:
if p.firstTok and p.tok.indent < 0: nil
if p.firstTok and p.tok.indent < 0: discard
else: parMessage(p, errInvalidIndentation)
p.firstTok = false
case p.tok.tokType
of tkSemicolon: getTok(p)
of tkSemiColon:
getTok(p)
if p.tok.indent <= 0: discard
else: parMessage(p, errInvalidIndentation)
of tkEof: break
else:
result = complexOrSimpleStmt(p)
@@ -1813,11 +1984,13 @@ proc parseTopLevelStmt(p: var TParser): PNode =
break
proc parseString(s: string, filename: string = "", line: int = 0): PNode =
var stream = LLStreamOpen(s)
var stream = llStreamOpen(s)
stream.lineOffset = line
var parser: TParser
OpenParser(parser, filename, stream)
# XXX for now the builtin 'parseStmt/Expr' functions do not know about strong
# spaces...
openParser(parser, filename, stream, false)
result = parser.parseAll
CloseParser(parser)
closeParser(parser)

View File

@@ -26,7 +26,7 @@ Options:
"""
proc main(infile, outfile: string, flags: set[TParserFlag]) =
var stream = LLStreamOpen(infile, fmRead)
var stream = llStreamOpen(infile, fmRead)
if stream == nil: rawMessage(errCannotOpenFile, infile)
var p: TParser
openParser(p, infile, stream, flags)

View File

@@ -78,7 +78,7 @@ type
proc getTok*(L: var TLexer, tok: var TToken)
proc PrintTok*(tok: TToken)
proc printTok*(tok: TToken)
proc `$`*(tok: TToken): string
# implementation
@@ -109,17 +109,17 @@ proc getLineInfo*(L: TLexer): TLineInfo =
result = newLineInfo(L.filename, L.linenumber, getColNumber(L, L.bufpos))
proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "") =
msgs.GlobalError(getLineInfo(L), msg, arg)
msgs.globalError(getLineInfo(L), msg, arg)
proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
var info = newLineInfo(L.filename, L.linenumber, pos - L.lineStart)
msgs.GlobalError(info, msg, arg)
msgs.globalError(info, msg, arg)
proc TokKindToStr*(k: TTokKind): string =
proc tokKindToStr*(k: TTokKind): string =
case k
of pxEof: result = "[EOF]"
of firstKeyword..lastKeyword:
result = keywords[ord(k)-ord(firstKeyword)]
result = Keywords[ord(k)-ord(firstKeyword)]
of pxInvalid, pxComment, pxStrLit: result = "string literal"
of pxCommand: result = "{@"
of pxAmp: result = "{&"
@@ -160,9 +160,9 @@ proc `$`(tok: TToken): string =
of pxSymbol: result = tok.ident.s
of pxIntLit, pxInt64Lit: result = $tok.iNumber
of pxFloatLit: result = $tok.fNumber
else: result = TokKindToStr(tok.xkind)
else: result = tokKindToStr(tok.xkind)
proc PrintTok(tok: TToken) =
proc printTok(tok: TToken) =
writeln(stdout, $tok)
proc setKeyword(L: var TLexer, tok: var TToken) =
@@ -177,12 +177,12 @@ proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
while true:
if buf[pos] in chars:
add(tok.literal, buf[pos])
Inc(pos)
inc(pos)
else:
break
if buf[pos] == '_':
add(tok.literal, '_')
Inc(pos)
inc(pos)
L.bufPos = pos
proc isFloatLiteral(s: string): bool =
@@ -199,7 +199,7 @@ proc getNumber2(L: var TLexer, tok: var TToken) =
inc(L.bufpos)
return
tok.base = base2
var xi: biggestInt = 0
var xi: BiggestInt = 0
var bits = 0
while true:
case L.buf[pos]
@@ -221,7 +221,7 @@ proc getNumber2(L: var TLexer, tok: var TToken) =
proc getNumber16(L: var TLexer, tok: var TToken) =
var pos = L.bufpos + 1 # skip $
tok.base = base16
var xi: biggestInt = 0
var xi: BiggestInt = 0
var bits = 0
while true:
case L.buf[pos]
@@ -261,7 +261,7 @@ proc getNumber10(L: var TLexer, tok: var TToken) =
tok.fnumber = parseFloat(tok.literal)
tok.xkind = pxFloatLit
else:
tok.iNumber = ParseInt(tok.literal)
tok.iNumber = parseInt(tok.literal)
if (tok.iNumber < low(int32)) or (tok.iNumber > high(int32)):
tok.xkind = pxInt64Lit
else:
@@ -271,10 +271,10 @@ proc getNumber10(L: var TLexer, tok: var TToken) =
except EOverflow:
lexMessage(L, errNumberOutOfRange, tok.literal)
proc HandleCRLF(L: var TLexer, pos: int): int =
proc handleCRLF(L: var TLexer, pos: int): int =
case L.buf[pos]
of CR: result = nimlexbase.HandleCR(L, pos)
of LF: result = nimlexbase.HandleLF(L, pos)
of CR: result = nimlexbase.handleCR(L, pos)
of LF: result = nimlexbase.handleLF(L, pos)
else: result = pos
proc getString(L: var TLexer, tok: var TToken) =
@@ -319,7 +319,7 @@ proc getString(L: var TLexer, tok: var TToken) =
xi = (xi * 10) + (ord(buf[pos]) - ord('0'))
inc(pos)
else: lexMessage(L, errInvalidCharacterConstant)
if (xi <= 255): add(tok.literal, Chr(xi))
if (xi <= 255): add(tok.literal, chr(xi))
else: lexMessage(L, errInvalidCharacterConstant)
else:
break
@@ -334,17 +334,17 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
var c = buf[pos]
case c
of 'a'..'z', '0'..'9', '\x80'..'\xFF':
h = h +% Ord(c)
h = h +% ord(c)
h = h +% h shl 10
h = h xor (h shr 6)
of 'A'..'Z':
c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
h = h +% Ord(c)
h = h +% ord(c)
h = h +% h shl 10
h = h xor (h shr 6)
of '_': nil
of '_': discard
else: break
Inc(pos)
inc(pos)
h = h +% h shl 3
h = h xor (h shr 11)
h = h +% h shl 15
@@ -385,7 +385,7 @@ proc scanCurlyComment(L: var TLexer, tok: var TToken) =
while true:
case buf[pos]
of CR, LF:
pos = HandleCRLF(L, pos)
pos = handleCRLF(L, pos)
buf = L.buf
add(tok.literal, "\n#")
of '}':
@@ -405,7 +405,7 @@ proc scanStarComment(L: var TLexer, tok: var TToken) =
while true:
case buf[pos]
of CR, LF:
pos = HandleCRLF(L, pos)
pos = handleCRLF(L, pos)
buf = L.buf
add(tok.literal, "\n#")
of '*':
@@ -428,9 +428,9 @@ proc skip(L: var TLexer, tok: var TToken) =
while true:
case buf[pos]
of ' ', Tabulator:
Inc(pos) # newline is special:
inc(pos) # newline is special:
of CR, LF:
pos = HandleCRLF(L, pos)
pos = handleCRLF(L, pos)
buf = L.buf
else:
break # EndOfFile also leaves the loop
@@ -449,7 +449,7 @@ proc getTok(L: var TLexer, tok: var TToken) =
case c
of ';':
tok.xkind = pxSemicolon
Inc(L.bufpos)
inc(L.bufpos)
of '/':
if L.buf[L.bufpos + 1] == '/':
scanLineComment(L, tok)
@@ -458,12 +458,12 @@ proc getTok(L: var TLexer, tok: var TToken) =
inc(L.bufpos)
of ',':
tok.xkind = pxComma
Inc(L.bufpos)
inc(L.bufpos)
of '(':
Inc(L.bufpos)
inc(L.bufpos)
if (L.buf[L.bufPos] == '*'):
if (L.buf[L.bufPos + 1] == '$'):
Inc(L.bufpos, 2)
inc(L.bufpos, 2)
skip(L, tok)
getSymbol(L, tok)
tok.xkind = pxStarDirLe
@@ -481,12 +481,12 @@ proc getTok(L: var TLexer, tok: var TToken) =
tok.xkind = pxStar
of ')':
tok.xkind = pxParRi
Inc(L.bufpos)
inc(L.bufpos)
of '[':
Inc(L.bufpos)
inc(L.bufpos)
tok.xkind = pxBracketLe
of ']':
Inc(L.bufpos)
inc(L.bufpos)
tok.xkind = pxBracketRi
of '.':
inc(L.bufpos)
@@ -496,21 +496,21 @@ proc getTok(L: var TLexer, tok: var TToken) =
else:
tok.xkind = pxDot
of '{':
Inc(L.bufpos)
inc(L.bufpos)
case L.buf[L.bufpos]
of '$':
Inc(L.bufpos)
inc(L.bufpos)
skip(L, tok)
getSymbol(L, tok)
tok.xkind = pxCurlyDirLe
of '&':
Inc(L.bufpos)
inc(L.bufpos)
tok.xkind = pxAmp
of '%':
Inc(L.bufpos)
inc(L.bufpos)
tok.xkind = pxPer
of '@':
Inc(L.bufpos)
inc(L.bufpos)
tok.xkind = pxCommand
else: scanCurlyComment(L, tok)
of '+':
@@ -554,7 +554,7 @@ proc getTok(L: var TLexer, tok: var TToken) =
inc(L.bufpos)
of '}':
tok.xkind = pxCurlyDirRi
Inc(L.bufpos)
inc(L.bufpos)
of '\'', '#':
getString(L, tok)
of '$':
@@ -567,4 +567,4 @@ proc getTok(L: var TLexer, tok: var TToken) =
tok.literal = c & ""
tok.xkind = pxInvalid
lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
Inc(L.bufpos)
inc(L.bufpos)

View File

@@ -57,7 +57,7 @@ const
["tbinaryfile", "tfile"], ["strstart", "0"], ["nl", "\"\\n\""],
["tostring", "$"]]
proc ParseUnit*(p: var TParser): PNode
proc parseUnit*(p: var TParser): PNode
proc openParser*(p: var TParser, filename: string, inputStream: PLLStream,
flags: set[TParserFlag] = {})
proc closeParser*(p: var TParser)
@@ -67,20 +67,20 @@ proc fixRecordDef*(n: var PNode)
# implementation
proc OpenParser(p: var TParser, filename: string,
proc openParser(p: var TParser, filename: string,
inputStream: PLLStream, flags: set[TParserFlag] = {}) =
OpenLexer(p.lex, filename, inputStream)
openLexer(p.lex, filename, inputStream)
initIdTable(p.repl)
for i in countup(low(stdReplacements), high(stdReplacements)):
IdTablePut(p.repl, getIdent(stdReplacements[i][0]),
idTablePut(p.repl, getIdent(stdReplacements[i][0]),
getIdent(stdReplacements[i][1]))
if pfMoreReplacements in flags:
for i in countup(low(nimReplacements), high(nimReplacements)):
IdTablePut(p.repl, getIdent(nimReplacements[i][0]),
idTablePut(p.repl, getIdent(nimReplacements[i][0]),
getIdent(nimReplacements[i][1]))
p.flags = flags
proc CloseParser(p: var TParser) = CloseLexer(p.lex)
proc closeParser(p: var TParser) = closeLexer(p.lex)
proc getTok(p: var TParser) = getTok(p.lex, p.tok)
proc parMessage(p: TParser, msg: TMsgKind, arg = "") =
@@ -98,15 +98,15 @@ proc skipCom(p: var TParser, n: PNode) =
parMessage(p, warnCommentXIgnored, p.tok.literal)
getTok(p)
proc ExpectIdent(p: TParser) =
proc expectIdent(p: TParser) =
if p.tok.xkind != pxSymbol:
lexMessage(p.lex, errIdentifierExpected, $(p.tok))
proc Eat(p: var TParser, xkind: TTokKind) =
proc eat(p: var TParser, xkind: TTokKind) =
if p.tok.xkind == xkind: getTok(p)
else: lexMessage(p.lex, errTokenExpected, TokKindToStr(xkind))
else: lexMessage(p.lex, errTokenExpected, tokKindToStr(xkind))
proc Opt(p: var TParser, xkind: TTokKind) =
proc opt(p: var TParser, xkind: TTokKind) =
if p.tok.xkind == xkind: getTok(p)
proc newNodeP(kind: TNodeKind, p: TParser): PNode =
@@ -131,7 +131,7 @@ proc newIdentNodeP(ident: PIdent, p: TParser): PNode =
proc createIdentNodeP(ident: PIdent, p: TParser): PNode =
result = newNodeP(nkIdent, p)
var x = PIdent(IdTableGet(p.repl, ident))
var x = PIdent(idTableGet(p.repl, ident))
if x != nil: result.ident = x
else: result.ident = ident
@@ -170,7 +170,7 @@ proc parseCommand(p: var TParser, definition: PNode = nil): PNode =
getTok(p)
eat(p, pxCurlyDirRi)
result = parseExpr(p)
if result.kind == nkEmpty: InternalError("emptyNode modified")
if result.kind == nkEmpty: internalError("emptyNode modified")
result.kind = nkCurly
elif p.tok.ident.id == getIdent("cast").id:
getTok(p)
@@ -251,7 +251,7 @@ proc bracketExprList(p: var TParser, first: PNode): PNode =
getTok(p)
break
if p.tok.xkind == pxEof:
parMessage(p, errTokenExpected, TokKindToStr(pxBracketRi))
parMessage(p, errTokenExpected, tokKindToStr(pxBracketRi))
break
var a = rangeExpr(p)
skipCom(p, a)
@@ -281,7 +281,7 @@ proc exprListAux(p: var TParser, elemKind: TNodeKind,
getTok(p)
break
if p.tok.xkind == pxEof:
parMessage(p, errTokenExpected, TokKindToStr(endtok))
parMessage(p, errTokenExpected, tokKindToStr(endTok))
break
var a = exprColonEqExpr(p, elemKind, sepTok)
skipCom(p, a)
@@ -319,7 +319,7 @@ proc qualifiedIdentListAux(p: var TParser, endTok: TTokKind,
getTok(p)
break
if p.tok.xkind == pxEof:
parMessage(p, errTokenExpected, TokKindToStr(endtok))
parMessage(p, errTokenExpected, tokKindToStr(endTok))
break
var a = qualifiedIdent(p)
skipCom(p, a)
@@ -335,7 +335,7 @@ proc exprColonEqExprList(p: var TParser, kind, elemKind: TNodeKind,
proc setBaseFlags(n: PNode, base: TNumericalBase) =
case base
of base10: nil
of base10: discard
of base2: incl(n.flags, nfBase2)
of base8: incl(n.flags, nfBase8)
of base16: incl(n.flags, nfBase16)
@@ -466,7 +466,7 @@ proc lowestExprAux(p: var TParser, v: var PNode, limit: int): TTokKind =
eat(p, pxCurlyDirRi)
opNode.ident = getIdent("&")
else:
nil
discard
of pxMinus:
if p.tok.xkind == pxPer:
getTok(p)
@@ -477,7 +477,7 @@ proc lowestExprAux(p: var TParser, v: var PNode, limit: int): TTokKind =
of pxNeq:
opNode.ident = getIdent("!=")
else:
nil
discard
skipCom(p, opNode) # read sub-expression with higher priority
nextop = lowestExprAux(p, v2, opPred)
addSon(node, opNode)
@@ -505,7 +505,7 @@ proc fixExpr(n: PNode): PNode =
(n.sons[2].kind in {nkCharLit, nkStrLit}):
n.sons[0].ident = getIdent("&") # fix operator
else:
nil
discard
if not (n.kind in {nkEmpty..nkNilLit}):
for i in countup(0, sonsLen(n) - 1): result.sons[i] = fixExpr(n.sons[i])
@@ -584,7 +584,7 @@ proc parseIncludeDir(p: var TParser): PNode =
proc definedExprAux(p: var TParser): PNode =
result = newNodeP(nkCall, p)
addSon(result, newIdentNodeP(getIdent("defined"), p))
ExpectIdent(p)
expectIdent(p)
addSon(result, createIdentNodeP(p.tok.ident, p))
getTok(p)
@@ -603,7 +603,7 @@ proc parseStmtList(p: var TParser): PNode =
of pxCurlyDirLe, pxStarDirLe:
if not isHandledDirective(p): break
else:
nil
discard
addSon(result, parseStmt(p))
if sonsLen(result) == 1: result = result.sons[0]
@@ -732,7 +732,7 @@ proc parseRepeat(p: var TParser): PNode =
addSon(b, c)
addSon(a, b)
if b.sons[0].kind == nkIdent and b.sons[0].ident.id == getIdent("false").id:
nil
discard
else:
addSon(s, a)
addSon(result, s)
@@ -753,7 +753,7 @@ proc parseCase(p: var TParser): PNode =
while (p.tok.xkind != pxEof) and (p.tok.xkind != pxColon):
addSon(b, rangeExpr(p))
opt(p, pxComma)
skipcom(p, b)
skipCom(p, b)
eat(p, pxColon)
skipCom(p, b)
addSon(b, parseStmt(p))
@@ -818,7 +818,7 @@ proc parseFor(p: var TParser): PNode =
getTok(p)
b = parseExpr(p)
else:
parMessage(p, errTokenExpected, TokKindToStr(pxTo))
parMessage(p, errTokenExpected, tokKindToStr(pxTo))
addSon(c, a)
addSon(c, b)
eat(p, pxDo)
@@ -840,7 +840,7 @@ proc parseParam(p: var TParser): PNode =
getTok(p)
v = newNodeP(nkVarTy, p)
else:
nil
discard
while true:
case p.tok.xkind
of pxSymbol: a = createIdentNodeP(p.tok.ident, p)
@@ -915,7 +915,7 @@ proc parseCallingConvention(p: var TParser): PNode =
getTok(p)
opt(p, pxSemicolon)
else:
nil
discard
proc parseRoutineSpecifiers(p: var TParser, noBody: var bool): PNode =
var e: PNode
@@ -1096,7 +1096,7 @@ proc parseRecordCase(p: var TParser): PNode =
while (p.tok.xkind != pxEof) and (p.tok.xkind != pxColon):
addSon(b, rangeExpr(p))
opt(p, pxComma)
skipcom(p, b)
skipCom(p, b)
eat(p, pxColon)
skipCom(p, b)
c = newNodeP(nkRecList, p)
@@ -1133,7 +1133,7 @@ proc parseRecordPart(p: var TParser): PNode =
proc exSymbol(n: var PNode) =
case n.kind
of nkPostfix:
nil
discard
of nkPragmaExpr:
exSymbol(n.sons[0])
of nkIdent, nkAccQuoted:
@@ -1154,7 +1154,7 @@ proc fixRecordDef(n: var PNode) =
for i in countup(0, sonsLen(n) - 1): fixRecordDef(n.sons[i])
of nkIdentDefs:
for i in countup(0, sonsLen(n) - 3): exSymbol(n.sons[i])
of nkNilLit, nkEmpty: nil
of nkNilLit, nkEmpty: discard
else: internalError(n.info, "fixRecordDef(): " & $n.kind)
proc addPragmaToIdent(ident: var PNode, pragma: PNode) =
@@ -1168,7 +1168,7 @@ proc addPragmaToIdent(ident: var PNode, pragma: PNode) =
else:
pragmasNode = ident.sons[1]
if pragmasNode.kind != nkPragma:
InternalError(ident.info, "addPragmaToIdent")
internalError(ident.info, "addPragmaToIdent")
addSon(pragmasNode, pragma)
proc parseRecordBody(p: var TParser, result, definition: PNode) =
@@ -1183,15 +1183,15 @@ proc parseRecordBody(p: var TParser, result, definition: PNode) =
if definition != nil:
addPragmaToIdent(definition.sons[0], newIdentNodeP(p.tok.ident, p))
else:
InternalError(result.info, "anonymous record is not supported")
internalError(result.info, "anonymous record is not supported")
getTok(p)
else:
InternalError(result.info, "parseRecordBody")
internalError(result.info, "parseRecordBody")
of pxCommand:
if definition != nil: addPragmaToIdent(definition.sons[0], parseCommand(p))
else: InternalError(result.info, "anonymous record is not supported")
else: internalError(result.info, "anonymous record is not supported")
else:
nil
discard
opt(p, pxSemicolon)
skipCom(p, result)
@@ -1223,7 +1223,7 @@ proc parseTypeDesc(p: var TParser, definition: PNode = nil): PNode =
getTok(p)
if p.tok.xkind == pxCommand:
result = parseCommand(p)
if result.kind != nkTupleTy: InternalError(result.info, "parseTypeDesc")
if result.kind != nkTupleTy: internalError(result.info, "parseTypeDesc")
parseRecordBody(p, result, definition)
var a = lastSon(result) # embed nkRecList directly into nkTupleTy
for i in countup(0, sonsLen(a) - 1):
@@ -1237,7 +1237,7 @@ proc parseTypeDesc(p: var TParser, definition: PNode = nil): PNode =
if definition != nil:
addPragmaToIdent(definition.sons[0], newIdentNodeP(getIdent("final"), p))
else:
InternalError(result.info, "anonymous record is not supported")
internalError(result.info, "anonymous record is not supported")
of pxObject: result = parseRecordOrObject(p, nkObjectTy, definition)
of pxParLe: result = parseEnum(p)
of pxArray:
@@ -1399,7 +1399,7 @@ proc fixVarSection(p: var TParser, counter: PNode) =
proc exSymbols(n: PNode) =
case n.kind
of nkEmpty..nkNilLit: nil
of nkEmpty..nkNilLit: discard
of nkProcDef..nkIteratorDef: exSymbol(n.sons[namePos])
of nkWhenStmt, nkStmtList:
for i in countup(0, sonsLen(n) - 1): exSymbols(n.sons[i])
@@ -1410,7 +1410,7 @@ proc exSymbols(n: PNode) =
exSymbol(n.sons[i].sons[0])
if n.sons[i].sons[2].kind == nkObjectTy:
fixRecordDef(n.sons[i].sons[2])
else: nil
else: discard
proc parseBegin(p: var TParser, result: PNode) =
getTok(p)

View File

@@ -19,12 +19,12 @@ proc verboseOpen(s: PSym): PPassContext =
proc verboseProcess(context: PPassContext, n: PNode): PNode =
result = n
if context != nil: InternalError("logpass: context is not nil")
if context != nil: internalError("logpass: context is not nil")
if gVerbosity == 3:
# system.nim deactivates all hints, for verbosity:3 we want the processing
# messages nonetheless, so we activate them again unconditionally:
incl(msgs.gNotes, hintProcessing)
Message(n.info, hintProcessing, $idgen.gBackendId)
message(n.info, hintProcessing, $idgen.gBackendId)
const verbosePass* = makePass(open = verboseOpen, process = verboseProcess)
@@ -34,14 +34,14 @@ proc cleanUp(c: PPassContext, n: PNode): PNode =
if optDeadCodeElim in gGlobalOptions or n == nil: return
case n.kind
of nkStmtList:
for i in countup(0, sonsLen(n) - 1): discard cleanup(c, n.sons[i])
for i in countup(0, sonsLen(n) - 1): discard cleanUp(c, n.sons[i])
of nkProcDef, nkMethodDef:
if n.sons[namePos].kind == nkSym:
var s = n.sons[namePos].sym
if sfDeadCodeElim notin getModule(s).flags and not astNeeded(s):
s.ast.sons[bodyPos] = ast.emptyNode # free the memory
else:
nil
discard
const cleanupPass* = makePass(process = cleanUp, close = cleanUp)

View File

@@ -13,7 +13,7 @@
import
strutils, lists, options, ast, astalgo, llstream, msgs, platform, os,
condsyms, idents, renderer, types, extccomp, math, magicsys, nversion,
nimsets, syntaxes, times, rodread, semthreads, idgen
nimsets, syntaxes, times, rodread, idgen
type
TPassContext* = object of TObject # the pass's context
@@ -30,8 +30,8 @@ type
TPass* = tuple[open: TPassOpen, openCached: TPassOpenCached,
process: TPassProcess, close: TPassClose]
TPassData* = tuple[input: PNode, closeOutput: Pnode]
TPasses* = openarray[TPass]
TPassData* = tuple[input: PNode, closeOutput: PNode]
TPasses* = openArray[TPass]
# a pass is a tuple of procedure vars ``TPass.close`` may produce additional
# nodes. These are passed to the other close procedures.
@@ -74,7 +74,8 @@ proc astNeeded*(s: PSym): bool =
({sfCompilerProc, sfCompileTime} * s.flags == {}) and
(s.typ.callConv != ccInline) and
(s.ast.sons[genericParamsPos].kind == nkEmpty):
result = semthreads.needsGlobalAnalysis()
result = false
# XXX this doesn't really make sense with excessive CTFE
else:
result = true
@@ -169,7 +170,7 @@ proc processModule(module: PSym, stream: PLLStream, rd: PRodReader) =
openPasses(a, module)
if stream == nil:
let filename = fileIdx.toFullPath
s = LLStreamOpen(filename, fmRead)
s = llStreamOpen(filename, fmRead)
if s == nil:
rawMessage(errCannotOpenFile, filename)
return
@@ -195,7 +196,7 @@ proc processModule(module: PSym, stream: PLLStream, rd: PRodReader) =
if s.kind != llsStdIn: break
closePasses(a)
# id synchronization point for more consistent code generation:
IDsynchronizationPoint(1000)
idSynchronizationPoint(1000)
else:
openPassesCached(a, module, rd)
var n = loadInitSection(rd)

View File

@@ -40,7 +40,7 @@ proc canonKind(n: PNode): TNodeKind =
of nkCallKinds: result = nkCall
of nkStrLit..nkTripleStrLit: result = nkStrLit
of nkFastAsgn: result = nkAsgn
else: nil
else: discard
proc sameKinds(a, b: PNode): bool {.inline.} =
result = a.kind == b.kind or a.canonKind == b.canonKind
@@ -87,22 +87,22 @@ proc matchChoice(c: PPatternContext, p, n: PNode): bool =
if matches(c, p.sons[i], n): return true
proc bindOrCheck(c: PPatternContext, param: PSym, n: PNode): bool =
var pp = GetLazy(c, param)
var pp = getLazy(c, param)
if pp != nil:
# check if we got the same pattern (already unified):
result = sameTrees(pp, n) #matches(c, pp, n)
elif n.kind == nkArgList or checkTypes(c, param, n):
PutLazy(c, param, n)
putLazy(c, param, n)
result = true
proc gather(c: PPatternContext, param: PSym, n: PNode) =
var pp = GetLazy(c, param)
var pp = getLazy(c, param)
if pp != nil and pp.kind == nkArgList:
pp.add(n)
else:
pp = newNodeI(nkArgList, n.info, 1)
pp.sons[0] = n
PutLazy(c, param, pp)
putLazy(c, param, pp)
proc matchNested(c: PPatternContext, p, n: PNode, rpn: bool): bool =
# match ``op * param`` or ``op *| param``
@@ -148,7 +148,7 @@ proc matches(c: PPatternContext, p, n: PNode): bool =
of "*": result = matchNested(c, p, n, rpn=false)
of "**": result = matchNested(c, p, n, rpn=true)
of "~": result = not matches(c, p.sons[1], n)
else: InternalError(p.info, "invalid pattern")
else: internalError(p.info, "invalid pattern")
# template {add(a, `&` * b)}(a: string{noalias}, b: varargs[string]) =
# add(a, b)
elif p.kind == nkCurlyExpr:
@@ -237,15 +237,6 @@ proc addToArgList(result, n: PNode) =
else:
for i in 0 .. <n.len: result.add(n.sons[i])
when false:
proc procPatternMatches*(c: PContext, s: PSym, n: PNode): bool =
## for AST-based overloading:
var ctx: TPatternContext
ctx.owner = s
ctx.c = c
ctx.formals = sonsLen(s.typ)-1
result = matches(ctx, s.ast.sons[patternPos], n)
proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
## returns a tree to semcheck if the rule triggered; nil otherwise
var ctx: TPatternContext
@@ -265,7 +256,7 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
args = newNodeI(nkArgList, n.info)
for i in 1 .. < params.len:
let param = params.sons[i].sym
let x = GetLazy(ctx, param)
let x = getLazy(ctx, param)
# couldn't bind parameter:
if isNil(x): return nil
result.add(x)
@@ -276,7 +267,7 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
var rs = result.sons[i]
let param = params.sons[i].sym
case whichAlias(param)
of aqNone: nil
of aqNone: discard
of aqShouldAlias:
# it suffices that it aliases for sure with *some* other param:
var ok = false

View File

@@ -10,7 +10,7 @@
import
llstream, lexer, parser, idents, strutils, ast, msgs
proc ParseAll*(p: var TParser): PNode =
proc parseAll*(p: var TParser): PNode =
result = nil
proc parseTopLevelStmt*(p: var TParser): PNode =

View File

@@ -1,18 +0,0 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
import
llstream, lexer, parser, idents, strutils, ast, msgs
proc ParseAll*(p: var TParser): PNode =
result = nil
proc parseTopLevelStmt*(p: var TParser): PNode =
result = nil

View File

@@ -147,7 +147,7 @@ const
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", props: {}),
(name: "Standalone", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
scriptExt: ".sh", curDir: ".", exeExt: ".elf", extSep: ".",
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
props: {})]
type
@@ -185,13 +185,13 @@ var
targetCPU*, hostCPU*: TSystemCPU
targetOS*, hostOS*: TSystemOS
proc NameToOS*(name: string): TSystemOS
proc NameToCPU*(name: string): TSystemCPU
proc nameToOS*(name: string): TSystemOS
proc nameToCPU*(name: string): TSystemCPU
var
IntSize*: int
intSize*: int
floatSize*: int
PtrSize*: int
ptrSize*: int
tnl*: string # target newline
proc setTarget*(o: TSystemOS, c: TSystemCPU) =
@@ -200,18 +200,18 @@ proc setTarget*(o: TSystemOS, c: TSystemCPU) =
#echo "new Target: OS: ", o, " CPU: ", c
targetCPU = c
targetOS = o
intSize = cpu[c].intSize div 8
floatSize = cpu[c].floatSize div 8
ptrSize = cpu[c].bit div 8
tnl = os[o].newLine
intSize = CPU[c].intSize div 8
floatSize = CPU[c].floatSize div 8
ptrSize = CPU[c].bit div 8
tnl = OS[o].newLine
proc NameToOS(name: string): TSystemOS =
proc nameToOS(name: string): TSystemOS =
for i in countup(succ(osNone), high(TSystemOS)):
if cmpIgnoreStyle(name, OS[i].name) == 0:
return i
result = osNone
proc NameToCPU(name: string): TSystemCPU =
proc nameToCPU(name: string): TSystemCPU =
for i in countup(succ(cpuNone), high(TSystemCPU)):
if cmpIgnoreStyle(name, CPU[i].name) == 0:
return i

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -20,62 +20,65 @@ const
const
procPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
wMagic, wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader,
wCompilerProc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
wMagic, wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
wCompilerproc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
wNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wHoist,
wGenSym, wInject, wRaises, wTags}
wAsmNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wCodegenDecl,
wGensym, wInject, wRaises, wTags, wUses, wOperator, wDelegator, wGcSafe}
converterPragmas* = procPragmas
methodPragmas* = procPragmas
templatePragmas* = {wImmediate, wDeprecated, wError, wGenSym, wInject, wDirty}
templatePragmas* = {wImmediate, wDeprecated, wError, wGensym, wInject, wDirty,
wDelegator}
macroPragmas* = {FirstCallConv..LastCallConv, wImmediate, wImportc, wExportc,
wNodecl, wMagic, wNosideEffect, wCompilerProc, wDeprecated, wExtern,
wImportcpp, wImportobjc, wError, wDiscardable, wGenSym, wInject}
iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideEffect, wSideEffect,
wNodecl, wMagic, wNosideeffect, wCompilerproc, wDeprecated, wExtern,
wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wDelegator}
iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideeffect, wSideeffect,
wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
wImportcpp, wImportobjc, wError, wDiscardable, wGenSym, wInject, wRaises,
wTags}
wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises,
wTags, wUses, wOperator, wGcSafe}
exprPragmas* = {wLine}
stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
wLinedir, wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError,
wFatal, wDefine, wUndef, wCompile, wLink, wLinkSys, wPure, wPush, wPop,
wBreakpoint, wWatchpoint, wPassL, wPassC, wDeadCodeElim, wDeprecated,
wFloatChecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
wLinearScanEnd, wPatterns, wEffects, wNoForward}
wFatal, wDefine, wUndef, wCompile, wLink, wLinksys, wPure, wPush, wPop,
wBreakpoint, wWatchPoint, wPassl, wPassc, wDeadCodeElim, wDeprecated,
wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto,
wInjectStmt}
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader,
wDeprecated, wExtern, wThread, wImportcpp, wImportobjc, wNoStackFrame,
wRaises, wTags}
wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame,
wRaises, wUses, wTags, wGcSafe}
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
wPure, wHeader, wCompilerProc, wFinal, wSize, wExtern, wShallow,
wImportcpp, wImportobjc, wError, wIncompleteStruct, wByCopy, wByRef,
wInheritable, wGenSym, wInject}
wPure, wHeader, wCompilerproc, wFinal, wSize, wExtern, wShallow,
wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef,
wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
wBorrow, wGcSafe}
fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
wImportcpp, wImportobjc, wError}
wImportCpp, wImportObjC, wError}
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
wMagic, wHeader, wDeprecated, wCompilerProc, wDynLib, wExtern,
wImportcpp, wImportobjc, wError, wNoInit, wCompileTime, wGlobal,
wGenSym, wInject}
wMagic, wHeader, wDeprecated, wCompilerproc, wDynlib, wExtern,
wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal,
wGensym, wInject, wCodegenDecl}
constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
wExtern, wImportcpp, wImportobjc, wError, wGenSym, wInject}
wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject}
letPragmas* = varPragmas
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideEffect,
wThread, wRaises, wTags}
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect,
wThread, wRaises, wUses, wTags, wGcSafe}
allRoutinePragmas* = procPragmas + iteratorPragmas + lambdaPragmas
proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)
# implementation
proc invalidPragma(n: PNode) =
LocalError(n.info, errInvalidPragmaX, renderTree(n, {renderNoComments}))
localError(n.info, errInvalidPragmaX, renderTree(n, {renderNoComments}))
proc pragmaAsm*(c: PContext, n: PNode): char =
result = '\0'
if n != nil:
for i in countup(0, sonsLen(n) - 1):
let it = n.sons[i]
if (it.kind == nkExprColonExpr) and (it.sons[0].kind == nkIdent):
if it.kind == nkExprColonExpr and it.sons[0].kind == nkIdent:
case whichKeyword(it.sons[0].ident)
of wSubsChar:
if it.sons[1].kind == nkCharLit: result = chr(int(it.sons[1].intVal))
@@ -84,16 +87,33 @@ proc pragmaAsm*(c: PContext, n: PNode): char =
else:
invalidPragma(it)
proc setExternName(s: PSym, extname: string) =
proc setExternName(s: PSym, extname: string) =
s.loc.r = toRope(extname % s.name.s)
if gCmd == cmdPretty and '$' notin extname:
# note that '{.importc.}' is transformed into '{.importc: "$1".}'
s.loc.flags.incl(lfFullExternalName)
proc MakeExternImport(s: PSym, extname: string) =
proc makeExternImport(s: PSym, extname: string) =
setExternName(s, extname)
incl(s.flags, sfImportc)
excl(s.flags, sfForward)
proc MakeExternExport(s: PSym, extname: string) =
proc validateExternCName(s: PSym, info: TLineInfo) =
## Validates that the symbol name in s.loc.r is a valid C identifier.
##
## Valid identifiers are those alphanumeric including the underscore not
## starting with a number. If the check fails, a generic error will be
## displayed to the user.
let target = ropeToStr(s.loc.r)
if target.len < 1 or target[0] notin IdentStartChars or
not target.allCharsInSet(IdentChars):
localError(info, errGenerated, "invalid exported symbol")
proc makeExternExport(s: PSym, extname: string, info: TLineInfo) =
setExternName(s, extname)
# XXX to fix make it work with nimrtl.
#if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC}:
# validateExternCName(s, info)
incl(s.flags, sfExportc)
proc processImportCompilerProc(s: PSym, extname: string) =
@@ -120,7 +140,7 @@ proc newEmptyStrNode(n: PNode): PNode {.noinline.} =
proc getStrLitNode(c: PContext, n: PNode): PNode =
if n.kind != nkExprColonExpr:
LocalError(n.info, errStringLiteralExpected)
localError(n.info, errStringLiteralExpected)
# error correction:
result = newEmptyStrNode(n)
else:
@@ -128,7 +148,7 @@ proc getStrLitNode(c: PContext, n: PNode): PNode =
case n.sons[1].kind
of nkStrLit, nkRStrLit, nkTripleStrLit: result = n.sons[1]
else:
LocalError(n.info, errStringLiteralExpected)
localError(n.info, errStringLiteralExpected)
# error correction:
result = newEmptyStrNode(n)
@@ -137,22 +157,25 @@ proc expectStrLit(c: PContext, n: PNode): string =
proc expectIntLit(c: PContext, n: PNode): int =
if n.kind != nkExprColonExpr:
LocalError(n.info, errIntLiteralExpected)
localError(n.info, errIntLiteralExpected)
else:
n.sons[1] = c.semConstExpr(c, n.sons[1])
case n.sons[1].kind
of nkIntLit..nkInt64Lit: result = int(n.sons[1].intVal)
else: LocalError(n.info, errIntLiteralExpected)
else: localError(n.info, errIntLiteralExpected)
proc getOptionalStr(c: PContext, n: PNode, defaultStr: string): string =
if n.kind == nkExprColonExpr: result = expectStrLit(c, n)
else: result = defaultStr
proc processCodegenDecl(c: PContext, n: PNode, sym: PSym) =
sym.constraint = getStrLitNode(c, n)
proc processMagic(c: PContext, n: PNode, s: PSym) =
#if sfSystemModule notin c.module.flags:
# liMessage(n.info, errMagicOnlyInSystem)
if n.kind != nkExprColonExpr:
LocalError(n.info, errStringLiteralExpected)
localError(n.info, errStringLiteralExpected)
return
var v: string
if n.sons[1].kind == nkIdent: v = n.sons[1].ident.s
@@ -161,57 +184,57 @@ proc processMagic(c: PContext, n: PNode, s: PSym) =
if substr($m, 1) == v:
s.magic = m
break
if s.magic == mNone: Message(n.info, warnUnknownMagic, v)
if s.magic == mNone: message(n.info, warnUnknownMagic, v)
proc wordToCallConv(sw: TSpecialWord): TCallingConvention =
# this assumes that the order of special words and calling conventions is
# the same
result = TCallingConvention(ord(ccDefault) + ord(sw) - ord(wNimcall))
proc IsTurnedOn(c: PContext, n: PNode): bool =
proc isTurnedOn(c: PContext, n: PNode): bool =
if n.kind == nkExprColonExpr:
let x = c.semConstBoolExpr(c, n.sons[1])
n.sons[1] = x
if x.kind == nkIntLit: return x.intVal != 0
LocalError(n.info, errOnOrOffExpected)
localError(n.info, errOnOrOffExpected)
proc onOff(c: PContext, n: PNode, op: TOptions) =
if IsTurnedOn(c, n): gOptions = gOptions + op
if isTurnedOn(c, n): gOptions = gOptions + op
else: gOptions = gOptions - op
proc pragmaDeadCodeElim(c: PContext, n: PNode) =
if IsTurnedOn(c, n): incl(c.module.flags, sfDeadCodeElim)
if isTurnedOn(c, n): incl(c.module.flags, sfDeadCodeElim)
else: excl(c.module.flags, sfDeadCodeElim)
proc pragmaNoForward(c: PContext, n: PNode) =
if IsTurnedOn(c, n): incl(c.module.flags, sfNoForward)
if isTurnedOn(c, n): incl(c.module.flags, sfNoForward)
else: excl(c.module.flags, sfNoForward)
proc processCallConv(c: PContext, n: PNode) =
if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent):
var sw = whichKeyword(n.sons[1].ident)
case sw
of firstCallConv..lastCallConv:
of FirstCallConv..LastCallConv:
POptionEntry(c.optionStack.tail).defaultCC = wordToCallConv(sw)
else: LocalError(n.info, errCallConvExpected)
else: localError(n.info, errCallConvExpected)
else:
LocalError(n.info, errCallConvExpected)
localError(n.info, errCallConvExpected)
proc getLib(c: PContext, kind: TLibKind, path: PNode): PLib =
var it = PLib(c.libs.head)
while it != nil:
if it.kind == kind:
if trees.ExprStructuralEquivalent(it.path, path): return it
if trees.exprStructuralEquivalent(it.path, path): return it
it = PLib(it.next)
result = newLib(kind)
result.path = path
Append(c.libs, result)
append(c.libs, result)
if path.kind in {nkStrLit..nkTripleStrLit}:
result.isOverriden = options.isDynLibOverride(path.strVal)
result.isOverriden = options.isDynlibOverride(path.strVal)
proc expectDynlibNode(c: PContext, n: PNode): PNode =
if n.kind != nkExprColonExpr:
LocalError(n.info, errStringLiteralExpected)
localError(n.info, errStringLiteralExpected)
# error correction:
result = newEmptyStrNode(n)
else:
@@ -221,7 +244,7 @@ proc expectDynlibNode(c: PContext, n: PNode): PNode =
if result.kind == nkSym and result.sym.kind == skConst:
result = result.sym.ast # look it up
if result.typ == nil or result.typ.kind notin {tyPointer, tyString, tyProc}:
LocalError(n.info, errStringLiteralExpected)
localError(n.info, errStringLiteralExpected)
result = newEmptyStrNode(n)
proc processDynLib(c: PContext, n: PNode, sym: PSym) =
@@ -239,7 +262,7 @@ proc processDynLib(c: PContext, n: PNode, sym: PSym) =
# since we'll be loading the dynlib symbols dynamically, we must use
# a calling convention that doesn't introduce custom name mangling
# cdecl is the default - the user can override this explicitly
if sym.kind in RoutineKinds and sym.typ != nil and
if sym.kind in routineKinds and sym.typ != nil and
sym.typ.callConv == ccDefault:
sym.typ.callConv = ccCDecl
@@ -253,11 +276,11 @@ proc processNote(c: PContext, n: PNode) =
of wHint:
var x = findStr(msgs.HintsToStr, n.sons[0].sons[1].ident.s)
if x >= 0: nk = TNoteKind(x + ord(hintMin))
else: invalidPragma(n)
else: invalidPragma(n); return
of wWarning:
var x = findStr(msgs.WarningsToStr, n.sons[0].sons[1].ident.s)
if x >= 0: nk = TNoteKind(x + ord(warnMin))
else: InvalidPragma(n)
else: invalidPragma(n); return
else:
invalidPragma(n)
return
@@ -276,27 +299,27 @@ proc processOption(c: PContext, n: PNode): bool =
else:
var sw = whichKeyword(n.sons[0].ident)
case sw
of wChecks: OnOff(c, n, checksOptions)
of wObjChecks: OnOff(c, n, {optObjCheck})
of wFieldchecks: OnOff(c, n, {optFieldCheck})
of wRangechecks: OnOff(c, n, {optRangeCheck})
of wBoundchecks: OnOff(c, n, {optBoundsCheck})
of wOverflowchecks: OnOff(c, n, {optOverflowCheck})
of wNilchecks: OnOff(c, n, {optNilCheck})
of wFloatChecks: OnOff(c, n, {optNanCheck, optInfCheck})
of wNaNchecks: OnOff(c, n, {optNanCheck})
of wInfChecks: OnOff(c, n, {optInfCheck})
of wAssertions: OnOff(c, n, {optAssert})
of wWarnings: OnOff(c, n, {optWarns})
of wHints: OnOff(c, n, {optHints})
of wCallConv: processCallConv(c, n)
of wLinedir: OnOff(c, n, {optLineDir})
of wStacktrace: OnOff(c, n, {optStackTrace})
of wLinetrace: OnOff(c, n, {optLineTrace})
of wDebugger: OnOff(c, n, {optEndb})
of wProfiler: OnOff(c, n, {optProfiler})
of wByRef: OnOff(c, n, {optByRef})
of wDynLib: processDynLib(c, n, nil)
of wChecks: onOff(c, n, ChecksOptions)
of wObjChecks: onOff(c, n, {optObjCheck})
of wFieldChecks: onOff(c, n, {optFieldCheck})
of wRangechecks: onOff(c, n, {optRangeCheck})
of wBoundchecks: onOff(c, n, {optBoundsCheck})
of wOverflowchecks: onOff(c, n, {optOverflowCheck})
of wNilchecks: onOff(c, n, {optNilCheck})
of wFloatchecks: onOff(c, n, {optNaNCheck, optInfCheck})
of wNanChecks: onOff(c, n, {optNaNCheck})
of wInfChecks: onOff(c, n, {optInfCheck})
of wAssertions: onOff(c, n, {optAssert})
of wWarnings: onOff(c, n, {optWarns})
of wHints: onOff(c, n, {optHints})
of wCallconv: processCallConv(c, n)
of wLinedir: onOff(c, n, {optLineDir})
of wStacktrace: onOff(c, n, {optStackTrace})
of wLinetrace: onOff(c, n, {optLineTrace})
of wDebugger: onOff(c, n, {optEndb})
of wProfiler: onOff(c, n, {optProfiler})
of wByRef: onOff(c, n, {optByRef})
of wDynlib: processDynLib(c, n, nil)
of wOptimization:
if n.sons[1].kind != nkIdent:
invalidPragma(n)
@@ -311,14 +334,14 @@ proc processOption(c: PContext, n: PNode): bool =
of "none":
excl(gOptions, optOptimizeSpeed)
excl(gOptions, optOptimizeSize)
else: LocalError(n.info, errNoneSpeedOrSizeExpected)
of wImplicitStatic: OnOff(c, n, {optImplicitStatic})
of wPatterns: OnOff(c, n, {optPatterns})
else: localError(n.info, errNoneSpeedOrSizeExpected)
of wImplicitStatic: onOff(c, n, {optImplicitStatic})
of wPatterns: onOff(c, n, {optPatterns})
else: result = true
proc processPush(c: PContext, n: PNode, start: int) =
if n.sons[start-1].kind == nkExprColonExpr:
LocalError(n.info, errGenerated, "':' after 'push' not supported")
localError(n.info, errGenerated, "':' after 'push' not supported")
var x = newOptionEntry()
var y = POptionEntry(c.optionStack.tail)
x.options = gOptions
@@ -336,7 +359,7 @@ proc processPush(c: PContext, n: PNode, start: int) =
proc processPop(c: PContext, n: PNode) =
if c.optionStack.counter <= 1:
LocalError(n.info, errAtPopWithoutPush)
localError(n.info, errAtPopWithoutPush)
else:
gOptions = POptionEntry(c.optionStack.tail).options
gNotes = POptionEntry(c.optionStack.tail).notes
@@ -344,15 +367,15 @@ proc processPop(c: PContext, n: PNode) =
proc processDefine(c: PContext, n: PNode) =
if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent):
DefineSymbol(n.sons[1].ident.s)
Message(n.info, warnDeprecated, "define")
defineSymbol(n.sons[1].ident.s)
message(n.info, warnDeprecated, "define")
else:
invalidPragma(n)
proc processUndef(c: PContext, n: PNode) =
if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent):
UndefSymbol(n.sons[1].ident.s)
Message(n.info, warnDeprecated, "undef")
undefSymbol(n.sons[1].ident.s)
message(n.info, warnDeprecated, "undef")
else:
invalidPragma(n)
@@ -364,13 +387,13 @@ proc processCompile(c: PContext, n: PNode) =
var s = expectStrLit(c, n)
var found = findFile(s)
if found == "": found = s
var trunc = ChangeFileExt(found, "")
var trunc = changeFileExt(found, "")
extccomp.addExternalFileToCompile(found)
extccomp.addFileToLink(completeCFilePath(trunc, false))
proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) =
var f = expectStrLit(c, n)
if splitFile(f).ext == "": f = addFileExt(f, cc[ccompiler].objExt)
if splitFile(f).ext == "": f = addFileExt(f, CC[cCompiler].objExt)
var found = findFile(f)
if found == "": found = f # use the default
case feature
@@ -379,16 +402,16 @@ proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) =
extccomp.addFileToLink(libpath / completeCFilePath(found, false))
else: internalError(n.info, "processCommonLink")
proc PragmaBreakpoint(c: PContext, n: PNode) =
proc pragmaBreakpoint(c: PContext, n: PNode) =
discard getOptionalStr(c, n, "")
proc PragmaCheckpoint(c: PContext, n: PNode) =
proc pragmaCheckpoint(c: PContext, n: PNode) =
# checkpoints can be used to debug the compiler; they are not documented
var info = n.info
inc(info.line) # next line is affected!
msgs.addCheckpoint(info)
proc PragmaWatchpoint(c: PContext, n: PNode) =
proc pragmaWatchpoint(c: PContext, n: PNode) =
if n.kind == nkExprColonExpr:
n.sons[1] = c.semExpr(c, n.sons[1])
else:
@@ -396,11 +419,11 @@ proc PragmaWatchpoint(c: PContext, n: PNode) =
proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
case n.sons[1].kind
of nkStrLit, nkRStrLit, nkTripleStrLit:
result = copyNode(n)
of nkStrLit, nkRStrLit, nkTripleStrLit:
result = newNode(if n.kind == nkAsmStmt: nkAsmStmt else: nkArgList, n.info)
var str = n.sons[1].strVal
if str == "":
LocalError(n.info, errEmptyAsm)
localError(n.info, errEmptyAsm)
return
# now parse the string literal and substitute symbols:
var a = 0
@@ -423,14 +446,14 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
a = c + 1
else: illFormedAst(n)
proc PragmaEmit(c: PContext, n: PNode) =
proc pragmaEmit(c: PContext, n: PNode) =
discard getStrLitNode(c, n)
n.sons[1] = semAsmOrEmit(c, n, '`')
proc noVal(n: PNode) =
if n.kind == nkExprColonExpr: invalidPragma(n)
proc PragmaUnroll(c: PContext, n: PNode) =
proc pragmaUnroll(c: PContext, n: PNode) =
if c.p.nestedLoopCounter <= 0:
invalidPragma(n)
elif n.kind == nkExprColonExpr:
@@ -440,10 +463,7 @@ proc PragmaUnroll(c: PContext, n: PNode) =
else:
invalidPragma(n)
proc PragmaLinearScanEnd(c: PContext, n: PNode) =
noVal(n)
proc PragmaLine(c: PContext, n: PNode) =
proc pragmaLine(c: PContext, n: PNode) =
if n.kind == nkExprColonExpr:
n.sons[1] = c.semConstExpr(c, n.sons[1])
let a = n.sons[1]
@@ -453,14 +473,14 @@ proc PragmaLine(c: PContext, n: PNode) =
if x.kind == nkExprColonExpr: x = x.sons[1]
if y.kind == nkExprColonExpr: y = y.sons[1]
if x.kind != nkStrLit:
LocalError(n.info, errStringLiteralExpected)
localError(n.info, errStringLiteralExpected)
elif y.kind != nkIntLit:
LocalError(n.info, errIntLiteralExpected)
localError(n.info, errIntLiteralExpected)
else:
n.info.fileIndex = msgs.fileInfoIdx(x.strVal)
n.info.line = int16(y.intVal)
else:
LocalError(n.info, errXExpected, "tuple")
localError(n.info, errXExpected, "tuple")
else:
# sensible default:
n.info = getInfoContext(-1)
@@ -471,11 +491,11 @@ proc processPragma(c: PContext, n: PNode, i: int) =
elif it.sons[0].kind != nkIdent: invalidPragma(n)
elif it.sons[1].kind != nkIdent: invalidPragma(n)
var userPragma = NewSym(skTemplate, it.sons[1].ident, nil, it.info)
var userPragma = newSym(skTemplate, it.sons[1].ident, nil, it.info)
var body = newNodeI(nkPragma, n.info)
for j in i+1 .. sonsLen(n)-1: addSon(body, n.sons[j])
userPragma.ast = body
StrTableAdd(c.userPragmas, userPragma)
strTableAdd(c.userPragmas, userPragma)
proc pragmaRaisesOrTags(c: PContext, n: PNode) =
proc processExc(c: PContext, x: PNode) =
@@ -493,28 +513,56 @@ proc pragmaRaisesOrTags(c: PContext, n: PNode) =
else:
invalidPragma(n)
proc pragmaUses(c: PContext, n: PNode) =
proc processExc(c: PContext, x: PNode): PNode =
if x.kind in {nkAccQuoted, nkIdent, nkSym,
nkOpenSymChoice, nkClosedSymChoice}:
if considerAcc(x).s == "*":
return newSymNode(ast.anyGlobal)
result = c.semExpr(c, x)
if result.kind != nkSym or sfGlobal notin result.sym.flags:
localError(x.info, "'$1' is not a global variable" % result.renderTree)
result = newSymNode(ast.anyGlobal)
if n.kind == nkExprColonExpr:
let it = n.sons[1]
if it.kind notin {nkCurly, nkBracket}:
n.sons[1] = processExc(c, it)
else:
for i in 0 .. <it.len:
it.sons[i] = processExc(c, it.sons[i])
else:
invalidPragma(n)
proc typeBorrow(sym: PSym, n: PNode) =
if n.kind == nkExprColonExpr:
let it = n.sons[1]
if it.kind != nkAccQuoted:
localError(n.info, "a type can only borrow `.` for now")
incl(sym.typ.flags, tfBorrowDot)
proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
validPragmas: TSpecialWords): bool =
var it = n.sons[i]
var key = if it.kind == nkExprColonExpr: it.sons[0] else: it
if key.kind == nkIdent:
var userPragma = StrTableGet(c.userPragmas, key.ident)
var userPragma = strTableGet(c.userPragmas, key.ident)
if userPragma != nil:
inc c.InstCounter
if c.InstCounter > 100:
GlobalError(it.info, errRecursiveDependencyX, userPragma.name.s)
inc c.instCounter
if c.instCounter > 100:
globalError(it.info, errRecursiveDependencyX, userPragma.name.s)
pragma(c, sym, userPragma.ast, validPragmas)
dec c.InstCounter
dec c.instCounter
else:
var k = whichKeyword(key.ident)
if k in validPragmas:
case k
of wExportc:
makeExternExport(sym, getOptionalStr(c, it, sym.name.s))
makeExternExport(sym, getOptionalStr(c, it, "$1"), it.info)
incl(sym.flags, sfUsed) # avoid wrong hints
of wImportc: makeExternImport(sym, getOptionalStr(c, it, sym.name.s))
of wImportc: makeExternImport(sym, getOptionalStr(c, it, "$1"))
of wImportCompilerProc:
processImportCompilerProc(sym, getOptionalStr(c, it, sym.name.s))
processImportCompilerProc(sym, getOptionalStr(c, it, "$1"))
of wExtern: setExternName(sym, expectStrLit(c, it))
of wImmediate:
if sym.kind in {skTemplate, skMacro}: incl(sym.flags, sfImmediate)
@@ -523,29 +571,31 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
if sym.kind == skTemplate: incl(sym.flags, sfDirty)
else: invalidPragma(it)
of wImportCpp:
processImportCpp(sym, getOptionalStr(c, it, sym.name.s))
processImportCpp(sym, getOptionalStr(c, it, "$1"))
of wImportObjC:
processImportObjC(sym, getOptionalStr(c, it, sym.name.s))
processImportObjC(sym, getOptionalStr(c, it, "$1"))
of wAlign:
if sym.typ == nil: invalidPragma(it)
var align = expectIntLit(c, it)
if not IsPowerOfTwo(align) and align != 0:
LocalError(it.info, errPowerOfTwoExpected)
if not isPowerOfTwo(align) and align != 0:
localError(it.info, errPowerOfTwoExpected)
else:
sym.typ.align = align
of wSize:
if sym.typ == nil: invalidPragma(it)
var size = expectIntLit(c, it)
if not IsPowerOfTwo(size) or size <= 0 or size > 8:
LocalError(it.info, errPowerOfTwoExpected)
if not isPowerOfTwo(size) or size <= 0 or size > 8:
localError(it.info, errPowerOfTwoExpected)
else:
sym.typ.size = size
of wNodecl:
noVal(it)
incl(sym.loc.Flags, lfNoDecl)
of wPure, wNoStackFrame:
incl(sym.loc.flags, lfNoDecl)
of wPure, wAsmNoStackFrame:
noVal(it)
if sym != nil: incl(sym.flags, sfPure)
if sym != nil:
if k == wPure and sym.kind in routineKinds: invalidPragma(it)
else: incl(sym.flags, sfPure)
of wVolatile:
noVal(it)
incl(sym.flags, sfVolatile)
@@ -561,19 +611,20 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
of wCompileTime:
noVal(it)
incl(sym.flags, sfCompileTime)
incl(sym.loc.Flags, lfNoDecl)
incl(sym.loc.flags, lfNoDecl)
of wGlobal:
noVal(it)
incl(sym.flags, sfGlobal)
incl(sym.flags, sfPure)
of wMerge:
noval(it)
noVal(it)
incl(sym.flags, sfMerge)
of wHeader:
var lib = getLib(c, libHeader, getStrLitNode(c, it))
addToLib(lib, sym)
incl(sym.flags, sfImportc)
incl(sym.loc.flags, lfHeader)
incl(sym.loc.Flags, lfNoDecl)
incl(sym.loc.flags, lfNoDecl)
# implies nodecl, because otherwise header would not make sense
if sym.loc.r == nil: sym.loc.r = toRope(sym.name.s)
of wDestructor:
@@ -585,23 +636,23 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
noVal(it)
incl(sym.flags, sfNoSideEffect)
if sym.typ != nil: incl(sym.typ.flags, tfNoSideEffect)
of wSideEffect:
of wSideeffect:
noVal(it)
incl(sym.flags, sfSideEffect)
of wNoReturn:
of wNoreturn:
noVal(it)
incl(sym.flags, sfNoReturn)
of wDynLib:
of wDynlib:
processDynLib(c, it, sym)
of wCompilerProc:
of wCompilerproc:
noVal(it) # compilerproc may not get a string!
makeExternExport(sym, sym.name.s)
makeExternExport(sym, "$1", it.info)
incl(sym.flags, sfCompilerProc)
incl(sym.flags, sfUsed) # suppress all those stupid warnings
registerCompilerProc(sym)
of wProcvar:
of wProcVar:
noVal(it)
incl(sym.flags, sfProcVar)
incl(sym.flags, sfProcvar)
of wDeprecated:
noVal(it)
if sym != nil: incl(sym.flags, sfDeprecated)
@@ -610,9 +661,12 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfVarargs)
of wBorrow:
noVal(it)
incl(sym.flags, sfBorrow)
of wBorrow:
if sym.kind == skType:
typeBorrow(sym, it)
else:
noVal(it)
incl(sym.flags, sfBorrow)
of wFinal:
noVal(it)
if sym.typ == nil: invalidPragma(it)
@@ -632,10 +686,20 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
of wThread:
noVal(it)
incl(sym.flags, sfThread)
incl(sym.flags, sfProcVar)
incl(sym.flags, sfProcvar)
if sym.typ != nil: incl(sym.typ.flags, tfThread)
of wHint: Message(it.info, hintUser, expectStrLit(c, it))
of wWarning: Message(it.info, warnUser, expectStrLit(c, it))
of wGcSafe:
if optThreadAnalysis in gGlobalOptions:
noVal(it)
if sym.kind != skType: incl(sym.flags, sfThread)
if sym.typ != nil: incl(sym.typ.flags, tfGcSafe)
else: invalidPragma(it)
of wPacked:
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfPacked)
of wHint: message(it.info, hintUser, expectStrLit(c, it))
of wWarning: message(it.info, warnUser, expectStrLit(c, it))
of wError:
if sym != nil and sym.isRoutine:
# This is subtle but correct: the error *statement* is only
@@ -645,17 +709,17 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
noVal(it)
incl(sym.flags, sfError)
else:
LocalError(it.info, errUser, expectStrLit(c, it))
of wFatal: Fatal(it.info, errUser, expectStrLit(c, it))
localError(it.info, errUser, expectStrLit(c, it))
of wFatal: fatal(it.info, errUser, expectStrLit(c, it))
of wDefine: processDefine(c, it)
of wUndef: processUndef(c, it)
of wCompile: processCompile(c, it)
of wLink: processCommonLink(c, it, linkNormal)
of wLinkSys: processCommonLink(c, it, linkSys)
of wPassL: extccomp.addLinkOption(expectStrLit(c, it))
of wPassC: extccomp.addCompileOption(expectStrLit(c, it))
of wBreakpoint: PragmaBreakpoint(c, it)
of wWatchpoint: PragmaWatchpoint(c, it)
of wLinksys: processCommonLink(c, it, linkSys)
of wPassl: extccomp.addLinkOption(expectStrLit(c, it))
of wPassc: extccomp.addCompileOption(expectStrLit(c, it))
of wBreakpoint: pragmaBreakpoint(c, it)
of wWatchPoint: pragmaWatchpoint(c, it)
of wPush:
processPush(c, n, i + 1)
result = true
@@ -669,25 +733,23 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
of wNoInit:
noVal(it)
if sym != nil: incl(sym.flags, sfNoInit)
of wHoist:
noVal(it)
if sym != nil: incl(sym.flags, sfHoist)
of wCodegenDecl: processCodegenDecl(c, it, sym)
of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks,
wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
wLinedir, wStacktrace, wLinetrace, wOptimization,
wCallConv,
wDebugger, wProfiler, wFloatChecks, wNanChecks, wInfChecks,
wCallconv,
wDebugger, wProfiler, wFloatchecks, wNanChecks, wInfChecks,
wPatterns:
if processOption(c, it):
# calling conventions (boring...):
LocalError(it.info, errOptionExpected)
of firstCallConv..lastCallConv:
localError(it.info, errOptionExpected)
of FirstCallConv..LastCallConv:
assert(sym != nil)
if sym.typ == nil: invalidPragma(it)
else: sym.typ.callConv = wordToCallConv(k)
of wEmit: PragmaEmit(c, it)
of wUnroll: PragmaUnroll(c, it)
of wLinearScanEnd: PragmaLinearScanEnd(c, it)
of wEmit: pragmaEmit(c, it)
of wUnroll: pragmaUnroll(c, it)
of wLinearScanEnd, wComputedGoto: noVal(it)
of wEffects:
# is later processed in effect analysis:
noVal(it)
@@ -695,50 +757,82 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfIncompleteStruct)
of wUnchecked:
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfUncheckedArray)
of wUnion:
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfUnion)
of wRequiresInit:
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfNeedsInit)
of wByRef:
noVal(it)
if sym == nil or sym.typ == nil:
if processOption(c, it): LocalError(it.info, errOptionExpected)
if processOption(c, it): localError(it.info, errOptionExpected)
else:
incl(sym.typ.flags, tfByRef)
of wByCopy:
noVal(it)
if sym.kind != skType or sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfByCopy)
of wInject, wGenSym:
of wInject, wGensym:
# We check for errors, but do nothing with these pragmas otherwise
# as they are handled directly in 'evalTemplate'.
noVal(it)
if sym == nil: invalidPragma(it)
of wLine: PragmaLine(c, it)
of wLine: pragmaLine(c, it)
of wRaises, wTags: pragmaRaisesOrTags(c, it)
of wUses: pragmaUses(c, it)
of wOperator:
if sym == nil: invalidPragma(it)
else: sym.position = expectIntLit(c, it)
of wInjectStmt:
if it.kind != nkExprColonExpr:
localError(it.info, errExprExpected)
else:
it.sons[1] = c.semExpr(c, it.sons[1])
else: invalidPragma(it)
else: invalidPragma(it)
else: processNote(c, it)
proc implictPragmas*(c: PContext, sym: PSym, n: PNode,
validPragmas: TSpecialWords) =
proc implicitPragmas*(c: PContext, sym: PSym, n: PNode,
validPragmas: TSpecialWords) =
if sym != nil and sym.kind != skModule:
var it = POptionEntry(c.optionstack.head)
var it = POptionEntry(c.optionStack.head)
while it != nil:
let o = it.otherPragmas
if not o.isNil:
for i in countup(0, sonsLen(o) - 1):
if singlePragma(c, sym, o, i, validPragmas):
InternalError(n.info, "implicitPragmas")
internalError(n.info, "implicitPragmas")
it = it.next.POptionEntry
if lfExportLib in sym.loc.flags and sfExportc notin sym.flags:
LocalError(n.info, errDynlibRequiresExportc)
var lib = POptionEntry(c.optionstack.tail).dynlib
if lfExportLib in sym.loc.flags and sfExportc notin sym.flags:
localError(n.info, errDynlibRequiresExportc)
var lib = POptionEntry(c.optionStack.tail).dynlib
if {lfDynamicLib, lfHeader} * sym.loc.flags == {} and
sfImportc in sym.flags and lib != nil:
incl(sym.loc.flags, lfDynamicLib)
addToLib(lib, sym)
if sym.loc.r == nil: sym.loc.r = toRope(sym.name.s)
proc hasPragma*(n: PNode, pragma: TSpecialWord): bool =
if n == nil or n.sons == nil:
return false
for p in n.sons:
var key = if p.kind == nkExprColonExpr: p[0] else: p
if key.kind == nkIdent and whichKeyword(key.ident) == pragma:
return true
return false
proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
if n == nil: return
for i in countup(0, sonsLen(n) - 1):
if singlePragma(c, sym, n, i, validPragmas): break
implictPragmas(c, sym, n, validPragmas)
implicitPragmas(c, sym, n, validPragmas)

325
compiler/pretty.nim Normal file
View File

@@ -0,0 +1,325 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements the code "prettifier". This is part of the toolchain
## to convert Nimrod code into a consistent style.
import
strutils, os, options, ast, astalgo, msgs, ropes, idents, passes,
intsets, strtabs, semdata
const
removeTP = false # when true, "nimrod pretty" converts TTyp to Typ.
type
TGen = object of TPassContext
module*: PSym
PGen = ref TGen
TSourceFile = object
lines: seq[string]
dirty: bool
fullpath: string
var
gSourceFiles: seq[TSourceFile] = @[]
gCheckExtern: bool
rules: PStringTable
proc loadFile(info: TLineInfo) =
let i = info.fileIndex
if i >= gSourceFiles.len:
gSourceFiles.setLen(i+1)
if gSourceFiles[i].lines.isNil:
gSourceFiles[i].lines = @[]
let path = info.toFullPath
gSourceFiles[i].fullpath = path
# we want to die here for EIO:
for line in lines(path):
gSourceFiles[i].lines.add(line)
proc overwriteFiles*() =
let overWrite = options.getConfigVar("pretty.overwrite").normalize == "on"
let doStrip = options.getConfigVar("pretty.strip").normalize == "on"
for i in 0 .. high(gSourceFiles):
if not gSourceFiles[i].dirty: continue
let newFile = if overWrite: gSourceFiles[i].fullpath
else: gSourceFiles[i].fullpath.changeFileExt(".pretty.nim")
try:
var f = open(newFile, fmWrite)
for line in gSourceFiles[i].lines:
if doStrip:
f.write line.strip(leading = false, trailing = true)
else:
f.write line
f.write("\L")
f.close
except EIO:
rawMessage(errCannotOpenFile, newFile)
proc `=~`(s: string, a: openArray[string]): bool =
for x in a:
if s.startsWith(x): return true
proc beautifyName(s: string, k: TSymKind): string =
# minimal set of rules here for transition:
# GC_ is allowed
let allUpper = allCharsInSet(s, {'A'..'Z', '0'..'9', '_'})
if allUpper and k in {skConst, skEnumField, skType}: return s
result = newStringOfCap(s.len)
var i = 0
case k
of skType, skGenericParam:
# Types should start with a capital unless builtins like 'int' etc.:
when removeTP:
if s[0] == 'T' and s[1] in {'A'..'Z'}:
i = 1
if s =~ ["int", "uint", "cint", "cuint", "clong", "cstring", "string",
"char", "byte", "bool", "openArray", "seq", "array", "void",
"pointer", "float", "csize", "cdouble", "cchar", "cschar",
"cshort", "cu", "nil", "expr", "stmt", "typedesc", "auto", "any",
"range", "openarray", "varargs", "set", "cfloat"
]:
result.add s[i]
else:
result.add toUpper(s[i])
of skConst, skEnumField:
# for 'const' we keep how it's spelt; either upper case or lower case:
result.add s[0]
else:
# as a special rule, don't transform 'L' to 'l'
if s.len == 1 and s[0] == 'L': result.add 'L'
elif '_' in s: result.add(s[i])
else: result.add toLower(s[0])
inc i
while i < s.len:
if s[i] == '_':
if i > 0 and s[i-1] in {'A'..'Z'}:
# don't skip '_' as it's essential for e.g. 'GC_disable'
result.add('_')
inc i
result.add s[i]
else:
inc i
result.add toUpper(s[i])
elif allUpper:
result.add toLower(s[i])
else:
result.add s[i]
inc i
proc checkStyle*(info: TLineInfo, s: string, k: TSymKind) =
let beau = beautifyName(s, k)
if s != beau:
message(info, errGenerated, "name should be: " & beau)
const
Letters = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '_'}
proc identLen(line: string, start: int): int =
while start+result < line.len and line[start+result] in Letters:
inc result
proc differ(line: string, a, b: int, x: string): bool =
let y = line[a..b]
result = cmpIgnoreStyle(y, x) == 0 and y != x
when false:
var j = 0
for i in a..b:
if line[i] != x[j]: return true
inc j
return false
proc checkDef*(n: PNode; s: PSym) =
# operators stay as they are:
if s.kind in {skResult, skTemp} or s.name.s[0] notin Letters: return
if s.kind in {skType, skGenericParam} and sfAnon in s.flags: return
if {sfImportc, sfExportc} * s.flags == {} or gCheckExtern:
checkStyle(n.info, s.name.s, s.kind)
proc checkDef(c: PGen; n: PNode) =
if n.kind != nkSym: return
checkDef(n, n.sym)
proc checkUse*(n: PNode, s: PSym) =
if n.info.fileIndex < 0: return
# we simply convert it to what it looks like in the definition
# for consistency
# operators stay as they are:
if s.kind in {skResult, skTemp} or s.name.s[0] notin Letters: return
if s.kind in {skType, skGenericParam} and sfAnon in s.flags: return
let newName = s.name.s
loadFile(n.info)
let line = gSourceFiles[n.info.fileIndex].lines[n.info.line-1]
var first = min(n.info.col.int, line.len)
if first < 0: return
#inc first, skipIgnoreCase(line, "proc ", first)
while first > 0 and line[first-1] in Letters: dec first
if first < 0: return
if line[first] == '`': inc first
let last = first+identLen(line, first)-1
if differ(line, first, last, newName):
# last-first+1 != newName.len or
var x = line.substr(0, first-1) & newName & line.substr(last+1)
when removeTP:
# the WinAPI module is full of 'TX = X' which after the substitution
# becomes 'X = X'. We remove those lines:
if x.match(peg"\s* {\ident} \s* '=' \s* y$1 ('#' .*)?"):
x = ""
system.shallowCopy(gSourceFiles[n.info.fileIndex].lines[n.info.line-1], x)
gSourceFiles[n.info.fileIndex].dirty = true
when false:
var cannotRename = initIntSet()
proc beautifyName(s: string, k: TSymKind): string =
let allUpper = allCharsInSet(s, {'A'..'Z', '0'..'9', '_'})
result = newStringOfCap(s.len)
var i = 0
case k
of skType, skGenericParam:
# skip leading 'T'
when removeTP:
if s[0] == 'T' and s[1] in {'A'..'Z'}:
i = 1
if s =~ ["int", "uint", "cint", "cuint", "clong", "cstring", "string",
"char", "byte", "bool", "openArray", "seq", "array", "void",
"pointer", "float", "csize", "cdouble", "cchar", "cschar",
"cshort", "cu"]:
result.add s[i]
else:
result.add toUpper(s[i])
of skConst, skEnumField:
# for 'const' we keep how it's spelt; either upper case or lower case:
result.add s[0]
else:
# as a special rule, don't transform 'L' to 'l'
if s.len == 1 and s[0] == 'L': result.add 'L'
else: result.add toLower(s[0])
inc i
while i < s.len:
if s[i] == '_':
inc i
result.add toUpper(s[i])
elif allUpper:
result.add toLower(s[i])
else:
result.add s[i]
inc i
proc checkUse(c: PGen; n: PNode) =
if n.info.fileIndex < 0: return
let s = n.sym
# operators stay as they are:
if s.kind in {skResult, skTemp} or s.name.s[0] notin Letters: return
if s.kind in {skType, skGenericParam} and sfAnon in s.flags: return
if s.id in cannotRename: return
let newName = if rules.hasKey(s.name.s): rules[s.name.s]
else: beautifyName(s.name.s, n.sym.kind)
loadFile(n.info)
let line = gSourceFiles[n.info.fileIndex].lines[n.info.line-1]
var first = min(n.info.col.int, line.len)
if first < 0: return
#inc first, skipIgnoreCase(line, "proc ", first)
while first > 0 and line[first-1] in Letters: dec first
if first < 0: return
if line[first] == '`': inc first
if {sfImportc, sfExportc} * s.flags != {}:
# careful, we must ensure the resulting name still matches the external
# name:
if newName != s.name.s and newName != s.loc.r.ropeToStr and
lfFullExternalName notin s.loc.flags:
#Message(n.info, errGenerated,
# "cannot rename $# to $# due to external name" % [s.name.s, newName])
cannotRename.incl(s.id)
return
let last = first+identLen(line, first)-1
if differ(line, first, last, newName):
# last-first+1 != newName.len or
var x = line.subStr(0, first-1) & newName & line.substr(last+1)
when removeTP:
# the WinAPI module is full of 'TX = X' which after the substitution
# becomes 'X = X'. We remove those lines:
if x.match(peg"\s* {\ident} \s* '=' \s* y$1 ('#' .*)?"):
x = ""
system.shallowCopy(gSourceFiles[n.info.fileIndex].lines[n.info.line-1], x)
gSourceFiles[n.info.fileIndex].dirty = true
proc check(c: PGen, n: PNode) =
case n.kind
of nkSym: checkUse(n, n.sym)
of nkBlockStmt, nkBlockExpr, nkBlockType:
checkDef(c, n[0])
check(c, n.sons[1])
of nkForStmt, nkParForStmt:
let L = n.len
for i in countup(0, L-3):
checkDef(c, n[i])
check(c, n[L-2])
check(c, n[L-1])
of nkProcDef, nkLambdaKinds, nkMethodDef, nkIteratorDef, nkTemplateDef,
nkMacroDef, nkConverterDef:
checkDef(c, n[namePos])
for i in namePos+1 .. <n.len: check(c, n.sons[i])
of nkIdentDefs, nkVarTuple:
let a = n
checkMinSonsLen(a, 3)
let L = len(a)
for j in countup(0, L-3): checkDef(c, a.sons[j])
check(c, a.sons[L-2])
check(c, a.sons[L-1])
of nkTypeSection, nkConstSection:
for i in countup(0, sonsLen(n) - 1):
let a = n.sons[i]
if a.kind == nkCommentStmt: continue
checkSonsLen(a, 3)
checkDef(c, a.sons[0])
check(c, a.sons[1])
check(c, a.sons[2])
else:
for i in 0 .. <n.safeLen: check(c, n.sons[i])
proc processSym(c: PPassContext, n: PNode): PNode =
result = n
check(PGen(c), n)
proc myOpen(module: PSym): PPassContext =
var g: PGen
new(g)
g.module = module
gCheckExtern = options.getConfigVar("pretty.checkextern").normalize == "on"
result = g
if rules.isNil:
rules = newStringTable(modeStyleInsensitive)
when removeTP:
# XXX activate when the T/P stuff is deprecated
let path = joinPath([getPrefixDir(), "config", "rename.rules.cfg"])
for line in lines(path):
if line.len > 0:
let colon = line.find(':')
if colon > 0:
rules[line.substr(0, colon-1)] = line.substr(colon+1)
else:
rules[line] = line
const prettyPass* = makePass(open = myOpen, process = processSym)

View File

@@ -17,52 +17,76 @@ proc equalGenericParams(procA, procB: PNode): bool =
if sonsLen(procA) != sonsLen(procB): return
for i in countup(0, sonsLen(procA) - 1):
if procA.sons[i].kind != nkSym:
InternalError(procA.info, "equalGenericParams")
internalError(procA.info, "equalGenericParams")
return
if procB.sons[i].kind != nkSym:
InternalError(procB.info, "equalGenericParams")
internalError(procB.info, "equalGenericParams")
return
let a = procA.sons[i].sym
let b = procB.sons[i].sym
if a.name.id != b.name.id or
not sameTypeOrNil(a.typ, b.typ, {TypeDescExactMatch}): return
not sameTypeOrNil(a.typ, b.typ, {ExactTypeDescValues}): return
if a.ast != nil and b.ast != nil:
if not ExprStructuralEquivalent(a.ast, b.ast): return
if not exprStructuralEquivalent(a.ast, b.ast): return
result = true
proc SearchForProc*(c: PContext, scope: PScope, fn: PSym): PSym =
proc searchForProcOld*(c: PContext, scope: PScope, fn: PSym): PSym =
# Searchs for a forward declaration or a "twin" symbol of fn
# in the symbol table. If the parameter lists are exactly
# the same the sym in the symbol table is returned, else nil.
var it: TIdentIter
result = initIdentIter(it, scope.symbols, fn.Name)
result = initIdentIter(it, scope.symbols, fn.name)
if isGenericRoutine(fn):
# we simply check the AST; this is imprecise but nearly the best what
# can be done; this doesn't work either though as type constraints are
# not kept in the AST ..
while result != nil:
if result.Kind == fn.kind and isGenericRoutine(result):
if result.kind == fn.kind and isGenericRoutine(result):
let genR = result.ast.sons[genericParamsPos]
let genF = fn.ast.sons[genericParamsPos]
if ExprStructuralEquivalent(genR, genF) and
ExprStructuralEquivalent(result.ast.sons[paramsPos],
if exprStructuralEquivalent(genR, genF) and
exprStructuralEquivalent(result.ast.sons[paramsPos],
fn.ast.sons[paramsPos]) and
equalGenericParams(genR, genF):
return
result = NextIdentIter(it, scope.symbols)
result = nextIdentIter(it, scope.symbols)
else:
while result != nil:
if result.Kind == fn.kind and not isGenericRoutine(result):
if result.kind == fn.kind and not isGenericRoutine(result):
case equalParams(result.typ.n, fn.typ.n)
of paramsEqual:
return
of paramsIncompatible:
LocalError(fn.info, errNotOverloadable, fn.name.s)
localError(fn.info, errNotOverloadable, fn.name.s)
return
of paramsNotEqual:
nil
result = NextIdentIter(it, scope.symbols)
discard
result = nextIdentIter(it, scope.symbols)
proc searchForProcNew(c: PContext, scope: PScope, fn: PSym): PSym =
const flags = {ExactGenericParams, ExactTypeDescValues,
ExactConstraints, IgnoreCC}
var it: TIdentIter
result = initIdentIter(it, scope.symbols, fn.name)
while result != nil:
if result.kind in skProcKinds and
sameType(result.typ, fn.typ, flags): return
result = nextIdentIter(it, scope.symbols)
return nil
proc searchForProc*(c: PContext, scope: PScope, fn: PSym): PSym =
result = searchForProcNew(c, scope, fn)
when false:
let old = searchForProcOld(c, scope, fn)
if old != result:
echo "Mismatch in searchForProc: ", fn.info
debug fn.typ
debug if result != nil: result.typ else: nil
debug if old != nil: old.typ else: nil
when false:
proc paramsFitBorrow(child, parent: PNode): bool =
var length = sonsLen(child)
@@ -77,7 +101,7 @@ when false:
dcEqOrDistinctOf): return
result = true
proc SearchForBorrowProc*(c: PContext, startScope: PScope, fn: PSym): PSym =
proc searchForBorrowProc*(c: PContext, startScope: PScope, fn: PSym): PSym =
# Searchs for the fn in the symbol table. If the parameter lists are suitable
# for borrowing the sym in the symbol table is returned, else nil.
var it: TIdentIter

View File

@@ -15,7 +15,7 @@ import
type
TRenderFlag* = enum
renderNone, renderNoBody, renderNoComments, renderDocComments,
renderNoPragmas, renderIds
renderNoPragmas, renderIds, renderNoProcDefs
TRenderFlags* = set[TRenderFlag]
TRenderTok*{.final.} = object
kind*: TTokType
@@ -33,6 +33,7 @@ type
# indentation value
comStack*: seq[PNode] # comment stack
flags*: TRenderFlags
checkAnon: bool # we're in a context that can contain sfAnon
proc renderModule*(n: PNode, filename: string, renderFlags: TRenderFlags = {})
@@ -50,10 +51,17 @@ proc isKeyword*(s: string): bool =
(i.id <= ord(tokKeywordHigh) - ord(tkSymbol)):
result = true
proc renderDefinitionName*(s: PSym): string =
proc renderDefinitionName*(s: PSym, noQuotes = false): string =
## Returns the definition name of the symbol.
##
## If noQuotes is false the symbol may be returned in backticks. This will
## happen if the name happens to be a keyword or the first character is not
## part of the SymStartChars set.
let x = s.name.s
if x[0] in SymStartChars and not renderer.isKeyword(x): result = x
else: result = '`' & x & '`'
if noQuotes or (x[0] in SymStartChars and not renderer.isKeyword(x)):
result = x
else:
result = '`' & x & '`'
const
IndentWidth = 2
@@ -61,7 +69,7 @@ const
MaxLineLen = 80
LineCommentColumn = 30
proc InitSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) =
proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) =
g.comStack = @[]
g.tokens = @[]
g.indent = 0
@@ -70,11 +78,12 @@ proc InitSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) =
g.idx = 0
g.buf = ""
g.flags = renderFlags
g.pendingNL = - 1
g.pendingNL = -1
g.checkAnon = false
proc addTok(g: var TSrcGen, kind: TTokType, s: string) =
var length = len(g.tokens)
setlen(g.tokens, length + 1)
setLen(g.tokens, length + 1)
g.tokens[length].kind = kind
g.tokens[length].length = int16(len(s))
add(g.buf, s)
@@ -102,16 +111,16 @@ proc optNL(g: var TSrcGen) =
optNL(g, g.indent)
proc indentNL(g: var TSrcGen) =
inc(g.indent, indentWidth)
inc(g.indent, IndentWidth)
g.pendingNL = g.indent
g.lineLen = g.indent
proc Dedent(g: var TSrcGen) =
dec(g.indent, indentWidth)
proc dedent(g: var TSrcGen) =
dec(g.indent, IndentWidth)
assert(g.indent >= 0)
if g.pendingNL > indentWidth:
Dec(g.pendingNL, indentWidth)
Dec(g.lineLen, indentWidth)
if g.pendingNL > IndentWidth:
dec(g.pendingNL, IndentWidth)
dec(g.lineLen, IndentWidth)
proc put(g: var TSrcGen, kind: TTokType, s: string) =
addPendingNL(g)
@@ -125,7 +134,7 @@ proc putLong(g: var TSrcGen, kind: TTokType, s: string, lineLen: int) =
addTok(g, kind, s)
g.lineLen = lineLen
proc toNimChar(c: Char): string =
proc toNimChar(c: char): string =
case c
of '\0': result = "\\0"
of '\x01'..'\x1F', '\x80'..'\xFF': result = "\\x" & strutils.toHex(ord(c), 2)
@@ -234,19 +243,19 @@ proc containsNL(s: string): bool =
of '\x0D', '\x0A':
return true
else:
nil
discard
result = false
proc pushCom(g: var TSrcGen, n: PNode) =
var length = len(g.comStack)
setlen(g.comStack, length + 1)
setLen(g.comStack, length + 1)
g.comStack[length] = n
proc popAllComs(g: var TSrcGen) =
setlen(g.comStack, 0)
setLen(g.comStack, 0)
proc popCom(g: var TSrcGen) =
setlen(g.comStack, len(g.comStack) - 1)
setLen(g.comStack, len(g.comStack) - 1)
const
Space = " "
@@ -267,7 +276,7 @@ proc gcom(g: var TSrcGen, n: PNode) =
if (g.pendingNL < 0) and (len(g.buf) > 0) and
(g.lineLen < LineCommentColumn):
var ml = maxLineLength(n.comment)
if ml + LineCommentColumn <= maxLineLen:
if ml + LineCommentColumn <= MaxLineLen:
put(g, tkSpaces, repeatChar(LineCommentColumn - g.lineLen))
putComment(g, n.comment) #assert(g.comStack[high(g.comStack)] = n);
@@ -276,7 +285,7 @@ proc gcoms(g: var TSrcGen) =
popAllComs(g)
proc lsub(n: PNode): int
proc litAux(n: PNode, x: biggestInt, size: int): string =
proc litAux(n: PNode, x: BiggestInt, size: int): string =
proc skip(t: PType): PType =
result = t
while result.kind in {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal,
@@ -293,7 +302,7 @@ proc litAux(n: PNode, x: biggestInt, size: int): string =
elif nfBase16 in n.flags: result = "0x" & toHex(x, size * 2)
else: result = $x
proc ulitAux(n: PNode, x: biggestInt, size: int): string =
proc ulitAux(n: PNode, x: BiggestInt, size: int): string =
if nfBase2 in n.flags: result = "0b" & toBin(x, size * 8)
elif nfBase8 in n.flags: result = "0o" & toOct(x, size * 3)
elif nfBase16 in n.flags: result = "0x" & toHex(x, size * 2)
@@ -327,7 +336,7 @@ proc atom(n: PNode): string =
if n.flags * {nfBase2, nfBase8, nfBase16} == {}:
result = $n.floatVal & "\'f32"
else:
f = n.floatVal
f = n.floatVal.float32
result = litAux(n, (cast[PInt32](addr(f)))[], 4) & "\'f32"
of nkFloat64Lit:
if n.flags * {nfBase2, nfBase8, nfBase16} == {}:
@@ -339,7 +348,7 @@ proc atom(n: PNode): string =
if (n.typ != nil) and (n.typ.sym != nil): result = n.typ.sym.name.s
else: result = "[type node]"
else:
InternalError("rnimsyn.atom " & $n.kind)
internalError("rnimsyn.atom " & $n.kind)
result = ""
proc lcomma(n: PNode, start: int = 0, theEnd: int = - 1): int =
@@ -359,11 +368,11 @@ proc lsons(n: PNode, start: int = 0, theEnd: int = - 1): int =
proc lsub(n: PNode): int =
# computes the length of a tree
if isNil(n): return 0
if n.comment != nil: return maxLineLen + 1
if n.comment != nil: return MaxLineLen + 1
case n.kind
of nkEmpty: result = 0
of nkTripleStrLit:
if containsNL(n.strVal): result = maxLineLen + 1
if containsNL(n.strVal): result = MaxLineLen + 1
else: result = len(atom(n))
of succ(nkEmpty)..pred(nkTripleStrLit), succ(nkTripleStrLit)..nkNilLit:
result = len(atom(n))
@@ -405,7 +414,8 @@ proc lsub(n: PNode): int =
result = result + lcomma(n, 1)
of nkExprColonExpr: result = lsons(n) + 2
of nkInfix: result = lsons(n) + 2
of nkPrefix: result = lsons(n) + 1
of nkPrefix:
result = lsons(n)+1+(if n.len > 0 and n.sons[1].kind == nkInfix: 2 else: 0)
of nkPostfix: result = lsons(n)
of nkCallStrLit: result = lsons(n)
of nkPragmaExpr: result = lsub(n.sons[0]) + lcomma(n, 1)
@@ -418,10 +428,16 @@ proc lsub(n: PNode): int =
of nkElifExpr: result = lsons(n) + len("_elif_:_")
of nkElseExpr: result = lsub(n.sons[0]) + len("_else:_") # type descriptions
of nkTypeOfExpr: result = lsub(n.sons[0]) + len("type_")
of nkRefTy: result = lsub(n.sons[0]) + len("ref_")
of nkPtrTy: result = lsub(n.sons[0]) + len("ptr_")
of nkVarTy: result = lsub(n.sons[0]) + len("var_")
of nkDistinctTy: result = lsub(n.sons[0]) + len("Distinct_")
of nkRefTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + len("ref")
of nkPtrTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + len("ptr")
of nkVarTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + len("var")
of nkDistinctTy:
result = len("distinct") + (if n.len > 0: lsub(n.sons[0])+1 else: 0)
if n.len > 1:
result += (if n[1].kind == nkWith: len("_with_") else: len("_without_"))
result += lcomma(n[1])
of nkStaticTy: result = (if n.len > 0: lsub(n.sons[0]) else: 0) +
len("static[]")
of nkTypeDef: result = lsons(n) + 3
of nkOfInherit: result = lsub(n.sons[0]) + len("of_")
of nkProcTy: result = lsons(n) + len("proc_")
@@ -434,7 +450,7 @@ proc lsub(n: PNode): int =
result = len("enum")
of nkEnumFieldDef: result = lsons(n) + 3
of nkVarSection, nkLetSection:
if sonsLen(n) > 1: result = maxLineLen + 1
if sonsLen(n) > 1: result = MaxLineLen + 1
else: result = lsons(n) + len("var_")
of nkReturnStmt: result = lsub(n.sons[0]) + len("return_")
of nkRaiseStmt: result = lsub(n.sons[0]) + len("raise_")
@@ -445,6 +461,7 @@ proc lsub(n: PNode): int =
of nkPragma: result = lcomma(n) + 4
of nkCommentStmt: result = len(n.comment)
of nkOfBranch: result = lcomma(n, 0, - 2) + lsub(lastSon(n)) + len("of_:_")
of nkImportAs: result = lsub(n.sons[0]) + len("_as_") + lsub(n.sons[1])
of nkElifBranch: result = lsons(n) + len("elif_:_")
of nkElse: result = lsub(n.sons[0]) + len("else:_")
of nkFinally: result = lsub(n.sons[0]) + len("finally:_")
@@ -454,10 +471,10 @@ proc lsub(n: PNode): int =
if n.sons[0].kind != nkEmpty: result = result + lsub(n.sons[0]) + 2
of nkExceptBranch:
result = lcomma(n, 0, -2) + lsub(lastSon(n)) + len("except_:_")
else: result = maxLineLen + 1
else: result = MaxLineLen + 1
proc fits(g: TSrcGen, x: int): bool =
result = x + g.lineLen <= maxLineLen
result = x + g.lineLen <= MaxLineLen
type
TSubFlag = enum
@@ -482,7 +499,7 @@ proc hasCom(n: PNode): bool =
result = false
if n.comment != nil: return true
case n.kind
of nkEmpty..nkNilLit: nil
of nkEmpty..nkNilLit: discard
else:
for i in countup(0, sonsLen(n) - 1):
if hasCom(n.sons[i]): return true
@@ -493,13 +510,15 @@ proc putWithSpace(g: var TSrcGen, kind: TTokType, s: string) =
proc gcommaAux(g: var TSrcGen, n: PNode, ind: int, start: int = 0,
theEnd: int = - 1, separator = tkComma) =
for i in countup(start, sonsLen(n) + theEnd):
for i in countup(start, sonsLen(n) + theEnd):
var c = i < sonsLen(n) + theEnd
var sublen = lsub(n.sons[i]) + ord(c)
if not fits(g, sublen) and (ind + sublen < maxLineLen): optNL(g, ind)
if not fits(g, sublen) and (ind + sublen < MaxLineLen): optNL(g, ind)
let oldLen = g.tokens.len
gsub(g, n.sons[i])
if c:
putWithSpace(g, separator, TokTypeToStr[separator])
if c:
if g.tokens.len > oldLen:
putWithSpace(g, separator, TokTypeToStr[separator])
if hasCom(n.sons[i]):
gcoms(g)
optNL(g, ind)
@@ -508,21 +527,21 @@ proc gcomma(g: var TSrcGen, n: PNode, c: TContext, start: int = 0,
theEnd: int = - 1) =
var ind: int
if rfInConstExpr in c.flags:
ind = g.indent + indentWidth
ind = g.indent + IndentWidth
else:
ind = g.lineLen
if ind > maxLineLen div 2: ind = g.indent + longIndentWid
if ind > MaxLineLen div 2: ind = g.indent + longIndentWid
gcommaAux(g, n, ind, start, theEnd)
proc gcomma(g: var TSrcGen, n: PNode, start: int = 0, theEnd: int = - 1) =
var ind = g.lineLen
if ind > maxLineLen div 2: ind = g.indent + longIndentWid
if ind > MaxLineLen div 2: ind = g.indent + longIndentWid
gcommaAux(g, n, ind, start, theEnd)
proc gsemicolon(g: var TSrcGen, n: PNode, start: int = 0, theEnd: int = - 1) =
var ind = g.lineLen
if ind > maxLineLen div 2: ind = g.indent + longIndentWid
gcommaAux(g, n, ind, start, theEnd, tkSemicolon)
if ind > MaxLineLen div 2: ind = g.indent + longIndentWid
gcommaAux(g, n, ind, start, theEnd, tkSemiColon)
proc gsons(g: var TSrcGen, n: PNode, c: TContext, start: int = 0,
theEnd: int = - 1) =
@@ -545,20 +564,23 @@ proc longMode(n: PNode, start: int = 0, theEnd: int = - 1): bool =
if not result:
# check further
for i in countup(start, sonsLen(n) + theEnd):
if (lsub(n.sons[i]) > maxLineLen):
if (lsub(n.sons[i]) > MaxLineLen):
result = true
break
proc gstmts(g: var TSrcGen, n: PNode, c: TContext) =
if n.kind == nkEmpty: return
if (n.kind == nkStmtList) or (n.kind == nkStmtListExpr):
indentNL(g)
for i in countup(0, sonsLen(n) - 1):
proc gstmts(g: var TSrcGen, n: PNode, c: TContext, doIndent=true) =
if n.kind == nkEmpty: return
if n.kind in {nkStmtList, nkStmtListExpr, nkStmtListType}:
if doIndent: indentNL(g)
for i in countup(0, sonsLen(n) - 1):
optNL(g)
gsub(g, n.sons[i])
if n.sons[i].kind in {nkStmtList, nkStmtListExpr, nkStmtListType}:
gstmts(g, n.sons[i], c, doIndent=false)
else:
gsub(g, n.sons[i])
gcoms(g)
dedent(g)
else:
if doIndent: dedent(g)
else:
if rfLongMode in c.flags: indentNL(g)
gsub(g, n)
gcoms(g)
@@ -570,7 +592,7 @@ proc gif(g: var TSrcGen, n: PNode) =
gsub(g, n.sons[0].sons[0])
initContext(c)
putWithSpace(g, tkColon, ":")
if longMode(n) or (lsub(n.sons[0].sons[1]) + g.lineLen > maxLineLen):
if longMode(n) or (lsub(n.sons[0].sons[1]) + g.lineLen > MaxLineLen):
incl(c.flags, rfLongMode)
gcoms(g) # a good place for comments
gstmts(g, n.sons[0].sons[1], c)
@@ -585,7 +607,7 @@ proc gwhile(g: var TSrcGen, n: PNode) =
gsub(g, n.sons[0])
putWithSpace(g, tkColon, ":")
initContext(c)
if longMode(n) or (lsub(n.sons[1]) + g.lineLen > maxLineLen):
if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen):
incl(c.flags, rfLongMode)
gcoms(g) # a good place for comments
gstmts(g, n.sons[1], c)
@@ -594,7 +616,7 @@ proc gpattern(g: var TSrcGen, n: PNode) =
var c: TContext
put(g, tkCurlyLe, "{")
initContext(c)
if longMode(n) or (lsub(n.sons[0]) + g.lineLen > maxLineLen):
if longMode(n) or (lsub(n.sons[0]) + g.lineLen > MaxLineLen):
incl(c.flags, rfLongMode)
gcoms(g) # a good place for comments
gstmts(g, n.sons[0], c)
@@ -605,7 +627,7 @@ proc gpragmaBlock(g: var TSrcGen, n: PNode) =
gsub(g, n.sons[0])
putWithSpace(g, tkColon, ":")
initContext(c)
if longMode(n) or (lsub(n.sons[1]) + g.lineLen > maxLineLen):
if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen):
incl(c.flags, rfLongMode)
gcoms(g) # a good place for comments
gstmts(g, n.sons[1], c)
@@ -615,7 +637,7 @@ proc gtry(g: var TSrcGen, n: PNode) =
put(g, tkTry, "try")
putWithSpace(g, tkColon, ":")
initContext(c)
if longMode(n) or (lsub(n.sons[0]) + g.lineLen > maxLineLen):
if longMode(n) or (lsub(n.sons[0]) + g.lineLen > MaxLineLen):
incl(c.flags, rfLongMode)
gcoms(g) # a good place for comments
gstmts(g, n.sons[0], c)
@@ -628,7 +650,7 @@ proc gfor(g: var TSrcGen, n: PNode) =
initContext(c)
if longMode(n) or
(lsub(n.sons[length - 1]) + lsub(n.sons[length - 2]) + 6 + g.lineLen >
maxLineLen):
MaxLineLen):
incl(c.flags, rfLongMode)
gcomma(g, n, c, 0, - 3)
put(g, tkSpaces, Space)
@@ -643,7 +665,7 @@ proc gmacro(g: var TSrcGen, n: PNode) =
initContext(c)
gsub(g, n.sons[0])
putWithSpace(g, tkColon, ":")
if longMode(n) or (lsub(n.sons[1]) + g.lineLen > maxLineLen):
if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen):
incl(c.flags, rfLongMode)
gcoms(g)
gsons(g, n, c, 1)
@@ -673,7 +695,10 @@ proc gproc(g: var TSrcGen, n: PNode) =
if n.sons[patternPos].kind != nkEmpty:
gpattern(g, n.sons[patternPos])
let oldCheckAnon = g.checkAnon
g.checkAnon = true
gsub(g, n.sons[genericParamsPos])
g.checkAnon = oldCheckAnon
gsub(g, n.sons[paramsPos])
gsub(g, n.sons[pragmasPos])
if renderNoBody notin g.flags:
@@ -691,6 +716,19 @@ proc gproc(g: var TSrcGen, n: PNode) =
gcoms(g)
dedent(g)
proc gTypeClassTy(g: var TSrcGen, n: PNode) =
var c: TContext
initContext(c)
putWithSpace(g, tkGeneric, "generic")
gsons(g, n[0], c) # arglist
gsub(g, n[1]) # pragmas
gsub(g, n[2]) # of
gcoms(g)
indentNL(g)
gcoms(g)
gstmts(g, n[3], c)
dedent(g)
proc gblock(g: var TSrcGen, n: PNode) =
var c: TContext
initContext(c)
@@ -700,7 +738,7 @@ proc gblock(g: var TSrcGen, n: PNode) =
else:
put(g, tkBlock, "block")
putWithSpace(g, tkColon, ":")
if longMode(n) or (lsub(n.sons[1]) + g.lineLen > maxLineLen):
if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen):
incl(c.flags, rfLongMode)
gcoms(g)
# XXX I don't get why this is needed here! gstmts should already handle this!
@@ -713,7 +751,7 @@ proc gstaticStmt(g: var TSrcGen, n: PNode) =
putWithSpace(g, tkStatic, "static")
putWithSpace(g, tkColon, ":")
initContext(c)
if longMode(n) or (lsub(n.sons[0]) + g.lineLen > maxLineLen):
if longMode(n) or (lsub(n.sons[0]) + g.lineLen > MaxLineLen):
incl(c.flags, rfLongMode)
gcoms(g) # a good place for comments
gstmts(g, n.sons[0], c)
@@ -724,7 +762,8 @@ proc gasm(g: var TSrcGen, n: PNode) =
gcoms(g)
gsub(g, n.sons[1])
proc gident(g: var TSrcGen, n: PNode) =
proc gident(g: var TSrcGen, n: PNode) =
if g.checkAnon and n.kind == nkSym and sfAnon in n.sym.flags: return
var t: TTokType
var s = atom(n)
if (s[0] in lexer.SymChars):
@@ -758,7 +797,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
if n.comment != nil: pushCom(g, n)
case n.kind # atoms:
of nkTripleStrLit: putRawStr(g, tkTripleStrLit, n.strVal)
of nkEmpty: nil
of nkEmpty: discard
of nkType: put(g, tkInvalid, atom(n))
of nkSym, nkIdent: gident(g, n)
of nkIntLit: put(g, tkIntLit, atom(n))
@@ -806,7 +845,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
put(g, tkParRi, ")")
of nkStaticExpr:
put(g, tkStatic, "static")
put(g, tkSpaces, space)
put(g, tkSpaces, Space)
gsub(g, n.sons[0])
of nkBracketExpr:
gsub(g, n.sons[0])
@@ -823,7 +862,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
gcomma(g, n, 1)
of nkCommand:
gsub(g, n.sons[0])
put(g, tkSpaces, space)
put(g, tkSpaces, Space)
gcomma(g, n, 1)
of nkExprEqExpr, nkAsgn, nkFastAsgn:
gsub(g, n.sons[0])
@@ -897,8 +936,8 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
gsub(g, n.sons[pragmasPos])
put(g, tkColon, ":")
gsub(g, n.sons[bodyPos])
of nkConstDef, nkIdentDefs:
gcomma(g, n, 0, - 3)
of nkConstDef, nkIdentDefs:
gcomma(g, n, 0, -3)
var L = sonsLen(n)
if n.sons[L - 2].kind != nkEmpty:
putWithSpace(g, tkColon, ":")
@@ -909,7 +948,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
gsub(g, n.sons[L - 1], c)
of nkVarTuple:
put(g, tkParLe, "(")
gcomma(g, n, 0, - 3)
gcomma(g, n, 0, -3)
put(g, tkParRi, ")")
put(g, tkSpaces, Space)
putWithSpace(g, tkEquals, "=")
@@ -930,8 +969,13 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
of nkPrefix:
gsub(g, n.sons[0])
if n.len > 1:
put(g, tkSpaces, space)
gsub(g, n.sons[1])
put(g, tkSpaces, Space)
if n.sons[1].kind == nkInfix:
put(g, tkParLe, "(")
gsub(g, n.sons[1])
put(g, tkParRi, ")")
else:
gsub(g, n.sons[1])
of nkPostfix:
gsub(g, n.sons[1])
gsub(g, n.sons[0])
@@ -986,9 +1030,15 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
else:
put(g, tkVar, "var")
of nkDistinctTy:
if sonsLen(n) > 0:
if n.len > 0:
putWithSpace(g, tkDistinct, "distinct")
gsub(g, n.sons[0])
if n.len > 1:
if n[1].kind == nkWith:
putWithSpace(g, tkWith, " with")
else:
putWithSpace(g, tkWithout, " without")
gcomma(g, n[1])
else:
put(g, tkDistinct, "distinct")
of nkTypeDef:
@@ -1032,12 +1082,12 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
gsub(g, n.sons[1])
else:
put(g, tkIterator, "iterator")
of nkSharedTy:
if sonsLen(n) > 0:
putWithSpace(g, tkShared, "shared")
of nkStaticTy:
put(g, tkStatic, "static")
put(g, tkBracketLe, "[")
if n.len > 0:
gsub(g, n.sons[0])
else:
put(g, tkShared, "shared")
put(g, tkBracketRi, "]")
of nkEnumTy:
if sonsLen(n) > 0:
putWithSpace(g, tkEnum, "enum")
@@ -1054,7 +1104,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
put(g, tkSpaces, Space)
putWithSpace(g, tkEquals, "=")
gsub(g, n.sons[1])
of nkStmtList, nkStmtListExpr: gstmts(g, n, emptyContext)
of nkStmtList, nkStmtListExpr, nkStmtListType: gstmts(g, n, emptyContext)
of nkIfStmt:
putWithSpace(g, tkIf, "if")
gif(g, n)
@@ -1070,22 +1120,22 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
of nkStaticStmt: gstaticStmt(g, n)
of nkAsmStmt: gasm(g, n)
of nkProcDef:
putWithSpace(g, tkProc, "proc")
if renderNoProcDefs notin g.flags: putWithSpace(g, tkProc, "proc")
gproc(g, n)
of nkConverterDef:
putWithSpace(g, tkConverter, "converter")
if renderNoProcDefs notin g.flags: putWithSpace(g, tkConverter, "converter")
gproc(g, n)
of nkMethodDef:
putWithSpace(g, tkMethod, "method")
if renderNoProcDefs notin g.flags: putWithSpace(g, tkMethod, "method")
gproc(g, n)
of nkIteratorDef:
putWithSpace(g, tkIterator, "iterator")
if renderNoProcDefs notin g.flags: putWithSpace(g, tkIterator, "iterator")
gproc(g, n)
of nkMacroDef:
putWithSpace(g, tkMacro, "macro")
if renderNoProcDefs notin g.flags: putWithSpace(g, tkMacro, "macro")
gproc(g, n)
of nkTemplateDef:
putWithSpace(g, tkTemplate, "template")
if renderNoProcDefs notin g.flags: putWithSpace(g, tkTemplate, "template")
gproc(g, n)
of nkTypeSection:
gsection(g, n, emptyContext, tkType, "type")
@@ -1177,6 +1227,11 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
putWithSpace(g, tkColon, ":")
gcoms(g)
gstmts(g, lastSon(n), c)
of nkImportAs:
gsub(g, n.sons[0])
put(g, tkSpaces, Space)
putWithSpace(g, tkAs, "as")
gsub(g, n.sons[1])
of nkBindStmt:
putWithSpace(g, tkBind, "bind")
gcomma(g, n, c)
@@ -1226,9 +1281,20 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
put(g, tkBracketLe, "[")
gcomma(g, n)
put(g, tkBracketRi, "]")
of nkMetaNode_Obsolete:
put(g, tkParLe, "(META|")
gsub(g, n.sons[0])
put(g, tkParRi, ")")
of nkGotoState, nkState:
var c: TContext
initContext c
putWithSpace g, tkSymbol, if n.kind == nkState: "state" else: "goto"
gsons(g, n, c)
of nkTypeClassTy:
gTypeClassTy(g, n)
else:
#nkNone, nkMetaNode, nkExplicitTypeListCall:
InternalError(n.info, "rnimsyn.gsub(" & $n.kind & ')')
#nkNone, nkExplicitTypeListCall:
internalError(n.info, "rnimsyn.gsub(" & $n.kind & ')')
proc renderTree(n: PNode, renderFlags: TRenderFlags = {}): string =
var g: TSrcGen
@@ -1239,7 +1305,7 @@ proc renderTree(n: PNode, renderFlags: TRenderFlags = {}): string =
proc renderModule(n: PNode, filename: string,
renderFlags: TRenderFlags = {}) =
var
f: tfile
f: TFile
g: TSrcGen
initSrcGen(g, renderFlags)
for i in countup(0, sonsLen(n) - 1):
@@ -1248,7 +1314,7 @@ proc renderModule(n: PNode, filename: string,
case n.sons[i].kind
of nkTypeSection, nkConstSection, nkVarSection, nkLetSection,
nkCommentStmt: putNL(g)
else: nil
else: discard
gcoms(g)
if optStdout in gGlobalOptions:
write(stdout, g.buf)
@@ -1271,4 +1337,3 @@ proc getNextTok(r: var TSrcGen, kind: var TTokType, literal: var string) =
inc(r.idx)
else:
kind = tkEof

View File

@@ -140,6 +140,7 @@ type
memfile: TMemFile # unfortunately there is no point in time where we
# can close this! XXX
methods*: TSymSeq
origFile: string
inViewMode: bool
PRodReader* = ref TRodReader
@@ -183,7 +184,7 @@ proc skipNode(r: PRodReader) =
if par == 0: break
dec par
of '(': inc par
else: nil
else: discard
inc pos
r.pos = pos+1 # skip ')'
@@ -247,7 +248,7 @@ proc decodeNodeLazyBody(r: PRodReader, fInfo: TLineInfo,
if r.s[r.pos] == ')': inc(r.pos)
else: internalError(result.info, "decodeNode: ')' missing")
else:
InternalError(fInfo, "decodeNode: '(' missing " & $r.pos)
internalError(fInfo, "decodeNode: '(' missing " & $r.pos)
proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode =
result = decodeNodeLazyBody(r, fInfo, nil)
@@ -285,7 +286,7 @@ proc decodeLoc(r: PRodReader, loc: var TLoc, info: TLineInfo) =
else:
loc.a = 0
if r.s[r.pos] == '>': inc(r.pos)
else: InternalError(info, "decodeLoc " & r.s[r.pos])
else: internalError(info, "decodeLoc " & r.s[r.pos])
proc decodeType(r: PRodReader, info: TLineInfo): PType =
result = nil
@@ -302,10 +303,10 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType =
setId(result.id)
if debugIds: registerID(result)
else:
InternalError(info, "decodeType: no id")
internalError(info, "decodeType: no id")
# here this also avoids endless recursion for recursive type
IdTablePut(gTypeTable, result, result)
if r.s[r.pos] == '(': result.n = decodeNode(r, UnknownLineInfo())
idTablePut(gTypeTable, result, result)
if r.s[r.pos] == '(': result.n = decodeNode(r, unknownLineInfo())
if r.s[r.pos] == '$':
inc(r.pos)
result.flags = cast[TTypeFlags](int32(decodeVInt(r.s, r.pos)))
@@ -334,7 +335,7 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType =
if r.s[r.pos] == '(':
inc(r.pos)
if r.s[r.pos] == ')': inc(r.pos)
else: InternalError(info, "decodeType ^(" & r.s[r.pos])
else: internalError(info, "decodeType ^(" & r.s[r.pos])
rawAddSon(result, nil)
else:
var d = decodeVInt(r.s, r.pos)
@@ -346,10 +347,10 @@ proc decodeLib(r: PRodReader, info: TLineInfo): PLib =
new(result)
inc(r.pos)
result.kind = TLibKind(decodeVInt(r.s, r.pos))
if r.s[r.pos] != '|': InternalError("decodeLib: 1")
if r.s[r.pos] != '|': internalError("decodeLib: 1")
inc(r.pos)
result.name = toRope(decodeStr(r.s, r.pos))
if r.s[r.pos] != '|': InternalError("decodeLib: 2")
if r.s[r.pos] != '|': internalError("decodeLib: 2")
inc(r.pos)
result.path = decodeNode(r, info)
@@ -369,21 +370,21 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
id = decodeVInt(r.s, r.pos)
setId(id)
else:
InternalError(info, "decodeSym: no id")
internalError(info, "decodeSym: no id")
if r.s[r.pos] == '&':
inc(r.pos)
ident = getIdent(decodeStr(r.s, r.pos))
else:
InternalError(info, "decodeSym: no ident")
internalError(info, "decodeSym: no ident")
#echo "decoding: {", ident.s
result = PSym(IdTableGet(r.syms, id))
result = PSym(idTableGet(r.syms, id))
if result == nil:
new(result)
result.id = id
IdTablePut(r.syms, result, result)
idTablePut(r.syms, result, result)
if debugIds: registerID(result)
elif result.id != id:
InternalError(info, "decodeSym: wrong id")
internalError(info, "decodeSym: wrong id")
elif result.kind != skStub and not r.inViewMode:
# we already loaded the symbol
return
@@ -426,7 +427,7 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
result.annex = decodeLib(r, info)
if r.s[r.pos] == '#':
inc(r.pos)
result.constraint = decodeNode(r, UnknownLineInfo())
result.constraint = decodeNode(r, unknownLineInfo())
if r.s[r.pos] == '(':
if result.kind in routineKinds:
result.ast = decodeNodeLazyBody(r, result.info, result)
@@ -454,10 +455,10 @@ proc skipSection(r: PRodReader) =
elif c > 0:
dec(c)
of '\0': break # end of file
else: nil
else: discard
inc(r.pos)
else:
InternalError("skipSection " & $r.line)
internalError("skipSection " & $r.line)
proc rdWord(r: PRodReader): string =
result = ""
@@ -471,11 +472,11 @@ proc newStub(r: PRodReader, name: string, id: int): PSym =
result.id = id
result.name = getIdent(name)
result.position = r.readerIndex
setID(id) #MessageOut(result.name.s);
setId(id) #MessageOut(result.name.s);
if debugIds: registerID(result)
proc processInterf(r: PRodReader, module: PSym) =
if r.interfIdx == 0: InternalError("processInterf")
if r.interfIdx == 0: internalError("processInterf")
r.pos = r.interfIdx
while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'):
var w = decodeStr(r.s, r.pos)
@@ -484,23 +485,23 @@ proc processInterf(r: PRodReader, module: PSym) =
inc(r.pos) # #10
var s = newStub(r, w, key)
s.owner = module
StrTableAdd(module.tab, s)
IdTablePut(r.syms, s, s)
strTableAdd(module.tab, s)
idTablePut(r.syms, s, s)
proc processCompilerProcs(r: PRodReader, module: PSym) =
if r.compilerProcsIdx == 0: InternalError("processCompilerProcs")
if r.compilerProcsIdx == 0: internalError("processCompilerProcs")
r.pos = r.compilerProcsIdx
while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'):
var w = decodeStr(r.s, r.pos)
inc(r.pos)
var key = decodeVInt(r.s, r.pos)
inc(r.pos) # #10
var s = PSym(IdTableGet(r.syms, key))
var s = PSym(idTableGet(r.syms, key))
if s == nil:
s = newStub(r, w, key)
s.owner = module
IdTablePut(r.syms, s, s)
StrTableAdd(rodCompilerProcs, s)
idTablePut(r.syms, s, s)
strTableAdd(rodCompilerprocs, s)
proc processIndex(r: PRodReader; idx: var TIndex; outf: TFile = nil) =
var key, val, tmp: int
@@ -515,11 +516,11 @@ proc processIndex(r: PRodReader; idx: var TIndex; outf: TFile = nil) =
else:
key = idx.lastIdxKey + 1
val = tmp + idx.lastIdxVal
IITablePut(idx.tab, key, val)
iiTablePut(idx.tab, key, val)
if not outf.isNil: outf.write(key, " ", val, "\n")
idx.lastIdxKey = key
idx.lastIdxVal = val
setID(key) # ensure that this id will not be used
setId(key) # ensure that this id will not be used
if r.s[r.pos] == '\x0A':
inc(r.pos)
inc(r.line)
@@ -538,7 +539,7 @@ proc cmdChangeTriggersRecompilation(old, new: TCommands): bool =
of cmdNone, cmdDoc, cmdInterpret, cmdPretty, cmdGenDepend, cmdDump,
cmdCheck, cmdParse, cmdScan, cmdIdeTools, cmdDef,
cmdRst2html, cmdRst2tex, cmdInteractive, cmdRun:
nil
discard
# else: trigger recompilation:
result = true
@@ -557,7 +558,10 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
of "ID":
inc(r.pos) # skip ':'
r.moduleID = decodeVInt(r.s, r.pos)
setID(r.moduleID)
setId(r.moduleID)
of "ORIGFILE":
inc(r.pos)
r.origFile = decodeStr(r.s, r.pos)
of "OPTIONS":
inc(r.pos) # skip ':'
r.options = cast[TOptions](int32(decodeVInt(r.s, r.pos)))
@@ -585,7 +589,7 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
inc(r.line)
while r.s[r.pos] != ')':
let relativePath = decodeStr(r.s, r.pos)
let resolvedPath = relativePath.findModule
let resolvedPath = relativePath.findModule(r.origFile)
let finalPath = if resolvedPath.len > 0: resolvedPath else: relativePath
r.files.add(finalPath.fileInfoIdx)
inc(r.pos) # skip #10
@@ -599,7 +603,7 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
inc(r.pos) # skip ' '
inclCrc = decodeVInt(r.s, r.pos)
if r.reason == rrNone:
if not ExistsFile(w) or (inclCrc != int(crcFromFile(w))):
if not existsFile(w) or (inclCrc != int(crcFromFile(w))):
r.reason = rrInclDeps
if r.s[r.pos] == '\x0A':
inc(r.pos)
@@ -635,7 +639,7 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
r.initIdx = r.pos + 2 # "(\10"
skipSection(r)
else:
InternalError("invalid section: '" & section &
internalError("invalid section: '" & section &
"' at " & $r.line & " in " & r.filename)
#MsgWriteln("skipping section: " & section &
# " at " & $r.line & " in " & r.filename)
@@ -654,7 +658,7 @@ proc newRodReader(modfilename: string, crc: TCrc32,
readerIndex: int): PRodReader =
new(result)
try:
result.memFile = memfiles.open(modfilename)
result.memfile = memfiles.open(modfilename)
except EOS:
return nil
result.files = @[]
@@ -666,13 +670,13 @@ proc newRodReader(modfilename: string, crc: TCrc32,
r.line = 1
r.readerIndex = readerIndex
r.filename = modfilename
InitIdTable(r.syms)
initIdTable(r.syms)
# we terminate the file explicitely with ``\0``, so the cast to `cstring`
# is safe:
r.s = cast[cstring](r.memFile.mem)
r.s = cast[cstring](r.memfile.mem)
if startsWith(r.s, "NIM:"):
initIITable(r.index.tab)
initIITable(r.imports.tab) # looks like a ROD file
initIiTable(r.index.tab)
initIiTable(r.imports.tab) # looks like a ROD file
inc(r.pos, 4)
var version = ""
while r.s[r.pos] notin {'\0', '\x0A'}:
@@ -687,12 +691,12 @@ proc newRodReader(modfilename: string, crc: TCrc32,
result = nil
proc rrGetType(r: PRodReader, id: int, info: TLineInfo): PType =
result = PType(IdTableGet(gTypeTable, id))
result = PType(idTableGet(gTypeTable, id))
if result == nil:
# load the type:
var oldPos = r.pos
var d = IITableGet(r.index.tab, id)
if d == invalidKey: InternalError(info, "rrGetType")
var d = iiTableGet(r.index.tab, id)
if d == InvalidKey: internalError(info, "rrGetType")
r.pos = d + r.dataIdx
result = decodeType(r, info)
r.pos = oldPos
@@ -711,7 +715,7 @@ var gMods*: TFileModuleMap = @[]
proc decodeSymSafePos(rd: PRodReader, offset: int, info: TLineInfo): PSym =
# all compiled modules
if rd.dataIdx == 0: InternalError(info, "dataIdx == 0")
if rd.dataIdx == 0: internalError(info, "dataIdx == 0")
var oldPos = rd.pos
rd.pos = offset + rd.dataIdx
result = decodeSym(rd, info)
@@ -721,8 +725,8 @@ proc findSomeWhere(id: int) =
for i in countup(0, high(gMods)):
var rd = gMods[i].rd
if rd != nil:
var d = IITableGet(rd.index.tab, id)
if d != invalidKey:
var d = iiTableGet(rd.index.tab, id)
if d != InvalidKey:
echo "found id ", id, " in ", gMods[i].filename
proc getReader(moduleId: int): PRodReader =
@@ -732,37 +736,37 @@ proc getReader(moduleId: int): PRodReader =
# problems:
for i in 0 .. <gMods.len:
result = gMods[i].rd
if result != nil and result.moduleId == moduleId: return result
if result != nil and result.moduleID == moduleId: return result
return nil
proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym =
result = PSym(IdTableGet(r.syms, id))
result = PSym(idTableGet(r.syms, id))
if result == nil:
# load the symbol:
var d = IITableGet(r.index.tab, id)
if d == invalidKey:
var d = iiTableGet(r.index.tab, id)
if d == InvalidKey:
# import from other module:
var moduleID = IiTableGet(r.imports.tab, id)
var moduleID = iiTableGet(r.imports.tab, id)
if moduleID < 0:
var x = ""
encodeVInt(id, x)
InternalError(info, "missing from both indexes: +" & x)
internalError(info, "missing from both indexes: +" & x)
var rd = getReader(moduleID)
d = IITableGet(rd.index.tab, id)
if d != invalidKey:
d = iiTableGet(rd.index.tab, id)
if d != InvalidKey:
result = decodeSymSafePos(rd, d, info)
else:
var x = ""
encodeVInt(id, x)
when false: findSomeWhere(id)
InternalError(info, "rrGetSym: no reader found: +" & x)
internalError(info, "rrGetSym: no reader found: +" & x)
else:
# own symbol:
result = decodeSymSafePos(r, d, info)
if result != nil and result.kind == skStub: rawLoadStub(result)
proc loadInitSection(r: PRodReader): PNode =
if r.initIdx == 0 or r.dataIdx == 0: InternalError("loadInitSection")
if r.initIdx == 0 or r.dataIdx == 0: internalError("loadInitSection")
var oldPos = r.pos
r.pos = r.initIdx
result = newNode(nkStmtList)
@@ -771,7 +775,7 @@ proc loadInitSection(r: PRodReader): PNode =
inc(r.pos) # #10
var p = r.pos
r.pos = d + r.dataIdx
addSon(result, decodeNode(r, UnknownLineInfo()))
addSon(result, decodeNode(r, unknownLineInfo()))
r.pos = p
r.pos = oldPos
@@ -779,24 +783,24 @@ proc loadConverters(r: PRodReader) =
# We have to ensure that no exported converter is a stub anymore, and the
# import mechanism takes care of the rest.
if r.convertersIdx == 0 or r.dataIdx == 0:
InternalError("importConverters")
internalError("importConverters")
r.pos = r.convertersIdx
while r.s[r.pos] > '\x0A':
var d = decodeVInt(r.s, r.pos)
discard rrGetSym(r, d, UnknownLineInfo())
discard rrGetSym(r, d, unknownLineInfo())
if r.s[r.pos] == ' ': inc(r.pos)
proc loadMethods(r: PRodReader) =
if r.methodsIdx == 0 or r.dataIdx == 0:
InternalError("loadMethods")
internalError("loadMethods")
r.pos = r.methodsIdx
while r.s[r.pos] > '\x0A':
var d = decodeVInt(r.s, r.pos)
r.methods.add(rrGetSym(r, d, UnknownLineInfo()))
r.methods.add(rrGetSym(r, d, unknownLineInfo()))
if r.s[r.pos] == ' ': inc(r.pos)
proc GetCRC*(fileIdx: int32): TCrc32 =
InternalAssert fileIdx >= 0 and fileIdx < gMods.len
proc getCRC*(fileIdx: int32): TCrc32 =
internalAssert fileIdx >= 0 and fileIdx < gMods.len
if gMods[fileIdx].crcDone:
return gMods[fileIdx].crc
@@ -814,14 +818,14 @@ proc checkDep(fileIdx: int32): TReasonForRecompile =
# reason has already been computed for this module:
return gMods[fileIdx].reason
let filename = fileIdx.toFilename
var crc = GetCRC(fileIdx)
var crc = getCRC(fileIdx)
gMods[fileIdx].reason = rrNone # we need to set it here to avoid cycles
result = rrNone
var r: PRodReader = nil
var rodfile = toGeneratedFile(filename, RodExt)
var rodfile = toGeneratedFile(filename.withPackageName, RodExt)
r = newRodReader(rodfile, crc, fileIdx)
if r == nil:
result = (if ExistsFile(rodfile): rrRodInvalid else: rrRodDoesNotExist)
result = (if existsFile(rodfile): rrRodInvalid else: rrRodDoesNotExist)
else:
processRodFile(r, crc)
result = r.reason
@@ -830,7 +834,7 @@ proc checkDep(fileIdx: int32): TReasonForRecompile =
# NOTE: we need to process the entire module graph so that no ID will
# be used twice! However, compilation speed does not suffer much from
# this, since results are cached.
var res = checkDep(SystemFileIdx)
var res = checkDep(systemFileIdx)
if res != rrNone: result = rrModDeps
for i in countup(0, high(r.modDeps)):
res = checkDep(r.modDeps[i])
@@ -841,7 +845,7 @@ proc checkDep(fileIdx: int32): TReasonForRecompile =
rawMessage(hintProcessing, reasonToFrmt[result] % filename)
if result != rrNone or optForceFullMake in gGlobalOptions:
# recompilation is necessary:
if r != nil: memfiles.close(r.memFile)
if r != nil: memfiles.close(r.memfile)
r = nil
gMods[fileIdx].rd = r
gMods[fileIdx].reason = result # now we know better
@@ -854,11 +858,11 @@ proc handleSymbolFile(module: PSym): PRodReader =
idgen.loadMaxIds(options.gProjectPath / options.gProjectName)
discard checkDep(fileIdx)
if gMods[fileIdx].reason == rrEmpty: InternalError("handleSymbolFile")
if gMods[fileIdx].reason == rrEmpty: internalError("handleSymbolFile")
result = gMods[fileIdx].rd
if result != nil:
module.id = result.moduleID
IdTablePut(result.syms, module, module)
idTablePut(result.syms, module, module)
processInterf(result, module)
processCompilerProcs(result, module)
loadConverters(result)
@@ -867,26 +871,26 @@ proc handleSymbolFile(module: PSym): PRodReader =
module.id = getID()
proc rawLoadStub(s: PSym) =
if s.kind != skStub: InternalError("loadStub")
if s.kind != skStub: internalError("loadStub")
var rd = gMods[s.position].rd
var theId = s.id # used for later check
var d = IITableGet(rd.index.tab, s.id)
if d == invalidKey: InternalError("loadStub: invalid key")
var rs = decodeSymSafePos(rd, d, UnknownLineInfo())
var d = iiTableGet(rd.index.tab, s.id)
if d == InvalidKey: internalError("loadStub: invalid key")
var rs = decodeSymSafePos(rd, d, unknownLineInfo())
if rs != s:
#echo "rs: ", toHex(cast[int](rs.position), int.sizeof * 2),
# "\ns: ", toHex(cast[int](s.position), int.sizeof * 2)
InternalError(rs.info, "loadStub: wrong symbol")
internalError(rs.info, "loadStub: wrong symbol")
elif rs.id != theId:
InternalError(rs.info, "loadStub: wrong ID")
internalError(rs.info, "loadStub: wrong ID")
#MessageOut('loaded stub: ' + s.name.s);
proc LoadStub*(s: PSym) =
proc loadStub*(s: PSym) =
## loads the stub symbol `s`.
# deactivate the GC here because we do a deep recursion and generate no
# garbage when restoring parts of the object graph anyway.
# Since we die with internal errors if this fails, so no try-finally is
# Since we die with internal errors if this fails, no try-finally is
# necessary.
GC_disable()
rawLoadStub(s)
@@ -908,8 +912,8 @@ proc getBody*(s: PSym): PNode =
s.ast.sons[bodyPos] = result
s.offset = 0
InitIdTable(gTypeTable)
InitStrTable(rodCompilerProcs)
initIdTable(gTypeTable)
initStrTable(rodCompilerprocs)
# viewer:
proc writeNode(f: TFile; n: PNode) =
@@ -1034,8 +1038,12 @@ proc viewFile(rodfile: string) =
of "ID":
inc(r.pos) # skip ':'
r.moduleID = decodeVInt(r.s, r.pos)
setID(r.moduleID)
setId(r.moduleID)
outf.writeln("ID:", $r.moduleID)
of "ORIGFILE":
inc(r.pos)
r.origFile = decodeStr(r.s, r.pos)
outf.writeln("ORIGFILE:", r.origFile)
of "OPTIONS":
inc(r.pos) # skip ':'
r.options = cast[TOptions](int32(decodeVInt(r.s, r.pos)))
@@ -1058,13 +1066,13 @@ proc viewFile(rodfile: string) =
outf.write(" ", w)
if r.s[r.pos] == ' ': inc(r.pos)
outf.write("\n")
of "FILES":
of "FILES":
inc(r.pos, 2) # skip "(\10"
inc(r.line)
outf.write("FILES(\n")
while r.s[r.pos] != ')':
let relativePath = decodeStr(r.s, r.pos)
let resolvedPath = relativePath.findModule
let resolvedPath = relativePath.findModule(r.origFile)
let finalPath = if resolvedPath.len > 0: resolvedPath else: relativePath
r.files.add(finalPath.fileInfoIdx)
inc(r.pos) # skip #10
@@ -1132,12 +1140,12 @@ proc viewFile(rodfile: string) =
outf.write("DATA(\n")
while r.s[r.pos] != ')':
if r.s[r.pos] == '(':
outf.writeNode decodeNode(r, UnknownLineInfo())
outf.writeNode decodeNode(r, unknownLineInfo())
outf.write("\n")
elif r.s[r.pos] == '[':
outf.writeType decodeType(r, UnknownLineInfo())
outf.writeType decodeType(r, unknownLineInfo())
else:
outf.writeSym decodeSym(r, UnknownLineInfo())
outf.writeSym decodeSym(r, unknownLineInfo())
if r.s[r.pos] == '\x0A':
inc(r.pos)
inc(r.line)
@@ -1158,7 +1166,7 @@ proc viewFile(rodfile: string) =
if r.s[r.pos] == ')': inc r.pos
outf.write("<not supported by viewer>)\n")
else:
InternalError("invalid section: '" & section &
internalError("invalid section: '" & section &
"' at " & $r.line & " in " & r.filename)
skipSection(r)
if r.s[r.pos] == '\x0A':

View File

@@ -12,7 +12,7 @@ import strutils
proc c_sprintf(buf, frmt: cstring) {.importc: "sprintf", nodecl, varargs.}
proc ToStrMaxPrecision*(f: BiggestFloat): string =
proc toStrMaxPrecision*(f: BiggestFloat): string =
if f != f:
result = "NAN"
elif f == 0.0:
@@ -36,7 +36,7 @@ proc hexChar(c: char, xi: var int) =
of '0'..'9': xi = (xi shl 4) or (ord(c) - ord('0'))
of 'a'..'f': xi = (xi shl 4) or (ord(c) - ord('a') + 10)
of 'A'..'F': xi = (xi shl 4) or (ord(c) - ord('A') + 10)
else: nil
else: discard
proc decodeStr*(s: cstring, pos: var int): string =
var i = pos
@@ -119,7 +119,7 @@ template decodeIntImpl() =
proc decodeVInt*(s: cstring, pos: var int): int =
decodeIntImpl()
proc decodeVBiggestInt*(s: cstring, pos: var int): biggestInt =
proc decodeVBiggestInt*(s: cstring, pos: var int): BiggestInt =
decodeIntImpl()
iterator decodeVIntArray*(s: cstring): int =

View File

@@ -34,6 +34,7 @@ type
sstack: TSymSeq # a stack of symbols to process
tstack: TTypeSeq # a stack of types to process
files: TStringSeq
origFile: string
PRodWriter = ref TRodWriter
@@ -45,21 +46,17 @@ proc addStmt(w: PRodWriter, n: PNode)
proc writeRod(w: PRodWriter)
proc getDefines(): string =
var it: TTabIter
var s = InitTabIter(it, gSymbols)
result = ""
while s != nil:
if s.position == 1:
if result.len != 0: add(result, " ")
add(result, s.name.s)
s = nextIter(it, gSymbols)
for d in definedSymbolNames():
if result.len != 0: add(result, " ")
add(result, d)
proc fileIdx(w: PRodWriter, filename: string): int =
for i in countup(0, high(w.files)):
if w.files[i] == filename:
return i
result = len(w.files)
setlen(w.files, result + 1)
setLen(w.files, result + 1)
w.files[result] = filename
template filename*(w: PRodWriter): string =
@@ -69,8 +66,8 @@ proc newRodWriter(crc: TCrc32, module: PSym): PRodWriter =
new(result)
result.sstack = @[]
result.tstack = @[]
InitIITable(result.index.tab)
InitIITable(result.imports.tab)
initIiTable(result.index.tab)
initIiTable(result.imports.tab)
result.index.r = ""
result.imports.r = ""
result.crc = crc
@@ -85,6 +82,7 @@ proc newRodWriter(crc: TCrc32, module: PSym): PRodWriter =
result.converters = ""
result.methods = ""
result.init = ""
result.origFile = module.info.toFilename
result.data = newStringOfCap(12_000)
proc addModDep(w: PRodWriter, dep: string) =
@@ -95,7 +93,7 @@ const
rodNL = "\x0A"
proc addInclDep(w: PRodWriter, dep: string) =
var resolved = dep.findModule
var resolved = dep.findModule(w.module.info.toFullPath)
encodeVInt(fileIdx(w, dep), w.inclDeps)
add(w.inclDeps, " ")
encodeVInt(crcFromFile(resolved), w.inclDeps)
@@ -103,12 +101,12 @@ proc addInclDep(w: PRodWriter, dep: string) =
proc pushType(w: PRodWriter, t: PType) =
# check so that the stack does not grow too large:
if IiTableGet(w.index.tab, t.id) == invalidKey:
if iiTableGet(w.index.tab, t.id) == InvalidKey:
w.tstack.add(t)
proc pushSym(w: PRodWriter, s: PSym) =
# check so that the stack does not grow too large:
if IiTableGet(w.index.tab, s.id) == invalidKey:
if iiTableGet(w.index.tab, s.id) == InvalidKey:
w.sstack.add(s)
proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
@@ -122,19 +120,19 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
# we do not write comments for now
# Line information takes easily 20% or more of the filesize! Therefore we
# omit line information if it is the same as the father's line information:
if finfo.fileIndex != n.info.fileIndex:
if fInfo.fileIndex != n.info.fileIndex:
result.add('?')
encodeVInt(n.info.col, result)
result.add(',')
encodeVInt(n.info.line, result)
result.add(',')
encodeVInt(fileIdx(w, toFilename(n.info)), result)
elif finfo.line != n.info.line:
elif fInfo.line != n.info.line:
result.add('?')
encodeVInt(n.info.col, result)
result.add(',')
encodeVInt(n.info.line, result)
elif finfo.col != n.info.col:
elif fInfo.col != n.info.col:
result.add('?')
encodeVInt(n.info.col, result)
# No need to output the file index, as this is the serialization of one
@@ -192,7 +190,7 @@ proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
if loc.a != 0:
add(result, '?')
encodeVInt(loc.a, result)
if oldlen + 1 == result.len:
if oldLen + 1 == result.len:
# no data was necessary, so remove the '<' again:
setLen(result, oldLen)
else:
@@ -204,7 +202,7 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
result.add("[]")
return
# we need no surrounding [] here because the type is in a line of its own
if t.kind == tyForward: InternalError("encodeType: tyForward")
if t.kind == tyForward: internalError("encodeType: tyForward")
# for the new rodfile viewer we use a preceeding [ so that the data section
# can easily be disambiguated:
add(result, '[')
@@ -212,7 +210,7 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
add(result, '+')
encodeVInt(t.id, result)
if t.n != nil:
encodeNode(w, UnknownLineInfo(), t.n, result)
encodeNode(w, unknownLineInfo(), t.n, result)
if t.flags != {}:
add(result, '$')
encodeVInt(cast[int32](t.flags), result)
@@ -294,7 +292,7 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
if s.annex != nil: encodeLib(w, s.annex, s.info, result)
if s.constraint != nil:
add(result, '#')
encodeNode(w, UnknownLineInfo(), s.constraint, result)
encodeNode(w, unknownLineInfo(), s.constraint, result)
# lazy loading will soon reload the ast lazily, so the ast needs to be
# the last entry of a symbol:
if s.ast != nil:
@@ -324,7 +322,7 @@ proc addToIndex(w: var TIndex, key, val: int) =
add(w.r, rodNL)
w.lastIdxKey = key
w.lastIdxVal = val
IiTablePut(w.tab, key, val)
iiTablePut(w.tab, key, val)
const debugWrittenIds = false
@@ -338,9 +336,9 @@ proc symStack(w: PRodWriter): int =
if sfForward in s.flags:
w.sstack[result] = s
inc result
elif IiTableGet(w.index.tab, s.id) == invalidKey:
elif iiTableGet(w.index.tab, s.id) == InvalidKey:
var m = getModule(s)
if m == nil: InternalError("symStack: module nil: " & s.name.s)
if m == nil: internalError("symStack: module nil: " & s.name.s)
if (m.id == w.module.id) or (sfFromGeneric in s.flags):
# put definition in here
var L = w.data.len
@@ -366,7 +364,7 @@ proc symStack(w: PRodWriter): int =
if s.kind == skMethod and sfDispatcher notin s.flags:
if w.methods.len != 0: add(w.methods, ' ')
encodeVInt(s.id, w.methods)
elif IiTableGet(w.imports.tab, s.id) == invalidKey:
elif iiTableGet(w.imports.tab, s.id) == InvalidKey:
addToIndex(w.imports, s.id, m.id)
when debugWrittenIds:
if not Contains(debugWritten, s.id):
@@ -376,7 +374,7 @@ proc symStack(w: PRodWriter): int =
debug(m)
InternalError("Symbol referred to but never written")
inc(i)
setlen(w.sstack, result)
setLen(w.sstack, result)
proc typeStack(w: PRodWriter): int =
var i = 0
@@ -385,13 +383,13 @@ proc typeStack(w: PRodWriter): int =
if t.kind == tyForward:
w.tstack[result] = t
inc result
elif IiTableGet(w.index.tab, t.id) == invalidKey:
elif iiTableGet(w.index.tab, t.id) == InvalidKey:
var L = w.data.len
addToIndex(w.index, t.id, L)
encodeType(w, t, w.data)
add(w.data, rodNL)
inc(i)
setlen(w.tstack, result)
setLen(w.tstack, result)
proc processStacks(w: PRodWriter, finalPass: bool) =
var oldS = 0
@@ -403,7 +401,7 @@ proc processStacks(w: PRodWriter, finalPass: bool) =
oldS = slen
oldT = tlen
if finalPass and (oldS != 0 or oldT != 0):
InternalError("could not serialize some forwarded symbols/types")
internalError("could not serialize some forwarded symbols/types")
proc rawAddInterfaceSym(w: PRodWriter, s: PSym) =
pushSym(w, s)
@@ -418,14 +416,15 @@ proc addInterfaceSym(w: PRodWriter, s: PSym) =
proc addStmt(w: PRodWriter, n: PNode) =
encodeVInt(w.data.len, w.init)
add(w.init, rodNL)
encodeNode(w, UnknownLineInfo(), n, w.data)
encodeNode(w, unknownLineInfo(), n, w.data)
add(w.data, rodNL)
processStacks(w, false)
proc writeRod(w: PRodWriter) =
processStacks(w, true)
var f: TFile
if not open(f, completeGeneratedFilePath(changeFileExt(w.filename, "rod")),
if not open(f, completeGeneratedFilePath(changeFileExt(
w.filename.withPackageName, RodExt)),
fmWrite):
#echo "couldn't write rod file for: ", w.filename
return
@@ -437,6 +436,11 @@ proc writeRod(w: PRodWriter) =
encodeVInt(w.module.id, id)
f.write(id)
f.write(rodNL)
var orig = "ORIGFILE:"
encodeStr(w.origFile, orig)
f.write(orig)
f.write(rodNL)
var crc = "CRC:"
encodeVInt(w.crc, crc)
@@ -530,9 +534,9 @@ proc process(c: PPassContext, n: PNode): PNode =
of nkProcDef, nkMethodDef, nkIteratorDef, nkConverterDef,
nkTemplateDef, nkMacroDef:
var s = n.sons[namePos].sym
if s == nil: InternalError(n.info, "rodwrite.process")
if s == nil: internalError(n.info, "rodwrite.process")
if n.sons[bodyPos] == nil:
InternalError(n.info, "rodwrite.process: body is nil")
internalError(n.info, "rodwrite.process: body is nil")
if n.sons[bodyPos].kind != nkEmpty or s.magic != mNone or
sfForward notin s.flags:
addInterfaceSym(w, s)
@@ -545,7 +549,7 @@ proc process(c: PPassContext, n: PNode): PNode =
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if a.sons[0].kind != nkSym: InternalError(a.info, "rodwrite.process")
if a.sons[0].kind != nkSym: internalError(a.info, "rodwrite.process")
var s = a.sons[0].sym
addInterfaceSym(w, s)
# this takes care of enum fields too
@@ -569,11 +573,11 @@ proc process(c: PPassContext, n: PNode): PNode =
of nkPragma:
addStmt(w, n)
else:
nil
discard
proc myOpen(module: PSym): PPassContext =
if module.id < 0: InternalError("rodwrite: module ID not set")
var w = newRodWriter(module.fileIdx.GetCRC, module)
if module.id < 0: internalError("rodwrite: module ID not set")
var w = newRodWriter(module.fileIdx.getCRC, module)
rawAddInterfaceSym(w, module)
result = w

View File

@@ -91,13 +91,13 @@ proc writeRopeIfNotEqual*(r: PRope, filename: string): bool
proc ropeToStr*(p: PRope): string
proc ropef*(frmt: TFormatStr, args: varargs[PRope]): PRope
proc appf*(c: var PRope, frmt: TFormatStr, args: varargs[PRope])
proc RopeEqualsFile*(r: PRope, f: string): bool
proc ropeEqualsFile*(r: PRope, f: string): bool
# returns true if the rope r is the same as the contents of file f
proc RopeInvariant*(r: PRope): bool
proc ropeInvariant*(r: PRope): bool
# exported for debugging
# implementation
var ErrorHandler*: proc(err: TRopesError, msg: string, useWarning = false)
var errorHandler*: proc(err: TRopesError, msg: string, useWarning = false)
# avoid dependency on msgs.nim
proc ropeLen(a: PRope): int =
@@ -126,7 +126,7 @@ proc resetRopeCache* =
for i in low(cache)..high(cache):
cache[i] = nil
proc RopeInvariant(r: PRope): bool =
proc ropeInvariant(r: PRope): bool =
if r == nil:
result = true
else:
@@ -157,14 +157,14 @@ proc toRope(s: string): PRope =
result = nil
else:
result = insertInCache(s)
assert(RopeInvariant(result))
assert(ropeInvariant(result))
proc RopeSeqInsert(rs: var TRopeSeq, r: PRope, at: Natural) =
proc ropeSeqInsert(rs: var TRopeSeq, r: PRope, at: Natural) =
var length = len(rs)
if at > length:
setlen(rs, at + 1)
setLen(rs, at + 1)
else:
setlen(rs, length + 1) # move old rope elements:
setLen(rs, length + 1) # move old rope elements:
for i in countdown(length, at + 1):
rs[i] = rs[i - 1] # this is correct, I used pen and paper to validate it
rs[at] = r
@@ -177,8 +177,8 @@ proc newRecRopeToStr(result: var string, resultLen: var int, r: PRope) =
add(stack, it.right)
it = it.left
assert(it.data != nil)
CopyMem(addr(result[resultLen]), addr(it.data[0]), it.length)
Inc(resultLen, it.length)
copyMem(addr(result[resultLen]), addr(it.data[0]), it.length)
inc(resultLen, it.length)
assert(resultLen <= len(result))
proc ropeToStr(p: PRope): string =
@@ -227,13 +227,13 @@ proc writeRope*(f: TFile, c: PRope) =
assert(it.data != nil)
write(f, it.data)
proc WriteRope*(head: PRope, filename: string, useWarning = false) =
var f: tfile
proc writeRope*(head: PRope, filename: string, useWarning = false) =
var f: TFile
if open(f, filename, fmWrite):
if head != nil: WriteRope(f, head)
if head != nil: writeRope(f, head)
close(f)
else:
ErrorHandler(rCannotOpenFile, filename, useWarning)
errorHandler(rCannotOpenFile, filename, useWarning)
var
rnl* = tnl.newRope
@@ -258,12 +258,12 @@ proc ropef(frmt: TFormatStr, args: varargs[PRope]): PRope =
of '0'..'9':
var j = 0
while true:
j = (j * 10) + Ord(frmt[i]) - ord('0')
j = (j * 10) + ord(frmt[i]) - ord('0')
inc(i)
if (i > length + 0 - 1) or not (frmt[i] in {'0'..'9'}): break
num = j
if j > high(args) + 1:
ErrorHandler(rInvalidFormatStr, $(j))
errorHandler(rInvalidFormatStr, $(j))
else:
app(result, args[j - 1])
of 'n':
@@ -273,22 +273,25 @@ proc ropef(frmt: TFormatStr, args: varargs[PRope]): PRope =
app(result, rnl)
inc(i)
else:
ErrorHandler(rInvalidFormatStr, $(frmt[i]))
errorHandler(rInvalidFormatStr, $(frmt[i]))
var start = i
while i < length:
if frmt[i] != '$': inc(i)
else: break
if i - 1 >= start:
app(result, substr(frmt, start, i - 1))
assert(RopeInvariant(result))
assert(ropeInvariant(result))
{.push stack_trace: off, line_trace: off.}
proc `~`*(r: expr[string]): PRope =
# this is the new optimized "to rope" operator
# the mnemonic is that `~` looks a bit like a rope :)
var r {.global.} = r.ropef
return r
{.pop.}
when true:
template `~`*(r: string): PRope = r.ropef
else:
{.push stack_trace: off, line_trace: off.}
proc `~`*(r: static[string]): PRope =
# this is the new optimized "to rope" operator
# the mnemonic is that `~` looks a bit like a rope :)
var r {.global.} = r.ropef
return r
{.pop.}
proc appf(c: var PRope, frmt: TFormatStr, args: varargs[PRope]) =
app(c, ropef(frmt, args))
@@ -296,10 +299,10 @@ proc appf(c: var PRope, frmt: TFormatStr, args: varargs[PRope]) =
const
bufSize = 1024 # 1 KB is reasonable
proc auxRopeEqualsFile(r: PRope, bin: var tfile, buf: Pointer): bool =
proc auxRopeEqualsFile(r: PRope, bin: var TFile, buf: pointer): bool =
if r.data != nil:
if r.length > bufSize:
ErrorHandler(rTokenTooLong, r.data)
errorHandler(rTokenTooLong, r.data)
return
var readBytes = readBuffer(bin, buf, r.length)
result = readBytes == r.length and
@@ -308,12 +311,12 @@ proc auxRopeEqualsFile(r: PRope, bin: var tfile, buf: Pointer): bool =
result = auxRopeEqualsFile(r.left, bin, buf)
if result: result = auxRopeEqualsFile(r.right, bin, buf)
proc RopeEqualsFile(r: PRope, f: string): bool =
var bin: tfile
proc ropeEqualsFile(r: PRope, f: string): bool =
var bin: TFile
result = open(bin, f)
if not result:
return # not equal if file does not exist
var buf = alloc(BufSize)
var buf = alloc(bufSize)
result = auxRopeEqualsFile(r, bin, buf)
if result:
result = readBuffer(bin, buf, bufSize) == 0 # really at the end of file?
@@ -346,7 +349,7 @@ proc newCrcFromRopeAux(r: PRope, startVal: TCrc32): TCrc32 =
inc(i)
proc crcFromRope(r: PRope): TCrc32 =
result = newCrcFromRopeAux(r, initCrc32)
result = newCrcFromRopeAux(r, InitCrc32)
proc writeRopeIfNotEqual(r: PRope, filename: string): bool =
# returns true if overwritten

View File

@@ -9,7 +9,7 @@
## Saturated arithmetic routines. XXX Make part of the stdlib?
proc `|+|`*(a, b: biggestInt): biggestInt =
proc `|+|`*(a, b: BiggestInt): BiggestInt =
## saturated addition.
result = a +% b
if (result xor a) >= 0'i64 or (result xor b) >= 0'i64:
@@ -19,7 +19,7 @@ proc `|+|`*(a, b: biggestInt): biggestInt =
else:
result = high(result)
proc `|-|`*(a, b: biggestInt): biggestInt =
proc `|-|`*(a, b: BiggestInt): BiggestInt =
result = a -% b
if (result xor a) >= 0'i64 or (result xor not b) >= 0'i64:
return result
@@ -28,14 +28,14 @@ proc `|-|`*(a, b: biggestInt): biggestInt =
else:
result = high(result)
proc `|abs|`*(a: biggestInt): biggestInt =
proc `|abs|`*(a: BiggestInt): BiggestInt =
if a != low(a):
if a >= 0: result = a
else: result = -a
else:
result = low(a)
proc `|div|`*(a, b: biggestInt): biggestInt =
proc `|div|`*(a, b: BiggestInt): BiggestInt =
# (0..5) div (0..4) == (0..5) div (1..4) == (0 div 4) .. (5 div 1)
if b == 0'i64:
# make the same as ``div 1``:
@@ -45,13 +45,13 @@ proc `|div|`*(a, b: biggestInt): biggestInt =
else:
result = a div b
proc `|mod|`*(a, b: biggestInt): biggestInt =
proc `|mod|`*(a, b: BiggestInt): BiggestInt =
if b == 0'i64:
result = a
else:
result = a mod b
proc `|*|`*(a, b: biggestInt): biggestInt =
proc `|*|`*(a, b: BiggestInt): BiggestInt =
var
resAsFloat, floatProd: float64
result = a *% b

View File

@@ -14,8 +14,8 @@ import
wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math,
magicsys, parser, nversion, nimsets, semfold, importer,
procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch,
semthreads, intsets, transf, evals, idgen, aliases, cgmeth, lambdalifting,
evaltempl, patterns, parampatterns, sempass2
intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
evaltempl, patterns, parampatterns, sempass2, pretty, semmacrosanity
# implementation
@@ -36,29 +36,40 @@ proc semParamList(c: PContext, n, genericParams: PNode, s: PSym)
proc addParams(c: PContext, n: PNode, kind: TSymKind)
proc maybeAddResult(c: PContext, s: PSym, n: PNode)
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc tryExpr(c: PContext, n: PNode,
flags: TExprFlags = {}, bufferErrors = false): PNode
proc fixImmediateParams(n: PNode): PNode
proc activate(c: PContext, n: PNode)
proc semQuoteAst(c: PContext, n: PNode): PNode
proc finishMethod(c: PContext, s: PSym)
proc IndexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode
proc indexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode
proc typeMismatch(n: PNode, formal, actual: PType) =
if formal.kind != tyError and actual.kind != tyError:
LocalError(n.Info, errGenerated, msgKindToString(errTypeMismatch) &
localError(n.info, errGenerated, msgKindToString(errTypeMismatch) &
typeToString(actual) & ") " &
`%`(msgKindToString(errButExpectedX), [typeToString(formal)]))
proc fitNode(c: PContext, formal: PType, arg: PNode): PNode =
result = IndexTypesMatch(c, formal, arg.typ, arg)
if result == nil:
typeMismatch(arg, formal, arg.typ)
proc fitNode(c: PContext, formal: PType, arg: PNode): PNode =
if arg.typ.isNil:
localError(arg.info, errExprXHasNoType,
renderTree(arg, {renderNoComments}))
# error correction:
result = copyNode(arg)
result.typ = formal
else:
result = indexTypesMatch(c, formal, arg.typ, arg)
if result == nil:
typeMismatch(arg, formal, arg.typ)
# error correction:
result = copyTree(arg)
result.typ = formal
var CommonTypeBegin = PType(kind: tyExpr)
proc inferWithMetatype(c: PContext, formal: PType,
arg: PNode, coerceDistincts = false): PNode
var commonTypeBegin = PType(kind: tyExpr)
proc commonType*(x, y: PType): PType =
# new type relation that is used for array constructors,
@@ -75,27 +86,48 @@ proc commonType*(x, y: PType): PType =
elif a.kind == tyTypeDesc:
# turn any concrete typedesc into the abstract typedesc type
if a.sons == nil: result = a
else: result = newType(tyTypeDesc, a.owner)
else:
result = newType(tyTypeDesc, a.owner)
rawAddSon(result, newType(tyNone, a.owner))
elif b.kind in {tyArray, tyArrayConstr, tySet, tySequence} and
a.kind == b.kind:
# check for seq[empty] vs. seq[int]
let idx = ord(b.kind in {tyArray, tyArrayConstr})
if a.sons[idx].kind == tyEmpty: return y
#elif b.sons[idx].kind == tyEmpty: return x
elif a.kind == tyRange and b.kind == tyRange:
# consider: (range[0..3], range[0..4]) here. We should make that
# range[0..4]. But then why is (range[0..4], 6) not range[0..6]?
# But then why is (2,4) not range[2..4]? But I think this would break
# too much code. So ... it's the same range or the base type. This means
# type(if b: 0 else 1) == int and not range[0..1]. For now. In the long
# run people expect ranges to work properly within a tuple.
if not sameType(a, b):
result = skipTypes(a, {tyRange}).skipIntLit
when false:
if a.kind != tyRange and b.kind == tyRange:
# XXX This really needs a better solution, but a proper fix now breaks
# code.
result = a #.skipIntLit
elif a.kind == tyRange and b.kind != tyRange:
result = b #.skipIntLit
elif a.kind in IntegralTypes and a.n != nil:
result = a #.skipIntLit
else:
var k = tyNone
if a.kind in {tyRef, tyPtr}:
k = a.kind
if b.kind != a.kind: return x
a = a.sons[0]
b = b.sons[0]
a = a.lastSon
b = b.lastSon
if a.kind == tyObject and b.kind == tyObject:
result = commonSuperclass(a, b)
# this will trigger an error later:
if result.isNil: return x
if result.isNil or result == a: return x
if result == b: return y
if k != tyNone:
let r = result
result = NewType(k, r.owner)
result = newType(k, r.owner)
result.addSonSkipIntLit(r)
proc isTopLevel(c: PContext): bool {.inline.} =
@@ -108,8 +140,12 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
# like newSymS, but considers gensym'ed symbols
if n.kind == nkSym:
result = n.sym
InternalAssert sfGenSym in result.flags
InternalAssert result.kind == kind
internalAssert sfGenSym in result.flags
internalAssert result.kind == kind
# when there is a nested proc inside a template, semtmpl
# will assign a wrong owner during the first pass over the
# template; we must fix it here: see #909
result.owner = getCurrOwner()
else:
result = newSym(kind, considerAcc(n), getCurrOwner(), n.info)
@@ -120,37 +156,18 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags): PSym
proc semStmtScope(c: PContext, n: PNode): PNode
proc ParamsTypeCheck(c: PContext, typ: PType) {.inline.} =
proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
if not typeAllowed(typ, skConst):
LocalError(typ.n.info, errXisNoType, typeToString(typ))
localError(typ.n.info, errXisNoType, typeToString(typ))
proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym
proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
semCheck: bool = true): PNode
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode
proc semWhen(c: PContext, n: PNode, semCheck: bool = true): PNode
proc evalTypedExpr(c: PContext, e: PNode): PNode =
result = getConstExpr(c.module, e)
if result == nil:
result = evalConstExpr(c.module, e)
if result == nil or result.kind == nkEmpty:
LocalError(e.info, errConstExprExpected)
# error correction:
result = e
proc semConstExpr(c: PContext, n: PNode): PNode =
var e = semExprWithType(c, n)
if e == nil:
LocalError(n.info, errConstExprExpected)
return n
result = evalTypedExpr(c, e)
include hlo, seminst, semcall
proc isOpImpl(c: PContext, n: PNode): PNode
proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
flags: TExprFlags = {}): PNode
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
flags: TExprFlags = {}): PNode
proc symFromType(t: PType, info: TLineInfo): PSym =
if t.sym != nil: return t.sym
@@ -162,10 +179,100 @@ proc symNodeFromType(c: PContext, t: PType, info: TLineInfo): PNode =
result = newSymNode(symFromType(t, info), info)
result.typ = makeTypeDesc(c, t)
proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode =
when false:
proc createEvalContext(c: PContext, mode: TEvalMode): PEvalContext =
result = newEvalContext(c.module, mode)
result.getType = proc (n: PNode): PNode =
result = tryExpr(c, n)
if result == nil:
result = newSymNode(errorSym(c, n))
elif result.typ == nil:
result = newSymNode(getSysSym"void")
else:
result.typ = makeTypeDesc(c, result.typ)
result.handleIsOperator = proc (n: PNode): PNode =
result = isOpImpl(c, n)
proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode): PNode =
# recompute the types as 'eval' isn't guaranteed to construct types nor
# that the types are sound:
when true:
if eOrig.typ.kind in {tyExpr, tyStmt, tyTypeDesc}:
result = semExprWithType(c, evaluated)
else:
result = evaluated
let expectedType = eOrig.typ.skipTypes({tyStatic})
semmacrosanity.annotateType(result, expectedType)
else:
result = semExprWithType(c, evaluated)
#result = fitNode(c, e.typ, result) inlined with special case:
let arg = result
result = indexTypesMatch(c, eOrig.typ, arg.typ, arg)
if result == nil:
result = arg
# for 'tcnstseq' we support [] to become 'seq'
if eOrig.typ.skipTypes(abstractInst).kind == tySequence and
arg.typ.skipTypes(abstractInst).kind == tyArrayConstr:
arg.typ = eOrig.typ
proc tryConstExpr(c: PContext, n: PNode): PNode =
var e = semExprWithType(c, n)
if e == nil: return
result = getConstExpr(c.module, e)
if result != nil: return
let oldErrorCount = msgs.gErrorCounter
let oldErrorMax = msgs.gErrorMax
let oldErrorOutputs = errorOutputs
errorOutputs = {}
msgs.gErrorMax = high(int)
try:
result = evalConstExpr(c.module, e)
if result == nil or result.kind == nkEmpty:
result = nil
else:
result = fixupTypeAfterEval(c, result, e)
except ERecoverableError:
result = nil
msgs.gErrorCounter = oldErrorCount
msgs.gErrorMax = oldErrorMax
errorOutputs = oldErrorOutputs
proc semConstExpr(c: PContext, n: PNode): PNode =
var e = semExprWithType(c, n)
if e == nil:
localError(n.info, errConstExprExpected)
return n
result = getConstExpr(c.module, e)
if result == nil:
result = evalConstExpr(c.module, e)
if result == nil or result.kind == nkEmpty:
if e.info != n.info:
pushInfoContext(n.info)
localError(e.info, errConstExprExpected)
popInfoContext()
else:
localError(e.info, errConstExprExpected)
# error correction:
result = e
else:
result = fixupTypeAfterEval(c, result, e)
include hlo, seminst, semcall
proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
flags: TExprFlags): PNode =
inc(evalTemplateCounter)
if evalTemplateCounter > 100:
GlobalError(s.info, errTemplateInstantiationTooNested)
globalError(s.info, errTemplateInstantiationTooNested)
let oldFriend = c.friendModule
c.friendModule = s.owner.getModule
result = n
if s.typ.sons[0] == nil:
@@ -176,38 +283,33 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode =
# BUGFIX: we cannot expect a type here, because module aliases would not
# work then (see the ``tmodulealias`` test)
# semExprWithType(c, result)
result = semExpr(c, result)
result = semExpr(c, result, flags)
of tyStmt:
result = semStmt(c, result)
of tyTypeDesc:
if n.kind == nkStmtList: result.kind = nkStmtListType
var typ = semTypeNode(c, result, nil)
result = symNodeFromType(c, typ, n.info)
result.typ = makeTypeDesc(c, typ)
#result = symNodeFromType(c, typ, n.info)
else:
result = semExpr(c, result)
result = semExpr(c, result, flags)
result = fitNode(c, s.typ.sons[0], result)
#GlobalError(s.info, errInvalidParamKindX, typeToString(s.typ.sons[0]))
dec(evalTemplateCounter)
c.friendModule = oldFriend
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
semCheck: bool = true): PNode =
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
flags: TExprFlags = {}): PNode =
markUsed(n, sym)
if sym == c.p.owner:
GlobalError(n.info, errRecursiveDependencyX, sym.name.s)
globalError(n.info, errRecursiveDependencyX, sym.name.s)
if c.evalContext == nil:
c.evalContext = newEvalContext(c.module, emStatic)
c.evalContext.getType = proc (n: PNode): PNode =
var e = tryExpr(c, n)
if e == nil:
result = symNodeFromType(c, errorType(c), n.info)
elif e.typ == nil:
result = newSymNode(getSysSym"void")
else:
result = symNodeFromType(c, e.typ, n.info)
#if c.evalContext == nil:
# c.evalContext = c.createEvalContext(emStatic)
result = evalMacroCall(c.evalContext, n, nOrig, sym)
if semCheck: result = semAfterMacroCall(c, result, sym)
result = evalMacroCall(c.module, n, nOrig, sym)
if efNoSemCheck notin flags:
result = semAfterMacroCall(c, result, sym, flags)
proc forceBool(c: PContext, n: PNode): PNode =
result = fitNode(c, getSysType(tyBool), n)
@@ -217,13 +319,21 @@ proc semConstBoolExpr(c: PContext, n: PNode): PNode =
let nn = semExprWithType(c, n)
result = fitNode(c, getSysType(tyBool), nn)
if result == nil:
LocalError(n.info, errConstExprExpected)
localError(n.info, errConstExprExpected)
return nn
result = getConstExpr(c.module, result)
if result == nil:
LocalError(n.info, errConstExprExpected)
localError(n.info, errConstExprExpected)
result = nn
type
TSemGenericFlag = enum
withinBind, withinTypeDesc, withinMixin
TSemGenericFlags = set[TSemGenericFlag]
proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags,
ctx: var TIntSet): PNode
include semtypes, semtempl, semgnrc, semstmts, semexprs
proc addCodeForGenerics(c: PContext, n: PNode) =
@@ -231,29 +341,33 @@ proc addCodeForGenerics(c: PContext, n: PNode) =
var prc = c.generics[i].inst.sym
if prc.kind in {skProc, skMethod, skConverter} and prc.magic == mNone:
if prc.ast == nil or prc.ast.sons[bodyPos] == nil:
InternalError(prc.info, "no code for " & prc.name.s)
internalError(prc.info, "no code for " & prc.name.s)
else:
addSon(n, prc.ast)
c.lastGenericIdx = c.generics.len
proc myOpen(module: PSym): PPassContext =
var c = newContext(module)
if c.p != nil: InternalError(module.info, "sem.myOpen")
if c.p != nil: internalError(module.info, "sem.myOpen")
c.semConstExpr = semConstExpr
c.semExpr = semExpr
c.semTryExpr = tryExpr
c.semTryConstExpr = tryConstExpr
c.semOperand = semOperand
c.semConstBoolExpr = semConstBoolExpr
c.semOverloadedCall = semOverloadedCall
c.semInferredLambda = semInferredLambda
c.semGenerateInstance = generateInstance
c.semTypeNode = semTypeNode
pushProcCon(c, module)
pushOwner(c.module)
c.importTable = openScope(c)
c.importTable.addSym(module) # a module knows itself
if sfSystemModule in module.flags:
magicsys.SystemModule = module # set global variable!
magicsys.systemModule = module # set global variable!
else:
c.importTable.addSym magicsys.SystemModule # import the "System" identifier
importAllSymbols(c, magicsys.SystemModule)
c.importTable.addSym magicsys.systemModule # import the "System" identifier
importAllSymbols(c, magicsys.systemModule)
c.topLevelScope = openScope(c)
result = c
@@ -261,7 +375,7 @@ proc myOpenCached(module: PSym, rd: PRodReader): PPassContext =
result = myOpen(module)
for m in items(rd.methods): methodDef(m, true)
proc SemStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
result = semStmt(c, n)
# BUGFIX: process newly generated generics here, not at the end!
if c.lastGenericIdx < c.generics.len:
@@ -276,7 +390,7 @@ proc SemStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
result = buildEchoStmt(c, result)
result = transformStmt(c.module, result)
proc RecoverContext(c: PContext) =
proc recoverContext(c: PContext) =
# clean up in case of a semantic error: We clean up the stacks, etc. This is
# faster than wrapping every stack operation in a 'try finally' block and
# requires far less code.
@@ -288,36 +402,30 @@ proc myProcess(context: PPassContext, n: PNode): PNode =
var c = PContext(context)
# no need for an expensive 'try' if we stop after the first error anyway:
if msgs.gErrorMax <= 1:
result = SemStmtAndGenerateGenerics(c, n)
result = semStmtAndGenerateGenerics(c, n)
else:
let oldContextLen = msgs.getInfoContextLen()
let oldInGenericInst = c.InGenericInst
let oldInGenericInst = c.inGenericInst
try:
result = SemStmtAndGenerateGenerics(c, n)
result = semStmtAndGenerateGenerics(c, n)
except ERecoverableError, ESuggestDone:
RecoverContext(c)
c.InGenericInst = oldInGenericInst
recoverContext(c)
c.inGenericInst = oldInGenericInst
msgs.setInfoContextLen(oldContextLen)
if getCurrentException() of ESuggestDone: result = nil
else: result = ast.emptyNode
#if gCmd == cmdIdeTools: findSuggest(c, n)
proc checkThreads(c: PContext) =
if not needsGlobalAnalysis(): return
for i in 0 .. c.threadEntries.len-1:
semthreads.AnalyseThreadProc(c.threadEntries[i])
proc myClose(context: PPassContext, n: PNode): PNode =
var c = PContext(context)
closeScope(c) # close module's scope
rawCloseScope(c) # imported symbols; don't check for unused ones!
result = newNode(nkStmtList)
if n != nil:
InternalError(n.info, "n is not nil") #result := n;
internalError(n.info, "n is not nil") #result := n;
addCodeForGenerics(c, result)
if c.module.ast != nil:
result.add(c.module.ast)
checkThreads(c)
popOwner()
popProcCon(c)

View File

@@ -19,7 +19,7 @@ proc sameMethodDispatcher(a, b: PSym): bool =
if aa.sym == bb.sym:
result = true
else:
nil
discard
# generics have no dispatcher yet, so we need to compare the method
# names; however, the names are equal anyway because otherwise we
# wouldn't even consider them to be overloaded. But even this does
@@ -34,9 +34,76 @@ proc sameMethodDispatcher(a, b: PSym): bool =
proc determineType(c: PContext, s: PSym)
proc resolveOverloads(c: PContext, n, orig: PNode,
proc pickBestCandidate(c: PContext, headSymbol: PNode,
n, orig: PNode,
initialBinding: PNode,
filter: TSymKinds,
best, alt: var TCandidate,
errors: var seq[string]) =
var o: TOverloadIter
var sym = initOverloadIter(o, c, headSymbol)
var symScope = o.lastOverloadScope
var z: TCandidate
if sym == nil: return
initCandidate(c, best, sym, initialBinding, symScope)
initCandidate(c, alt, sym, initialBinding, symScope)
best.state = csNoMatch
while sym != nil:
if sym.kind in filter:
determineType(c, sym)
initCandidate(c, z, sym, initialBinding, o.lastOverloadScope)
z.calleeSym = sym
matches(c, n, orig, z)
if errors != nil:
errors.safeAdd(getProcHeader(sym))
if z.errors != nil:
for err in z.errors:
errors[errors.len - 1].add("\n " & err)
if z.state == csMatch:
# little hack so that iterators are preferred over everything else:
if sym.kind in skIterators: inc(z.exactMatches, 200)
case best.state
of csEmpty, csNoMatch: best = z
of csMatch:
var cmp = cmpCandidates(best, z)
if cmp < 0: best = z # x is better than the best so far
elif cmp == 0: alt = z # x is as good as the best so far
else: discard
sym = nextOverloadIter(o, c, headSymbol)
proc notFoundError*(c: PContext, n: PNode, errors: seq[string]) =
# Gives a detailed error message; this is separated from semOverloadedCall,
# as semOverlodedCall is already pretty slow (and we need this information
# only in case of an error).
if c.inCompilesContext > 0:
# fail fast:
globalError(n.info, errTypeMismatch, "")
var result = msgKindToString(errTypeMismatch)
add(result, describeArgs(c, n, 1))
add(result, ')')
var candidates = ""
for err in errors:
add(candidates, err)
add(candidates, "\n")
if candidates != "":
add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates)
localError(n.info, errGenerated, result)
proc gatherUsedSyms(c: PContext, usedSyms: var seq[PNode]) =
for scope in walkScopes(c.currentScope):
if scope.usingSyms != nil:
for s in scope.usingSyms: usedSyms.safeAdd(s)
proc resolveOverloads(c: PContext, n, orig: PNode,
filter: TSymKinds): TCandidate =
var initialBinding: PNode
var alt: TCandidate
var f = n.sons[0]
if f.kind == nkBracketExpr:
# fill in the bindings:
@@ -44,51 +111,89 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
f = f.sons[0]
else:
initialBinding = nil
var
o: TOverloadIter
alt, z: TCandidate
template best: expr = result
#Message(n.info, warnUser, renderTree(n))
var sym = initOverloadIter(o, c, f)
var symScope = o.lastOverloadScope
if sym == nil: return
initCandidate(best, sym, initialBinding, symScope)
initCandidate(alt, sym, initialBinding, symScope)
var errors: seq[string]
var usedSyms: seq[PNode]
while sym != nil:
if sym.kind in filter:
determineType(c, sym)
initCandidate(z, sym, initialBinding, o.lastOverloadScope)
z.calleeSym = sym
matches(c, n, orig, z)
if z.state == csMatch:
# little hack so that iterators are preferred over everything else:
if sym.kind == skIterator: inc(z.exactMatches, 200)
case best.state
of csEmpty, csNoMatch: best = z
of csMatch:
var cmp = cmpCandidates(best, z)
if cmp < 0: best = z # x is better than the best so far
elif cmp == 0: alt = z # x is as good as the best so far
else: nil
sym = nextOverloadIter(o, c, f)
template pickBest(headSymbol: expr) =
pickBestCandidate(c, headSymbol, n, orig, initialBinding,
filter, result, alt, errors)
if best.state == csEmpty:
# no overloaded proc found
# do not generate an error yet; the semantic checking will check for
# an overloaded () operator
elif alt.state == csMatch and cmpCandidates(best, alt) == 0 and
not sameMethodDispatcher(best.calleeSym, alt.calleeSym):
if best.state != csMatch:
InternalError(n.info, "x.state is not csMatch")
#writeMatches(best)
gatherUsedSyms(c, usedSyms)
if usedSyms != nil:
var hiddenArg = if usedSyms.len > 1: newNode(nkClosedSymChoice, n.info, usedSyms)
else: usedSyms[0]
n.sons.insert(hiddenArg, 1)
orig.sons.insert(hiddenArg, 1)
pickBest(f)
if result.state != csMatch:
n.sons.delete(1)
orig.sons.delete(1)
else: return
pickBest(f)
let overloadsState = result.state
if overloadsState != csMatch:
if nfDotField in n.flags:
internalAssert f.kind == nkIdent and n.sonsLen >= 2
let calleeName = newStrNode(nkStrLit, f.ident.s).withInfo(n.info)
# leave the op head symbol empty,
# we are going to try multiple variants
n.sons[0..1] = [nil, n[1], calleeName]
orig.sons[0..1] = [nil, orig[1], calleeName]
template tryOp(x) =
let op = newIdentNode(getIdent(x), n.info)
n.sons[0] = op
orig.sons[0] = op
pickBest(op)
if nfExplicitCall in n.flags:
tryOp ".()"
if result.state in {csEmpty, csNoMatch}:
tryOp "."
elif nfDotSetter in n.flags:
internalAssert f.kind == nkIdent and n.sonsLen == 3
let calleeName = newStrNode(nkStrLit, f.ident.s[0.. -2]).withInfo(n.info)
let callOp = newIdentNode(getIdent".=", n.info)
n.sons[0..1] = [callOp, n[1], calleeName]
orig.sons[0..1] = [callOp, orig[1], calleeName]
pickBest(callOp)
if overloadsState == csEmpty and result.state == csEmpty:
localError(n.info, errUndeclaredIdentifier, considerAcc(f).s)
return
elif result.state != csMatch:
if nfExprCall in n.flags:
localError(n.info, errExprXCannotBeCalled,
renderTree(n, {renderNoComments}))
else:
if {nfDotField, nfDotSetter} * n.flags != {}:
# clean up the inserted ops
n.sons.delete(2)
n.sons[0] = f
errors = @[]
pickBest(f)
notFoundError(c, n, errors)
return
if alt.state == csMatch and cmpCandidates(result, alt) == 0 and
not sameMethodDispatcher(result.calleeSym, alt.calleeSym):
internalAssert result.state == csMatch
#writeMatches(result)
#writeMatches(alt)
if c.inCompilesContext > 0:
# quick error message for performance of 'compiles' built-in:
GlobalError(n.Info, errGenerated, "ambiguous call")
globalError(n.info, errGenerated, "ambiguous call")
elif gErrorCounter == 0:
# don't cascade errors
var args = "("
@@ -97,8 +202,8 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
add(args, typeToString(n.sons[i].typ))
add(args, ")")
LocalError(n.Info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [
getProcHeader(best.calleeSym), getProcHeader(alt.calleeSym),
localError(n.info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [
getProcHeader(result.calleeSym), getProcHeader(alt.calleeSym),
args])
@@ -116,19 +221,32 @@ proc instGenericConvertersSons*(c: PContext, n: PNode, x: TCandidate) =
for i in 1 .. <n.len:
instGenericConvertersArg(c, n.sons[i], x)
proc IndexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode =
proc indexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode =
var m: TCandidate
initCandidate(m, f)
result = paramTypesMatch(c, m, f, a, arg, nil)
initCandidate(c, m, f)
result = paramTypesMatch(m, f, a, arg, nil)
if m.genericConverter and result != nil:
instGenericConvertersArg(c, result, m)
proc ConvertTo*(c: PContext, f: PType, n: PNode): PNode =
proc inferWithMetatype(c: PContext, formal: PType,
arg: PNode, coerceDistincts = false): PNode =
var m: TCandidate
initCandidate(m, f)
result = paramTypesMatch(c, m, f, n.typ, n, nil)
initCandidate(c, m, formal)
m.coerceDistincts = coerceDistincts
result = paramTypesMatch(m, formal, arg.typ, arg, nil)
if m.genericConverter and result != nil:
instGenericConvertersArg(c, result, m)
if result != nil:
# This almost exactly replicates the steps taken by the compiler during
# param matching. It performs an embarassing ammount of back-and-forth
# type jugling, but it's the price to pay for consistency and correctness
result.typ = generateTypeInstance(c, m.bindings, arg.info,
formal.skipTypes({tyCompositeTypeClass}))
else:
typeMismatch(arg, formal, arg.typ)
# error correction:
result = copyTree(arg)
result.typ = formal
proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
assert x.state == csMatch
@@ -144,7 +262,7 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
result = x.call
result.sons[0] = newSymNode(finalCallee, result.sons[0].info)
result.typ = finalCallee.typ.sons[0]
if ContainsGenericType(result.typ): result.typ = errorType(c)
if containsGenericType(result.typ): result.typ = errorType(c)
return
result = x.call
instGenericConvertersSons(c, result, x)
@@ -155,15 +273,16 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
filter: TSymKinds): PNode =
var r = resolveOverloads(c, n, nOrig, filter)
if r.state == csMatch: result = semResolvedCall(c, n, r)
# else: result = errorNode(c, n)
proc explicitGenericInstError(n: PNode): PNode =
LocalError(n.info, errCannotInstantiateX, renderTree(n))
localError(n.info, errCannotInstantiateX, renderTree(n))
result = n
proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
var x: TCandidate
initCandidate(x, s, n)
var newInst = generateInstance(c, s, x.bindings, n.info)
var m: TCandidate
initCandidate(c, m, s, n)
var newInst = generateInstance(c, s, m.bindings, n.info)
markUsed(n, s)
result = newSymNode(newInst, n.info)
@@ -178,7 +297,7 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
# number of generic type parameters:
if safeLen(s.ast.sons[genericParamsPos]) != n.len-1:
let expected = safeLen(s.ast.sons[genericParamsPos])
LocalError(n.info, errGenerated, "cannot instantiate: " & renderTree(n) &
localError(n.info, errGenerated, "cannot instantiate: " & renderTree(n) &
"; got " & $(n.len-1) & " type(s) but expected " & $expected)
return n
result = explicitGenericSym(c, n, s)
@@ -189,8 +308,9 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
result = newNodeI(a.kind, n.info)
for i in countup(0, len(a)-1):
var candidate = a.sons[i].sym
if candidate.kind in {skProc, skMethod, skConverter, skIterator}:
# if suffices that the candidate has the proper number of generic
if candidate.kind in {skProc, skMethod, skConverter,
skIterator, skClosureIterator}:
# it suffices that the candidate has the proper number of generic
# type parameters:
if safeLen(candidate.ast.sons[genericParamsPos]) == n.len-1:
result.add(explicitGenericSym(c, n, candidate))
@@ -201,17 +321,20 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
else:
result = explicitGenericInstError(n)
proc SearchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym =
proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym =
# Searchs for the fn in the symbol table. If the parameter lists are suitable
# for borrowing the sym in the symbol table is returned, else nil.
# New approach: generate fn(x, y, z) where x, y, z have the proper types
# and use the overloading resolution mechanism:
var call = newNode(nkCall)
var call = newNodeI(nkCall, fn.info)
var hasDistinct = false
call.add(newIdentNode(fn.name, fn.info))
for i in 1.. <fn.typ.n.len:
let param = fn.typ.n.sons[i]
let t = skipTypes(param.typ, abstractVar-{tyTypeDesc})
if t.kind == tyDistinct or param.typ.kind == tyDistinct: hasDistinct = true
call.add(newNodeIT(nkEmpty, fn.info, t.baseOfDistinct))
var resolved = semOverloadedCall(c, call, call, {fn.kind})
if resolved != nil:
result = resolved.sons[0].sym
if hasDistinct:
var resolved = semOverloadedCall(c, call, call, {fn.kind})
if resolved != nil:
result = resolved.sons[0].sym

View File

@@ -13,7 +13,7 @@ import
strutils, lists, intsets, options, lexer, ast, astalgo, trees, treetab,
wordrecg,
ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math,
magicsys, nversion, nimsets, parser, times, passes, rodread, evals
magicsys, nversion, nimsets, parser, times, passes, rodread, vmdef
type
TOptionEntry* = object of lists.TListEntry # entries to put on a
@@ -21,7 +21,7 @@ type
options*: TOptions
defaultCC*: TCallingConvention
dynlib*: PLib
Notes*: TNoteKinds
notes*: TNoteKinds
otherPragmas*: PNode # every pragma can be pushed
POptionEntry* = ref TOptionEntry
@@ -32,7 +32,7 @@ type
resultSym*: PSym # the result symbol (if we are in a proc)
nestedLoopCounter*: int # whether we are in a loop or not
nestedBlockCounter*: int # whether we are in a block or not
InTryStmt*: int # whether we are in a try statement; works also
inTryStmt*: int # whether we are in a try statement; works also
# in standalone ``except`` and ``finally``
next*: PProcCon # used for stacking procedure contexts
@@ -42,7 +42,7 @@ type
TExprFlag* = enum
efLValue, efWantIterator, efInTypeof, efWantStmt, efDetermineType,
efAllowDestructor
efAllowDestructor, efWantValue, efOperand, efNoSemCheck
TExprFlags* = set[TExprFlag]
PContext* = ref TContext
@@ -55,15 +55,15 @@ type
friendModule*: PSym # current friend module; may access private data;
# this is used so that generic instantiations
# can access private object fields
InstCounter*: int # to prevent endless instantiations
instCounter*: int # to prevent endless instantiations
threadEntries*: TSymSeq # list of thread entries to check
AmbiguousSymbols*: TIntSet # ids of all ambiguous symbols (cannot
ambiguousSymbols*: TIntSet # ids of all ambiguous symbols (cannot
# store this info in the syms themselves!)
InGenericContext*: int # > 0 if we are in a generic type
InUnrolledContext*: int # > 0 if we are unrolling a loop
InCompilesContext*: int # > 0 if we are in a ``compiles`` magic
InGenericInst*: int # > 0 if we are instantiating a generic
inTypeClass*: int # > 0 if we are in a user-defined type class
inGenericContext*: int # > 0 if we are in a generic type
inUnrolledContext*: int # > 0 if we are unrolling a loop
inCompilesContext*: int # > 0 if we are in a ``compiles`` magic
inGenericInst*: int # > 0 if we are instantiating a generic
converters*: TSymSeq # sequence of converters
patterns*: TSymSeq # sequence of pattern matchers
optionStack*: TLinkedList
@@ -72,18 +72,25 @@ type
libs*: TLinkedList # all libs used by this module
semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
semTryExpr*: proc (c: PContext, n: PNode,flags: TExprFlags = {},
bufferErrors = false): PNode {.nimcall.}
semTryConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.}
semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet
semOverloadedCall*: proc (c: PContext, n, nOrig: PNode,
filter: TSymKinds): PNode {.nimcall.}
semTypeNode*: proc(c: PContext, n: PNode, prev: PType): PType {.nimcall.}
semInferredLambda*: proc(c: PContext, pt: TIdTable, n: PNode): PNode
semGenerateInstance*: proc (c: PContext, fn: PSym, pt: TIdTable,
info: TLineInfo): PSym
includedFiles*: TIntSet # used to detect recursive include files
userPragmas*: TStrTable
evalContext*: PEvalContext
UnknownIdents*: TIntSet # ids of all unknown identifiers to prevent
unknownIdents*: TIntSet # ids of all unknown identifiers to prevent
# naming it multiple times
generics*: seq[TInstantiationPair] # pending list of instantiated generics to compile
lastGenericIdx*: int # used for the generics stack
hloLoopDetector*: int # used to prevent endless loops in the HLO
proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
result.genericSym = s
@@ -110,8 +117,8 @@ proc scopeDepth*(c: PContext): int {.inline.} =
# owner handling:
proc getCurrOwner*(): PSym
proc PushOwner*(owner: PSym)
proc PopOwner*()
proc pushOwner*(owner: PSym)
proc popOwner*()
# implementation
var gOwners*: seq[PSym] = @[]
@@ -124,20 +131,20 @@ proc getCurrOwner(): PSym =
# BUGFIX: global array is needed!
result = gOwners[high(gOwners)]
proc PushOwner(owner: PSym) =
proc pushOwner(owner: PSym) =
add(gOwners, owner)
proc PopOwner() =
proc popOwner() =
var length = len(gOwners)
if length > 0: setlen(gOwners, length - 1)
else: InternalError("popOwner")
if length > 0: setLen(gOwners, length - 1)
else: internalError("popOwner")
proc lastOptionEntry(c: PContext): POptionEntry =
result = POptionEntry(c.optionStack.tail)
proc pushProcCon*(c: PContext, owner: PSym) {.inline.} =
if owner == nil:
InternalError("owner is nil")
internalError("owner is nil")
return
var x: PProcCon
new(x)
@@ -156,25 +163,24 @@ proc newOptionEntry(): POptionEntry =
proc newContext(module: PSym): PContext =
new(result)
result.AmbiguousSymbols = initIntset()
result.ambiguousSymbols = initIntSet()
initLinkedList(result.optionStack)
initLinkedList(result.libs)
append(result.optionStack, newOptionEntry())
result.module = module
result.friendModule = module
result.threadEntries = @[]
result.converters = @[]
result.patterns = @[]
result.includedFiles = initIntSet()
initStrTable(result.userPragmas)
result.generics = @[]
result.UnknownIdents = initIntSet()
result.unknownIdents = initIntSet()
proc inclSym(sq: var TSymSeq, s: PSym) =
var L = len(sq)
for i in countup(0, L - 1):
if sq[i].id == s.id: return
setlen(sq, L + 1)
setLen(sq, L + 1)
sq[L] = s
proc addConverter*(c: PContext, conv: PSym) =
@@ -187,24 +193,84 @@ proc newLib(kind: TLibKind): PLib =
new(result)
result.kind = kind #initObjectSet(result.syms)
proc addToLib(lib: PLib, sym: PSym) =
#ObjectSetIncl(lib.syms, sym);
if sym.annex != nil: LocalError(sym.info, errInvalidPragma)
proc addToLib(lib: PLib, sym: PSym) =
#if sym.annex != nil and not isGenericRoutine(sym):
# LocalError(sym.info, errInvalidPragma)
sym.annex = lib
proc makePtrType(c: PContext, baseType: PType): PType =
result = newTypeS(tyPtr, c)
addSonSkipIntLit(result, baseType.AssertNotNil)
addSonSkipIntLit(result, baseType.assertNotNil)
proc makeVarType(c: PContext, baseType: PType): PType =
result = newTypeS(tyVar, c)
addSonSkipIntLit(result, baseType.AssertNotNil)
addSonSkipIntLit(result, baseType.assertNotNil)
proc makeTypeDesc*(c: PContext, typ: PType): PType =
result = newTypeS(tyTypeDesc, c)
result.addSonSkipIntLit(typ.AssertNotNil)
result.addSonSkipIntLit(typ.assertNotNil)
proc newTypeS(kind: TTypeKind, c: PContext): PType =
proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode =
let typedesc = makeTypeDesc(c, typ)
let sym = newSym(skType, idAnon, getCurrOwner(), info).linkTo(typedesc)
return newSymNode(sym, info)
proc makeTypeFromExpr*(c: PContext, n: PNode): PType =
result = newTypeS(tyFromExpr, c)
result.n = n
proc newTypeWithSons*(c: PContext, kind: TTypeKind,
sons: seq[PType]): PType =
result = newType(kind, getCurrOwner())
result.sons = sons
proc makeStaticExpr*(c: PContext, n: PNode): PNode =
result = newNodeI(nkStaticExpr, n.info)
result.sons = @[n]
result.typ = newTypeWithSons(c, tyStatic, @[n.typ])
proc makeAndType*(c: PContext, t1, t2: PType): PType =
result = newTypeS(tyAnd, c)
result.sons = @[t1, t2]
propagateToOwner(result, t1)
propagateToOwner(result, t2)
result.flags.incl((t1.flags + t2.flags) * {tfHasStatic})
proc makeOrType*(c: PContext, t1, t2: PType): PType =
result = newTypeS(tyOr, c)
result.sons = @[t1, t2]
propagateToOwner(result, t1)
propagateToOwner(result, t2)
result.flags.incl((t1.flags + t2.flags) * {tfHasStatic})
proc makeNotType*(c: PContext, t1: PType): PType =
result = newTypeS(tyNot, c)
result.sons = @[t1]
propagateToOwner(result, t1)
result.flags.incl(t1.flags * {tfHasStatic})
proc nMinusOne*(n: PNode): PNode =
result = newNode(nkCall, n.info, @[
newSymNode(getSysMagic("<", mUnaryLt)),
n])
# Remember to fix the procs below this one when you make changes!
proc makeRangeWithStaticExpr*(c: PContext, n: PNode): PType =
let intType = getSysType(tyInt)
result = newTypeS(tyRange, c)
result.sons = @[intType]
result.n = newNode(nkRange, n.info, @[
newIntTypeNode(nkIntLit, 0, intType),
makeStaticExpr(c, n.nMinusOne)])
template rangeHasStaticIf*(t: PType): bool =
# this accepts the ranges's node
t.n[1].kind == nkStaticExpr
template getStaticTypeFromRange*(t: PType): PType =
t.n[1][0][1].typ
proc newTypeS(kind: TTypeKind, c: PContext): PType =
result = newType(kind, getCurrOwner())
proc errorType*(c: PContext): PType =
@@ -220,22 +286,22 @@ proc fillTypeS(dest: PType, kind: TTypeKind, c: PContext) =
dest.owner = getCurrOwner()
dest.size = - 1
proc makeRangeType*(c: PContext, first, last: biggestInt,
info: TLineInfo): PType =
proc makeRangeType*(c: PContext; first, last: BiggestInt;
info: TLineInfo; intType = getSysType(tyInt)): PType =
var n = newNodeI(nkRange, info)
addSon(n, newIntNode(nkIntLit, first))
addSon(n, newIntNode(nkIntLit, last))
addSon(n, newIntTypeNode(nkIntLit, first, intType))
addSon(n, newIntTypeNode(nkIntLit, last, intType))
result = newTypeS(tyRange, c)
result.n = n
rawAddSon(result, getSysType(tyInt)) # basetype of range
addSonSkipIntLit(result, intType) # basetype of range
proc markIndirect*(c: PContext, s: PSym) {.inline.} =
if s.kind in {skProc, skConverter, skMethod, skIterator}:
if s.kind in {skProc, skConverter, skMethod, skIterator, skClosureIterator}:
incl(s.flags, sfAddrTaken)
# XXX add to 'c' for global analysis
proc illFormedAst*(n: PNode) =
GlobalError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
globalError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
proc checkSonsLen*(n: PNode, length: int) =
if sonsLen(n) != length: illFormedAst(n)

View File

@@ -9,26 +9,39 @@
## This module implements destructors.
# included from sem.nim
# special marker values that indicates that we are
# 1) AnalyzingDestructor: currently analyzing the type for destructor
# generation (needed for recursive types)
# 2) DestructorIsTrivial: completed the analysis before and determined
# that the type has a trivial destructor
var AnalyzingDestructor, DestructorIsTrivial: PSym
new(AnalyzingDestructor)
new(DestructorIsTrivial)
var analyzingDestructor, destructorIsTrivial: PSym
new(analyzingDestructor)
new(destructorIsTrivial)
var
destructorName = getIdent"destroy_"
destructorParam = getIdent"this_"
destructorPragma = newIdentNode(getIdent"destructor", UnknownLineInfo())
destructorPragma = newIdentNode(getIdent"destructor", unknownLineInfo())
rangeDestructorProc*: PSym
proc instantiateDestructor(c: PContext, typ: PType): bool
proc instantiateDestructor(c: PContext, typ: PType): PType
proc doDestructorStuff(c: PContext, s: PSym, n: PNode) =
let t = s.typ.sons[1].skipTypes({tyVar})
var t = s.typ.sons[1].skipTypes({tyVar})
if t.kind == tyGenericInvokation:
for i in 1 .. <t.sonsLen:
if t.sons[i].kind != tyGenericParam:
localError(n.info, errDestructorNotGenericEnough)
return
t = t.base
elif t.kind == tyCompositeTypeClass:
t = t.base
if t.kind != tyGenericBody:
localError(n.info, errDestructorNotGenericEnough)
return
t.destructor = s
# automatically insert calls to base classes' destructors
if n.sons[bodyPos].kind != nkEmpty:
@@ -36,15 +49,19 @@ proc doDestructorStuff(c: PContext, s: PSym, n: PNode) =
# when inheriting directly from object
# there will be a single nil son
if t.sons[i] == nil: continue
if instantiateDestructor(c, t.sons[i]):
let destructableT = instantiateDestructor(c, t.sons[i])
if destructableT != nil:
n.sons[bodyPos].addSon(newNode(nkCall, t.sym.info, @[
useSym(t.sons[i].destructor),
useSym(destructableT.destructor),
n.sons[paramsPos][1][0]]))
proc destroyField(c: PContext, field: PSym, holder: PNode): PNode =
if instantiateDestructor(c, field.typ):
proc destroyFieldOrFields(c: PContext, field: PNode, holder: PNode): PNode
proc destroySym(c: PContext, field: PSym, holder: PNode): PNode =
let destructableT = instantiateDestructor(c, field.typ)
if destructableT != nil:
result = newNode(nkCall, field.info, @[
useSym(field.typ.destructor),
useSym(destructableT.destructor),
newNode(nkDotExpr, field.info, @[holder, useSym(field)])])
proc destroyCase(c: PContext, n: PNode, holder: PNode): PNode =
@@ -55,78 +72,83 @@ proc destroyCase(c: PContext, n: PNode, holder: PNode): PNode =
for i in countup(1, n.len - 1):
# of A, B:
var caseBranch = newNode(n[i].kind, n[i].info, n[i].sons[0 .. -2])
let recList = n[i].lastSon
var destroyRecList = newNode(nkStmtList, n[i].info, @[])
template addField(f: expr): stmt =
let stmt = destroyField(c, f, holder)
if stmt != nil:
destroyRecList.addSon(stmt)
inc nonTrivialFields
case recList.kind
of nkSym:
addField(recList.sym)
of nkRecList:
for j in countup(0, recList.len - 1):
addField(recList[j].sym)
let stmt = destroyFieldOrFields(c, n[i].lastSon, holder)
if stmt == nil:
caseBranch.addSon(newNode(nkStmtList, n[i].info, @[]))
else:
internalAssert false
caseBranch.addSon(destroyRecList)
caseBranch.addSon(stmt)
nonTrivialFields += stmt.len
result.addSon(caseBranch)
# maybe no fields were destroyed?
if nonTrivialFields == 0:
result = nil
proc destroyFieldOrFields(c: PContext, field: PNode, holder: PNode): PNode =
template maybeAddLine(e: expr): stmt =
let stmt = e
if stmt != nil:
if result == nil: result = newNode(nkStmtList)
result.addSon(stmt)
case field.kind
of nkRecCase:
maybeAddLine destroyCase(c, field, holder)
of nkSym:
maybeAddLine destroySym(c, field.sym, holder)
of nkRecList:
for son in field:
maybeAddLine destroyFieldOrFields(c, son, holder)
else:
internalAssert false
proc generateDestructor(c: PContext, t: PType): PNode =
## generate a destructor for a user-defined object or tuple type
## returns nil if the destructor turns out to be trivial
template addLine(e: expr): stmt =
if result == nil: result = newNode(nkStmtList)
result.addSon(e)
# XXX: This may be true for some C-imported types such as
# Tposix_spawnattr
if t.n == nil or t.n.sons == nil: return
internalAssert t.n.kind == nkRecList
let destructedObj = newIdentNode(destructorParam, UnknownLineInfo())
let destructedObj = newIdentNode(destructorParam, unknownLineInfo())
# call the destructods of all fields
for s in countup(0, t.n.sons.len - 1):
case t.n.sons[s].kind
of nkRecCase:
let stmt = destroyCase(c, t.n.sons[s], destructedObj)
if stmt != nil: addLine(stmt)
of nkSym:
let stmt = destroyField(c, t.n.sons[s].sym, destructedObj)
if stmt != nil: addLine(stmt)
else:
internalAssert false
result = destroyFieldOrFields(c, t.n, destructedObj)
# base classes' destructors will be automatically called by
# semProcAux for both auto-generated and user-defined destructors
proc instantiateDestructor(c: PContext, typ: PType): bool =
# returns true if the type already had a user-defined
# destructor or if the compiler generated a default
# member-wise one
var t = skipTypes(typ, {tyConst, tyMutable})
proc instantiateDestructor(c: PContext, typ: PType): PType =
# returns nil if a variable of type `typ` doesn't require a
# destructor. Otherwise, returns the type, which holds the
# destructor that must be used for the varialbe.
# The destructor is either user-defined or automatically
# generated by the compiler in a member-wise fashion.
var t = skipTypes(typ, {tyConst, tyMutable}).skipGenericAlias
let typeHoldingUserDefinition = if t.kind == tyGenericInst: t.base
else: t
if t.destructor != nil:
if typeHoldingUserDefinition.destructor != nil:
# XXX: This is not entirely correct for recursive types, but we need
# it temporarily to hide the "destroy is already defined" problem
return t.destructor notin [AnalyzingDestructor, DestructorIsTrivial]
if typeHoldingUserDefinition.destructor notin
[analyzingDestructor, destructorIsTrivial]:
return typeHoldingUserDefinition
else:
return nil
t = t.skipTypes({tyGenericInst})
case t.kind
of tySequence, tyArray, tyArrayConstr, tyOpenArray, tyVarargs:
if instantiateDestructor(c, t.sons[0]):
if instantiateDestructor(c, t.sons[0]) != nil:
if rangeDestructorProc == nil:
rangeDestructorProc = searchInScopes(c, getIdent"nimDestroyRange")
t.destructor = rangeDestructorProc
return true
return t
else:
return false
return nil
of tyTuple, tyObject:
t.destructor = AnalyzingDestructor
t.destructor = analyzingDestructor
let generated = generateDestructor(c, t)
if generated != nil:
internalAssert t.sym != nil
@@ -139,21 +161,21 @@ proc instantiateDestructor(c: PContext, typ: PType): bool =
emptyNode,
newNode(nkIdentDefs, i, @[
newIdentNode(destructorParam, i),
useSym(t.sym),
symNodeFromType(c, makeVarType(c, t), t.sym.info),
emptyNode]),
]),
newNode(nkPragma, i, @[destructorPragma]),
emptyNode,
generated
])
discard semProc(c, fullDef)
internalAssert t.destructor != nil
return true
let semantizedDef = semProc(c, fullDef)
t.destructor = semantizedDef[namePos].sym
return t
else:
t.destructor = DestructorIsTrivial
return false
t.destructor = destructorIsTrivial
return nil
else:
return false
return nil
proc insertDestructors(c: PContext,
varSection: PNode): tuple[outer, inner: PNode] =
@@ -179,9 +201,11 @@ proc insertDestructors(c: PContext,
varId = varSection[j][0]
varTyp = varId.sym.typ
info = varId.info
if varTyp != nil and instantiateDestructor(c, varTyp) and
sfGlobal notin varId.sym.flags:
if varTyp == nil or sfGlobal in varId.sym.flags: continue
let destructableT = instantiateDestructor(c, varTyp)
if destructableT != nil:
var tryStmt = newNodeI(nkTryStmt, info)
if j < totalVars - 1:
@@ -198,11 +222,11 @@ proc insertDestructors(c: PContext,
else:
result.inner = newNodeI(nkStmtList, info)
tryStmt.addSon(result.inner)
tryStmt.addSon(
newNode(nkFinally, info, @[
semStmt(c, newNode(nkCall, info, @[
useSym(varTyp.destructor),
useSym(destructableT.destructor),
useSym(varId.sym)]))]))
result.outer = newNodeI(nkStmtList, info)

File diff suppressed because it is too large Load Diff

View File

@@ -21,7 +21,7 @@ proc getConstExpr*(m: PSym, n: PNode): PNode
proc evalOp*(m: TMagic, n, a, b, c: PNode): PNode
proc leValueConv*(a, b: PNode): bool
proc newIntNodeT*(intVal: BiggestInt, n: PNode): PNode
proc newFloatNodeT*(floatVal: BiggestFloat, n: PNode): PNode
proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode
proc newStrNodeT*(strVal: string, n: PNode): PNode
# implementation
@@ -43,7 +43,10 @@ proc newIntNodeT(intVal: BiggestInt, n: PNode): PNode =
proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode =
result = newFloatNode(nkFloatLit, floatVal)
result.typ = n.typ
if skipTypes(n.typ, abstractVarRange).kind == tyFloat:
result.typ = getFloatLitType(result)
else:
result.typ = n.typ
result.info = n.info
proc newStrNodeT(strVal: string, n: PNode): PNode =
@@ -51,7 +54,7 @@ proc newStrNodeT(strVal: string, n: PNode): PNode =
result.typ = n.typ
result.info = n.info
proc ordinalValToString(a: PNode): string =
proc ordinalValToString*(a: PNode): string =
# because $ has the param ordinal[T], `a` is not necessarily an enum, but an
# ordinal
var x = getInt(a)
@@ -63,14 +66,14 @@ proc ordinalValToString(a: PNode): string =
of tyEnum:
var n = t.n
for i in countup(0, sonsLen(n) - 1):
if n.sons[i].kind != nkSym: InternalError(a.info, "ordinalValToString")
if n.sons[i].kind != nkSym: internalError(a.info, "ordinalValToString")
var field = n.sons[i].sym
if field.position == x:
if field.ast == nil:
return field.name.s
else:
return field.ast.strVal
InternalError(a.info, "no symbol for ordinal value: " & $x)
internalError(a.info, "no symbol for ordinal value: " & $x)
else:
result = $x
@@ -89,7 +92,7 @@ proc pickIntRange(a, b: PType): PType =
proc isIntRangeOrLit(t: PType): bool =
result = isIntRange(t) or isIntLit(t)
proc pickMinInt(n: PNode): biggestInt =
proc pickMinInt(n: PNode): BiggestInt =
if n.kind in {nkIntLit..nkUInt64Lit}:
result = n.intVal
elif isIntLit(n.typ):
@@ -97,9 +100,9 @@ proc pickMinInt(n: PNode): biggestInt =
elif isIntRange(n.typ):
result = firstOrd(n.typ)
else:
InternalError(n.info, "pickMinInt")
internalError(n.info, "pickMinInt")
proc pickMaxInt(n: PNode): biggestInt =
proc pickMaxInt(n: PNode): BiggestInt =
if n.kind in {nkIntLit..nkUInt64Lit}:
result = n.intVal
elif isIntLit(n.typ):
@@ -107,17 +110,23 @@ proc pickMaxInt(n: PNode): biggestInt =
elif isIntRange(n.typ):
result = lastOrd(n.typ)
else:
InternalError(n.info, "pickMaxInt")
internalError(n.info, "pickMaxInt")
proc makeRange(typ: PType, first, last: biggestInt): PType =
var n = newNode(nkRange)
addSon(n, newIntNode(nkIntLit, min(first, last)))
addSon(n, newIntNode(nkIntLit, max(first, last)))
result = newType(tyRange, typ.owner)
result.n = n
addSonSkipIntLit(result, skipTypes(typ, {tyRange}))
proc makeRange(typ: PType, first, last: BiggestInt): PType =
let minA = min(first, last)
let maxA = max(first, last)
let lowerNode = newIntNode(nkIntLit, minA)
if typ.kind == tyInt and minA == maxA:
result = getIntLitType(lowerNode)
else:
var n = newNode(nkRange)
addSon(n, lowerNode)
addSon(n, newIntNode(nkIntLit, maxA))
result = newType(tyRange, typ.owner)
result.n = n
addSonSkipIntLit(result, skipTypes(typ, {tyRange}))
proc makeRangeF(typ: PType, first, last: biggestFloat): PType =
proc makeRangeF(typ: PType, first, last: BiggestFloat): PType =
var n = newNode(nkRange)
addSon(n, newFloatNode(nkFloatLit, min(first.float, last.float)))
addSon(n, newFloatNode(nkFloatLit, max(first.float, last.float)))
@@ -219,13 +228,40 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
commutativeOp(min)
of mMaxI, mMaxI64:
commutativeOp(max)
else: nil
else: discard
discard """
mShlI, mShlI64,
mShrI, mShrI64, mAddF64, mSubF64, mMulF64, mDivF64, mMaxF64, mMinF64
"""
proc evalIs(n, a: PNode): PNode =
# XXX: This should use the standard isOpImpl
internalAssert a.kind == nkSym and a.sym.kind == skType
internalAssert n.sonsLen == 3 and
n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
let t1 = a.sym.typ
if n[2].kind in {nkStrLit..nkTripleStrLit}:
case n[2].strVal.normalize
of "closure":
let t = skipTypes(t1, abstractRange)
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
t.callConv == ccClosure and
tfIterator notin t.flags))
of "iterator":
let t = skipTypes(t1, abstractRange)
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
t.callConv == ccClosure and
tfIterator in t.flags))
else:
# XXX semexprs.isOpImpl is slightly different and requires a context. yay.
let t2 = n[2].typ
var match = sameType(t1, t2)
result = newIntNode(nkIntLit, ord(match))
result.typ = n.typ
proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
# b and c may be nil
result = nil
@@ -273,7 +309,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
of tyInt32: result = newIntNodeT(int32(getInt(a)) shl int32(getInt(b)), n)
of tyInt64, tyInt, tyUInt..tyUInt64:
result = newIntNodeT(`shl`(getInt(a), getInt(b)), n)
else: InternalError(n.info, "constant folding for shl")
else: internalError(n.info, "constant folding for shl")
of mShrI, mShrI64:
case skipTypes(n.typ, abstractRange).kind
of tyInt8: result = newIntNodeT(int8(getInt(a)) shr int8(getInt(b)), n)
@@ -281,7 +317,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
of tyInt32: result = newIntNodeT(int32(getInt(a)) shr int32(getInt(b)), n)
of tyInt64, tyInt, tyUInt..tyUInt64:
result = newIntNodeT(`shr`(getInt(a), getInt(b)), n)
else: InternalError(n.info, "constant folding for shr")
else: internalError(n.info, "constant folding for shr")
of mDivI, mDivI64: result = newIntNodeT(getInt(a) div getInt(b), n)
of mModI, mModI64: result = newIntNodeT(getInt(a) mod getInt(b), n)
of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n)
@@ -324,10 +360,10 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
of mMulU: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n)
of mModU: result = newIntNodeT(`%%`(getInt(a), getInt(b)), n)
of mDivU: result = newIntNodeT(`/%`(getInt(a), getInt(b)), n)
of mLeSet: result = newIntNodeT(Ord(containsSets(a, b)), n)
of mEqSet: result = newIntNodeT(Ord(equalSets(a, b)), n)
of mLeSet: result = newIntNodeT(ord(containsSets(a, b)), n)
of mEqSet: result = newIntNodeT(ord(equalSets(a, b)), n)
of mLtSet:
result = newIntNodeT(Ord(containsSets(a, b) and not equalSets(a, b)), n)
result = newIntNodeT(ord(containsSets(a, b) and not equalSets(a, b)), n)
of mMulSet:
result = nimsets.intersectSets(a, b)
result.info = n.info
@@ -341,7 +377,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
result = nimsets.symdiffSets(a, b)
result.info = n.info
of mConStrStr: result = newStrNodeT(getStrOrChar(a) & getStrOrChar(b), n)
of mInSet: result = newIntNodeT(Ord(inSet(a, b)), n)
of mInSet: result = newIntNodeT(ord(inSet(a, b)), n)
of mRepr:
# BUGFIX: we cannot eval mRepr here for reasons that I forgot.
of mIntToStr, mInt64ToStr: result = newStrNodeT($(getOrdValue(a)), n)
@@ -360,19 +396,19 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
result = copyTree(a)
result.typ = n.typ
of mCompileOption:
result = newIntNodeT(Ord(commands.testCompileOption(a.getStr, n.info)), n)
result = newIntNodeT(ord(commands.testCompileOption(a.getStr, n.info)), n)
of mCompileOptionArg:
result = newIntNodeT(Ord(
result = newIntNodeT(ord(
testCompileOptionArg(getStr(a), getStr(b), n.info)), n)
of mNewString, mNewStringOfCap,
mExit, mInc, ast.mDec, mEcho, mSwap, mAppendStrCh,
mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq,
mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait,
mNLen..mNError, mEqRef, mSlurp, mStaticExec:
nil
mNLen..mNError, mEqRef, mSlurp, mStaticExec, mNGenSym, mSpawn:
discard
of mRand:
result = newIntNodeT(math.random(a.getInt.int), n)
else: InternalError(a.info, "evalOp(" & $m & ')')
else: internalError(a.info, "evalOp(" & $m & ')')
proc getConstIfExpr(c: PSym, n: PNode): PNode =
result = nil
@@ -422,13 +458,13 @@ proc leValueConv(a, b: PNode): bool =
case b.kind
of nkCharLit..nkUInt64Lit: result = a.intVal <= b.intVal
of nkFloatLit..nkFloat128Lit: result = a.intVal <= round(b.floatVal)
else: InternalError(a.info, "leValueConv")
else: internalError(a.info, "leValueConv")
of nkFloatLit..nkFloat128Lit:
case b.kind
of nkFloatLit..nkFloat128Lit: result = a.floatVal <= b.floatVal
of nkCharLit..nkUInt64Lit: result = a.floatVal <= toFloat(int(b.intVal))
else: InternalError(a.info, "leValueConv")
else: InternalError(a.info, "leValueConv")
else: internalError(a.info, "leValueConv")
else: internalError(a.info, "leValueConv")
proc magicCall(m: PSym, n: PNode): PNode =
if sonsLen(n) <= 1: return
@@ -443,8 +479,6 @@ proc magicCall(m: PSym, n: PNode): PNode =
if sonsLen(n) > 3:
c = getConstExpr(m, n.sons[3])
if c == nil: return
else:
b = nil
result = evalOp(s.magic, n, a, b, c)
proc getAppType(n: PNode): PNode =
@@ -457,9 +491,9 @@ proc getAppType(n: PNode): PNode =
else:
result = newStrNodeT("console", n)
proc rangeCheck(n: PNode, value: biggestInt) =
proc rangeCheck(n: PNode, value: BiggestInt) =
if value < firstOrd(n.typ) or value > lastOrd(n.typ):
LocalError(n.info, errGenerated, "cannot convert " & $value &
localError(n.info, errGenerated, "cannot convert " & $value &
" to " & typeToString(n.typ))
proc foldConv*(n, a: PNode; check = false): PNode =
@@ -482,7 +516,7 @@ proc foldConv*(n, a: PNode; check = false): PNode =
result = a
result.typ = n.typ
of tyOpenArray, tyVarargs, tyProc:
nil
discard
else:
result = a
result.typ = n.typ
@@ -508,19 +542,19 @@ proc foldArrayAccess(m: PSym, n: PNode): PNode =
result = x.sons[int(idx)]
if result.kind == nkExprColonExpr: result = result.sons[1]
else:
LocalError(n.info, errIndexOutOfBounds)
of nkBracket, nkMetaNode:
localError(n.info, errIndexOutOfBounds)
of nkBracket:
if (idx >= 0) and (idx < sonsLen(x)): result = x.sons[int(idx)]
else: LocalError(n.info, errIndexOutOfBounds)
else: localError(n.info, errIndexOutOfBounds)
of nkStrLit..nkTripleStrLit:
result = newNodeIT(nkCharLit, x.info, n.typ)
if (idx >= 0) and (idx < len(x.strVal)):
result.intVal = ord(x.strVal[int(idx)])
elif idx == len(x.strVal):
nil
discard
else:
LocalError(n.info, errIndexOutOfBounds)
else: nil
localError(n.info, errIndexOutOfBounds)
else: discard
proc foldFieldAccess(m: PSym, n: PNode): PNode =
# a real field access; proc calls have already been transformed
@@ -558,9 +592,10 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
case n.kind
of nkSym:
var s = n.sym
if s.kind == skEnumField:
case s.kind
of skEnumField:
result = newIntNodeT(s.position, n)
elif s.kind == skConst:
of skConst:
case s.magic
of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n)
of mCompileDate: result = newStrNodeT(times.getDateStr(), n)
@@ -578,10 +613,18 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
of mNegInf: result = newFloatNodeT(NegInf, n)
else:
if sfFakeConst notin s.flags: result = copyTree(s.ast)
elif s.kind in {skProc, skMethod}: # BUGFIX
of {skProc, skMethod}:
result = n
elif s.kind in {skType, skGenericParam}:
of skType:
result = newSymNodeTypeDesc(s, n.info)
of skGenericParam:
if s.typ.kind == tyStatic:
if s.typ.n != nil:
result = s.typ.n
result.typ = s.typ.sons[0]
else:
result = newSymNodeTypeDesc(s, n.info)
else: discard
of nkCharLit..nkNilLit:
result = copyNode(n)
of nkIfExpr:
@@ -593,11 +636,12 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
try:
case s.magic
of mNone:
return # XXX: if it has no sideEffect, it should be evaluated
# If it has no sideEffect, it should be evaluated. But not here.
return
of mSizeOf:
var a = n.sons[1]
if computeSize(a.typ) < 0:
LocalError(a.info, errCannotEvalXBecauseIncompletelyDefined,
localError(a.info, errCannotEvalXBecauseIncompletelyDefined,
"sizeof")
result = nil
elif skipTypes(a.typ, typedescInst).kind in
@@ -625,16 +669,24 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
result = newIntNodeT(sonsLen(a), n)
else:
result = magicCall(m, n)
of mLengthArray:
# It doesn't matter if the argument is const or not for mLengthArray.
# This fixes bug #544.
result = newIntNodeT(lengthOrd(n.sons[1].typ), n)
of mAstToStr:
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
of mConStrStr:
result = foldConStrStr(m, n)
of mIs:
let a = getConstExpr(m, n[1])
if a != nil and a.kind == nkSym and a.sym.kind == skType:
result = evalIs(n, a)
else:
result = magicCall(m, n)
except EOverflow:
LocalError(n.info, errOverOrUnderflow)
localError(n.info, errOverOrUnderflow)
except EDivByZero:
LocalError(n.info, errConstantDivisionByZero)
localError(n.info, errConstantDivisionByZero)
of nkAddr:
var a = getConstExpr(m, n.sons[0])
if a != nil:
@@ -690,7 +742,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
result = a # a <= x and x <= b
result.typ = n.typ
else:
LocalError(n.info, errGenerated, `%`(
localError(n.info, errGenerated, `%`(
msgKindToString(errIllegalConvFromXtoY),
[typeToString(n.sons[0].typ), typeToString(n.typ)]))
of nkStringToCString, nkCStringToString:
@@ -712,4 +764,4 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
of nkBracketExpr: result = foldArrayAccess(m, n)
of nkDotExpr: result = foldFieldAccess(m, n)
else:
nil
discard

View File

@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -17,11 +17,6 @@
# included from sem.nim
type
TSemGenericFlag = enum
withinBind, withinTypeDesc, withinMixin
TSemGenericFlags = set[TSemGenericFlag]
proc getIdentNode(n: PNode): PNode =
case n.kind
of nkPostfix: result = getIdentNode(n.sons[1])
@@ -31,8 +26,6 @@ proc getIdentNode(n: PNode): PNode =
illFormedAst(n)
result = n
proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags,
ctx: var TIntSet): PNode
proc semGenericStmtScope(c: PContext, n: PNode,
flags: TSemGenericFlags,
ctx: var TIntSet): PNode =
@@ -49,17 +42,17 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode =
of skUnknown:
# Introduced in this pass! Leave it as an identifier.
result = n
of skProc, skMethod, skIterator, skConverter:
of skProc, skMethod, skIterators, skConverter:
result = symChoice(c, n, s, scOpen)
of skTemplate:
if macroToExpand(s):
let n = fixImmediateParams(n)
result = semTemplateExpr(c, n, s, false)
result = semTemplateExpr(c, n, s, {efNoSemCheck})
else:
result = symChoice(c, n, s, scOpen)
of skMacro:
if macroToExpand(s):
result = semMacroExpr(c, n, n, s, false)
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
else:
result = symChoice(c, n, s, scOpen)
of skGenericParam:
@@ -73,7 +66,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode =
result = n
else: result = newSymNode(s, n.info)
proc Lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
ctx: var TIntSet): PNode =
result = n
let ident = considerAcc(n)
@@ -96,10 +89,10 @@ proc semGenericStmt(c: PContext, n: PNode,
if gCmd == cmdIdeTools: suggestStmt(c, n)
case n.kind
of nkIdent, nkAccQuoted:
result = Lookup(c, n, flags, ctx)
result = lookup(c, n, flags, ctx)
of nkDotExpr:
let luf = if withinMixin notin flags: {checkUndeclared} else: {}
var s = QualifiedLookUp(c, n, luf)
var s = qualifiedLookUp(c, n, luf)
if s != nil: result = semGenericStmtSymbol(c, n, s)
# XXX for example: ``result.add`` -- ``add`` needs to be looked up here...
of nkEmpty, nkSym..nkNilLit:
@@ -110,7 +103,7 @@ proc semGenericStmt(c: PContext, n: PNode,
# not work. Copying the symbol does not work either because we're already
# the owner of the symbol! What we need to do is to copy the symbol
# in the generic instantiation process...
nil
discard
of nkBind:
result = semGenericStmt(c, n.sons[0], flags+{withinBind}, ctx)
of nkMixinStmt:
@@ -119,7 +112,7 @@ proc semGenericStmt(c: PContext, n: PNode,
# check if it is an expression macro:
checkMinSonsLen(n, 1)
let fn = n.sons[0]
var s = qualifiedLookup(c, fn, {})
var s = qualifiedLookUp(c, fn, {})
if s == nil and withinMixin notin flags and
fn.kind in {nkIdent, nkAccQuoted} and considerAcc(fn).id notin ctx:
localError(n.info, errUndeclaredIdentifier, fn.renderTree)
@@ -133,14 +126,14 @@ proc semGenericStmt(c: PContext, n: PNode,
case s.kind
of skMacro:
if macroToExpand(s):
result = semMacroExpr(c, n, n, s, false)
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
else:
n.sons[0] = symChoice(c, n.sons[0], s, scOption)
result = n
of skTemplate:
if macroToExpand(s):
let n = fixImmediateParams(n)
result = semTemplateExpr(c, n, s, false)
result = semTemplateExpr(c, n, s, {efNoSemCheck})
else:
n.sons[0] = symChoice(c, n.sons[0], s, scOption)
result = n
@@ -148,7 +141,7 @@ proc semGenericStmt(c: PContext, n: PNode,
# symbol lookup ...
of skUnknown, skParam:
# Leave it as an identifier.
of skProc, skMethod, skIterator, skConverter:
of skProc, skMethod, skIterators, skConverter:
result.sons[0] = symChoice(c, n.sons[0], s, scOption)
first = 1
of skGenericParam:
@@ -219,22 +212,20 @@ proc semGenericStmt(c: PContext, n: PNode,
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): IllFormedAst(a)
if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a)
checkMinSonsLen(a, 3)
var L = sonsLen(a)
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc},
ctx)
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
for j in countup(0, L-3):
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
of nkGenericParams:
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if (a.kind != nkIdentDefs): IllFormedAst(a)
if (a.kind != nkIdentDefs): illFormedAst(a)
checkMinSonsLen(a, 3)
var L = sonsLen(a)
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc},
ctx)
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
# do not perform symbol lookup for default expressions
for j in countup(0, L-3):
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
@@ -242,7 +233,7 @@ proc semGenericStmt(c: PContext, n: PNode,
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if (a.kind != nkConstDef): IllFormedAst(a)
if (a.kind != nkConstDef): illFormedAst(a)
checkSonsLen(a, 3)
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[0]), c))
a.sons[1] = semGenericStmt(c, a.sons[1], flags+{withinTypeDesc}, ctx)
@@ -251,13 +242,13 @@ proc semGenericStmt(c: PContext, n: PNode,
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if (a.kind != nkTypeDef): IllFormedAst(a)
if (a.kind != nkTypeDef): illFormedAst(a)
checkSonsLen(a, 3)
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[0]), c))
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if (a.kind != nkTypeDef): IllFormedAst(a)
if (a.kind != nkTypeDef): illFormedAst(a)
checkSonsLen(a, 3)
if a.sons[1].kind != nkEmpty:
openScope(c)
@@ -278,18 +269,17 @@ proc semGenericStmt(c: PContext, n: PNode,
else: illFormedAst(n)
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c))
of nkObjectTy, nkTupleTy:
nil
discard
of nkFormalParams:
checkMinSonsLen(n, 1)
if n.sons[0].kind != nkEmpty:
n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx)
for i in countup(1, sonsLen(n) - 1):
var a = n.sons[i]
if (a.kind != nkIdentDefs): IllFormedAst(a)
if (a.kind != nkIdentDefs): illFormedAst(a)
checkMinSonsLen(a, 3)
var L = sonsLen(a)
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc},
ctx)
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
for j in countup(0, L-3):
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
@@ -311,8 +301,8 @@ proc semGenericStmt(c: PContext, n: PNode,
else: body = n.sons[bodyPos]
n.sons[bodyPos] = semGenericStmtScope(c, body, flags, ctx)
closeScope(c)
of nkPragma, nkPragmaExpr: nil
of nkExprColonExpr:
of nkPragma, nkPragmaExpr: discard
of nkExprColonExpr, nkExprEqExpr:
checkMinSonsLen(n, 2)
result.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx)
else:

View File

@@ -13,32 +13,31 @@
proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
entry: var TInstantiation) =
if n.kind != nkGenericParams:
InternalError(n.info, "instantiateGenericParamList; no generic params")
internalError(n.info, "instantiateGenericParamList; no generic params")
newSeq(entry.concreteTypes, n.len)
for i in countup(0, n.len - 1):
var a = n.sons[i]
for i, a in n.pairs:
if a.kind != nkSym:
InternalError(a.info, "instantiateGenericParamList; no symbol")
internalError(a.info, "instantiateGenericParamList; no symbol")
var q = a.sym
if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyTypeClass, tyExpr}: continue
if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic, tyIter}+tyTypeClasses:
continue
var s = newSym(skType, q.name, getCurrOwner(), q.info)
s.flags = s.flags + {sfUsed, sfFromGeneric}
var t = PType(IdTableGet(pt, q.typ))
var t = PType(idTableGet(pt, q.typ))
if t == nil:
if tfRetType in q.typ.flags:
# keep the generic type and allow the return type to be bound
# later by semAsgn in return type inference scenario
t = q.typ
else:
LocalError(a.info, errCannotInstantiateX, s.name.s)
localError(a.info, errCannotInstantiateX, s.name.s)
t = errorType(c)
elif t.kind == tyGenericParam:
InternalError(a.info, "instantiateGenericParamList: " & q.name.s)
internalError(a.info, "instantiateGenericParamList: " & q.name.s)
elif t.kind == tyGenericInvokation:
#t = instGenericContainer(c, a, t)
t = generateTypeInstance(c, pt, a, t)
#t = ReplaceTypeVarsT(cl, t)
t.flags.incl tfInstantiated
s.typ = t
addDecl(c, s)
entry.concreteTypes[i] = t
@@ -47,10 +46,10 @@ proc sameInstantiation(a, b: TInstantiation): bool =
if a.concreteTypes.len == b.concreteTypes.len:
for i in 0..a.concreteTypes.high:
if not compareTypes(a.concreteTypes[i], b.concreteTypes[i],
flags = {TypeDescExactMatch}): return
flags = {ExactTypeDescValues}): return
result = true
proc GenericCacheGet(genericSym: Psym, entry: TInstantiation): PSym =
proc genericCacheGet(genericSym: PSym, entry: TInstantiation): PSym =
if genericSym.procInstCache != nil:
for inst in genericSym.procInstCache:
if sameInstantiation(entry, inst[]):
@@ -75,31 +74,42 @@ proc removeDefaultParamValues(n: PNode) =
proc freshGenSyms(n: PNode, owner: PSym, symMap: var TIdTable) =
# we need to create a fresh set of gensym'ed symbols:
if n.kind == nkSym and sfGenSym in n.sym.flags:
var x = PSym(IdTableGet(symMap, n.sym))
var x = PSym(idTableGet(symMap, n.sym))
if x == nil:
x = copySym(n.sym, false)
x.owner = owner
IdTablePut(symMap, n.sym, x)
idTablePut(symMap, n.sym, x)
n.sym = x
else:
for i in 0 .. <safeLen(n): freshGenSyms(n.sons[i], owner, symMap)
proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind)
proc addProcDecls(c: PContext, fn: PSym) =
# get the proc itself in scope (e.g. for recursion)
addDecl(c, fn)
for i in 1 .. <fn.typ.n.len:
var param = fn.typ.n.sons[i].sym
param.owner = fn
addParamOrResult(c, param, fn.kind)
maybeAddResult(c, fn, fn.ast)
proc instantiateBody(c: PContext, n: PNode, result: PSym) =
if n.sons[bodyPos].kind != nkEmpty:
inc c.inGenericInst
# add it here, so that recursive generic procs are possible:
addDecl(c, result)
pushProcCon(c, result)
maybeAddResult(c, result, n)
var b = n.sons[bodyPos]
var symMap: TIdTable
InitIdTable symMap
initIdTable symMap
freshGenSyms(b, result, symMap)
b = semProcBody(c, b)
b = hloBody(c, b)
n.sons[bodyPos] = transformBody(c.module, b, result)
#echo "code instantiated ", result.name.s
excl(result.flags, sfForward)
popProcCon(c)
dec c.inGenericInst
proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
for i in countup(0, c.generics.len - 1):
@@ -109,8 +119,6 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
openScope(c)
var n = oldPrc.ast
n.sons[bodyPos] = copyTree(s.getBody)
if n.sons[paramsPos].kind != nkEmpty:
addParams(c, oldPrc.typ.n, oldPrc.kind)
instantiateBody(c, n, oldPrc)
closeScope(c)
popInfoContext()
@@ -118,51 +126,99 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
proc sideEffectsCheck(c: PContext, s: PSym) =
if {sfNoSideEffect, sfSideEffect} * s.flags ==
{sfNoSideEffect, sfSideEffect}:
LocalError(s.info, errXhasSideEffects, s.name.s)
elif sfThread in s.flags and semthreads.needsGlobalAnalysis() and
s.ast.sons[genericParamsPos].kind == nkEmpty:
c.threadEntries.add(s)
localError(s.info, errXhasSideEffects, s.name.s)
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
allowMetaTypes = false): PType =
var cl: TReplTypeVars
initIdTable(cl.symMap)
initIdTable(cl.typeMap)
initIdTable(cl.localCache)
cl.info = info
cl.c = c
cl.allowMetaTypes = allowMetaTypes
result = replaceTypeVarsT(cl, header)
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
result = instGenericContainer(c, n.info, header)
proc instantiateProcType(c: PContext, pt: TIdTable,
prc: PSym, info: TLineInfo) =
# XXX: Instantiates a generic proc signature, while at the same
# time adding the instantiated proc params into the current scope.
# This is necessary, because the instantiation process may refer to
# these params in situations like this:
# proc foo[Container](a: Container, b: a.type.Item): type(b.x)
#
# Alas, doing this here is probably not enough, because another
# proc signature could appear in the params:
# proc foo[T](a: proc (x: T, b: type(x.y))
#
# The solution would be to move this logic into semtypinst, but
# at this point semtypinst have to become part of sem, because it
# will need to use openScope, addDecl, etc
#
addDecl(c, prc)
pushInfoContext(info)
var cl = initTypeVars(c, pt, info)
var result = instCopyType(cl, prc.typ)
let originalParams = result.n
result.n = originalParams.shallowCopy
for i in 1 .. <result.len:
result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
propagateToOwner(result, result.sons[i])
let param = replaceTypeVarsN(cl, originalParams[i])
result.n.sons[i] = param
if param.kind == nkSym:
# XXX: this won't be true for void params
# implement pass-through of void params and
# the "sort by distance to point" container
param.sym.owner = prc
addDecl(c, param.sym)
result.sons[0] = replaceTypeVarsT(cl, result.sons[0])
result.n.sons[0] = originalParams[0].copyTree
eraseVoidParams(result)
skipIntLiteralParams(result)
prc.typ = result
maybeAddResult(c, prc, prc.ast)
popInfoContext()
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
info: TLineInfo): PSym =
# no need to instantiate generic templates/macros:
if fn.kind in {skTemplate, skMacro}: return fn
# generates an instantiated proc
if c.InstCounter > 1000: InternalError(fn.ast.info, "nesting too deep")
inc(c.InstCounter)
if c.instCounter > 1000: internalError(fn.ast.info, "nesting too deep")
inc(c.instCounter)
# careful! we copy the whole AST including the possibly nil body!
var n = copyTree(fn.ast)
# NOTE: for access of private fields within generics from a different module
# we set the friend module:
var oldFriend = c.friendModule
c.friendModule = getModule(fn)
#let oldScope = c.currentScope
#c.currentScope = fn.scope
result = copySym(fn, false)
incl(result.flags, sfFromGeneric)
# keep the owner if it's an inner proc (for proper closure transformations):
if fn.owner.kind == skModule:
result.owner = getCurrOwner().owner
result.owner = fn
result.ast = n
pushOwner(result)
openScope(c)
if n.sons[genericParamsPos].kind == nkEmpty:
InternalError(n.info, "generateInstance")
internalAssert n.sons[genericParamsPos].kind != nkEmpty
n.sons[namePos] = newSymNode(result)
pushInfoContext(info)
var entry = TInstantiation.new
entry.sym = result
instantiateGenericParamList(c, n.sons[genericParamsPos], pt, entry[])
pushProcCon(c, result)
instantiateProcType(c, pt, result, info)
n.sons[genericParamsPos] = ast.emptyNode
# semantic checking for the parameters:
if n.sons[paramsPos].kind != nkEmpty:
removeDefaultParamValues(n.sons[ParamsPos])
semParamList(c, n.sons[ParamsPos], nil, result)
else:
result.typ = newTypeS(tyProc, c)
rawAddSon(result.typ, nil)
result.typ.callConv = fn.typ.callConv
if result.kind == skIterator: result.typ.flags.incl(tfIterator)
var oldPrc = GenericCacheGet(fn, entry[])
var oldPrc = genericCacheGet(fn, entry[])
if oldPrc == nil:
fn.procInstCache.safeAdd(entry)
c.generics.add(makeInstPair(fn, entry))
@@ -170,24 +226,16 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
pragma(c, result, n.sons[pragmasPos], allRoutinePragmas)
if isNil(n.sons[bodyPos]):
n.sons[bodyPos] = copyTree(fn.getBody)
if fn.kind != skTemplate:
instantiateBody(c, n, result)
sideEffectsCheck(c, result)
ParamsTypeCheck(c, result.typ)
instantiateBody(c, n, result)
sideEffectsCheck(c, result)
paramsTypeCheck(c, result.typ)
else:
result = oldPrc
popProcCon(c)
popInfoContext()
closeScope(c) # close scope for parameters
popOwner()
#c.currentScope = oldScope
c.friendModule = oldFriend
dec(c.InstCounter)
dec(c.instCounter)
if result.kind == skMethod: finishMethod(c, result)
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
var cl: TReplTypeVars
InitIdTable(cl.symMap)
InitIdTable(cl.typeMap)
cl.info = n.info
cl.c = c
result = ReplaceTypeVarsT(cl, header)

View File

@@ -0,0 +1,89 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Implements type sanity checking for ASTs resulting from macros. Lots of
## room for improvement here.
import ast, astalgo, msgs, types
proc ithField(n: PNode, field: int): PSym =
result = nil
case n.kind
of nkRecList:
for i in countup(0, sonsLen(n) - 1):
result = ithField(n.sons[i], field-i)
if result != nil: return
of nkRecCase:
if n.sons[0].kind != nkSym: internalError(n.info, "ithField")
result = ithField(n.sons[0], field-1)
if result != nil: return
for i in countup(1, sonsLen(n) - 1):
case n.sons[i].kind
of nkOfBranch, nkElse:
result = ithField(lastSon(n.sons[i]), field-1)
if result != nil: return
else: internalError(n.info, "ithField(record case branch)")
of nkSym:
if field == 0: result = n.sym
else: discard
proc annotateType*(n: PNode, t: PType) =
let x = t.skipTypes(abstractInst)
# Note: x can be unequal to t and we need to be careful to use 't'
# to not to skip tyGenericInst
case n.kind
of nkPar:
if x.kind == tyObject:
n.typ = t
for i in 0 .. <n.len:
let field = x.n.ithField(i)
if field.isNil: globalError n.info, "invalid field at index " & $i
else: annotateType(n.sons[i], field.typ)
elif x.kind == tyTuple:
n.typ = t
for i in 0 .. <n.len:
if i >= x.len: globalError n.info, "invalid field at index " & $i
else: annotateType(n.sons[i], x.sons[i])
elif x.kind == tyProc and x.callConv == ccClosure:
n.typ = t
else:
globalError(n.info, "() must have an object or tuple type")
of nkBracket:
if x.kind in {tyArrayConstr, tyArray, tySequence, tyOpenarray}:
n.typ = t
for m in n: annotateType(m, x.elemType)
else:
globalError(n.info, "[] must have some form of array type")
of nkCurly:
if x.kind in {tySet}:
n.typ = t
for m in n: annotateType(m, x.elemType)
else:
globalError(n.info, "{} must have the set type")
of nkFloatLit..nkFloat128Lit:
if x.kind in {tyFloat..tyFloat128}:
n.typ = t
else:
globalError(n.info, "float literal must have some float type")
of nkCharLit..nkUInt64Lit:
if x.kind in {tyInt..tyUInt64, tyBool, tyChar, tyEnum}:
n.typ = t
else:
globalError(n.info, "integer literal must have some int type")
of nkStrLit..nkTripleStrLit:
if x.kind in {tyString, tyCString}:
n.typ = t
else:
globalError(n.info, "string literal must be of some string type")
of nkNilLit:
if x.kind in NilableTypes:
n.typ = t
else:
globalError(n.info, "nil literal must be of some pointer type")
else: discard

View File

@@ -18,7 +18,7 @@ proc expectIntLit(c: PContext, n: PNode): int =
let x = c.semConstExpr(c, n)
case x.kind
of nkIntLit..nkInt64Lit: result = int(x.intVal)
else: LocalError(n.info, errIntLiteralExpected)
else: localError(n.info, errIntLiteralExpected)
proc semInstantiationInfo(c: PContext, n: PNode): PNode =
result = newNodeIT(nkPar, n.info, n.typ)
@@ -26,21 +26,34 @@ proc semInstantiationInfo(c: PContext, n: PNode): PNode =
let useFullPaths = expectIntLit(c, n.sons[2])
let info = getInfoContext(idx)
var filename = newNodeIT(nkStrLit, n.info, getSysType(tyString))
filename.strVal = if useFullPaths != 0: info.toFullPath else: info.ToFilename
filename.strVal = if useFullPaths != 0: info.toFullPath else: info.toFilename
var line = newNodeIT(nkIntLit, n.info, getSysType(tyInt))
line.intVal = ToLinenumber(info)
line.intVal = toLinenumber(info)
result.add(filename)
result.add(line)
proc evalTypeTrait(trait: PNode, operand: PType, context: PSym): PNode =
let typ = operand.skipTypes({tyTypeDesc})
case trait.sym.name.s.normalize
of "name":
result = newStrNode(nkStrLit, typ.typeToString(preferName))
result.typ = newType(tyString, context)
result.info = trait.info
of "arity":
result = newIntNode(nkIntLit, typ.n.len-1)
result.typ = newType(tyInt, context)
result.info = trait.info
else:
internalAssert false
proc semTypeTraits(c: PContext, n: PNode): PNode =
checkMinSonsLen(n, 2)
internalAssert n.sons[1].kind == nkSym
let typArg = n.sons[1].sym
if typArg.kind == skType or
(typArg.kind == skParam and typArg.typ.sonsLen > 0):
let t = n.sons[1].typ
internalAssert t != nil and t.kind == tyTypeDesc
if t.sonsLen > 0:
# This is either a type known to sem or a typedesc
# param to a regular proc (again, known at instantiation)
result = evalTypeTrait(n, GetCurrOwner())
result = evalTypeTrait(n[0], t, getCurrOwner())
else:
# a typedesc variable, pass unmodified to evals
result = n
@@ -56,23 +69,23 @@ proc semBindSym(c: PContext, n: PNode): PNode =
let sl = semConstExpr(c, n.sons[1])
if sl.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}:
LocalError(n.sons[1].info, errStringLiteralExpected)
localError(n.sons[1].info, errStringLiteralExpected)
return errorNode(c, n)
let isMixin = semConstExpr(c, n.sons[2])
if isMixin.kind != nkIntLit or isMixin.intVal < 0 or
isMixin.intVal > high(TSymChoiceRule).int:
LocalError(n.sons[2].info, errConstExprExpected)
localError(n.sons[2].info, errConstExprExpected)
return errorNode(c, n)
let id = newIdentNode(getIdent(sl.strVal), n.info)
let s = QualifiedLookUp(c, id)
let s = qualifiedLookUp(c, id)
if s != nil:
# we need to mark all symbols:
var sc = symChoice(c, id, s, TSymChoiceRule(isMixin.intVal))
result.add(sc)
else:
LocalError(n.sons[1].info, errUndeclaredIdentifier, sl.strVal)
localError(n.sons[1].info, errUndeclaredIdentifier, sl.strVal)
proc semLocals(c: PContext, n: PNode): PNode =
var counter = 0
@@ -88,7 +101,7 @@ proc semLocals(c: PContext, n: PNode): PNode =
#if it.owner != c.p.owner: return result
if it.kind in skLocalVars and
it.typ.skipTypes({tyGenericInst, tyVar}).kind notin
{tyVarargs, tyOpenArray, tyTypeDesc, tyExpr, tyStmt, tyEmpty}:
{tyVarargs, tyOpenArray, tyTypeDesc, tyStatic, tyExpr, tyStmt, tyEmpty}:
var field = newSym(skField, it.name, getCurrOwner(), n.info)
field.typ = it.typ.skipTypes({tyGenericInst, tyVar})
@@ -113,6 +126,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
result.typ = getSysType(tyString)
of mInstantiationInfo: result = semInstantiationInfo(c, n)
of mOrd: result = semOrd(c, n)
of mHigh: result = semLowHigh(c, n, mHigh)
of mShallowCopy: result = semShallowCopy(c, n, flags)
of mNBindSym: result = semBindSym(c, n)
of mLocals: result = semLocals(c, n)

Some files were not shown because too many files have changed in this diff Show More