diff options
author | Adam Strzelecki <ono@java.pl> | 2015-09-04 23:10:48 +0200 |
---|---|---|
committer | Adam Strzelecki <ono@java.pl> | 2015-09-04 23:10:48 +0200 |
commit | 0b44d812f10c6dbf7eb7cbf13ae0dc053bb2de9d (patch) | |
tree | 3ecdeaa24c4fd828d9408b68f5b4eb9b47171e77 /doc/intern.txt | |
parent | 51488766e79a2ce21068b34ecd368c1344ce7cc1 (diff) | |
download | Nim-0b44d812f10c6dbf7eb7cbf13ae0dc053bb2de9d.tar.gz |
doc: Trim .txt files trailing whitespace
via OSX: find . -name '*.txt' -exec sed -i '' -E 's/[[:space:]]+$//' {} +
Diffstat (limited to 'doc/intern.txt')
-rw-r--r-- | doc/intern.txt | 92 |
1 files changed, 46 insertions, 46 deletions
diff --git a/doc/intern.txt b/doc/intern.txt index 9582fc96f..05847169f 100644 --- a/doc/intern.txt +++ b/doc/intern.txt @@ -22,8 +22,8 @@ Path Purpose ``bin`` generated binary files ``build`` generated C code for the installation ``compiler`` the Nim compiler itself; note that this - code has been translated from a bootstrapping - version written in Pascal, so the code is **not** + code has been translated from a bootstrapping + version written in Pascal, so the code is **not** a poster child of good Nim code ``config`` configuration files for Nim ``dist`` additional packages for the distribution @@ -38,8 +38,8 @@ Path Purpose Bootstrapping the compiler ========================== -As of version 0.8.5 the compiler is maintained in Nim. (The first versions -have been implemented in Object Pascal.) The Python-based build system has +As of version 0.8.5 the compiler is maintained in Nim. (The first versions +have been implemented in Object Pascal.) The Python-based build system has been rewritten in Nim too. Compiling the compiler is a simple matter of running:: @@ -121,7 +121,7 @@ Look at the file ``lib/system/hti.nim`` for more information. Debugging the compiler ====================== -You can of course use GDB or Visual Studio to debug the +You can of course use GDB or Visual Studio to debug the compiler (via ``--debuginfo --lineDir:on``). However, there are also lots of procs that aid in debugging: @@ -180,7 +180,7 @@ children. Types and symbols are represented by other nodes, because they may contain cycles. The AST changes its shape after semantic checking. This is needed to make life easier for the code generators. See the "ast" module for the type definitions. The `macros <macros.html>`_ module contains many -examples how the AST represents each syntactic structure. +examples how the AST represents each syntactic structure. How the RTL is compiled @@ -202,7 +202,7 @@ Compilation cache ================= The implementation of the compilation cache is tricky: There are lots -of issues to be solved for the front- and backend. In the following +of issues to be solved for the front- and backend. In the following sections *global* means *shared between modules* or *property of the whole program*. @@ -214,31 +214,31 @@ Methods and type converters ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Nim contains language features that are *global*. The best example for that -are multi methods: Introducing a new method with the same name and some +are multi methods: Introducing a new method with the same name and some compatible object parameter means that the method's dispatcher needs to take the new method into account. So the dispatching logic is only completely known after the whole program has been translated! -Other features that are *implicitly* triggered cause problems for modularity +Other features that are *implicitly* triggered cause problems for modularity too. Type converters fall into this category: .. code-block:: nim # module A converter toBool(x: int): bool = result = x != 0 - + .. code-block:: nim # module B import A - + if 1: echo "ugly, but should work" If in the above example module ``B`` is re-compiled, but ``A`` is not then ``B`` needs to be aware of ``toBool`` even though ``toBool`` is not referenced -in ``B`` *explicitly*. +in ``B`` *explicitly*. -Both the multi method and the type converter problems are solved by storing +Both the multi method and the type converter problems are solved by storing them in special sections in the ROD file that are loaded *unconditionally* when the ROD file is read. @@ -266,7 +266,7 @@ Backend issues - Emulated thread vars are global. -However the biggest problem is that dead code elimination breaks modularity! +However the biggest problem is that dead code elimination breaks modularity! To see why, consider this scenario: The module ``G`` (for example the huge Gtk2 module...) is compiled with dead code elimination turned on. So none of ``G``'s procs is generated at all. @@ -274,13 +274,13 @@ of ``G``'s procs is generated at all. Then module ``B`` is compiled that requires ``G.P1``. Ok, no problem, ``G.P1`` is loaded from the symbol file and ``G.c`` now contains ``G.P1``. -Then module ``A`` (that depends onto ``B`` and ``G``) is compiled and ``B`` +Then module ``A`` (that depends onto ``B`` and ``G``) is compiled and ``B`` and ``G`` are left unchanged. ``A`` requires ``G.P2``. -So now ``G.c`` MUST contain both ``P1`` and ``P2``, but we haven't even -loaded ``P1`` from the symbol file, nor do we want to because we then quickly -would restore large parts of the whole program. But we also don't want to -store ``P1`` in ``B.c`` because that would mean to store every symbol where +So now ``G.c`` MUST contain both ``P1`` and ``P2``, but we haven't even +loaded ``P1`` from the symbol file, nor do we want to because we then quickly +would restore large parts of the whole program. But we also don't want to +store ``P1`` in ``B.c`` because that would mean to store every symbol where it is referred from which ultimately means the main module and putting everything in a single C file. @@ -290,7 +290,7 @@ that is implemented in the C code generator (have a look at the ``ccgmerge`` module). The merging may lead to *cruft* (aka dead code) in generated C code which can only be removed by recompiling a project with the compilation cache turned off. Nevertheless the merge solution is way superior to the -cheap solution "turn off dead code elimination if the compilation cache is +cheap solution "turn off dead code elimination if the compilation cache is turned on". @@ -394,7 +394,7 @@ Consider this example: # r is on the stack setRef(r.left) # here we should update the refcounts! -We have to decide at runtime whether the reference is on the stack or not. +We have to decide at runtime whether the reference is on the stack or not. The generated code looks roughly like this: .. code-block:: C @@ -422,7 +422,7 @@ Design A ``closure`` proc var can call ordinary procs of the default Nim calling convention. But not the other way round! A closure is implemented as a ``tuple[prc, env]``. ``env`` can be nil implying a call without a closure. -This means that a call through a closure generates an ``if`` but the +This means that a call through a closure generates an ``if`` but the interoperability is worth the cost of the ``if``. Thunk generation would be possible too, but it's slightly more effort to implement. @@ -430,7 +430,7 @@ Tests with GCC on Amd64 showed that it's really beneficical if the 'environment' pointer is passed as the last argument, not as the first argument. Proper thunk generation is harder because the proc that is to wrap -could stem from a complex expression: +could stem from a complex expression: .. code-block:: nim receivesClosure(returnsDefaultCC[i]) @@ -438,15 +438,15 @@ could stem from a complex expression: A thunk would need to call 'returnsDefaultCC[i]' somehow and that would require an *additional* closure generation... Ok, not really, but it requires to pass the function to call. So we'd end up with 2 indirect calls instead of one. -Another much more severe problem which this solution is that it's not GC-safe +Another much more severe problem which this solution is that it's not GC-safe to pass a proc pointer around via a generic ``ref`` type. Example code: .. code-block:: nim - proc add(x: int): proc (y: int): int {.closure.} = - return proc (y: int): int = + proc add(x: int): proc (y: int): int {.closure.} = + return proc (y: int): int = return x + y var add2 = add(2) @@ -458,16 +458,16 @@ This should produce roughly this code: type PEnv = ref object x: int # data - - proc anon(y: int, c: PClosure): int = + + proc anon(y: int, c: PClosure): int = return y + c.x - + proc add(x: int): tuple[prc, data] = var env: PEnv new env env.x = x result = (anon, env) - + var add2 = add(2) let tmp = if add2.data == nil: add2.prc(5) else: add2.prc(5, add2.data) echo tmp @@ -476,9 +476,9 @@ This should produce roughly this code: Beware of nesting: .. code-block:: nim - proc add(x: int): proc (y: int): proc (z: int): int {.closure.} {.closure.} = - return lamba (y: int): proc (z: int): int {.closure.} = - return lambda (z: int): int = + proc add(x: int): proc (y: int): proc (z: int): int {.closure.} {.closure.} = + return lamba (y: int): proc (z: int): int {.closure.} = + return lambda (z: int): int = return x + y + z var add24 = add(2)(4) @@ -490,26 +490,26 @@ This should produce roughly this code: type PEnvX = ref object x: int # data - + PEnvY = ref object y: int ex: PEnvX - + proc lambdaZ(z: int, ey: PEnvY): int = return ey.ex.x + ey.y + z - + proc lambdaY(y: int, ex: PEnvX): tuple[prc, data: PEnvY] = var ey: PEnvY new ey ey.y = y ey.ex = ex result = (lambdaZ, ey) - + proc add(x: int): tuple[prc, data: PEnvX] = var ex: PEnvX ex.x = x result = (labmdaY, ex) - + var tmp = add(2) var tmp2 = tmp.fn(4, tmp.data) var add24 = tmp2.fn(4, tmp2.data) @@ -517,14 +517,14 @@ This should produce roughly this code: We could get rid of nesting environments by always inlining inner anon procs. -More useful is escape analysis and stack allocation of the environment, +More useful is escape analysis and stack allocation of the environment, however. Alternative ----------- -Process the closure of all inner procs in one pass and accumulate the +Process the closure of all inner procs in one pass and accumulate the environments. This is however not always possible. @@ -532,21 +532,21 @@ Accumulator ----------- .. code-block:: nim - proc getAccumulator(start: int): proc (): int {.closure} = + proc getAccumulator(start: int): proc (): int {.closure} = var i = start - return lambda: int = + return lambda: int = inc i return i - + proc p = var delta = 7 proc accumulator(start: int): proc(): int = var x = start-1 - result = proc (): int = + result = proc (): int = x = x + delta inc delta return x - + var a = accumulator(3) var b = accumulator(4) echo a() + b() @@ -560,7 +560,7 @@ pass generates code to setup the environment and to pass it around. However, this pass does not change the types! So we have some kind of mismatch here; on the one hand the proc expression becomes an explicit tuple, on the other hand the tyProc(ccClosure) type is not changed. For C code generation it's also -important the hidden formal param is ``void*`` and not something more +important the hidden formal param is ``void*`` and not something more specialized. However the more specialized env type needs to passed to the backend somehow. We deal with this by modifying ``s.ast[paramPos]`` to contain the formal hidden parameter, but not ``s.typ``! |