mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-18 13:30:33 +00:00
implemented multi methods
This commit is contained in:
@@ -182,6 +182,7 @@
|
||||
|
||||
'nkModule', # the syntax tree of a module
|
||||
'nkProcDef', # a proc
|
||||
'nkMethodDef', # a method
|
||||
'nkConverterDef', # a converter
|
||||
'nkMacroDef', # a macro
|
||||
'nkTemplateDef', # a template
|
||||
@@ -258,6 +259,7 @@
|
||||
'skConst', # a constant
|
||||
'skVar', # a variable
|
||||
'skProc', # a proc
|
||||
'skMethod', # a method
|
||||
'skIterator', # an iterator
|
||||
'skConverter', # a type converter
|
||||
'skMacro', # a macro
|
||||
|
||||
@@ -165,7 +165,6 @@
|
||||
'AppendStrCh',
|
||||
'AppendStrStr',
|
||||
'AppendSeqElem',
|
||||
'AppendSeqSeq',
|
||||
'InRange',
|
||||
'InSet',
|
||||
'Repr',
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
.. contents::
|
||||
|
||||
Abstraction is layering ignorance on top of reality. -- unknown
|
||||
|
||||
|
||||
Directory structure
|
||||
===================
|
||||
@@ -72,18 +74,6 @@ the same::
|
||||
./boot [-d:release]
|
||||
|
||||
|
||||
Coding Guidelines
|
||||
=================
|
||||
|
||||
* Use CamelCase, not underscored_identifiers.
|
||||
* Indent with two spaces.
|
||||
* Max line length is 80 characters.
|
||||
* Provide spaces around binary operators if that enhances readability.
|
||||
* Use a space after a colon, but not before it.
|
||||
* Start types with a capital ``T``, unless they are pointers which start with
|
||||
``P``.
|
||||
|
||||
|
||||
Pascal annotations
|
||||
==================
|
||||
There are some annotations that the Pascal sources use so that they can
|
||||
|
||||
118
doc/lib.txt
118
doc/lib.txt
@@ -5,6 +5,10 @@ Nimrod Standard Library
|
||||
:Author: Andreas Rumpf
|
||||
:Version: |nimrodversion|
|
||||
|
||||
..
|
||||
|
||||
The good thing about reinventing the wheel is that you can get a round one.
|
||||
|
||||
Though the Nimrod Standard Library is still evolving, it is already quite
|
||||
usable. It is divided into *pure libraries*, *impure libraries* and *wrappers*.
|
||||
|
||||
@@ -12,10 +16,15 @@ Pure libraries do not depend on any external ``*.dll`` or ``lib*.so`` binary
|
||||
while impure libraries do. A wrapper is an impure library that is a very
|
||||
low-level interface to a C library.
|
||||
|
||||
Read this `document <apis.html>`_ for a quick overview of the API design.
|
||||
|
||||
|
||||
Pure libraries
|
||||
==============
|
||||
|
||||
Core
|
||||
----
|
||||
|
||||
* `system <system.html>`_
|
||||
Basic procs and operators that every program needs. It also provides IO
|
||||
facilities for reading and writing text and binary files. It is imported
|
||||
@@ -25,11 +34,35 @@ Pure libraries
|
||||
* `macros <macros.html>`_
|
||||
Contains the AST API and documentation of Nimrod for writing macros.
|
||||
|
||||
|
||||
String handling
|
||||
---------------
|
||||
|
||||
* `strutils <strutils.html>`_
|
||||
This module contains common string handling operations like converting a
|
||||
string into uppercase, splitting a string into substrings, searching for
|
||||
substrings, replacing substrings.
|
||||
|
||||
* `strtabs <strtabs.html>`_
|
||||
The ``strtabs`` module implements an efficient hash table that is a mapping
|
||||
from strings to strings. Supports a case-sensitive, case-insensitive and
|
||||
style-insensitive mode. An efficient string substitution operator ``%``
|
||||
for the string table is also provided.
|
||||
|
||||
* `unicode <unicode.html>`_
|
||||
This module provides support to handle the Unicode UTF-8 encoding.
|
||||
|
||||
* `regexprs <regexprs.html>`_
|
||||
This module contains procedures and operators for handling regular
|
||||
expressions. Consider using `pegs` instead.
|
||||
|
||||
* `pegs <pegs.html>`_
|
||||
This module contains procedures and operators for handling PEGs.
|
||||
|
||||
|
||||
Generic Operating System Services
|
||||
---------------------------------
|
||||
|
||||
* `os <os.html>`_
|
||||
Basic operating system facilities like retrieving environment variables,
|
||||
reading command line arguments, working with directories, running shell
|
||||
@@ -37,7 +70,28 @@ Pure libraries
|
||||
platform independant.
|
||||
|
||||
* `osproc <osproc.html>`_
|
||||
Module for process communication beyond ``os.executeShellCommand``.
|
||||
Module for process communication beyond ``os.execShellCmd``.
|
||||
|
||||
* `times <times.html>`_
|
||||
The ``times`` module contains basic support for working with time.
|
||||
|
||||
* `dynlib <dynlib.html>`_
|
||||
This module implements the ability to access symbols from shared libraries.
|
||||
|
||||
* `streams <streams.html>`_
|
||||
This module provides a stream interface and two implementations thereof:
|
||||
the `PFileStream` and the `PStringStream` which implement the stream
|
||||
interface for Nimrod file objects (`TFile`) and strings. Other modules
|
||||
may provide other implementations for this standard stream interface.
|
||||
|
||||
* `terminal <terminal.html>`_
|
||||
This module contains a few procedures to control the *terminal*
|
||||
(also called *console*). The implementation simply uses ANSI escape
|
||||
sequences and does not depend on any other module.
|
||||
|
||||
|
||||
Math libraries
|
||||
--------------
|
||||
|
||||
* `math <math.html>`_
|
||||
Mathematical operations like cosine, square root.
|
||||
@@ -45,11 +99,17 @@ Pure libraries
|
||||
* `complex <complex.html>`_
|
||||
This module implements complex numbers and their mathematical operations.
|
||||
|
||||
* `times <times.html>`_
|
||||
The ``times`` module contains basic support for working with time.
|
||||
|
||||
* `dynlib <dynlib.html>`_
|
||||
This module implements the ability to access symbols from shared libraries.
|
||||
|
||||
Internet Protocols and Support
|
||||
------------------------------
|
||||
|
||||
* `cgi <cgi.html>`_
|
||||
This module implements helpers for CGI applictions.
|
||||
|
||||
|
||||
Parsers
|
||||
-------
|
||||
|
||||
* `parseopt <parseopt.html>`_
|
||||
The ``parseopt`` module implements a command line option parser. This
|
||||
@@ -71,48 +131,32 @@ Pure libraries
|
||||
|
||||
* `parsecsv <parsecsv.html>`_
|
||||
The ``parsecsv`` module implements a simple high performance CSV parser.
|
||||
|
||||
* `parsesql <parsesql.html>`_
|
||||
The ``parsesql`` module implements a simple high performance SQL parser.
|
||||
|
||||
* `strtabs <strtabs.html>`_
|
||||
The ``strtabs`` module implements an efficient hash table that is a mapping
|
||||
from strings to strings. Supports a case-sensitive, case-insensitive and
|
||||
style-insensitive mode. An efficient string substitution operator ``%``
|
||||
for the string table is also provided.
|
||||
* `lexbase <lexbase.html>`_
|
||||
This is a low level module that implements an extremely efficient buffering
|
||||
scheme for lexers and parsers. This is used by the diverse parsing modules.
|
||||
|
||||
* `streams <streams.html>`_
|
||||
This module provides a stream interface and two implementations thereof:
|
||||
the `PFileStream` and the `PStringStream` which implement the stream
|
||||
interface for Nimrod file objects (`TFile`) and strings. Other modules
|
||||
may provide other implementations for this standard stream interface.
|
||||
|
||||
Code generation
|
||||
---------------
|
||||
|
||||
* `xmlgen <xmlgen.html>`_
|
||||
This module implements macros for XML/HTML code generation.
|
||||
|
||||
|
||||
Cryptography and Hashing
|
||||
------------------------
|
||||
|
||||
* `hashes <hashes.html>`_
|
||||
This module implements efficient computations of hash values for diverse
|
||||
Nimrod types.
|
||||
|
||||
* `lexbase <lexbase.html>`_
|
||||
This is a low level module that implements an extremely efficient buffering
|
||||
scheme for lexers and parsers. This is used by the ``parsecfg`` module.
|
||||
|
||||
* `terminal <terminal.html>`_
|
||||
This module contains a few procedures to control the *terminal*
|
||||
(also called *console*). The implementation simply uses ANSI escape
|
||||
sequences and does not depend on any other module.
|
||||
|
||||
* `cgi <cgi.html>`_
|
||||
This module implements helper procs for CGI applictions.
|
||||
|
||||
* `unicode <unicode.html>`_
|
||||
This module provides support to handle the Unicode UTF-8 encoding.
|
||||
|
||||
* `regexprs <regexprs.html>`_
|
||||
This module contains procedures and operators for handling regular
|
||||
expressions.
|
||||
|
||||
* `md5 <md5.html>`_
|
||||
This module implements the MD5 checksum algorithm.
|
||||
|
||||
* `xmlgen <xmlgen.html>`_
|
||||
This module implements macros for HTML code generation.
|
||||
|
||||
|
||||
|
||||
Impure libraries
|
||||
|
||||
@@ -1357,7 +1357,7 @@ given *slicelist* the ``else`` part is executed. If there is no ``else``
|
||||
part and not all possible values that ``expr`` can hold occur in a ``vallist``,
|
||||
a static error is given. This holds only for expressions of ordinal types.
|
||||
If the expression is not of an ordinal type, and no ``else`` part is
|
||||
given, control just passes after the ``case`` statement.
|
||||
given, control passes after the ``case`` statement.
|
||||
|
||||
To suppress the static error in the ordinal case an ``else`` part with a ``nil``
|
||||
statement can be used.
|
||||
@@ -1604,7 +1604,9 @@ statement is syntactic sugar for a nested block:
|
||||
continue
|
||||
stmt2
|
||||
|
||||
# is equivalent to:
|
||||
Is equivalent to:
|
||||
|
||||
.. code-block:: nimrod
|
||||
while expr1:
|
||||
block myBlockName:
|
||||
stmt1
|
||||
@@ -1669,7 +1671,7 @@ object on the stack and can thus reference a non-existing object.
|
||||
|
||||
Procedures
|
||||
~~~~~~~~~~
|
||||
What most programming languages call `methods`:idx: or `funtions`:idx: are
|
||||
What most programming languages call `methods`:idx: or `functions`:idx: are
|
||||
called `procedures`:idx: in Nimrod (which is the correct terminology). A
|
||||
procedure declaration defines an identifier and associates it with a block
|
||||
of code. A procedure may call itself recursively. The syntax is::
|
||||
|
||||
@@ -51,8 +51,8 @@ that its extension should be ``.cfg``.
|
||||
Command line settings have priority over configuration file settings.
|
||||
|
||||
|
||||
Nimrod's directory structure
|
||||
----------------------------
|
||||
Generated C code directory
|
||||
--------------------------
|
||||
The generated files that Nimrod produces all go into a subdirectory called
|
||||
``nimcache`` in your project directory. This makes it easy to delete all
|
||||
generated files.
|
||||
@@ -116,7 +116,7 @@ No_decl Pragma
|
||||
The `no_decl`:idx: pragma can be applied to almost any symbol (variable, proc,
|
||||
type, etc.) and is sometimes useful for interoperability with C:
|
||||
It tells Nimrod that it should not generate a declaration for the symbol in
|
||||
the C code. Thus it makes the following possible, for example:
|
||||
the C code. For example:
|
||||
|
||||
.. code-block:: Nimrod
|
||||
var
|
||||
@@ -129,12 +129,12 @@ However, the ``header`` pragma is often the better alternative.
|
||||
Header Pragma
|
||||
~~~~~~~~~~~~~
|
||||
The `header`:idx: pragma is very similar to the ``no_decl`` pragma: It can be
|
||||
applied to almost any symbol and specifies that not only it should not be
|
||||
declared but also that it leads to the inclusion of a given header file:
|
||||
applied to almost any symbol and specifies that it should not be declared
|
||||
and instead the generated code should contain an ``#include``:
|
||||
|
||||
.. code-block:: Nimrod
|
||||
type
|
||||
PFile {.importc: "FILE*", header: "<stdio.h>".} = pointer
|
||||
PFile {.importc: "FILE*", header: "<stdio.h>".} = distinct pointer
|
||||
# import C's FILE* type; Nimrod will treat it as a new pointer type
|
||||
|
||||
The ``header`` pragma expects always a string constant. The string contant
|
||||
@@ -159,7 +159,7 @@ strings automatically:
|
||||
Line_dir Option
|
||||
~~~~~~~~~~~~~~~
|
||||
The `line_dir`:idx: option can be turned on or off. If on the generated C code
|
||||
contains ``#line`` directives.
|
||||
contains ``#line`` directives. This may be helpful for debugging with GDB.
|
||||
|
||||
|
||||
Stack_trace Option
|
||||
@@ -198,7 +198,7 @@ Register Pragma
|
||||
The `register`:idx: pragma is for variables only. It declares the variable as
|
||||
``register``, giving the compiler a hint that the variable should be placed
|
||||
in a hardware register for faster access. C compilers usually ignore this
|
||||
though and for good reason: Often they do a better job without it anyway.
|
||||
though and for good reasons: Often they do a better job without it anyway.
|
||||
|
||||
In highly specific cases (a dispatch loop of an bytecode interpreter for
|
||||
example) it may provide benefits, though.
|
||||
@@ -228,7 +228,7 @@ memory, but nothing worse happens.
|
||||
Dead_code_elim Pragma
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
The `dead_code_elim`:idx: pragma only applies to whole modules: It tells the
|
||||
compiler to active (or deactivate) dead code elimination for the module the
|
||||
compiler to activate (or deactivate) dead code elimination for the module the
|
||||
pragma appers in.
|
||||
|
||||
The ``--dead_code_elim:on`` command line switch has the same effect as marking
|
||||
@@ -288,9 +288,9 @@ Optimizing string handling
|
||||
String assignments are sometimes expensive in Nimrod: They are required to
|
||||
copy the whole string. However, the compiler is often smart enough to not copy
|
||||
strings. Due to the argument passing semantics, strings are never copied when
|
||||
passed to subroutines. The compiler does not copy strings that are returned by
|
||||
a routine, because a routine returns a new string anyway. Thus it is efficient
|
||||
to do:
|
||||
passed to subroutines. The compiler does not copy strings that are result from
|
||||
a procedure call, because the called procedure returns a new string anyway.
|
||||
Thus it is efficient to do:
|
||||
|
||||
.. code-block:: Nimrod
|
||||
var s = procA() # assignment will not copy the string; procA allocates a new
|
||||
|
||||
1051
doc/theindex.txt
1051
doc/theindex.txt
File diff suppressed because it is too large
Load Diff
38
doc/tut1.txt
38
doc/tut1.txt
@@ -1,6 +1,6 @@
|
||||
============================
|
||||
The Nimrod Tutorial (Part I)
|
||||
============================
|
||||
========================
|
||||
Nimrod Tutorial (Part I)
|
||||
========================
|
||||
|
||||
:Author: Andreas Rumpf
|
||||
:Version: |nimrodversion|
|
||||
@@ -63,7 +63,8 @@ Nimrod: It is a good compromise between brevity and readability.
|
||||
|
||||
The "hallo world" program contains several identifiers that are already
|
||||
known to the compiler: ``echo``, ``readLine``, etc. These built-in items are
|
||||
declared in the system_ module which is implicitly imported by any other module.
|
||||
declared in the system_ module which is implicitly imported by any other
|
||||
module.
|
||||
|
||||
|
||||
Lexical elements
|
||||
@@ -173,7 +174,7 @@ to a storage location:
|
||||
var x = "abc" # introduces a new variable `x` and assigns a value to it
|
||||
x = "xyz" # assigns a new value to `x`
|
||||
|
||||
The ``=`` is called the *assignment operator*. The assignment operator cannot
|
||||
``=`` is the *assignment operator*. The assignment operator cannot
|
||||
be overloaded, overwritten or forbidden, but this might change in a future
|
||||
version of Nimrod.
|
||||
|
||||
@@ -196,7 +197,7 @@ constants:
|
||||
x = 1
|
||||
# a comment can occur here too
|
||||
y = 2
|
||||
z = y + 5 # simple computations are possible
|
||||
z = y + 5 # computations are possible
|
||||
|
||||
|
||||
Control flow statements
|
||||
@@ -277,14 +278,13 @@ the compiler that for every other value nothing should be done:
|
||||
The ``nil`` statement is a *do nothing* statement. The compiler knows that a
|
||||
case statement with an else part cannot fail and thus the error disappers. Note
|
||||
that it is impossible to cover any possible string value: That is why there is
|
||||
no such compiler check for string cases.
|
||||
no such check for string cases.
|
||||
|
||||
In general the case statement is used for subrange types or enumerations where
|
||||
it is of great help that the compiler checks that you covered any possible
|
||||
value.
|
||||
|
||||
|
||||
|
||||
While statement
|
||||
---------------
|
||||
|
||||
@@ -327,7 +327,7 @@ the same:
|
||||
Echo($i)
|
||||
inc(i) # increment i by 1
|
||||
|
||||
Counting down can be achieved as easily (but is much less needed):
|
||||
Counting down can be achieved as easily (but is less often needed):
|
||||
|
||||
.. code-block:: nimrod
|
||||
Echo("Counting down from 10 to 1: ")
|
||||
@@ -372,7 +372,7 @@ Break statement
|
||||
---------------
|
||||
A block can be left prematurely with a ``break`` statement. The break statement
|
||||
can leave a while, for, or a block statement. It leaves the innermost construct,
|
||||
unless the label of a block is given:
|
||||
unless a label of a block is given:
|
||||
|
||||
.. code-block:: nimrod
|
||||
block myblock:
|
||||
@@ -392,7 +392,7 @@ unless the label of a block is given:
|
||||
|
||||
Continue statement
|
||||
------------------
|
||||
Like in many other programming languages, a ``continue`` statement leads to
|
||||
Like in many other programming languages, a ``continue`` statement starts
|
||||
the next iteration immediately:
|
||||
|
||||
.. code-block:: nimrod
|
||||
@@ -512,7 +512,7 @@ the procedure (and therefore the while loop) immediately. The
|
||||
parameter named ``question`` of type ``string`` and returns a value of type
|
||||
``bool``. ``Bool`` is a built-in type: The only valid values for ``bool`` are
|
||||
``true`` and ``false``.
|
||||
The conditions in if or while statements need to have the type ``bool``.
|
||||
The conditions in if or while statements should be of the type ``bool``.
|
||||
|
||||
Some terminology: In the example ``question`` is called a (formal) *parameter*,
|
||||
``"Should I..."`` is called an *argument* that is passed to this parameter.
|
||||
@@ -614,7 +614,7 @@ Now the call to ``createWindow`` only needs to set the values that differ
|
||||
from the defaults.
|
||||
|
||||
Note that type inference works for parameters with default values, there is
|
||||
no need to specify ``title: string = "unknown"``, for example.
|
||||
no need to write ``title: string = "unknown"``, for example.
|
||||
|
||||
|
||||
Overloaded procedures
|
||||
@@ -857,7 +857,6 @@ loses information, the `EOutOfRange`:idx: exception is raised (if the error
|
||||
cannot be detected at compile time).
|
||||
|
||||
|
||||
|
||||
Floats
|
||||
------
|
||||
Nimrod has these floating point types built-in: ``float float32 float64``.
|
||||
@@ -1232,7 +1231,7 @@ mysterious crashes.
|
||||
**Note**: The example only works because the memory is initialized with zero
|
||||
(``alloc0`` instead of ``alloc`` does this): ``d.s`` is thus initialized to
|
||||
``nil`` which the string assignment can handle. You need to know low level
|
||||
details like this when mixing garbage collected data with unmanaged memory!
|
||||
details like this when mixing garbage collected data with unmanaged memory.
|
||||
|
||||
|
||||
Procedural type
|
||||
@@ -1240,8 +1239,7 @@ Procedural type
|
||||
A `procedural type`:idx: is a (somewhat abstract) pointer to a procedure.
|
||||
``nil`` is an allowed value for a variable of a procedural type.
|
||||
Nimrod uses procedural types to achieve `functional`:idx: programming
|
||||
techniques. Dynamic dispatch for OOP constructs can also be implemented with
|
||||
procedural types (details follow in the OOP section).
|
||||
techniques.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -1303,9 +1301,9 @@ because then one module cannot be reused without the other.
|
||||
|
||||
The algorithm for compiling modules is:
|
||||
|
||||
- Compile the whole module as usual, following import statements recursively
|
||||
- if there is a cycle only import the already parsed symbols (that are
|
||||
exported); if an unknown identifier occurs then abort
|
||||
- Compile the whole module as usual, following import statements recursively.
|
||||
- If there is a cycle only import the already parsed symbols (that are
|
||||
exported); if an unknown identifier occurs then abort.
|
||||
|
||||
This is best illustrated by an example:
|
||||
|
||||
|
||||
176
doc/tut2.txt
176
doc/tut2.txt
@@ -1,6 +1,6 @@
|
||||
=============================
|
||||
The Nimrod Tutorial (Part II)
|
||||
=============================
|
||||
=========================
|
||||
Nimrod Tutorial (Part II)
|
||||
=========================
|
||||
|
||||
:Author: Andreas Rumpf
|
||||
:Version: |nimrodversion|
|
||||
@@ -73,9 +73,9 @@ section.
|
||||
|
||||
Inheritance is done with the ``object of`` syntax. Multiple inheritance is
|
||||
currently not supported. If an object type has no suitable ancestor, ``TObject``
|
||||
should be used as its ancestor, but this is only a convention.
|
||||
can be used as its ancestor, but this is only a convention.
|
||||
|
||||
Note that aggregation (*has-a* relation) is often preferable to inheritance
|
||||
**Note**: Aggregation (*has-a* relation) is often preferable to inheritance
|
||||
(*is-a* relation) for simple code reuse. Since objects are value types in
|
||||
Nimrod, aggregation is as efficient as inheritance.
|
||||
|
||||
@@ -84,9 +84,9 @@ Mutually recursive types
|
||||
------------------------
|
||||
|
||||
Objects, tuples and references can model quite complex data structures which
|
||||
depend on each other. This is called *mutually recursive types*. In Nimrod
|
||||
these types need to be declared within a single type section. Anything else
|
||||
would require arbitrary symbol lookahead which slows down compilation.
|
||||
depend on each other; they are *mutually recursive*. In Nimrod
|
||||
these types can only be declared within a single type section. (Anything else
|
||||
would require arbitrary symbol lookahead which slows down compilation.)
|
||||
|
||||
Example:
|
||||
|
||||
@@ -147,7 +147,7 @@ An example:
|
||||
TNode = object
|
||||
case kind: TNodeKind # the ``kind`` field is the discriminator
|
||||
of nkInt: intVal: int
|
||||
of nkFloat: floavVal: float
|
||||
of nkFloat: floatVal: float
|
||||
of nkString: strVal: string
|
||||
of nkAdd, nkSub:
|
||||
leftOp, rightOp: PNode
|
||||
@@ -176,18 +176,25 @@ bound to a class. This has disadvantages:
|
||||
|
||||
* Adding a method to a class the programmer has no control over is
|
||||
impossible or needs ugly workarounds.
|
||||
* Often it is unclear where the procedure should belong to: Is
|
||||
* Often it is unclear where the method should belong to: Is
|
||||
``join`` a string method or an array method? Should the complex
|
||||
``vertexCover`` algorithm really be a method of the ``graph`` class?
|
||||
|
||||
Nimrod avoids these problems by not distinguishing between methods and
|
||||
procedures. Methods are just ordinary procedures. However, there is a special
|
||||
syntactic sugar for calling procedures: The syntax ``obj.method(args)`` can be
|
||||
used instead of ``method(obj, args)``. If there are no remaining arguments, the
|
||||
parentheses can be omitted: ``obj.len`` (instead of ``len(obj)``).
|
||||
Nimrod avoids these problems by not assigning methods to a class. All methods
|
||||
in Nimrod are `multi-methods`:idx:. As we will see later, multi-methods are
|
||||
distinguished from procs only for dynamic binding purposes.
|
||||
|
||||
|
||||
Method call syntax
|
||||
------------------
|
||||
|
||||
There is a syntactic sugar for calling routines:
|
||||
The syntax ``obj.method(args)`` can be used instead of ``method(obj, args)``.
|
||||
If there are no remaining arguments, the parentheses can be omitted:
|
||||
``obj.len`` (instead of ``len(obj)``).
|
||||
|
||||
This `method call syntax`:idx: is not restricted to objects, it can be used
|
||||
for any type:
|
||||
for any type:
|
||||
|
||||
.. code-block:: nimrod
|
||||
|
||||
@@ -196,9 +203,17 @@ for any type:
|
||||
echo({'a', 'b', 'c'}.card)
|
||||
stdout.writeln("Hallo") # the same as write(stdout, "Hallo")
|
||||
|
||||
If it gives you warm fuzzy feelings, you can even write ``1.`+`(2)`` instead of
|
||||
``1 + 2`` and claim that Nimrod is a pure object oriented language. (But
|
||||
that's not true. :-)
|
||||
(Another way to look at the method call syntax is that it provides the missing
|
||||
postfix notation.)
|
||||
|
||||
So code that looks "pure object oriented" is easy to write:
|
||||
|
||||
.. code-block:: nimrod
|
||||
import strutils
|
||||
|
||||
stdout.writeln("Give a list of numbers (separated by spaces): ")
|
||||
stdout.write(stdin.readLine.split.each(parseInt).max.`$`)
|
||||
stdout.writeln(" is the maximum!")
|
||||
|
||||
|
||||
Properties
|
||||
@@ -261,60 +276,75 @@ already provides ``v[]`` access.
|
||||
|
||||
Dynamic dispatch
|
||||
----------------
|
||||
In Nimrod procedural types are used to implement dynamic dispatch. The
|
||||
following example also shows some more conventions: The ``self`` or ``this``
|
||||
object is named ``my`` (because it is shorter than the alternatives), each
|
||||
class provides a constructor, etc.
|
||||
|
||||
Procedures always use static dispatch. To get dynamic dispatch, replace the
|
||||
``proc`` keyword by ``method``:
|
||||
|
||||
.. code-block:: nimrod
|
||||
type
|
||||
TFigure = object of TObject # abstract base class:
|
||||
fDraw: proc (my: var TFigure) # concrete classes implement this proc
|
||||
TExpr = object ## abstract base class for an expression
|
||||
TLiteral = object of TExpr
|
||||
x: int
|
||||
TPlusExpr = object of TExpr
|
||||
a, b: ref TExpr
|
||||
|
||||
method eval(e: ref TExpr): int =
|
||||
# override this base method
|
||||
quit "to override!"
|
||||
|
||||
method eval(e: ref TLiteral): int = return e.x
|
||||
|
||||
method eval(e: ref TPlusExpr): int =
|
||||
# watch out: relies on dynamic binding
|
||||
return eval(e.a) + eval(e.b)
|
||||
|
||||
proc newLit(x: int): ref TLiteral =
|
||||
new(result)
|
||||
result.x = x
|
||||
|
||||
proc init(f: var TFigure) =
|
||||
f.fDraw = nil
|
||||
proc newPlus(a, b: ref TExpr): ref TPlusExpr =
|
||||
new(result)
|
||||
result.a = a
|
||||
result.b = b
|
||||
|
||||
proc draw(f: var TFigure) =
|
||||
# ``draw`` dispatches dynamically:
|
||||
f.fDraw(f)
|
||||
echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4)))
|
||||
|
||||
type
|
||||
TCircle = object of TFigure
|
||||
radius: int
|
||||
|
||||
proc drawCircle(my: var TCircle) = echo("o " & $my.radius)
|
||||
|
||||
proc init(my: var TCircle) =
|
||||
init(TFigure(my)) # call base constructor
|
||||
my.radius = 5
|
||||
my.fdraw = drawCircle
|
||||
Note that in the example the constructors ``newLit`` and ``newPlus`` are procs
|
||||
because they should use static binding, but ``eval`` is a method because it
|
||||
requires dynamic binding.
|
||||
|
||||
In a multi-method all parameters that have an object type are used for the
|
||||
dispatching:
|
||||
|
||||
.. code-block:: nimrod
|
||||
|
||||
type
|
||||
TRectangle = object of TFigure
|
||||
width, height: int
|
||||
TThing = object
|
||||
TUnit = object of TThing
|
||||
x: int
|
||||
|
||||
method collide(a, b: TThing) {.inline.} =
|
||||
quit "to override!"
|
||||
|
||||
method collide(a: TThing, b: TUnit) {.inline.} =
|
||||
echo "1"
|
||||
|
||||
proc drawRectangle(my: var TRectangle) = echo("[]")
|
||||
method collide(a: TUnit, b: TThing) {.inline.} =
|
||||
echo "2"
|
||||
|
||||
proc init(my: var TRectangle) =
|
||||
init(TFigure(my)) # call base constructor
|
||||
my.width = 5
|
||||
my.height = 10
|
||||
my.fdraw = drawRectangle
|
||||
|
||||
# now use these classes:
|
||||
var
|
||||
r: TRectangle
|
||||
c: TCircle
|
||||
init(r)
|
||||
init(c)
|
||||
r.draw()
|
||||
c.draw()
|
||||
a, b: TUnit
|
||||
collide(a, b) # output: 2
|
||||
|
||||
The code uses a ``draw`` procedure that is bound statically, but inside it
|
||||
the dynamic dispatch happens with the help of the ``fdraw`` field. Even though
|
||||
this solution has its advantages compared to traditional OOP-languages, it is
|
||||
a **preliminary** solution. Multimethods are a planned language feature that
|
||||
provide a more flexible and efficient mechanism.
|
||||
|
||||
As the example demonstrates, invokation of a multi-method cannot be ambiguous:
|
||||
Collide 2 is prefered over collide 1 because the resolution works from left to
|
||||
right. Thus ``TUnit, TThing`` is prefered over ``TThing, TUnit``.
|
||||
|
||||
**Perfomance note**: Nimrod does not produce a virtual method table, but
|
||||
generates dispatch trees. This avoids the expensive indirect branch for method
|
||||
calls and enables inlining. However, other optimizations like compile time
|
||||
evaluation or dead code elimination do not work with methods.
|
||||
|
||||
|
||||
Exceptions
|
||||
@@ -497,8 +527,7 @@ simple proc for logging:
|
||||
debug = True
|
||||
|
||||
proc log(msg: string) {.inline.} =
|
||||
if debug:
|
||||
stdout.writeln(msg)
|
||||
if debug: stdout.writeln(msg)
|
||||
|
||||
var
|
||||
x = 4
|
||||
@@ -506,7 +535,7 @@ simple proc for logging:
|
||||
|
||||
This code has a shortcoming: If ``debug`` is set to false someday, the quite
|
||||
expensive ``$`` and ``&`` operations are still performed! (The argument
|
||||
evaluation for procedures is said to be *eager*).
|
||||
evaluation for procedures is *eager*).
|
||||
|
||||
Turning the ``log`` proc into a template solves this problem:
|
||||
|
||||
@@ -514,21 +543,20 @@ Turning the ``log`` proc into a template solves this problem:
|
||||
const
|
||||
debug = True
|
||||
|
||||
template log(msg: expr): stmt =
|
||||
if debug:
|
||||
stdout.writeln(msg)
|
||||
template log(msg: string) =
|
||||
if debug: stdout.writeln(msg)
|
||||
|
||||
var
|
||||
x = 4
|
||||
log("x has the value: " & $x)
|
||||
|
||||
The "types" of templates can be the symbols ``expr`` (stands for *expression*),
|
||||
``stmt`` (stands for *statement*) or ``typedesc`` (stands for *type
|
||||
description*). These are no real types, they just help the compiler parsing.
|
||||
However, real types are supported too.
|
||||
The parameters' types can be ordinary types or the meta types ``expr``
|
||||
(stands for *expression*), ``stmt`` (stands for *statement*) or ``typedesc``
|
||||
(stands for *type description*). If the template has no explicit return type,
|
||||
``stmt`` is used for consistency with procs and methods.
|
||||
|
||||
The template body does not open a new scope. To open a new scope
|
||||
use a ``block`` statement:
|
||||
The template body does not open a new scope. To open a new scope use a ``block``
|
||||
statement:
|
||||
|
||||
.. code-block:: nimrod
|
||||
template declareInScope(x: expr, t: typeDesc): stmt =
|
||||
@@ -573,7 +601,7 @@ In the example the two ``writeln`` statements are bound to the ``actions``
|
||||
parameter. The ``withFile`` template contains boilerplate code and helps to
|
||||
avoid a common bug: To forget to close the file. Note how the
|
||||
``var fn = filename`` statement ensures that ``filename`` is evaluated only
|
||||
once.
|
||||
once.
|
||||
|
||||
|
||||
Macros
|
||||
|
||||
@@ -51,20 +51,21 @@ type
|
||||
nnkObjDownConv, nnkObjUpConv, nnkChckRangeF, nnkChckRange64,
|
||||
nnkChckRange, nnkStringToCString, nnkCStringToString, nnkPassAsOpenArray,
|
||||
nnkAsgn, nnkFastAsgn, nnkGenericParams, nnkFormalParams,
|
||||
nnkOfInherit, nnkModule, nnkProcDef, nnkConverterDef,
|
||||
nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch,
|
||||
nnkElifBranch, nnkExceptBranch, nnkElse, nnkMacroStmt,
|
||||
nnkAsmStmt, nnkPragma, nnkIfStmt, nnkWhenStmt,
|
||||
nnkForStmt, nnkWhileStmt, nnkCaseStmt, nnkVarSection,
|
||||
nnkConstSection, nnkConstDef, nnkTypeSection, nnkTypeDef,
|
||||
nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt,
|
||||
nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt,
|
||||
nnkDiscardStmt, nnkStmtList, nnkImportStmt, nnkFromStmt,
|
||||
nnkIncludeStmt, nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr,
|
||||
nnkStmtListType, nnkBlockType, nnkTypeOfExpr, nnkObjectTy,
|
||||
nnkTupleTy, nnkRecList, nnkRecCase, nnkRecWhen,
|
||||
nnkRefTy, nnkPtrTy, nnkVarTy, nnkDistinctTy,
|
||||
nnkProcTy, nnkEnumTy, nnkEnumFieldDef, nnkReturnToken
|
||||
nnkOfInherit, nnkModule, nnkProcDef, nnkMethodDef,
|
||||
nnkConverterDef, nnkMacroDef, nnkTemplateDef, nnkIteratorDef,
|
||||
nnkOfBranch, nnkElifBranch, nnkExceptBranch, nnkElse,
|
||||
nnkMacroStmt, nnkAsmStmt, nnkPragma, nnkIfStmt,
|
||||
nnkWhenStmt, nnkForStmt, nnkWhileStmt, nnkCaseStmt,
|
||||
nnkVarSection, nnkConstSection, nnkConstDef, nnkTypeSection,
|
||||
nnkTypeDef, nnkYieldStmt, nnkTryStmt, nnkFinally,
|
||||
nnkRaiseStmt, nnkReturnStmt, nnkBreakStmt, nnkContinueStmt,
|
||||
nnkBlockStmt, nnkDiscardStmt, nnkStmtList, nnkImportStmt,
|
||||
nnkFromStmt, nnkIncludeStmt, nnkCommentStmt, nnkStmtListExpr,
|
||||
nnkBlockExpr, nnkStmtListType, nnkBlockType, nnkTypeOfExpr,
|
||||
nnkObjectTy, nnkTupleTy, nnkRecList, nnkRecCase,
|
||||
nnkRecWhen, nnkRefTy, nnkPtrTy, nnkVarTy,
|
||||
nnkDistinctTy, nnkProcTy, nnkEnumTy, nnkEnumFieldDef,
|
||||
nnkReturnToken
|
||||
TNimNodeKinds* = set[TNimrodNodeKind]
|
||||
TNimrodTypeKind* = enum
|
||||
ntyNone, ntyBool, ntyChar, ntyEmpty,
|
||||
@@ -81,9 +82,10 @@ type
|
||||
TNimrodSymKind* = enum
|
||||
nskUnknown, nskConditional, nskDynLib, nskParam,
|
||||
nskGenericParam, nskTemp, nskType, nskConst,
|
||||
nskVar, nskProc, nskIterator, nskConverter,
|
||||
nskMacro, nskTemplate, nskField, nskEnumField,
|
||||
nskForVar, nskModule, nskLabel, nskStub
|
||||
nskVar, nskProc, nskMethod, nskIterator,
|
||||
nskConverter, nskMacro, nskTemplate, nskField,
|
||||
nskEnumField, nskForVar, nskModule, nskLabel,
|
||||
nskStub
|
||||
TNimSymKinds* = set[TNimrodSymKind]
|
||||
#[[[end]]]
|
||||
|
||||
|
||||
127
lib/pure/os.nim
127
lib/pure/os.nim
@@ -363,7 +363,24 @@ proc `/` * (head, tail: string): string {.noSideEffect.} =
|
||||
## The same as ``joinPath(head, tail)``
|
||||
return joinPath(head, tail)
|
||||
|
||||
proc SplitPath*(path: string, head, tail: var string) {.noSideEffect.} =
|
||||
proc SplitPath*(path: string, head, tail: var string) {.noSideEffect,
|
||||
deprecated.} =
|
||||
## **Deprecated since version 0.8.2**: use the version that returns a tuple
|
||||
## instead
|
||||
var
|
||||
sepPos = -1
|
||||
for i in countdown(len(path)-1, 0):
|
||||
if path[i] in {dirsep, altsep}:
|
||||
sepPos = i
|
||||
break
|
||||
if sepPos >= 0:
|
||||
head = copy(path, 0, sepPos-1)
|
||||
tail = copy(path, sepPos+1)
|
||||
else:
|
||||
head = ""
|
||||
tail = path # make a string copy here
|
||||
|
||||
proc SplitPath*(path: string): tuple[head, tail: string] {.noSideEffect.} =
|
||||
## Splits a directory into (head, tail), so that
|
||||
## ``JoinPath(head, tail) == path``.
|
||||
##
|
||||
@@ -378,11 +395,11 @@ proc SplitPath*(path: string, head, tail: var string) {.noSideEffect.} =
|
||||
sepPos = i
|
||||
break
|
||||
if sepPos >= 0:
|
||||
head = copy(path, 0, sepPos-1)
|
||||
tail = copy(path, sepPos+1)
|
||||
result.head = copy(path, 0, sepPos-1)
|
||||
result.tail = copy(path, sepPos+1)
|
||||
else:
|
||||
head = ""
|
||||
tail = path # make a string copy here
|
||||
result.head = ""
|
||||
result.tail = path
|
||||
|
||||
proc parentDir*(path: string): string {.noSideEffect.} =
|
||||
## Returns the parent directory of `path`.
|
||||
@@ -422,25 +439,50 @@ proc searchExtPos(s: string): int =
|
||||
elif s[i] in {dirsep, altsep}:
|
||||
break # do not skip over path
|
||||
|
||||
proc extractDir*(path: string): string {.noSideEffect.} =
|
||||
proc splitFile*(path: string): tuple[dir, name, ext: string] {.noSideEffect.} =
|
||||
## Splits a filename into (dir, filename, extension).
|
||||
## `dir` does not end in `DirSep`.
|
||||
## `extension` includes the leading dot.
|
||||
##
|
||||
## Example:
|
||||
##
|
||||
## .. code-block:: nimrod
|
||||
## var (dir, name, ext) = splitFile("usr/local/nimrodc.html")
|
||||
## assert dir == "usr/local"
|
||||
## assert name == "nimrodc"
|
||||
## assert ext == ".html"
|
||||
## If `path` has no extension, `ext` is the empty string.
|
||||
## If `path` has no directory component, `dir` is the empty string.
|
||||
## If `path` has no filename component, `name` and `ext` are empty strings.
|
||||
if path.len == 0 or path[path.len-1] in {dirSep, altSep}:
|
||||
result = (path, "", "")
|
||||
else:
|
||||
var sepPos = -1
|
||||
var dotPos = path.len
|
||||
for i in countdown(len(path)-1, 0):
|
||||
if path[i] == ExtSep:
|
||||
if dotPos == path.len: dotPos = i
|
||||
elif path[i] in {dirsep, altsep}:
|
||||
sepPos = i
|
||||
break
|
||||
result.dir = copy(path, 0, sepPos-1)
|
||||
result.name = copy(path, sepPos+1, dotPos-1)
|
||||
result.ext = copy(path, dotPos)
|
||||
|
||||
proc extractDir*(path: string): string {.noSideEffect, deprecated.} =
|
||||
## Extracts the directory of a given path. This is almost the
|
||||
## same as the `head` result of `splitPath`, except that
|
||||
## ``extractDir("/usr/lib/") == "/usr/lib/"``.
|
||||
if path.len == 0 or path[path.len-1] in {dirSep, altSep}:
|
||||
result = path
|
||||
else:
|
||||
var tail: string
|
||||
splitPath(path, result, tail)
|
||||
## **Deprecated since version 0.8.2**: Use ``splitFile(path).dir`` instead.
|
||||
result = splitFile(path).dir
|
||||
|
||||
proc extractFilename*(path: string): string {.noSideEffect.} =
|
||||
## Extracts the filename of a given `path`. This is almost the
|
||||
## same as the `tail` result of `splitPath`, except that
|
||||
## ``extractFilename("/usr/lib/") == ""``.
|
||||
## Extracts the filename of a given `path`. This is the same as
|
||||
## ``name & ext`` from ``splitFile(path)``.
|
||||
if path.len == 0 or path[path.len-1] in {dirSep, altSep}:
|
||||
result = ""
|
||||
else:
|
||||
var head: string
|
||||
splitPath(path, head, result)
|
||||
result = splitPath(path).tail
|
||||
|
||||
proc expandFilename*(filename: string): string =
|
||||
## Returns the full path of `filename`, raises EOS in case of an error.
|
||||
@@ -457,13 +499,14 @@ proc expandFilename*(filename: string): string =
|
||||
c_free(res)
|
||||
|
||||
proc SplitFilename*(filename: string, name, extension: var string) {.
|
||||
noSideEffect.} =
|
||||
noSideEffect, deprecated.} =
|
||||
## Splits a filename into (name, extension), so that
|
||||
## ``name & extension == filename``.
|
||||
##
|
||||
## Example: After ``SplitFilename("usr/local/nimrodc.html", name, ext)``,
|
||||
## `name` is "usr/local/nimrodc" and `ext` is ".html".
|
||||
## It the file has no extension, extention is the empty string.
|
||||
## If the file has no extension, extension is the empty string.
|
||||
## **Deprecated since version 0.8.2**: Use ``splitFile(filename)`` instead.
|
||||
var extPos = searchExtPos(filename)
|
||||
if extPos >= 0:
|
||||
name = copy(filename, 0, extPos-1)
|
||||
@@ -472,18 +515,19 @@ proc SplitFilename*(filename: string, name, extension: var string) {.
|
||||
name = filename # make a string copy here
|
||||
extension = ""
|
||||
|
||||
proc extractFileExt*(filename: string): string {.noSideEffect.} =
|
||||
proc extractFileExt*(filename: string): string {.noSideEffect, deprecated.} =
|
||||
## Extracts the file extension of a given `filename`. This is the
|
||||
## same as the `extension` result of `splitFilename`.
|
||||
var dummy: string
|
||||
splitFilename(filename, dummy, result)
|
||||
## **Deprecated since version 0.8.2**: Use ``splitFile(filename).ext``
|
||||
## instead.
|
||||
result = splitFile(filename).ext
|
||||
|
||||
proc extractFileTrunk*(filename: string): string {.noSideEffect.} =
|
||||
proc extractFileTrunk*(filename: string): string {.noSideEffect, deprecated.} =
|
||||
## Extracts the file name of a given `filename`. This removes any
|
||||
## directory information and the file extension.
|
||||
var dummy: string
|
||||
splitFilename(extractFilename(filename), result, dummy)
|
||||
|
||||
## **Deprecated since version 0.8.2**: Use ``splitFile(path).name`` instead.
|
||||
result = splitFile(filename).name
|
||||
|
||||
proc ChangeFileExt*(filename, ext: string): string {.noSideEffect.} =
|
||||
## Changes the file extension to `ext`.
|
||||
##
|
||||
@@ -496,8 +540,8 @@ proc ChangeFileExt*(filename, ext: string): string {.noSideEffect.} =
|
||||
if extPos < 0: result = filename & normExt(ext)
|
||||
else: result = copy(filename, 0, extPos-1) & normExt(ext)
|
||||
|
||||
proc AppendFileExt*(filename, ext: string): string {.noSideEffect.} =
|
||||
## Appends the file extension `ext` to `filename`, unless
|
||||
proc addFileExt*(filename, ext: string): string {.noSideEffect.} =
|
||||
## Adds the file extension `ext` to `filename`, unless
|
||||
## `filename` already has an extension.
|
||||
##
|
||||
## `Ext` should be given without the leading '.', because some
|
||||
@@ -505,7 +549,12 @@ proc AppendFileExt*(filename, ext: string): string {.noSideEffect.} =
|
||||
## (Although I know of none such beast.)
|
||||
var extPos = searchExtPos(filename)
|
||||
if extPos < 0: result = filename & normExt(ext)
|
||||
else: result = filename #make a string copy here
|
||||
else: result = filename
|
||||
|
||||
proc AppendFileExt*(filename, ext: string): string {.
|
||||
noSideEffect, deprecated.} =
|
||||
## **Deprecated since version 0.8.2**: Use `addFileExt` instead.
|
||||
result = addFileExt(filename, ext)
|
||||
|
||||
proc cmpPaths*(pathA, pathB: string): int {.noSideEffect.} =
|
||||
## Compares two paths.
|
||||
@@ -610,14 +659,18 @@ proc removeFile*(file: string) =
|
||||
## Removes the `file`. If this fails, `EOS` is raised.
|
||||
if cremove(file) != 0'i32: OSError()
|
||||
|
||||
proc executeShellCommand*(command: string): int =
|
||||
proc executeShellCommand*(command: string): int {.deprecated.} =
|
||||
## **Deprecated since version 0.8.2**: Use `execShellCmd` instead.
|
||||
result = csystem(command)
|
||||
|
||||
proc execShellCmd*(command: string): int =
|
||||
## Executes a shell command.
|
||||
##
|
||||
## Command has the form 'program args' where args are the command
|
||||
## line arguments given to program. The proc returns the error code
|
||||
## of the shell when it has finished. The proc does not return until
|
||||
## the process has finished. To execute a program without having a
|
||||
## shell involved, use the `executeProcess` proc of the `osproc`
|
||||
## shell involved, use the `execProcess` proc of the `osproc`
|
||||
## module.
|
||||
result = csystem(command)
|
||||
|
||||
@@ -707,7 +760,16 @@ proc putEnv*(key, val: string) =
|
||||
if SetEnvironmentVariableA(key, val) == 0'i32:
|
||||
OSError()
|
||||
|
||||
iterator iterOverEnvironment*(): tuple[key, value: string] =
|
||||
iterator iterOverEnvironment*(): tuple[key, value: string] {.deprecated.} =
|
||||
## Iterate over all environments variables. In the first component of the
|
||||
## tuple is the name of the current variable stored, in the second its value.
|
||||
## **Deprecated since version 0.8.2**: Use `envPairs` instead.
|
||||
getEnvVarsC()
|
||||
for i in 0..high(environment):
|
||||
var p = find(environment[i], '=')
|
||||
yield (copy(environment[i], 0, p-1), copy(environment[i], p+1))
|
||||
|
||||
iterator envPairs*(): tuple[key, value: string] =
|
||||
## Iterate over all environments variables. In the first component of the
|
||||
## tuple is the name of the current variable stored, in the second its value.
|
||||
getEnvVarsC()
|
||||
@@ -1039,7 +1101,6 @@ proc getApplicationFilename*(): string =
|
||||
|
||||
proc getApplicationDir*(): string =
|
||||
## Returns the directory of the application's executable.
|
||||
var tail: string
|
||||
splitPath(getApplicationFilename(), result, tail)
|
||||
result = splitFile(getApplicationFilename()).dir
|
||||
|
||||
{.pop.}
|
||||
|
||||
@@ -36,16 +36,28 @@ type
|
||||
## often creates a security whole!
|
||||
poStdErrToStdOut ## merge stdout and stderr to the stdout stream
|
||||
|
||||
proc executeProcess*(command: string,
|
||||
options: set[TProcessOption] = {poStdErrToStdOut,
|
||||
poUseShell}): string
|
||||
proc execProcess*(command: string,
|
||||
options: set[TProcessOption] = {poStdErrToStdOut,
|
||||
poUseShell}): string
|
||||
## A convience procedure that executes ``command`` with ``startProcess``
|
||||
## and returns its output as a string.
|
||||
|
||||
proc executeCommand*(command: string): int
|
||||
proc executeProcess*(command: string,
|
||||
options: set[TProcessOption] = {poStdErrToStdOut,
|
||||
poUseShell}): string {.
|
||||
deprecated.} =
|
||||
## **Deprecated since version 0.8.2**: Use `execProcess` instead.
|
||||
result = execProcess(command, options)
|
||||
|
||||
proc execCmd*(command: string): int
|
||||
## Executes ``command`` and returns its error code. Standard input, output,
|
||||
## error streams are inherited from the calling process.
|
||||
|
||||
proc executeCommand*(command: string): int {.deprecated.} =
|
||||
## **Deprecated since version 0.8.2**: Use `execCmd` instead.
|
||||
result = execCmd(command)
|
||||
|
||||
|
||||
proc startProcess*(command: string,
|
||||
workingDir: string = "",
|
||||
args: openarray[string] = [],
|
||||
@@ -56,11 +68,12 @@ proc startProcess*(command: string,
|
||||
## is used. `args` are the command line arguments that are passed to the
|
||||
## process. On many operating systems, the first command line argument is the
|
||||
## name of the executable. `args` should not contain this argument!
|
||||
## `startProcess` takes care of that. `env` is the environment that will be
|
||||
## passed to the process. If ``env == nil`` the environment is inherited of
|
||||
## `env` is the environment that will be passed to the process.
|
||||
## If ``env == nil`` the environment is inherited of
|
||||
## the parent process. `options` are additional flags that may be passed
|
||||
## to `startProcess`. See the documentation of ``TProcessOption`` for the
|
||||
## meaning of these flags.
|
||||
##
|
||||
## Return value: The newly created process object. Nil is never returned,
|
||||
## but ``EOS`` is raised in case of an error.
|
||||
|
||||
@@ -104,9 +117,9 @@ proc outputStream*(p: PProcess): PStream
|
||||
proc errorStream*(p: PProcess): PStream
|
||||
## returns ``p``'s output stream for reading from
|
||||
|
||||
proc executeProcess*(command: string,
|
||||
options: set[TProcessOption] = {poStdErrToStdOut,
|
||||
poUseShell}): string =
|
||||
proc execProcess(command: string,
|
||||
options: set[TProcessOption] = {poStdErrToStdOut,
|
||||
poUseShell}): string =
|
||||
var c = parseCmdLine(command)
|
||||
var a: seq[string] = @[] # slicing is not yet implemented :-(
|
||||
for i in 1 .. c.len-1: add(a, c[i])
|
||||
@@ -208,24 +221,24 @@ when defined(Windows):
|
||||
SI.dwFlags = STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES
|
||||
CreatePipeHandles(SI.hStdInput, HI)
|
||||
CreatePipeHandles(HO, Si.hStdOutput)
|
||||
#SI.hStdInput = GetStdHandle(STD_INPUT_HANDLE())
|
||||
#SI.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE())
|
||||
if poStdErrToStdOut in options:
|
||||
SI.hStdError = SI.hStdOutput
|
||||
HE = HO
|
||||
else:
|
||||
CreatePipeHandles(HE, Si.hStdError)
|
||||
#SI.hStdError = GetStdHandle(STD_ERROR_HANDLE())
|
||||
#result.inputHandle = open_osfhandle(HI, O_WRONLY)
|
||||
#if result.inputHandle == -1'i32: OSError()
|
||||
result.inputHandle = hi
|
||||
result.outputHandle = ho
|
||||
result.errorHandle = he
|
||||
#result.outputHandle = open_osfhandle(HO, O_RDONLY)
|
||||
#if result.outputHandle == -1'i32: OSError()
|
||||
#result.errorHandle = open_osfhandle(HE, O_RDONLY)
|
||||
#if result.errorHandle == -1'i32: OSError()
|
||||
var cmdl = buildCommandLine(command, args)
|
||||
var cmdl: cstring
|
||||
if poUseShell in options:
|
||||
var comspec = getEnv("COMSPEC")
|
||||
var a: seq[string] = @[]
|
||||
add(a, "/c")
|
||||
add(a, command)
|
||||
add(a, args)
|
||||
cmdl = buildCommandLine(comspec, a)
|
||||
else:
|
||||
cmdl = buildCommandLine(command, args)
|
||||
var wd: cstring = nil
|
||||
if len(workingDir) > 0: wd = workingDir
|
||||
if env == nil:
|
||||
@@ -239,6 +252,9 @@ when defined(Windows):
|
||||
dealloc(cmdl)
|
||||
if success == 0:
|
||||
OSError()
|
||||
# NEW:
|
||||
# Close the handles now so anyone waiting is woken.
|
||||
discard closeHandle(procInfo.hThread)
|
||||
result.FProcessHandle = procInfo.hProcess
|
||||
result.FThreadHandle = procInfo.hThread
|
||||
result.id = procInfo.dwProcessID
|
||||
@@ -258,7 +274,7 @@ when defined(Windows):
|
||||
discard TerminateProcess(p.FProcessHandle, 0)
|
||||
|
||||
proc waitForExit(p: PProcess): int =
|
||||
discard CloseHandle(p.FThreadHandle)
|
||||
#CloseHandle(p.FThreadHandle)
|
||||
discard WaitForSingleObject(p.FProcessHandle, Infinite)
|
||||
var res: int32
|
||||
discard GetExitCodeProcess(p.FProcessHandle, res)
|
||||
@@ -274,7 +290,7 @@ when defined(Windows):
|
||||
proc errorStream(p: PProcess): PStream =
|
||||
result = newFileHandleStream(p.errorHandle)
|
||||
|
||||
proc executeCommand(command: string): int =
|
||||
proc execCmd(command: string): int =
|
||||
var
|
||||
SI: TStartupInfo
|
||||
ProcInfo: TProcessInformation
|
||||
@@ -420,8 +436,8 @@ else:
|
||||
|
||||
proc csystem(cmd: cstring): cint {.nodecl, importc: "system".}
|
||||
|
||||
proc executeCommand(command: string): int =
|
||||
proc execCmd(command: string): int =
|
||||
result = csystem(command)
|
||||
|
||||
when isMainModule:
|
||||
echo executeCommand("gcc -v")
|
||||
echo execCmd("gcc -v")
|
||||
|
||||
@@ -138,7 +138,7 @@ proc getEscapedChar(c: var TCfgParser, tok: var TToken) =
|
||||
inc(c.bufpos) # skip '\'
|
||||
case c.buf[c.bufpos]
|
||||
of 'n', 'N':
|
||||
add(tok.literal, nl)
|
||||
add(tok.literal, "\n")
|
||||
Inc(c.bufpos)
|
||||
of 'r', 'R', 'c', 'C':
|
||||
add(tok.literal, '\c')
|
||||
@@ -208,7 +208,7 @@ proc getString(c: var TCfgParser, tok: var TToken, rawMode: bool) =
|
||||
of '\c', '\L':
|
||||
pos = HandleCRLF(c, pos)
|
||||
buf = c.buf
|
||||
add(tok.literal, nl)
|
||||
add(tok.literal, "\n")
|
||||
of lexbase.EndOfFile:
|
||||
tok.kind = tkInvalid
|
||||
break
|
||||
@@ -302,7 +302,7 @@ proc rawGetTok(c: var TCfgParser, tok: var TToken) =
|
||||
|
||||
proc errorStr(c: TCfgParser, msg: string): string =
|
||||
result = `%`("$1($2, $3) Error: $4",
|
||||
[c.filename, toString(getLine(c)), toString(getColumn(c)), msg])
|
||||
[c.filename, $getLine(c), $getColumn(c), msg])
|
||||
|
||||
proc getKeyValPair(c: var TCfgParser, kind: TCfgEventKind): TCfgEvent =
|
||||
if c.tok.kind == tkSymbol:
|
||||
|
||||
@@ -32,21 +32,10 @@ type
|
||||
## or the argument, ``value`` is not "" if
|
||||
## the option was given a value
|
||||
|
||||
proc init*(cmdline: string = ""): TOptParser
|
||||
proc initOptParser*(cmdline = ""): TOptParser =
|
||||
## inits the option parser. If ``cmdline == ""``, the real command line
|
||||
## (as provided by the ``OS`` module) is taken.
|
||||
|
||||
proc next*(p: var TOptParser)
|
||||
## parses the first or next option; ``p.kind`` describes what token has been
|
||||
## parsed. ``p.key`` and ``p.val`` are set accordingly.
|
||||
|
||||
proc getRestOfCommandLine*(p: TOptParser): string
|
||||
## retrieves the rest of the command line that has not been parsed yet.
|
||||
|
||||
# implementation
|
||||
|
||||
proc init(cmdline: string = ""): TOptParser =
|
||||
result.pos = strStart
|
||||
result.pos = 0
|
||||
result.inShortState = false
|
||||
if cmdline != "":
|
||||
result.cmd = cmdline
|
||||
@@ -58,6 +47,10 @@ proc init(cmdline: string = ""): TOptParser =
|
||||
result.key = ""
|
||||
result.val = ""
|
||||
|
||||
proc init*(cmdline: string = ""): TOptParser {.deprecated.} =
|
||||
## **Deprecated since version 0.8.2**: Use `initOptParser` instead.
|
||||
result = initOptParser(cmdline)
|
||||
|
||||
proc parseWord(s: string, i: int, w: var string,
|
||||
delim: TCharSet = {'\x09', ' ', '\0'}): int =
|
||||
result = i
|
||||
@@ -89,7 +82,9 @@ proc handleShortOption(p: var TOptParser) =
|
||||
if p.cmd[i] == '\0': p.inShortState = false
|
||||
p.pos = i
|
||||
|
||||
proc next(p: var TOptParser) =
|
||||
proc next*(p: var TOptParser) =
|
||||
## parses the first or next option; ``p.kind`` describes what token has been
|
||||
## parsed. ``p.key`` and ``p.val`` are set accordingly.
|
||||
var i = p.pos
|
||||
while p.cmd[i] in {'\x09', ' '}: inc(i)
|
||||
p.pos = i
|
||||
@@ -121,12 +116,17 @@ proc next(p: var TOptParser) =
|
||||
p.kind = cmdArgument
|
||||
p.pos = parseWord(p.cmd, i, p.key)
|
||||
|
||||
proc getRestOfCommandLine(p: TOptParser): string =
|
||||
result = strip(copy(p.cmd, p.pos + strStart, len(p.cmd) - 1))
|
||||
proc cmdLineRest*(p: TOptParser): string =
|
||||
## retrieves the rest of the command line that has not been parsed yet.
|
||||
result = strip(copy(p.cmd, p.pos, len(p.cmd) - 1))
|
||||
|
||||
proc getRestOfCommandLine*(p: TOptParser): string {.deprecated.} =
|
||||
## **Deprecated since version 0.8.2**: Use `cmdLineRest` instead.
|
||||
result = cmdLineRest(p)
|
||||
|
||||
iterator getopt*(): tuple[kind: TCmdLineKind, key, val: string] =
|
||||
##this is an convenience iterator for iterating over the command line.
|
||||
##This uses the TOptParser object. Example:
|
||||
## This is an convenience iterator for iterating over the command line.
|
||||
## This uses the TOptParser object. Example:
|
||||
##
|
||||
## .. code-block:: nimrod
|
||||
## var
|
||||
@@ -143,7 +143,7 @@ iterator getopt*(): tuple[kind: TCmdLineKind, key, val: string] =
|
||||
## if filename == "":
|
||||
## # no filename has been given, so we show the help:
|
||||
## writeHelp()
|
||||
var p = init()
|
||||
var p = initOptParser()
|
||||
while true:
|
||||
next(p)
|
||||
if p.kind == cmdEnd: break
|
||||
|
||||
@@ -483,7 +483,7 @@ proc errorStr(L: TSqlLexer, msg: string): string =
|
||||
# OR left logical disjunction
|
||||
|
||||
type
|
||||
TSqlNodeKind* = enum
|
||||
TSqlNodeKind* = enum ## kind of SQL abstract syntax tree
|
||||
nkNone,
|
||||
nkIdent,
|
||||
nkStringLit,
|
||||
@@ -536,17 +536,18 @@ type
|
||||
nkEnumDef
|
||||
|
||||
type
|
||||
EInvalidSql* = object of EBase
|
||||
PSqlNode* = ref TSqlNode
|
||||
TSqlNode* = object
|
||||
case kind*: TSqlNodeKind
|
||||
EInvalidSql* = object of EBase ## Invalid SQL encountered
|
||||
PSqlNode* = ref TSqlNode ## an SQL abstract syntax tree node
|
||||
TSqlNode* = object ## an SQL abstract syntax tree node
|
||||
case kind*: TSqlNodeKind ## kind of syntax tree
|
||||
of nkIdent, nkStringLit, nkBitStringLit, nkHexStringLit,
|
||||
nkIntegerLit, nkNumericLit:
|
||||
strVal*: string
|
||||
strVal*: string ## AST leaf: the identifier, numeric literal
|
||||
## string literal, etc.
|
||||
else:
|
||||
sons*: seq[PSqlNode]
|
||||
sons*: seq[PSqlNode] ## the node's children
|
||||
|
||||
TSqlParser = object of TSqlLexer
|
||||
TSqlParser* = object of TSqlLexer ## SQL parser object
|
||||
tok: TToken
|
||||
|
||||
proc newNode(k: TSqlNodeKind): PSqlNode =
|
||||
@@ -1070,7 +1071,17 @@ proc parseStmt(p: var TSqlParser): PSqlNode =
|
||||
else:
|
||||
sqlError(p, "CREATE expected")
|
||||
|
||||
proc parse*(p: var TSqlParser): PSqlNode =
|
||||
proc open(p: var TSqlParser, input: PStream, filename: string) =
|
||||
## opens the parser `p` and assigns the input stream `input` to it.
|
||||
## `filename` is only used for error messages.
|
||||
open(TSqlLexer(p), input, filename)
|
||||
p.tok.kind = tkInvalid
|
||||
p.tok.literal = ""
|
||||
getTok(p)
|
||||
|
||||
proc parse(p: var TSqlParser): PSqlNode =
|
||||
## parses the content of `p`'s input stream and returns the SQL AST.
|
||||
## Syntax errors raise an `EInvalidSql` exception.
|
||||
result = newNode(nkStmtList)
|
||||
while p.tok.kind != tkEof:
|
||||
var s = parseStmt(p)
|
||||
@@ -1078,21 +1089,21 @@ proc parse*(p: var TSqlParser): PSqlNode =
|
||||
result.add(s)
|
||||
if result.len == 1:
|
||||
result = result.sons[0]
|
||||
|
||||
proc open*(p: var TSqlParser, input: PStream, filename: string) =
|
||||
open(TSqlLexer(p), input, filename)
|
||||
p.tok.kind = tkInvalid
|
||||
p.tok.literal = ""
|
||||
getTok(p)
|
||||
|
||||
proc close*(p: var TSqlParser) =
|
||||
proc close(p: var TSqlParser) =
|
||||
## closes the parser `p`. The associated input stream is closed too.
|
||||
close(TSqlLexer(p))
|
||||
|
||||
proc parseSQL*(input: PStream, filename: string): PSqlNode =
|
||||
## parses the SQL from `input` into an AST and returns the AST.
|
||||
## `filename` is only used for error messages.
|
||||
## Syntax errors raise an `EInvalidSql` exception.
|
||||
var p: TSqlParser
|
||||
open(p, input, filename)
|
||||
result = parse(p)
|
||||
close(p)
|
||||
try:
|
||||
result = parse(p)
|
||||
finally:
|
||||
close(p)
|
||||
|
||||
proc ra(n: PSqlNode, s: var string, indent: int)
|
||||
|
||||
@@ -1114,7 +1125,7 @@ proc ra(n: PSqlNode, s: var string, indent: int) =
|
||||
if allCharsInSet(n.strVal, {'\33'..'\127'}):
|
||||
s.add(n.strVal)
|
||||
else:
|
||||
s.add("\"" & replaceStr(n.strVal, "\"", "\"\"") & "\"")
|
||||
s.add("\"" & replace(n.strVal, "\"", "\"\"") & "\"")
|
||||
of nkStringLit:
|
||||
s.add(escape(n.strVal, "e'", "'"))
|
||||
of nkBitStringLit:
|
||||
|
||||
@@ -297,7 +297,7 @@ proc parseEntity(my: var TXmlParser, dest: var string) =
|
||||
var buf = my.buf
|
||||
my.kind = xmlCharData
|
||||
if buf[pos] == '#':
|
||||
var r: TRune
|
||||
var r: int
|
||||
inc(pos)
|
||||
if buf[pos] == 'x':
|
||||
inc(pos)
|
||||
@@ -312,7 +312,7 @@ proc parseEntity(my: var TXmlParser, dest: var string) =
|
||||
while buf[pos] in {'0'..'9'}:
|
||||
r = r * 10 + (ord(buf[pos]) - ord('0'))
|
||||
inc(pos)
|
||||
add(dest, toUTF8(r))
|
||||
add(dest, toUTF8(TRune(r)))
|
||||
elif buf[pos] == 'l' and buf[pos+1] == 't':
|
||||
add(dest, '<')
|
||||
inc(pos, 2)
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
#
|
||||
|
||||
## Regular expression support for Nimrod.
|
||||
## **Deprecated** since version 0.8.2. Use the module `re` instead.
|
||||
{.deprecated.}
|
||||
|
||||
## Currently this module is implemented by providing a wrapper around the
|
||||
## `PRCE (Perl-Compatible Regular Expressions) <http://www.pcre.org>`_
|
||||
## C library. This means that your application will depend on the PRCE
|
||||
@@ -131,13 +134,14 @@ template `=~` *(s, pattern: expr): expr =
|
||||
## echo("comment: ", matches[1])
|
||||
## else:
|
||||
## echo("syntax error")
|
||||
##
|
||||
var matches: array[0..maxSubPatterns-1, string]
|
||||
##
|
||||
when not definedInScope(matches):
|
||||
var matches: array[0..maxSubPatterns-1, string]
|
||||
match(s, pattern, matches)
|
||||
|
||||
|
||||
const ## common regular expressions
|
||||
reIdentifier* = r"\b[a-zA-Z_]+[a-zA-Z_0-9]*\b" ## describes an identifier
|
||||
reIdentifier* = r"\b[a-zA-Z_][a-zA-Z_0-9]*\b" ## describes an identifier
|
||||
reNatural* = r"\b\d+\b" ## describes a natural number
|
||||
reInteger* = r"\b[-+]?\d+\b" ## describes an integer
|
||||
reHex* = r"\b0[xX][0-9a-fA-F]+\b" ## describes a hexadecimal number
|
||||
|
||||
@@ -45,9 +45,9 @@ const
|
||||
IdentStartChars* = {'a'..'z', 'A'..'Z', '_'}
|
||||
## the set of characters an identifier can start with
|
||||
|
||||
strStart* = 0 ## this is only for bootstraping
|
||||
## XXX: remove this someday
|
||||
nl* = "\n" ## this is only for bootstraping XXX: remove this somehow
|
||||
# strStart* = 0 ## this is only for bootstraping
|
||||
# ## XXX: remove this someday
|
||||
# nl* = "\n" ## this is only for bootstraping XXX: remove this someday
|
||||
|
||||
proc `%` *(formatstr: string, a: openarray[string]): string {.noSideEffect.}
|
||||
## The `substitution`:idx: operator performs string substitutions in
|
||||
@@ -272,43 +272,39 @@ iterator splitLines*(s: string): string =
|
||||
else: break # was '\0'
|
||||
first = last
|
||||
|
||||
template iterToProc(iter: expr): stmt =
|
||||
result = @[]
|
||||
for x in iter: add(result, x)
|
||||
|
||||
proc splitLinesSeq*(s: string): seq[string] {.noSideEffect, deprecated.} =
|
||||
## The same as `splitLines`, but is a proc that returns a sequence
|
||||
## of substrings.
|
||||
## **Deprecated since version 0.8.0**: Use `splitLines` instead.
|
||||
iterToProc(splitLines(s))
|
||||
accumulateResult(splitLines(s))
|
||||
|
||||
proc splitSeq*(s: string, seps: set[char] = Whitespace): seq[string] {.
|
||||
noSideEffect, deprecated.} =
|
||||
## The same as `split`, but is a proc that returns a sequence of substrings.
|
||||
## **Deprecated since version 0.8.0**: Use `split` instead.
|
||||
iterToProc(split(s, seps))
|
||||
accumulateResult(split(s, seps))
|
||||
|
||||
proc splitSeq*(s: string, sep: char): seq[string] {.noSideEffect,
|
||||
deprecated.} =
|
||||
## The same as `split`, but is a proc that returns a sequence of substrings.
|
||||
## **Deprecated since version 0.8.0**: Use `split` instead.
|
||||
iterToProc(split(s, sep))
|
||||
accumulateResult(split(s, sep))
|
||||
|
||||
proc splitLines*(s: string): seq[string] {.noSideEffect.} =
|
||||
## The same as the `splitLines` iterator, but is a proc that returns a
|
||||
## sequence of substrings.
|
||||
iterToProc(splitLines(s))
|
||||
accumulateResult(splitLines(s))
|
||||
|
||||
proc split*(s: string, seps: set[char] = Whitespace): seq[string] {.
|
||||
noSideEffect.} =
|
||||
## The same as the `split` iterator, but is a proc that returns a
|
||||
## sequence of substrings.
|
||||
iterToProc(split(s, seps))
|
||||
accumulateResult(split(s, seps))
|
||||
|
||||
proc split*(s: string, sep: char): seq[string] {.noSideEffect.} =
|
||||
## The same as the `split` iterator, but is a proc that returns a sequence
|
||||
## of substrings.
|
||||
iterToProc(split(s, sep))
|
||||
accumulateResult(split(s, sep))
|
||||
|
||||
proc cmpIgnoreCase*(a, b: string): int {.noSideEffect.}
|
||||
## Compares two strings in a case insensitive manner. Returns:
|
||||
@@ -358,8 +354,10 @@ proc ParseFloat*(s: string): float {.noSideEffect.}
|
||||
## ``INF``, ``-INF`` are also supported (case insensitive comparison).
|
||||
|
||||
# the stringify and format operators:
|
||||
proc toString*[Ty](x: Ty): string
|
||||
proc toString*[Ty](x: Ty): string {.deprecated.}
|
||||
## This generic proc is the same as the stringify operator `$`.
|
||||
##
|
||||
## **Deprecated since version 0.8.2:** Use `$` instead.
|
||||
|
||||
proc repeatChar*(count: int, c: Char = ' '): string
|
||||
## Returns a string of length `count` consisting only of
|
||||
|
||||
@@ -12,9 +12,14 @@
|
||||
{.deadCodeElim: on.}
|
||||
|
||||
type
|
||||
TRune* = int ## type that can hold any Unicode character
|
||||
TRune16* = int16 ## 16 bit Unicode character
|
||||
irune = int # underlying type of TRune
|
||||
TRune* = distinct irune ## type that can hold any Unicode character
|
||||
TRune16* = distinct int16 ## 16 bit Unicode character
|
||||
|
||||
proc `<=%`*(a, b: TRune): bool {.borrow.}
|
||||
proc `<%`*(a, b: TRune): bool {.borrow.}
|
||||
proc `==`*(a, b: TRune): bool {.borrow.}
|
||||
|
||||
template ones(n: expr): expr = ((1 shl n)-1)
|
||||
|
||||
proc runeLen*(s: string): int =
|
||||
@@ -28,77 +33,71 @@ proc runeLen*(s: string): int =
|
||||
else: assert(false)
|
||||
inc(result)
|
||||
|
||||
proc runeLenAt*(s: string, i: int): int =
|
||||
## returns the number of bytes the rune starting at ``s[i]`` takes.
|
||||
if ord(s[i]) <=% 127: result = 1
|
||||
elif ord(s[i]) shr 5 == 0b110: result = 2
|
||||
elif ord(s[i]) shr 4 == 0b1110: result = 3
|
||||
elif ord(s[i]) shr 3 == 0b11110: result = 4
|
||||
else: assert(false)
|
||||
|
||||
template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
|
||||
## Returns the unicode character ``s[i]`` in `result`. If ``doInc == true``
|
||||
## `i` is incremented by the number of bytes that have been processed.
|
||||
when not defined(ones):
|
||||
template ones(n: expr): expr = ((1 shl n)-1)
|
||||
|
||||
if ord(s[i]) <=% 127:
|
||||
result = TRune(ord(s[i]))
|
||||
when doInc: inc(i)
|
||||
elif ord(s[i]) shr 5 == 0b110:
|
||||
assert(ord(s[i+1]) shr 6 == 0b10)
|
||||
result = TRune((ord(s[i]) and ones(5)) shl 6 or (ord(s[i+1]) and ones(6)))
|
||||
when doInc: inc(i, 2)
|
||||
elif ord(s[i]) shr 4 == 0b1110:
|
||||
assert(ord(s[i+1]) shr 6 == 0b10)
|
||||
assert(ord(s[i+2]) shr 6 == 0b10)
|
||||
result = TRune((ord(s[i]) and ones(4)) shl 12 or
|
||||
(ord(s[i+1]) and ones(6)) shl 6 or
|
||||
(ord(s[i+2]) and ones(6)))
|
||||
when doInc: inc(i, 3)
|
||||
elif ord(s[i]) shr 3 == 0b11110:
|
||||
assert(ord(s[i+1]) shr 6 == 0b10)
|
||||
assert(ord(s[i+2]) shr 6 == 0b10)
|
||||
assert(ord(s[i+3]) shr 6 == 0b10)
|
||||
result = TRune((ord(s[i]) and ones(3)) shl 18 or
|
||||
(ord(s[i+1]) and ones(6)) shl 12 or
|
||||
(ord(s[i+2]) and ones(6)) shl 6 or
|
||||
(ord(s[i+3]) and ones(6)))
|
||||
when doInc: inc(i, 4)
|
||||
else:
|
||||
assert(false)
|
||||
|
||||
proc runeAt*(s: string, i: int): TRune =
|
||||
## returns the unicode character in `s` at byte index `i`
|
||||
if ord(s[i]) <=% 127:
|
||||
result = ord(s[i])
|
||||
elif ord(s[i]) shr 5 == 0b110:
|
||||
assert(ord(s[i+1]) shr 6 == 0b10)
|
||||
result = (ord(s[i]) and ones(5)) shl 6 or (ord(s[i+1]) and ones(6))
|
||||
elif ord(s[i]) shr 4 == 0b1110:
|
||||
assert(ord(s[i+1]) shr 6 == 0b10)
|
||||
assert(ord(s[i+2]) shr 6 == 0b10)
|
||||
result = (ord(s[i]) and ones(4)) shl 12 or
|
||||
(ord(s[i+1]) and ones(6)) shl 6 or
|
||||
(ord(s[i+2]) and ones(6))
|
||||
elif ord(s[i]) shr 3 == 0b11110:
|
||||
assert(ord(s[i+1]) shr 6 == 0b10)
|
||||
assert(ord(s[i+2]) shr 6 == 0b10)
|
||||
assert(ord(s[i+3]) shr 6 == 0b10)
|
||||
result = (ord(s[i]) and ones(3)) shl 18 or
|
||||
(ord(s[i+1]) and ones(6)) shl 12 or
|
||||
(ord(s[i+2]) and ones(6)) shl 6 or
|
||||
(ord(s[i+3]) and ones(6))
|
||||
else:
|
||||
assert(false)
|
||||
|
||||
template fastRuneAt(s, i, result: expr): stmt =
|
||||
if ord(s[i]) <=% 127:
|
||||
result = ord(s[i])
|
||||
inc(i)
|
||||
elif ord(s[i]) shr 5 == 0b110:
|
||||
assert(ord(s[i+1]) shr 6 == 0b10)
|
||||
result = (ord(s[i]) and ones(5)) shl 6 or (ord(s[i+1]) and ones(6))
|
||||
inc(i, 2)
|
||||
elif ord(s[i]) shr 4 == 0b1110:
|
||||
assert(ord(s[i+1]) shr 6 == 0b10)
|
||||
assert(ord(s[i+2]) shr 6 == 0b10)
|
||||
result = (ord(s[i]) and ones(4)) shl 12 or
|
||||
(ord(s[i+1]) and ones(6)) shl 6 or
|
||||
(ord(s[i+2]) and ones(6))
|
||||
inc(i, 3)
|
||||
elif ord(s[i]) shr 3 == 0b11110:
|
||||
assert(ord(s[i+1]) shr 6 == 0b10)
|
||||
assert(ord(s[i+2]) shr 6 == 0b10)
|
||||
assert(ord(s[i+3]) shr 6 == 0b10)
|
||||
result = (ord(s[i]) and ones(3)) shl 18 or
|
||||
(ord(s[i+1]) and ones(6)) shl 12 or
|
||||
(ord(s[i+2]) and ones(6)) shl 6 or
|
||||
(ord(s[i+3]) and ones(6))
|
||||
inc(i, 4)
|
||||
else:
|
||||
assert(false)
|
||||
fastRuneAt(s, i, result, false)
|
||||
|
||||
proc toUTF8*(c: TRune): string =
|
||||
## converts a character into its UTF8 representation
|
||||
if c <=% 127:
|
||||
## converts a rune into its UTF8 representation
|
||||
var i = irune(c)
|
||||
if i <=% 127:
|
||||
result = newString(1)
|
||||
result[0] = chr(c)
|
||||
elif c <=% 0x07FF:
|
||||
result[0] = chr(i)
|
||||
elif i <=% 0x07FF:
|
||||
result = newString(2)
|
||||
result[0] = chr(c shr 6 or 0b110_0000)
|
||||
result[1] = chr(c and ones(6) or 0b10_000000)
|
||||
elif c <=% 0xFFFF:
|
||||
result[0] = chr(i shr 6 or 0b110_0000)
|
||||
result[1] = chr(i and ones(6) or 0b10_000000)
|
||||
elif i <=% 0xFFFF:
|
||||
result = newString(3)
|
||||
result[0] = chr(c shr 12 or 0b1110_0000)
|
||||
result[1] = chr(c shr 6 and ones(6) or 0b10_0000_00)
|
||||
result[2] = chr(c and ones(6) or 0b10_0000_00)
|
||||
elif c <=% 0x0010FFFF:
|
||||
result[0] = chr(i shr 12 or 0b1110_0000)
|
||||
result[1] = chr(i shr 6 and ones(6) or 0b10_0000_00)
|
||||
result[2] = chr(i and ones(6) or 0b10_0000_00)
|
||||
elif i <=% 0x0010FFFF:
|
||||
result = newString(4)
|
||||
result[0] = chr(c shr 18 or 0b1111_0000)
|
||||
result[1] = chr(c shr 12 and ones(6) or 0b10_0000_00)
|
||||
result[2] = chr(c shr 6 and ones(6) or 0b10_0000_00)
|
||||
result[3] = chr(c and ones(6) or 0b10_0000_00)
|
||||
result[0] = chr(i shr 18 or 0b1111_0000)
|
||||
result[1] = chr(i shr 12 and ones(6) or 0b10_0000_00)
|
||||
result[2] = chr(i shr 6 and ones(6) or 0b10_0000_00)
|
||||
result[3] = chr(i and ones(6) or 0b10_0000_00)
|
||||
else:
|
||||
assert false
|
||||
|
||||
@@ -1061,7 +1060,7 @@ const
|
||||
0x01f1, 501, # DZ Dz
|
||||
0x01f3, 499] # dz Dz
|
||||
|
||||
proc binarySearch(c: TRune, tab: openArray[TRune], len, stride: int): int =
|
||||
proc binarySearch(c: irune, tab: openArray[iRune], len, stride: int): int =
|
||||
var n = len
|
||||
var t = 0
|
||||
while n > 1:
|
||||
@@ -1078,32 +1077,39 @@ proc binarySearch(c: TRune, tab: openArray[TRune], len, stride: int): int =
|
||||
|
||||
proc toLower*(c: TRune): TRune =
|
||||
## Converts `c` into lower case. This works for any Unicode character.
|
||||
## If possible, prefer `toLower` over `toUpper`.
|
||||
var c = irune(c)
|
||||
var p = binarySearch(c, tolowerRanges, len(toLowerRanges) div 3, 3)
|
||||
if p >= 0 and c >= tolowerRanges[p] and c <= tolowerRanges[p+1]:
|
||||
return c + tolowerRanges[p+2] - 500
|
||||
return TRune(c + tolowerRanges[p+2] - 500)
|
||||
p = binarySearch(c, toLowerSinglets, len(toLowerSinglets) div 2, 2)
|
||||
if p >= 0 and c == toLowerSinglets[p]:
|
||||
return c + toLowerSinglets[p+1] - 500
|
||||
return c
|
||||
return TRune(c + toLowerSinglets[p+1] - 500)
|
||||
return TRune(c)
|
||||
|
||||
proc toUpper*(c: TRune): TRune =
|
||||
## Converts `c` into upper case. This works for any Unicode character.
|
||||
## If possible, prefer `toLower` over `toUpper`.
|
||||
var c = irune(c)
|
||||
var p = binarySearch(c, toUpperRanges, len(toUpperRanges) div 3, 3)
|
||||
if p >= 0 and c >= toUpperRanges[p] and c <= toUpperRanges[p+1]:
|
||||
return c + toUpperRanges[p+2] - 500
|
||||
return TRune(c + toUpperRanges[p+2] - 500)
|
||||
p = binarySearch(c, toUpperSinglets, len(toUpperSinglets) div 2, 2)
|
||||
if p >= 0 and c == toUpperSinglets[p]:
|
||||
return c + toUpperSinglets[p+1] - 500
|
||||
return c
|
||||
return TRune(c + toUpperSinglets[p+1] - 500)
|
||||
return TRune(c)
|
||||
|
||||
proc toTitle*(c: TRune): TRune =
|
||||
var c = irune(c)
|
||||
var p = binarySearch(c, toTitleSinglets, len(toTitleSinglets) div 2, 2)
|
||||
if p >= 0 and c == toTitleSinglets[p]:
|
||||
return c + toTitleSinglets[p+1] - 500
|
||||
return c
|
||||
return TRune(c + toTitleSinglets[p+1] - 500)
|
||||
return TRune(c)
|
||||
|
||||
proc isLower*(c: TRune): bool =
|
||||
## returns true iff `c` is a lower case Unicode character
|
||||
## If possible, prefer `isLower` over `isUpper`.
|
||||
var c = irune(c)
|
||||
# Note: toUpperRanges is correct here!
|
||||
var p = binarySearch(c, toUpperRanges, len(toUpperRanges) div 3, 3)
|
||||
if p >= 0 and c >= toUpperRanges[p] and c <= toUpperRanges[p+1]:
|
||||
@@ -1114,6 +1120,8 @@ proc isLower*(c: TRune): bool =
|
||||
|
||||
proc isUpper*(c: TRune): bool =
|
||||
## returns true iff `c` is a upper case Unicode character
|
||||
## If possible, prefer `isLower` over `isUpper`.
|
||||
var c = irune(c)
|
||||
# Note: toLowerRanges is correct here!
|
||||
var p = binarySearch(c, toLowerRanges, len(toLowerRanges) div 3, 3)
|
||||
if p >= 0 and c >= toLowerRanges[p] and c <= toLowerRanges[p+1]:
|
||||
@@ -1126,6 +1134,7 @@ proc isAlpha*(c: TRune): bool =
|
||||
## returns true iff `c` is an *alpha* Unicode character (i.e. a letter)
|
||||
if isUpper(c) or isLower(c):
|
||||
return true
|
||||
var c = irune(c)
|
||||
var p = binarySearch(c, alphaRanges, len(alphaRanges) div 2, 2)
|
||||
if p >= 0 and c >= alphaRanges[p] and c <= alphaRanges[p+1]:
|
||||
return true
|
||||
@@ -1138,6 +1147,7 @@ proc isTitle*(c: TRune): bool =
|
||||
|
||||
proc isWhiteSpace*(c: TRune): bool =
|
||||
## returns true iff `c` is a Unicode whitespace character
|
||||
var c = irune(c)
|
||||
var p = binarySearch(c, spaceRanges, len(spaceRanges) div 2, 2)
|
||||
if p >= 0 and c >= spaceRanges[p] and c <= spaceRanges[p+1]:
|
||||
return true
|
||||
@@ -1148,7 +1158,7 @@ iterator runes*(s: string): TRune =
|
||||
i = 0
|
||||
result: TRune
|
||||
while i < len(s):
|
||||
fastRuneAt(s, i, result)
|
||||
fastRuneAt(s, i, result, true)
|
||||
yield result
|
||||
|
||||
proc cmpRunesIgnoreCase*(a, b: string): int =
|
||||
@@ -1164,7 +1174,7 @@ proc cmpRunesIgnoreCase*(a, b: string): int =
|
||||
# slow path:
|
||||
fastRuneAt(a, i, ar)
|
||||
fastRuneAt(b, j, br)
|
||||
result = toLower(ar) - toLower(br)
|
||||
result = irune(toLower(ar)) - irune(toLower(br))
|
||||
if result != 0: return
|
||||
result = a.len - b.len
|
||||
|
||||
|
||||
@@ -13,9 +13,6 @@
|
||||
## Each module implicitly imports the System module; it may not be listed
|
||||
## explicitly. Because of this there can not be a user-defined module named
|
||||
## ``system``.
|
||||
##
|
||||
## *The good thing about reinventing the wheel is that you can get a
|
||||
## round one.*
|
||||
|
||||
{.push hints: off.}
|
||||
|
||||
@@ -58,11 +55,10 @@ proc defined*[T](x: T): bool {.magic: "Defined", noSideEffect.}
|
||||
## # provide our own toUpper proc here, because strutils is
|
||||
## # missing it.
|
||||
|
||||
proc definedInScope*[T](x: T, scope=0): bool {.
|
||||
proc definedInScope*[T](x: T): bool {.
|
||||
magic: "DefinedInScope", noSideEffect.}
|
||||
## Special comile-time procedure that checks whether `x` is
|
||||
## defined in the scope `scope`. `x` has to be an identifier.
|
||||
## 0 means the current scope, 1 means the scope above the current scope, etc.
|
||||
## defined in the current scope. `x` has to be an identifier.
|
||||
|
||||
# these require compiler magic:
|
||||
proc `not` *(x: bool): bool {.magic: "Not", noSideEffect.}
|
||||
@@ -617,6 +613,27 @@ proc `@` * [IDX, T](a: array[IDX, T]): seq[T] {.
|
||||
## sequences with the array constructor: ``@[1, 2, 3]`` has the type
|
||||
## ``seq[int]``, while ``[1, 2, 3]`` has the type ``array[0..2, int]``.
|
||||
|
||||
proc setLen*[T](s: var seq[T], newlen: int) {.
|
||||
magic: "SetLengthSeq", noSideEffect.}
|
||||
## sets the length of `s` to `newlen`.
|
||||
## ``T`` may be any sequence type.
|
||||
## If the current length is greater than the new length,
|
||||
## ``s`` will be truncated.
|
||||
|
||||
proc setLen*(s: var string, newlen: int) {.
|
||||
magic: "SetLengthStr", noSideEffect.}
|
||||
## sets the length of `s` to `newlen`.
|
||||
## If the current length is greater than the new length,
|
||||
## ``s`` will be truncated.
|
||||
|
||||
proc newString*(len: int): string {.
|
||||
magic: "NewString", importc: "mnewString", noSideEffect.}
|
||||
## returns a new string of length ``len`` but with uninitialized
|
||||
## content. One needs to fill the string character after character
|
||||
## with the index operator ``s[i]``. This procedure exists only for
|
||||
## optimization purposes; the same effect can be achieved with the
|
||||
## ``&`` operator.
|
||||
|
||||
# concat operator:
|
||||
proc `&` * (x: string, y: char): string {.
|
||||
magic: "ConStrStr", noSideEffect, merge.}
|
||||
@@ -651,12 +668,15 @@ else:
|
||||
"""
|
||||
|
||||
proc add *[T](x: var seq[T], y: T) {.magic: "AppendSeqElem", noSideEffect.}
|
||||
proc add *[T](x: var seq[T], y: seq[T]) {.magic: "AppendSeqSeq", noSideEffect.}
|
||||
proc add *[T](x: var seq[T], y: seq[T]) {.noSideEffect.} =
|
||||
## Generic proc for adding a data item `y` to a container `x`.
|
||||
## For containers that have an order, `add` means *append*. New generic
|
||||
## containers should also call their adding proc `add` for consistency.
|
||||
## Generic code becomes much easier to write if the Nimrod naming scheme is
|
||||
## respected.
|
||||
var xl = x.len
|
||||
setLen(x, xl + y.len)
|
||||
for i in 0..high(y): x[xl+i] = y[i]
|
||||
|
||||
proc repr*[T](x: T): string {.magic: "Repr", noSideEffect.}
|
||||
## takes any Nimrod variable and returns its string representation. It
|
||||
@@ -798,20 +818,6 @@ proc copy*(s: string, first, last: int): string {.
|
||||
## the first and last characters that shall be copied. If ``last``
|
||||
## is omitted, it is treated as ``high(s)``.
|
||||
|
||||
proc setLen*(s: var string, newlen: int) {.
|
||||
magic: "SetLengthStr", noSideEffect.}
|
||||
## sets the length of `s` to `newlen`.
|
||||
## If the current length is greater than the new length,
|
||||
## ``s`` will be truncated.
|
||||
|
||||
proc newString*(len: int): string {.
|
||||
magic: "NewString", importc: "mnewString", noSideEffect.}
|
||||
## returns a new string of length ``len`` but with uninitialized
|
||||
## content. One needs to fill the string character after character
|
||||
## with the index operator ``s[i]``. This procedure exists only for
|
||||
## optimization purposes; the same effect can be achieved with the
|
||||
## ``&`` operator.
|
||||
|
||||
proc zeroMem*(p: Pointer, size: int) {.importc, noDecl.}
|
||||
## overwrites the contents of the memory at ``p`` with the value 0.
|
||||
## Exactly ``size`` bytes will be overwritten. Like any procedure
|
||||
@@ -861,13 +867,6 @@ proc dealloc*(p: Pointer) {.noconv.}
|
||||
## or other memory may be corrupted. So this procedure is really
|
||||
## *unsafe*.
|
||||
|
||||
proc setLen*[T](s: var seq[T], newlen: int) {.
|
||||
magic: "SetLengthSeq", noSideEffect.}
|
||||
## sets the length of `s` to `newlen`.
|
||||
## ``T`` may be any sequence type.
|
||||
## If the current length is greater than the new length,
|
||||
## ``s`` will be truncated.
|
||||
|
||||
proc assert*(cond: bool) {.magic: "Assert", noSideEffect.}
|
||||
## provides a means to implement `programming by contracts` in Nimrod.
|
||||
## ``assert`` evaluates expression ``cond`` and if ``cond`` is false, it
|
||||
@@ -1195,6 +1194,10 @@ proc GC_unref*[T](x: seq[T]) {.magic: "GCunref".}
|
||||
proc GC_unref*(x: string) {.magic: "GCunref".}
|
||||
## see the documentation of `GC_ref`.
|
||||
|
||||
template accumulateResult*(iter: expr) =
|
||||
## helps to convert an iterator to a proc.
|
||||
result = @[]
|
||||
for x in iter: add(result, x)
|
||||
|
||||
{.push checks: off, line_dir: off, debugger: off.}
|
||||
# obviously we cannot generate checking operations here :-)
|
||||
|
||||
@@ -74,26 +74,16 @@ proc hashString(s: string): int {.compilerproc.} =
|
||||
h = h +% h shl 15
|
||||
result = h
|
||||
|
||||
# copy(s: string, start = 0): string
|
||||
# {.extern: "copyStr", noDecl, noSideEffect.}
|
||||
# copy(s: string, start, len: int): string
|
||||
# {.extern: "copyStrLen", noDecl, noSideEffect.}
|
||||
#
|
||||
# setLength(var s: string, newlen: int)
|
||||
# {.extern: "setLengthStr", noDecl, noSideEffect.}
|
||||
|
||||
proc copyStrLast(s: NimString, start, last: int): NimString {.exportc.} =
|
||||
var
|
||||
len: int
|
||||
if start >= s.len: return mnewString(0) # BUGFIX
|
||||
if last >= s.len:
|
||||
len = s.len - start # - 1 + 1
|
||||
var start = max(start, 0)
|
||||
var len = min(last, s.len-1) - start + 1
|
||||
if len > 0:
|
||||
result = rawNewString(len)
|
||||
result.len = len
|
||||
c_memcpy(result.data, addr(s.data[start]), len * sizeof(Char))
|
||||
result.data[len] = '\0'
|
||||
else:
|
||||
len = last - start + 1
|
||||
result = rawNewString(len)
|
||||
result.len = len
|
||||
c_memcpy(result.data, addr(s.data[start]), len * sizeof(Char))
|
||||
result.data[len] = '\0'
|
||||
result = mnewString(0)
|
||||
|
||||
proc copyStr(s: NimString, start: int): NimString {.exportc.} =
|
||||
return copyStrLast(s, start, s.len-1)
|
||||
|
||||
@@ -1,110 +1,110 @@
|
||||
#
|
||||
#
|
||||
# Nimrod's Runtime Library
|
||||
# (c) Copyright 2009 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This module implements a small wrapper for some needed Win API procedures,
|
||||
## so that the Nimrod compiler does not depend on the huge Windows module.
|
||||
|
||||
type
|
||||
THandle* = int
|
||||
WINBOOL* = int32
|
||||
|
||||
TSECURITY_ATTRIBUTES* {.final, pure.} = object
|
||||
nLength*: int32
|
||||
lpSecurityDescriptor*: pointer
|
||||
bInheritHandle*: WINBOOL
|
||||
|
||||
TSTARTUPINFO* {.final, pure.} = object
|
||||
cb*: int32
|
||||
lpReserved*: cstring
|
||||
lpDesktop*: cstring
|
||||
lpTitle*: cstring
|
||||
dwX*: int32
|
||||
dwY*: int32
|
||||
dwXSize*: int32
|
||||
dwYSize*: int32
|
||||
dwXCountChars*: int32
|
||||
dwYCountChars*: int32
|
||||
dwFillAttribute*: int32
|
||||
dwFlags*: int32
|
||||
wShowWindow*: int16
|
||||
cbReserved2*: int16
|
||||
lpReserved2*: pointer
|
||||
hStdInput*: THANDLE
|
||||
hStdOutput*: THANDLE
|
||||
hStdError*: THANDLE
|
||||
|
||||
TPROCESS_INFORMATION* {.final, pure.} = object
|
||||
hProcess*: THANDLE
|
||||
hThread*: THANDLE
|
||||
dwProcessId*: int32
|
||||
dwThreadId*: int32
|
||||
|
||||
const
|
||||
STARTF_USESHOWWINDOW* = 1'i32
|
||||
STARTF_USESTDHANDLES* = 256'i32
|
||||
HIGH_PRIORITY_CLASS* = 128'i32
|
||||
IDLE_PRIORITY_CLASS* = 64'i32
|
||||
NORMAL_PRIORITY_CLASS* = 32'i32
|
||||
REALTIME_PRIORITY_CLASS* = 256'i32
|
||||
WAIT_TIMEOUT* = 0x00000102'i32
|
||||
INFINITE* = -1'i32
|
||||
|
||||
STD_INPUT_HANDLE* = -10'i32
|
||||
STD_OUTPUT_HANDLE* = -11'i32
|
||||
STD_ERROR_HANDLE* = -12'i32
|
||||
|
||||
proc CloseHandle*(hObject: THANDLE): WINBOOL {.stdcall, dynlib: "kernel32",
|
||||
importc: "CloseHandle".}
|
||||
|
||||
proc ReadFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToRead: int32,
|
||||
lpNumberOfBytesRead: var int32, lpOverlapped: pointer): WINBOOL{.
|
||||
stdcall, dynlib: "kernel32", importc: "ReadFile".}
|
||||
|
||||
proc WriteFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToWrite: int32,
|
||||
lpNumberOfBytesWritten: var int32,
|
||||
lpOverlapped: pointer): WINBOOL{.
|
||||
stdcall, dynlib: "kernel32", importc: "WriteFile".}
|
||||
|
||||
proc CreatePipe*(hReadPipe, hWritePipe: var THandle,
|
||||
lpPipeAttributes: var TSECURITY_ATTRIBUTES,
|
||||
nSize: int32): WINBOOL{.
|
||||
stdcall, dynlib: "kernel32", importc: "CreatePipe".}
|
||||
|
||||
proc CreateProcess*(lpApplicationName, lpCommandLine: cstring,
|
||||
lpProcessAttributes: ptr TSECURITY_ATTRIBUTES,
|
||||
lpThreadAttributes: ptr TSECURITY_ATTRIBUTES,
|
||||
bInheritHandles: WINBOOL, dwCreationFlags: int32,
|
||||
lpEnvironment: pointer, lpCurrentDirectory: cstring,
|
||||
lpStartupInfo: var TSTARTUPINFO,
|
||||
lpProcessInformation: var TPROCESS_INFORMATION): WINBOOL{.
|
||||
stdcall, dynlib: "kernel32", importc: "CreateProcessA".}
|
||||
|
||||
proc SuspendThread*(hThread: THANDLE): int32 {.stdcall, dynlib: "kernel32",
|
||||
importc: "SuspendThread".}
|
||||
proc ResumeThread*(hThread: THANDLE): int32 {.stdcall, dynlib: "kernel32",
|
||||
importc: "ResumeThread".}
|
||||
|
||||
proc WaitForSingleObject*(hHandle: THANDLE, dwMilliseconds: int32): int32 {.
|
||||
stdcall, dynlib: "kernel32", importc: "WaitForSingleObject".}
|
||||
|
||||
proc TerminateProcess*(hProcess: THANDLE, uExitCode: int): WINBOOL {.stdcall,
|
||||
dynlib: "kernel32", importc: "TerminateProcess".}
|
||||
|
||||
proc GetExitCodeProcess*(hProcess: THANDLE, lpExitCode: var int32): WINBOOL {.
|
||||
stdcall, dynlib: "kernel32", importc: "GetExitCodeProcess".}
|
||||
|
||||
proc GetStdHandle*(nStdHandle: int32): THANDLE {.stdcall, dynlib: "kernel32",
|
||||
importc: "GetStdHandle".}
|
||||
proc SetStdHandle*(nStdHandle: int32, hHandle: THANDLE): WINBOOL {.stdcall,
|
||||
dynlib: "kernel32", importc: "SetStdHandle".}
|
||||
proc FlushFileBuffers*(hFile: THANDLE): WINBOOL {.stdcall, dynlib: "kernel32",
|
||||
importc: "FlushFileBuffers".}
|
||||
#
|
||||
#
|
||||
# Nimrod's Runtime Library
|
||||
# (c) Copyright 2009 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This module implements a small wrapper for some needed Win API procedures,
|
||||
## so that the Nimrod compiler does not depend on the huge Windows module.
|
||||
|
||||
type
|
||||
THandle* = int
|
||||
WINBOOL* = int32
|
||||
|
||||
TSECURITY_ATTRIBUTES* {.final, pure.} = object
|
||||
nLength*: int32
|
||||
lpSecurityDescriptor*: pointer
|
||||
bInheritHandle*: WINBOOL
|
||||
|
||||
TSTARTUPINFO* {.final, pure.} = object
|
||||
cb*: int32
|
||||
lpReserved*: cstring
|
||||
lpDesktop*: cstring
|
||||
lpTitle*: cstring
|
||||
dwX*: int32
|
||||
dwY*: int32
|
||||
dwXSize*: int32
|
||||
dwYSize*: int32
|
||||
dwXCountChars*: int32
|
||||
dwYCountChars*: int32
|
||||
dwFillAttribute*: int32
|
||||
dwFlags*: int32
|
||||
wShowWindow*: int16
|
||||
cbReserved2*: int16
|
||||
lpReserved2*: pointer
|
||||
hStdInput*: THANDLE
|
||||
hStdOutput*: THANDLE
|
||||
hStdError*: THANDLE
|
||||
|
||||
TPROCESS_INFORMATION* {.final, pure.} = object
|
||||
hProcess*: THANDLE
|
||||
hThread*: THANDLE
|
||||
dwProcessId*: int32
|
||||
dwThreadId*: int32
|
||||
|
||||
const
|
||||
STARTF_USESHOWWINDOW* = 1'i32
|
||||
STARTF_USESTDHANDLES* = 256'i32
|
||||
HIGH_PRIORITY_CLASS* = 128'i32
|
||||
IDLE_PRIORITY_CLASS* = 64'i32
|
||||
NORMAL_PRIORITY_CLASS* = 32'i32
|
||||
REALTIME_PRIORITY_CLASS* = 256'i32
|
||||
WAIT_TIMEOUT* = 0x00000102'i32
|
||||
INFINITE* = -1'i32
|
||||
|
||||
STD_INPUT_HANDLE* = -10'i32
|
||||
STD_OUTPUT_HANDLE* = -11'i32
|
||||
STD_ERROR_HANDLE* = -12'i32
|
||||
|
||||
proc CloseHandle*(hObject: THANDLE): WINBOOL {.stdcall, dynlib: "kernel32",
|
||||
importc: "CloseHandle".}
|
||||
|
||||
proc ReadFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToRead: int32,
|
||||
lpNumberOfBytesRead: var int32, lpOverlapped: pointer): WINBOOL{.
|
||||
stdcall, dynlib: "kernel32", importc: "ReadFile".}
|
||||
|
||||
proc WriteFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToWrite: int32,
|
||||
lpNumberOfBytesWritten: var int32,
|
||||
lpOverlapped: pointer): WINBOOL{.
|
||||
stdcall, dynlib: "kernel32", importc: "WriteFile".}
|
||||
|
||||
proc CreatePipe*(hReadPipe, hWritePipe: var THandle,
|
||||
lpPipeAttributes: var TSECURITY_ATTRIBUTES,
|
||||
nSize: int32): WINBOOL{.
|
||||
stdcall, dynlib: "kernel32", importc: "CreatePipe".}
|
||||
|
||||
proc CreateProcess*(lpApplicationName, lpCommandLine: cstring,
|
||||
lpProcessAttributes: ptr TSECURITY_ATTRIBUTES,
|
||||
lpThreadAttributes: ptr TSECURITY_ATTRIBUTES,
|
||||
bInheritHandles: WINBOOL, dwCreationFlags: int32,
|
||||
lpEnvironment: pointer, lpCurrentDirectory: cstring,
|
||||
lpStartupInfo: var TSTARTUPINFO,
|
||||
lpProcessInformation: var TPROCESS_INFORMATION): WINBOOL{.
|
||||
stdcall, dynlib: "kernel32", importc: "CreateProcessA".}
|
||||
|
||||
proc SuspendThread*(hThread: THANDLE): int32 {.stdcall, dynlib: "kernel32",
|
||||
importc: "SuspendThread".}
|
||||
proc ResumeThread*(hThread: THANDLE): int32 {.stdcall, dynlib: "kernel32",
|
||||
importc: "ResumeThread".}
|
||||
|
||||
proc WaitForSingleObject*(hHandle: THANDLE, dwMilliseconds: int32): int32 {.
|
||||
stdcall, dynlib: "kernel32", importc: "WaitForSingleObject".}
|
||||
|
||||
proc TerminateProcess*(hProcess: THANDLE, uExitCode: int): WINBOOL {.stdcall,
|
||||
dynlib: "kernel32", importc: "TerminateProcess".}
|
||||
|
||||
proc GetExitCodeProcess*(hProcess: THANDLE, lpExitCode: var int32): WINBOOL {.
|
||||
stdcall, dynlib: "kernel32", importc: "GetExitCodeProcess".}
|
||||
|
||||
proc GetStdHandle*(nStdHandle: int32): THANDLE {.stdcall, dynlib: "kernel32",
|
||||
importc: "GetStdHandle".}
|
||||
proc SetStdHandle*(nStdHandle: int32, hHandle: THANDLE): WINBOOL {.stdcall,
|
||||
dynlib: "kernel32", importc: "SetStdHandle".}
|
||||
proc FlushFileBuffers*(hFile: THANDLE): WINBOOL {.stdcall, dynlib: "kernel32",
|
||||
importc: "FlushFileBuffers".}
|
||||
|
||||
proc GetLastError*(): int32 {.importc, stdcall, dynlib: "kernel32".}
|
||||
proc FormatMessageA*(dwFlags: int32, lpSource: pointer,
|
||||
|
||||
259
lib/wrappers/tre/config.h
Normal file
259
lib/wrappers/tre/config.h
Normal file
@@ -0,0 +1,259 @@
|
||||
/* config.h. Generated from config.h.in by configure. */
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
|
||||
systems. This function is required for `alloca.c' support on those systems.
|
||||
*/
|
||||
/* #undef CRAY_STACKSEG_END */
|
||||
|
||||
/* Define to 1 if using `alloca.c'. */
|
||||
/* #undef C_ALLOCA */
|
||||
|
||||
/* Define to 1 if translation of program messages to the user's native
|
||||
language is requested. */
|
||||
#define ENABLE_NLS 1
|
||||
|
||||
/* Define to 1 if you have `alloca', as a function or macro. */
|
||||
/* #undef HAVE_ALLOCA */
|
||||
|
||||
/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
|
||||
*/
|
||||
/* #undef HAVE_ALLOCA_H */
|
||||
|
||||
/* Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the
|
||||
CoreFoundation framework. */
|
||||
#define HAVE_CFLOCALECOPYCURRENT 1
|
||||
|
||||
/* Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in
|
||||
the CoreFoundation framework. */
|
||||
#define HAVE_CFPREFERENCESCOPYAPPVALUE 1
|
||||
|
||||
/* Define if the GNU dcgettext() function is already present or preinstalled.
|
||||
*/
|
||||
#define HAVE_DCGETTEXT 1
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#define HAVE_DLFCN_H 1
|
||||
|
||||
/* Define to 1 if you have the <getopt.h> header file. */
|
||||
#define HAVE_GETOPT_H 1
|
||||
|
||||
/* Define to 1 if you have the `getopt_long' function. */
|
||||
#define HAVE_GETOPT_LONG 1
|
||||
|
||||
/* Define if the GNU gettext() function is already present or preinstalled. */
|
||||
#define HAVE_GETTEXT 1
|
||||
|
||||
/* Define if you have the iconv() function and it works. */
|
||||
#define HAVE_ICONV 1
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
/* #undef HAVE_INTTYPES_H */
|
||||
|
||||
/* Define to 1 if you have the `isascii' function. */
|
||||
#define HAVE_ISASCII 1
|
||||
|
||||
/* Define to 1 if you have the `isblank' function. */
|
||||
#define HAVE_ISBLANK 1
|
||||
|
||||
/* Define to 1 if you have the `iswascii' function or macro. */
|
||||
/* #undef HAVE_ISWASCII */
|
||||
|
||||
/* Define to 1 if you have the `iswblank' function or macro. */
|
||||
/* #undef HAVE_ISWBLANK */
|
||||
|
||||
/* Define to 1 if you have the `iswctype' function or macro. */
|
||||
/* #undef HAVE_ISWCTYPE */
|
||||
|
||||
/* Define to 1 if you have the `iswlower' function or macro. */
|
||||
/* #undef HAVE_ISWLOWER */
|
||||
|
||||
/* Define to 1 if you have the `iswupper' function or macro. */
|
||||
/* #undef HAVE_ISWUPPER */
|
||||
|
||||
/* Define to 1 if you have the <libutf8.h> header file. */
|
||||
/* #undef HAVE_LIBUTF8_H */
|
||||
|
||||
/* Define to 1 if you have the `mbrtowc' function or macro. */
|
||||
/* #undef HAVE_MBRTOWC */
|
||||
|
||||
/* Define to 1 if the system has the type `mbstate_t'. */
|
||||
/* #undef HAVE_MBSTATE_T */
|
||||
|
||||
/* Define to 1 if you have the `mbtowc' function or macro. */
|
||||
/* #undef HAVE_MBTOWC */
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
/* #undef HAVE_MEMORY_H */
|
||||
|
||||
/* Define to 1 if you have the <regex.h> header file. */
|
||||
/* #undef HAVE_REGEX_H */
|
||||
|
||||
/* Define to 1 if the system has the type `reg_errcode_t'. */
|
||||
/* #undef HAVE_REG_ERRCODE_T */
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
/* #undef HAVE_STDINT_H */
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
/* #undef HAVE_STDLIB_H */
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
/* #undef HAVE_STRINGS_H */
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
/* #undef HAVE_STRING_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
/* #undef HAVE_SYS_STAT_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
/* #undef HAVE_SYS_TYPES_H */
|
||||
|
||||
/* Define to 1 if you have the `towlower' function or macro. */
|
||||
/* #undef HAVE_TOWLOWER */
|
||||
|
||||
/* Define to 1 if you have the `towupper' function or macro. */
|
||||
/* #undef HAVE_TOWUPPER */
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
/* #undef HAVE_UNISTD_H */
|
||||
|
||||
/* Define to 1 if you have the <wchar.h> header file. */
|
||||
/* #undef HAVE_WCHAR_H */
|
||||
|
||||
/* Define to 1 if the system has the type `wchar_t'. */
|
||||
/* #undef HAVE_WCHAR_T */
|
||||
|
||||
/* Define to 1 if you have the `wcschr' function or macro. */
|
||||
/* #undef HAVE_WCSCHR */
|
||||
|
||||
/* Define to 1 if you have the `wcscpy' function or macro. */
|
||||
/* #undef HAVE_WCSCPY */
|
||||
|
||||
/* Define to 1 if you have the `wcslen' function or macro. */
|
||||
/* #undef HAVE_WCSLEN */
|
||||
|
||||
/* Define to 1 if you have the `wcsncpy' function or macro. */
|
||||
/* #undef HAVE_WCSNCPY */
|
||||
|
||||
/* Define to 1 if you have the `wcsrtombs' function or macro. */
|
||||
/* #undef HAVE_WCSRTOMBS */
|
||||
|
||||
/* Define to 1 if you have the `wcstombs' function or macro. */
|
||||
/* #undef HAVE_WCSTOMBS */
|
||||
|
||||
/* Define to 1 if you have the `wctype' function or macro. */
|
||||
/* #undef HAVE_WCTYPE */
|
||||
|
||||
/* Define to 1 if you have the <wctype.h> header file. */
|
||||
/* #undef HAVE_WCTYPE_H */
|
||||
|
||||
/* Define to 1 if the system has the type `wint_t'. */
|
||||
/* #undef HAVE_WINT_T */
|
||||
|
||||
/* Define if you want to disable debug assertions. */
|
||||
#define NDEBUG 1
|
||||
|
||||
/* Define to 1 if your C compiler doesn't accept -c and -o together. */
|
||||
/* #undef NO_MINUS_C_MINUS_O */
|
||||
|
||||
/* Name of package */
|
||||
#define PACKAGE "tre"
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#define PACKAGE_BUGREPORT "tre-general@lists.laurikari.net"
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME "TRE"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "TRE 0.7.6"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "tre"
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "0.7.6"
|
||||
|
||||
/* If using the C implementation of alloca, define if you know the
|
||||
direction of stack growth for your system; otherwise it will be
|
||||
automatically deduced at runtime.
|
||||
STACK_DIRECTION > 0 => grows toward higher addresses
|
||||
STACK_DIRECTION < 0 => grows toward lower addresses
|
||||
STACK_DIRECTION = 0 => direction of growth unknown */
|
||||
/* #undef STACK_DIRECTION */
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* Define if you want to enable approximate matching functionality. */
|
||||
/* #undef TRE_APPROX */
|
||||
|
||||
/* Define if you want TRE to print debug messages to stdout. */
|
||||
/* #undef TRE_DEBUG */
|
||||
|
||||
/* Define to enable multibyte character set support. */
|
||||
/* #undef TRE_MULTIBYTE */
|
||||
|
||||
/* Define to a field in the regex_t struct where TRE should store a pointer to
|
||||
the internal tre_tnfa_t structure */
|
||||
#define TRE_REGEX_T_FIELD value
|
||||
|
||||
/* Define to the absolute path to the system regex.h */
|
||||
/* #undef TRE_SYSTEM_REGEX_H_PATH */
|
||||
|
||||
/* Define if you want TRE to use alloca() instead of malloc() when allocating
|
||||
memory needed for regexec operations. */
|
||||
/* #undef TRE_USE_ALLOCA */
|
||||
|
||||
/* Define to include the system regex.h from TRE regex.h */
|
||||
/* #undef TRE_USE_SYSTEM_REGEX_H */
|
||||
|
||||
/* TRE version string. */
|
||||
#define TRE_VERSION "0.7.6"
|
||||
|
||||
/* TRE version level 1. */
|
||||
#define TRE_VERSION_1 0
|
||||
|
||||
/* TRE version level 2. */
|
||||
#define TRE_VERSION_2 7
|
||||
|
||||
/* TRE version level 3. */
|
||||
#define TRE_VERSION_3 6
|
||||
|
||||
/* Define to enable wide character (wchar_t) support. */
|
||||
/* #undef TRE_WCHAR */
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "0.7.6"
|
||||
|
||||
/* Define to the maximum value of wchar_t if not already defined elsewhere */
|
||||
/* #undef WCHAR_MAX */
|
||||
|
||||
/* Define if wchar_t is signed */
|
||||
/* #undef WCHAR_T_SIGNED */
|
||||
|
||||
/* Define if wchar_t is unsigned */
|
||||
/* #undef WCHAR_T_UNSIGNED */
|
||||
|
||||
/* Number of bits in a file offset, on hosts where this is settable. */
|
||||
/* #undef _FILE_OFFSET_BITS */
|
||||
|
||||
/* Define to enable GNU extensions in glibc */
|
||||
#define _GNU_SOURCE 1
|
||||
|
||||
/* Define for large files, on AIX-style hosts. */
|
||||
/* #undef _LARGE_FILES */
|
||||
|
||||
/* Define on IRIX */
|
||||
/* #undef _REGCOMP_INTERNAL */
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
/* #undef const */
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
/* #undef inline */
|
||||
#endif
|
||||
8873
lib/wrappers/tre/tre_all.c
Normal file
8873
lib/wrappers/tre/tre_all.c
Normal file
File diff suppressed because it is too large
Load Diff
1
lib/wrappers/tre/version.txt
Normal file
1
lib/wrappers/tre/version.txt
Normal file
@@ -0,0 +1 @@
|
||||
0.7.6
|
||||
147
nim/ast.pas
147
nim/ast.pas
@@ -84,20 +84,21 @@ type
|
||||
nkObjDownConv, nkObjUpConv, nkChckRangeF, nkChckRange64,
|
||||
nkChckRange, nkStringToCString, nkCStringToString, nkPassAsOpenArray,
|
||||
nkAsgn, nkFastAsgn, nkGenericParams, nkFormalParams,
|
||||
nkOfInherit, nkModule, nkProcDef, nkConverterDef,
|
||||
nkMacroDef, nkTemplateDef, nkIteratorDef, nkOfBranch,
|
||||
nkElifBranch, nkExceptBranch, nkElse, nkMacroStmt,
|
||||
nkAsmStmt, nkPragma, nkIfStmt, nkWhenStmt,
|
||||
nkForStmt, nkWhileStmt, nkCaseStmt, nkVarSection,
|
||||
nkConstSection, nkConstDef, nkTypeSection, nkTypeDef,
|
||||
nkYieldStmt, nkTryStmt, nkFinally, nkRaiseStmt,
|
||||
nkReturnStmt, nkBreakStmt, nkContinueStmt, nkBlockStmt,
|
||||
nkDiscardStmt, nkStmtList, nkImportStmt, nkFromStmt,
|
||||
nkIncludeStmt, nkCommentStmt, nkStmtListExpr, nkBlockExpr,
|
||||
nkStmtListType, nkBlockType, nkTypeOfExpr, nkObjectTy,
|
||||
nkTupleTy, nkRecList, nkRecCase, nkRecWhen,
|
||||
nkRefTy, nkPtrTy, nkVarTy, nkDistinctTy,
|
||||
nkProcTy, nkEnumTy, nkEnumFieldDef, nkReturnToken);
|
||||
nkOfInherit, nkModule, nkProcDef, nkMethodDef,
|
||||
nkConverterDef, nkMacroDef, nkTemplateDef, nkIteratorDef,
|
||||
nkOfBranch, nkElifBranch, nkExceptBranch, nkElse,
|
||||
nkMacroStmt, nkAsmStmt, nkPragma, nkIfStmt,
|
||||
nkWhenStmt, nkForStmt, nkWhileStmt, nkCaseStmt,
|
||||
nkVarSection, nkConstSection, nkConstDef, nkTypeSection,
|
||||
nkTypeDef, nkYieldStmt, nkTryStmt, nkFinally,
|
||||
nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt,
|
||||
nkBlockStmt, nkDiscardStmt, nkStmtList, nkImportStmt,
|
||||
nkFromStmt, nkIncludeStmt, nkCommentStmt, nkStmtListExpr,
|
||||
nkBlockExpr, nkStmtListType, nkBlockType, nkTypeOfExpr,
|
||||
nkObjectTy, nkTupleTy, nkRecList, nkRecCase,
|
||||
nkRecWhen, nkRefTy, nkPtrTy, nkVarTy,
|
||||
nkDistinctTy, nkProcTy, nkEnumTy, nkEnumFieldDef,
|
||||
nkReturnToken);
|
||||
TNodeKinds = set of TNodeKind;
|
||||
const
|
||||
NodeKindToStr: array [TNodeKind] of string = (
|
||||
@@ -118,20 +119,21 @@ const
|
||||
'nkObjDownConv', 'nkObjUpConv', 'nkChckRangeF', 'nkChckRange64',
|
||||
'nkChckRange', 'nkStringToCString', 'nkCStringToString', 'nkPassAsOpenArray',
|
||||
'nkAsgn', 'nkFastAsgn', 'nkGenericParams', 'nkFormalParams',
|
||||
'nkOfInherit', 'nkModule', 'nkProcDef', 'nkConverterDef',
|
||||
'nkMacroDef', 'nkTemplateDef', 'nkIteratorDef', 'nkOfBranch',
|
||||
'nkElifBranch', 'nkExceptBranch', 'nkElse', 'nkMacroStmt',
|
||||
'nkAsmStmt', 'nkPragma', 'nkIfStmt', 'nkWhenStmt',
|
||||
'nkForStmt', 'nkWhileStmt', 'nkCaseStmt', 'nkVarSection',
|
||||
'nkConstSection', 'nkConstDef', 'nkTypeSection', 'nkTypeDef',
|
||||
'nkYieldStmt', 'nkTryStmt', 'nkFinally', 'nkRaiseStmt',
|
||||
'nkReturnStmt', 'nkBreakStmt', 'nkContinueStmt', 'nkBlockStmt',
|
||||
'nkDiscardStmt', 'nkStmtList', 'nkImportStmt', 'nkFromStmt',
|
||||
'nkIncludeStmt', 'nkCommentStmt', 'nkStmtListExpr', 'nkBlockExpr',
|
||||
'nkStmtListType', 'nkBlockType', 'nkTypeOfExpr', 'nkObjectTy',
|
||||
'nkTupleTy', 'nkRecList', 'nkRecCase', 'nkRecWhen',
|
||||
'nkRefTy', 'nkPtrTy', 'nkVarTy', 'nkDistinctTy',
|
||||
'nkProcTy', 'nkEnumTy', 'nkEnumFieldDef', 'nkReturnToken');
|
||||
'nkOfInherit', 'nkModule', 'nkProcDef', 'nkMethodDef',
|
||||
'nkConverterDef', 'nkMacroDef', 'nkTemplateDef', 'nkIteratorDef',
|
||||
'nkOfBranch', 'nkElifBranch', 'nkExceptBranch', 'nkElse',
|
||||
'nkMacroStmt', 'nkAsmStmt', 'nkPragma', 'nkIfStmt',
|
||||
'nkWhenStmt', 'nkForStmt', 'nkWhileStmt', 'nkCaseStmt',
|
||||
'nkVarSection', 'nkConstSection', 'nkConstDef', 'nkTypeSection',
|
||||
'nkTypeDef', 'nkYieldStmt', 'nkTryStmt', 'nkFinally',
|
||||
'nkRaiseStmt', 'nkReturnStmt', 'nkBreakStmt', 'nkContinueStmt',
|
||||
'nkBlockStmt', 'nkDiscardStmt', 'nkStmtList', 'nkImportStmt',
|
||||
'nkFromStmt', 'nkIncludeStmt', 'nkCommentStmt', 'nkStmtListExpr',
|
||||
'nkBlockExpr', 'nkStmtListType', 'nkBlockType', 'nkTypeOfExpr',
|
||||
'nkObjectTy', 'nkTupleTy', 'nkRecList', 'nkRecCase',
|
||||
'nkRecWhen', 'nkRefTy', 'nkPtrTy', 'nkVarTy',
|
||||
'nkDistinctTy', 'nkProcTy', 'nkEnumTy', 'nkEnumFieldDef',
|
||||
'nkReturnToken');
|
||||
type
|
||||
TSymFlag = (
|
||||
sfUsed, sfStar, sfMinus, sfInInterface,
|
||||
@@ -200,17 +202,19 @@ type
|
||||
TSymKind = (
|
||||
skUnknown, skConditional, skDynLib, skParam,
|
||||
skGenericParam, skTemp, skType, skConst,
|
||||
skVar, skProc, skIterator, skConverter,
|
||||
skMacro, skTemplate, skField, skEnumField,
|
||||
skForVar, skModule, skLabel, skStub);
|
||||
skVar, skProc, skMethod, skIterator,
|
||||
skConverter, skMacro, skTemplate, skField,
|
||||
skEnumField, skForVar, skModule, skLabel,
|
||||
skStub);
|
||||
TSymKinds = set of TSymKind;
|
||||
const
|
||||
SymKindToStr: array [TSymKind] of string = (
|
||||
'skUnknown', 'skConditional', 'skDynLib', 'skParam',
|
||||
'skGenericParam', 'skTemp', 'skType', 'skConst',
|
||||
'skVar', 'skProc', 'skIterator', 'skConverter',
|
||||
'skMacro', 'skTemplate', 'skField', 'skEnumField',
|
||||
'skForVar', 'skModule', 'skLabel', 'skStub');
|
||||
'skVar', 'skProc', 'skMethod', 'skIterator',
|
||||
'skConverter', 'skMacro', 'skTemplate', 'skField',
|
||||
'skEnumField', 'skForVar', 'skModule', 'skLabel',
|
||||
'skStub');
|
||||
{[[[end]]]}
|
||||
|
||||
type
|
||||
@@ -223,9 +227,9 @@ type
|
||||
// if (i+1) % 6 == 0: cog.outl("")
|
||||
//cog.outl("m" + magics[-1])
|
||||
//]]]
|
||||
mNone, mDefined, mLow, mHigh, mSizeOf, mIs,
|
||||
mEcho, mSucc, mPred, mInc, mDec, mOrd,
|
||||
mNew, mNewFinalize, mNewSeq, mRegisterFinalizer, mLengthOpenArray, mLengthStr,
|
||||
mNone, mDefined, mDefinedInScope, mLow, mHigh, mSizeOf,
|
||||
mIs, mEcho, mSucc, mPred, mInc, mDec,
|
||||
mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray, mLengthStr,
|
||||
mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr,
|
||||
mGCref, mGCunref, mAddI, mSubI, mMulI, mDivI,
|
||||
mModI, mAddI64, mSubI64, mMulI64, mDivI64, mModI64,
|
||||
@@ -247,21 +251,20 @@ type
|
||||
mStrToStr, mEnumToStr, mAnd, mOr, mEqStr, mLeStr,
|
||||
mLtStr, mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet,
|
||||
mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT, mConTArr,
|
||||
mConTT, mSlice, mAppendStrCh, mAppendStrStr, mAppendSeqElem, mAppendSeqSeq,
|
||||
mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq,
|
||||
mAssert, mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast,
|
||||
mNewString, mArray, mOpenArray, mRange, mSet, mSeq,
|
||||
mOrdinal, mInt, mInt8, mInt16, mInt32, mInt64,
|
||||
mFloat, mFloat32, mFloat64, mBool, mChar, mString,
|
||||
mCstring, mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr,
|
||||
mStmt, mTypeDesc, mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion,
|
||||
mNimrodMajor, mNimrodMinor, mNimrodPatch, mCpuEndian, mHostOS, mHostCPU,
|
||||
mNaN, mInf, mNegInf, mNLen, mNChild, mNSetChild,
|
||||
mNAdd, mNAddMultiple, mNDel, mNKind, mNIntVal, mNFloatVal,
|
||||
mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal, mNSetFloatVal,
|
||||
mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNNewNimNode, mNCopyNimNode,
|
||||
mNCopyNimTree, mStrToIdent, mIdentToStr, mEqIdent, mNHint, mNWarning,
|
||||
mNError
|
||||
mConTT, mSlice, mAppendStrCh, mAppendStrStr, mAppendSeqElem, mInRange,
|
||||
mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq, mAssert,
|
||||
mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast, mNewString,
|
||||
mArray, mOpenArray, mRange, mSet, mSeq, mOrdinal,
|
||||
mInt, mInt8, mInt16, mInt32, mInt64, mFloat,
|
||||
mFloat32, mFloat64, mBool, mChar, mString, mCstring,
|
||||
mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt,
|
||||
mTypeDesc, mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion, mNimrodMajor,
|
||||
mNimrodMinor, mNimrodPatch, mCpuEndian, mHostOS, mHostCPU, mNaN,
|
||||
mInf, mNegInf, mNLen, mNChild, mNSetChild, mNAdd,
|
||||
mNAddMultiple, mNDel, mNKind, mNIntVal, mNFloatVal, mNSymbol,
|
||||
mNIdent, mNGetType, mNStrVal, mNSetIntVal, mNSetFloatVal, mNSetSymbol,
|
||||
mNSetIdent, mNSetType, mNSetStrVal, mNNewNimNode, mNCopyNimNode, mNCopyNimTree,
|
||||
mStrToIdent, mIdentToStr, mEqIdent, mNHint, mNWarning, mNError
|
||||
//[[[end]]]
|
||||
);
|
||||
|
||||
@@ -472,7 +475,7 @@ type
|
||||
end;
|
||||
|
||||
const
|
||||
OverloadableSyms = {@set}[skProc, skIterator, skConverter];
|
||||
OverloadableSyms = {@set}[skProc, skMethod, skIterator, skConverter];
|
||||
|
||||
const // "MagicToStr" array:
|
||||
MagicToStr: array [TMagic] of string = (
|
||||
@@ -482,9 +485,9 @@ const // "MagicToStr" array:
|
||||
// if (i+1) % 6 == 0: cog.outl("")
|
||||
//cog.outl("'%s'" % magics[-1])
|
||||
//]]]
|
||||
'None', 'Defined', 'Low', 'High', 'SizeOf', 'Is',
|
||||
'Echo', 'Succ', 'Pred', 'Inc', 'Dec', 'Ord',
|
||||
'New', 'NewFinalize', 'NewSeq', 'RegisterFinalizer', 'LengthOpenArray', 'LengthStr',
|
||||
'None', 'Defined', 'DefinedInScope', 'Low', 'High', 'SizeOf',
|
||||
'Is', 'Echo', 'Succ', 'Pred', 'Inc', 'Dec',
|
||||
'Ord', 'New', 'NewFinalize', 'NewSeq', 'LengthOpenArray', 'LengthStr',
|
||||
'LengthArray', 'LengthSeq', 'Incl', 'Excl', 'Card', 'Chr',
|
||||
'GCref', 'GCunref', 'AddI', 'SubI', 'MulI', 'DivI',
|
||||
'ModI', 'AddI64', 'SubI64', 'MulI64', 'DivI64', 'ModI64',
|
||||
@@ -506,21 +509,20 @@ const // "MagicToStr" array:
|
||||
'StrToStr', 'EnumToStr', 'And', 'Or', 'EqStr', 'LeStr',
|
||||
'LtStr', 'EqSet', 'LeSet', 'LtSet', 'MulSet', 'PlusSet',
|
||||
'MinusSet', 'SymDiffSet', 'ConStrStr', 'ConArrArr', 'ConArrT', 'ConTArr',
|
||||
'ConTT', 'Slice', 'AppendStrCh', 'AppendStrStr', 'AppendSeqElem', 'AppendSeqSeq',
|
||||
'InRange', 'InSet', 'Repr', 'Exit', 'SetLengthStr', 'SetLengthSeq',
|
||||
'Assert', 'Swap', 'IsNil', 'ArrToSeq', 'CopyStr', 'CopyStrLast',
|
||||
'NewString', 'Array', 'OpenArray', 'Range', 'Set', 'Seq',
|
||||
'Ordinal', 'Int', 'Int8', 'Int16', 'Int32', 'Int64',
|
||||
'Float', 'Float32', 'Float64', 'Bool', 'Char', 'String',
|
||||
'Cstring', 'Pointer', 'EmptySet', 'IntSetBaseType', 'Nil', 'Expr',
|
||||
'Stmt', 'TypeDesc', 'IsMainModule', 'CompileDate', 'CompileTime', 'NimrodVersion',
|
||||
'NimrodMajor', 'NimrodMinor', 'NimrodPatch', 'CpuEndian', 'HostOS', 'HostCPU',
|
||||
'NaN', 'Inf', 'NegInf', 'NLen', 'NChild', 'NSetChild',
|
||||
'NAdd', 'NAddMultiple', 'NDel', 'NKind', 'NIntVal', 'NFloatVal',
|
||||
'NSymbol', 'NIdent', 'NGetType', 'NStrVal', 'NSetIntVal', 'NSetFloatVal',
|
||||
'NSetSymbol', 'NSetIdent', 'NSetType', 'NSetStrVal', 'NNewNimNode', 'NCopyNimNode',
|
||||
'NCopyNimTree', 'StrToIdent', 'IdentToStr', 'EqIdent', 'NHint', 'NWarning',
|
||||
'NError'
|
||||
'ConTT', 'Slice', 'AppendStrCh', 'AppendStrStr', 'AppendSeqElem', 'InRange',
|
||||
'InSet', 'Repr', 'Exit', 'SetLengthStr', 'SetLengthSeq', 'Assert',
|
||||
'Swap', 'IsNil', 'ArrToSeq', 'CopyStr', 'CopyStrLast', 'NewString',
|
||||
'Array', 'OpenArray', 'Range', 'Set', 'Seq', 'Ordinal',
|
||||
'Int', 'Int8', 'Int16', 'Int32', 'Int64', 'Float',
|
||||
'Float32', 'Float64', 'Bool', 'Char', 'String', 'Cstring',
|
||||
'Pointer', 'EmptySet', 'IntSetBaseType', 'Nil', 'Expr', 'Stmt',
|
||||
'TypeDesc', 'IsMainModule', 'CompileDate', 'CompileTime', 'NimrodVersion', 'NimrodMajor',
|
||||
'NimrodMinor', 'NimrodPatch', 'CpuEndian', 'HostOS', 'HostCPU', 'NaN',
|
||||
'Inf', 'NegInf', 'NLen', 'NChild', 'NSetChild', 'NAdd',
|
||||
'NAddMultiple', 'NDel', 'NKind', 'NIntVal', 'NFloatVal', 'NSymbol',
|
||||
'NIdent', 'NGetType', 'NStrVal', 'NSetIntVal', 'NSetFloatVal', 'NSetSymbol',
|
||||
'NSetIdent', 'NSetType', 'NSetStrVal', 'NNewNimNode', 'NCopyNimNode', 'NCopyNimTree',
|
||||
'StrToIdent', 'IdentToStr', 'EqIdent', 'NHint', 'NWarning', 'NError'
|
||||
//[[[end]]]
|
||||
);
|
||||
|
||||
@@ -553,7 +555,7 @@ const
|
||||
tyFloat..tyFloat128
|
||||
];
|
||||
ConstantDataTypes: TTypeKinds = {@set}[tyArray, tySet, tyTuple];
|
||||
ExportableSymKinds = {@set}[skVar, skConst, skProc, skType,
|
||||
ExportableSymKinds = {@set}[skVar, skConst, skProc, skMethod, skType,
|
||||
skIterator, skMacro, skTemplate, skConverter,
|
||||
skStub];
|
||||
PersistentNodeFlags: TNodeFlags = {@set}[
|
||||
@@ -564,6 +566,7 @@ const
|
||||
pragmasPos = 3;
|
||||
codePos = 4;
|
||||
resultPos = 5;
|
||||
dispatcherPos = 6;
|
||||
|
||||
var
|
||||
gId: int;
|
||||
|
||||
@@ -1285,14 +1285,14 @@ begin
|
||||
genAssignment(p, a, c, {@set}[]);
|
||||
end;
|
||||
|
||||
procedure genIs(p: BProc; n: PNode; var d: TLoc);
|
||||
procedure genIs(p: BProc; x: PNode; typ: PType; var d: TLoc); overload;
|
||||
var
|
||||
a: TLoc;
|
||||
dest, t: PType;
|
||||
r, nilcheck: PRope;
|
||||
begin
|
||||
initLocExpr(p, n.sons[1], a);
|
||||
dest := skipTypes(n.sons[2].typ, abstractPtrs);
|
||||
initLocExpr(p, x, a);
|
||||
dest := skipTypes(typ, abstractPtrs);
|
||||
useMagic(p.module, 'isObj');
|
||||
r := rdLoc(a);
|
||||
nilCheck := nil;
|
||||
@@ -1313,7 +1313,12 @@ begin
|
||||
else
|
||||
r := ropef('isObj($1.m_type, $2)',
|
||||
[r, genTypeInfo(p.module, dest)]);
|
||||
putIntoDest(p, d, n.typ, r);
|
||||
putIntoDest(p, d, getSysType(tyBool), r);
|
||||
end;
|
||||
|
||||
procedure genIs(p: BProc; n: PNode; var d: TLoc); overload;
|
||||
begin
|
||||
genIs(p, n.sons[1], n.sons[2].typ, d);
|
||||
end;
|
||||
|
||||
procedure genNewFinalize(p: BProc; e: PNode);
|
||||
@@ -1330,14 +1335,14 @@ begin
|
||||
// This is a little hack:
|
||||
// XXX this is also a bug, if the finalizer expression produces side-effects
|
||||
oldModule := p.module;
|
||||
p.module := gmti;
|
||||
p.module := gNimDat;
|
||||
InitLocExpr(p, e.sons[2], f);
|
||||
p.module := oldModule;
|
||||
|
||||
initLoc(b, locExpr, a.t, OnHeap);
|
||||
ti := genTypeInfo(p.module, refType);
|
||||
|
||||
appf(gmti.s[cfsTypeInit3], '$1->finalizer = (void*)$2;$n', [
|
||||
appf(gNimDat.s[cfsTypeInit3], '$1->finalizer = (void*)$2;$n', [
|
||||
ti, rdLoc(f)]);
|
||||
b.r := ropef('($1) newObj($2, sizeof($3))',
|
||||
[getTypeDesc(p.module, refType), ti,
|
||||
@@ -2164,6 +2169,16 @@ begin
|
||||
nkSym: begin
|
||||
sym := e.sym;
|
||||
case sym.Kind of
|
||||
skMethod: begin
|
||||
if sym.ast.sons[codePos] = nil then begin
|
||||
// we cannot produce code for the dispatcher yet:
|
||||
fillProcLoc(sym);
|
||||
genProcPrototype(p.module, sym);
|
||||
end
|
||||
else
|
||||
genProc(p.module, sym);
|
||||
putLocIntoDest(p, d, sym.loc);
|
||||
end;
|
||||
skProc, skConverter: begin
|
||||
genProc(p.module, sym);
|
||||
if ((sym.loc.r = nil) or (sym.loc.t = nil)) then
|
||||
|
||||
@@ -326,7 +326,7 @@ begin
|
||||
nkStrLit..nkTripleStrLit: app(s, t.sons[i].strVal);
|
||||
nkSym: begin
|
||||
sym := t.sons[i].sym;
|
||||
if sym.kind = skProc then begin
|
||||
if sym.kind in [skProc, skMethod] then begin
|
||||
initLocExpr(p, t.sons[i], a);
|
||||
app(s, rdLoc(a));
|
||||
end
|
||||
@@ -970,12 +970,13 @@ begin
|
||||
nkCommentStmt, nkNilLit, nkIteratorDef, nkIncludeStmt, nkImportStmt,
|
||||
nkFromStmt, nkTemplateDef, nkMacroDef: begin end;
|
||||
nkPragma: genPragma(p, t);
|
||||
nkProcDef, nkConverterDef: begin
|
||||
nkProcDef, nkMethodDef, nkConverterDef: begin
|
||||
if (t.sons[genericParamsPos] = nil) then begin
|
||||
prc := t.sons[namePos].sym;
|
||||
if not (optDeadCodeElim in gGlobalOptions) and
|
||||
not (sfDeadCodeElim in getModule(prc).flags)
|
||||
or ([sfExportc, sfCompilerProc] * prc.flags = [sfExportc]) then begin
|
||||
or ([sfExportc, sfCompilerProc] * prc.flags = [sfExportc])
|
||||
or (prc.kind = skMethod) then begin
|
||||
if (t.sons[codePos] <> nil) or (lfDynamicLib in prc.loc.flags) then begin
|
||||
genProc(p.module, prc)
|
||||
end
|
||||
|
||||
@@ -47,7 +47,7 @@ begin
|
||||
if result = nil then begin
|
||||
if gCmd = cmdCompileToLLVM then begin
|
||||
case s.kind of
|
||||
skProc, skConverter, skConst: result := toRope('@'+'');
|
||||
skProc, skMethod, skConverter, skConst: result := toRope('@'+'');
|
||||
skVar: begin
|
||||
if (sfGlobal in s.flags) then result := toRope('@'+'')
|
||||
else result := toRope('%'+'');
|
||||
@@ -1026,15 +1026,15 @@ begin
|
||||
tyEmpty: result := toRope('0'+'');
|
||||
tyPointer, tyProc, tyBool, tyChar, tyCString, tyString,
|
||||
tyInt..tyFloat128, tyVar:
|
||||
genTypeInfoAuxBase(gmti, t, result, toRope('0'+''));
|
||||
tyRef, tyPtr, tySequence, tyRange: genTypeInfoAux(gmti, t, result);
|
||||
tyArrayConstr, tyArray: genArrayInfo(gmti, t, result);
|
||||
tySet: genSetInfo(gmti, t, result);
|
||||
tyEnum: genEnumInfo(gmti, t, result);
|
||||
tyObject: genObjectInfo(gmti, t, result);
|
||||
genTypeInfoAuxBase(gNimDat, t, result, toRope('0'+''));
|
||||
tyRef, tyPtr, tySequence, tyRange: genTypeInfoAux(gNimDat, t, result);
|
||||
tyArrayConstr, tyArray: genArrayInfo(gNimDat, t, result);
|
||||
tySet: genSetInfo(gNimDat, t, result);
|
||||
tyEnum: genEnumInfo(gNimDat, t, result);
|
||||
tyObject: genObjectInfo(gNimDat, t, result);
|
||||
tyTuple: begin
|
||||
if t.n <> nil then genObjectInfo(gmti, t, result)
|
||||
else genTupleInfo(gmti, t, result);
|
||||
if t.n <> nil then genObjectInfo(gNimDat, t, result)
|
||||
else genTupleInfo(gNimDat, t, result);
|
||||
end;
|
||||
else InternalError('genTypeInfo(' + typekindToStr[t.kind] + ')');
|
||||
end
|
||||
|
||||
33
nim/cgen.pas
33
nim/cgen.pas
@@ -19,7 +19,7 @@ uses
|
||||
nsystem, ast, astalgo, strutils, nhashes, trees, platform, magicsys,
|
||||
extccomp, options, nversion, nimsets, msgs, crc, bitsets, idents,
|
||||
lists, types, ccgutils, nos, ntime, ropes, nmath, passes, rodread,
|
||||
wordrecg, rnimsyn, treetab;
|
||||
wordrecg, rnimsyn, treetab, cgmeth;
|
||||
|
||||
function cgenPass(): TPass;
|
||||
|
||||
@@ -131,7 +131,7 @@ var
|
||||
gPendingModules: array of BModule = {@ignore} nil {@emit @[]};
|
||||
// list of modules that are not finished with code generation
|
||||
gForwardedProcsCounter: int = 0;
|
||||
gmti: BModule; // generated type info: no need to initialize: defaults fit
|
||||
gNimDat: BModule; // generated global data
|
||||
|
||||
function ropeff(const cformat, llvmformat: string;
|
||||
const args: array of PRope): PRope;
|
||||
@@ -557,7 +557,7 @@ begin
|
||||
sym := magicsys.getCompilerProc(name);
|
||||
if sym <> nil then
|
||||
case sym.kind of
|
||||
skProc, skConverter: genProc(m, sym);
|
||||
skProc, skMethod, skConverter: genProc(m, sym);
|
||||
skVar: genVarPrototype(m, sym);
|
||||
skType: {@discard} getTypeDesc(m, sym.typ);
|
||||
else InternalError('useMagic: ' + name)
|
||||
@@ -730,6 +730,7 @@ begin
|
||||
app(generatedProc, '}' + tnl);
|
||||
end;
|
||||
app(m.s[cfsProcs], generatedProc);
|
||||
//if prc.kind = skMethod then addMethodToCompile(gNimDat, prc);
|
||||
end;
|
||||
|
||||
procedure genProcPrototype(m: BModule; sym: PSym);
|
||||
@@ -746,8 +747,9 @@ begin
|
||||
end
|
||||
end
|
||||
else begin
|
||||
if not IntSetContainsOrIncl(m.declaredProtos, sym.id) then
|
||||
if not IntSetContainsOrIncl(m.declaredProtos, sym.id) then begin
|
||||
appf(m.s[cfsProcHeaders], '$1;$n', [genProcHeader(m, sym)]);
|
||||
end
|
||||
end
|
||||
end;
|
||||
|
||||
@@ -836,18 +838,18 @@ function getFileHeader(const cfilenoext: string): PRope;
|
||||
begin
|
||||
if optCompileOnly in gGlobalOptions then
|
||||
result := ropeff(
|
||||
'/* Generated by the Nimrod Compiler v$1 */$n' +
|
||||
'/* Generated by Nimrod Compiler v$1 */$n' +
|
||||
'/* (c) 2009 Andreas Rumpf */$n',
|
||||
'; Generated by the Nimrod Compiler v$1$n' +
|
||||
'; Generated by Nimrod Compiler v$1$n' +
|
||||
'; (c) 2009 Andreas Rumpf$n',
|
||||
[toRope(versionAsString)])
|
||||
else
|
||||
result := ropeff(
|
||||
'/* Generated by the Nimrod Compiler v$1 */$n' +
|
||||
'/* Generated by Nimrod Compiler v$1 */$n' +
|
||||
'/* (c) 2009 Andreas Rumpf */$n' +
|
||||
'/* Compiled for: $2, $3, $4 */$n' +
|
||||
'/* Command for C compiler:$n $5 */$n',
|
||||
'; Generated by the Nimrod Compiler v$1$n' +
|
||||
'; Generated by Nimrod Compiler v$1$n' +
|
||||
'; (c) 2009 Andreas Rumpf$n' +
|
||||
'; Compiled for: $2, $3, $4$n' +
|
||||
'; Command for LLVM compiler:$n $5$n',
|
||||
@@ -1115,15 +1117,15 @@ var
|
||||
s: PSym;
|
||||
begin
|
||||
s := NewSym(skModule, getIdent(moduleName), nil);
|
||||
gmti := rawNewModule(s, joinPath(options.projectPath, moduleName)+'.nim');
|
||||
addPendingModule(gmti);
|
||||
gNimDat := rawNewModule(s, joinPath(options.projectPath, moduleName)+'.nim');
|
||||
addPendingModule(gNimDat);
|
||||
appff(mainModProcs, 'N_NOINLINE(void, $1)(void);$n',
|
||||
'declare void $1() noinline$n', [getInitName(s)]);
|
||||
end;
|
||||
|
||||
function myOpen(module: PSym; const filename: string): PPassContext;
|
||||
begin
|
||||
if gmti = nil then registerTypeInfoModule();
|
||||
if gNimDat = nil then registerTypeInfoModule();
|
||||
result := newModule(module, filename);
|
||||
end;
|
||||
|
||||
@@ -1132,7 +1134,7 @@ function myOpenCached(module: PSym; const filename: string;
|
||||
var
|
||||
cfile, cfilenoext, objFile: string;
|
||||
begin
|
||||
if gmti = nil then registerTypeInfoModule();
|
||||
if gNimDat = nil then registerTypeInfoModule();
|
||||
//MessageOut('cgen.myOpenCached has been called ' + filename);
|
||||
cfile := changeFileExt(completeCFilePath(filename), cExt);
|
||||
cfilenoext := changeFileExt(cfile, '');
|
||||
@@ -1177,7 +1179,7 @@ begin
|
||||
i := 0;
|
||||
while i <= high(m.forwardedProcs) do begin
|
||||
// Note: ``genProc`` may add to ``m.forwardedProcs``, so we cannot use
|
||||
// a for loop here
|
||||
// a ``for`` loop here
|
||||
prc := m.forwardedProcs[i];
|
||||
if sfForward in prc.flags then InternalError(prc.info, 'still forwarded');
|
||||
genProcNoForward(m, prc);
|
||||
@@ -1214,6 +1216,7 @@ function myClose(b: PPassContext; n: PNode): PNode;
|
||||
var
|
||||
m: BModule;
|
||||
i: int;
|
||||
disp: PNode;
|
||||
begin
|
||||
result := n;
|
||||
if b = nil then exit;
|
||||
@@ -1227,6 +1230,8 @@ begin
|
||||
not (sfDeadCodeElim in m.module.flags) then
|
||||
finishModule(m);
|
||||
if sfMainModule in m.module.flags then begin
|
||||
disp := generateMethodDispatchers();
|
||||
for i := 0 to sonsLen(disp)-1 do genProcAux(gNimDat, disp.sons[i].sym);
|
||||
genMainProc(m);
|
||||
// we need to process the transitive closure because recursive module
|
||||
// deps are allowed (and the system module is processed in the wrong
|
||||
@@ -1241,7 +1246,7 @@ begin
|
||||
not (sfDeadCodeElim in m.module.flags) then
|
||||
writeModule(m);
|
||||
if sfMainModule in m.module.flags then
|
||||
writeMapping(gMapping);
|
||||
writeMapping(gMapping);
|
||||
end;
|
||||
|
||||
function cgenPass(): TPass;
|
||||
|
||||
269
nim/cgmeth.pas
Normal file
269
nim/cgmeth.pas
Normal file
@@ -0,0 +1,269 @@
|
||||
//
|
||||
//
|
||||
// The Nimrod Compiler
|
||||
// (c) Copyright 2009 Andreas Rumpf
|
||||
//
|
||||
// See the file "copying.txt", included in this
|
||||
// distribution, for details about the copyright.
|
||||
//
|
||||
|
||||
unit cgmeth;
|
||||
|
||||
// This module implements code generation for multi methods.
|
||||
|
||||
interface
|
||||
|
||||
{$include 'config.inc'}
|
||||
|
||||
uses
|
||||
sysutils, nsystem,
|
||||
options, ast, astalgo, msgs, idents, rnimsyn, types, magicsys;
|
||||
|
||||
procedure methodDef(s: PSym);
|
||||
function methodCall(n: PNode): PNode;
|
||||
function generateMethodDispatchers(): PNode;
|
||||
|
||||
implementation
|
||||
|
||||
const
|
||||
skipPtrs = {@set}[tyVar, tyPtr, tyRef, tyGenericInst];
|
||||
|
||||
function genConv(n: PNode; d: PType; downcast: bool): PNode;
|
||||
var
|
||||
dest, source: PType;
|
||||
diff: int;
|
||||
begin
|
||||
dest := skipTypes(d, abstractPtrs);
|
||||
source := skipTypes(n.typ, abstractPtrs);
|
||||
if (source.kind = tyObject) and (dest.kind = tyObject) then begin
|
||||
diff := inheritanceDiff(dest, source);
|
||||
if diff = high(int) then InternalError(n.info, 'cgmeth.genConv');
|
||||
if diff < 0 then begin
|
||||
result := newNodeIT(nkObjUpConv, n.info, d);
|
||||
addSon(result, n);
|
||||
if downCast then
|
||||
InternalError(n.info, 'cgmeth.genConv: no upcast allowed');
|
||||
end
|
||||
else if diff > 0 then begin
|
||||
result := newNodeIT(nkObjDownConv, n.info, d);
|
||||
addSon(result, n);
|
||||
if not downCast then
|
||||
InternalError(n.info, 'cgmeth.genConv: no downcast allowed');
|
||||
end
|
||||
else result := n
|
||||
end
|
||||
else result := n
|
||||
end;
|
||||
|
||||
function methodCall(n: PNode): PNode;
|
||||
var
|
||||
disp: PSym;
|
||||
i: int;
|
||||
begin
|
||||
result := n;
|
||||
disp := lastSon(result.sons[0].sym.ast).sym;
|
||||
result.sons[0].sym := disp;
|
||||
for i := 1 to sonsLen(result)-1 do
|
||||
result.sons[i] := genConv(result.sons[i], disp.typ.sons[i], true)
|
||||
end;
|
||||
|
||||
var
|
||||
gMethods: array of TSymSeq;
|
||||
|
||||
function sameMethodBucket(a, b: PSym): bool;
|
||||
var
|
||||
i: int;
|
||||
aa, bb: PType;
|
||||
begin
|
||||
result := false;
|
||||
if a.name.id <> b.name.id then exit;
|
||||
if sonsLen(a.typ) <> sonsLen(b.typ) then exit;
|
||||
// check for return type:
|
||||
if not sameTypeOrNil(a.typ.sons[0], b.typ.sons[0]) then exit;
|
||||
for i := 1 to sonsLen(a.typ)-1 do begin
|
||||
aa := a.typ.sons[i];
|
||||
bb := b.typ.sons[i];
|
||||
while true do begin
|
||||
aa := skipTypes(aa, {@set}[tyGenericInst]);
|
||||
bb := skipTypes(bb, {@set}[tyGenericInst]);
|
||||
if (aa.kind = bb.kind) and (aa.kind in [tyVar, tyPtr, tyRef]) then begin
|
||||
aa := aa.sons[0];
|
||||
bb := bb.sons[0];
|
||||
end
|
||||
else
|
||||
break
|
||||
end;
|
||||
if sameType(aa, bb)
|
||||
or (aa.kind = tyObject) and (bb.kind = tyObject)
|
||||
and (inheritanceDiff(bb, aa) < 0) then begin end
|
||||
else exit;
|
||||
end;
|
||||
result := true
|
||||
end;
|
||||
|
||||
procedure methodDef(s: PSym);
|
||||
var
|
||||
i, L, q: int;
|
||||
disp: PSym;
|
||||
begin
|
||||
L := length(gMethods);
|
||||
for i := 0 to L-1 do begin
|
||||
if sameMethodBucket(gMethods[i][0], s) then begin
|
||||
{@ignore}
|
||||
q := length(gMethods[i]);
|
||||
setLength(gMethods[i], q+1);
|
||||
gMethods[i][q] := s;
|
||||
{@emit
|
||||
add(gMethods[i], s);
|
||||
}
|
||||
// store a symbol to the dispatcher:
|
||||
addSon(s.ast, lastSon(gMethods[i][0].ast));
|
||||
exit
|
||||
end
|
||||
end;
|
||||
{@ignore}
|
||||
setLength(gMethods, L+1);
|
||||
setLength(gMethods[L], 1);
|
||||
gMethods[L][0] := s;
|
||||
{@emit
|
||||
add(gMethods, @[s]);
|
||||
}
|
||||
// create a new dispatcher:
|
||||
disp := copySym(s);
|
||||
disp.typ := copyType(disp.typ, disp.typ.owner, false);
|
||||
if disp.typ.callConv = ccInline then disp.typ.callConv := ccDefault;
|
||||
disp.ast := copyTree(s.ast);
|
||||
disp.ast.sons[codePos] := nil;
|
||||
if s.typ.sons[0] <> nil then
|
||||
disp.ast.sons[resultPos].sym := copySym(s.ast.sons[resultPos].sym);
|
||||
addSon(s.ast, newSymNode(disp));
|
||||
end;
|
||||
|
||||
function relevantCol(methods: TSymSeq; col: int): bool;
|
||||
var
|
||||
t: PType;
|
||||
i: int;
|
||||
begin
|
||||
// returns true iff the position is relevant
|
||||
t := methods[0].typ.sons[col];
|
||||
result := false;
|
||||
if skipTypes(t, skipPtrs).kind = tyObject then
|
||||
for i := 1 to high(methods) do
|
||||
if not SameType(methods[i].typ.sons[col], t) then begin
|
||||
result := true; exit
|
||||
end
|
||||
end;
|
||||
|
||||
function cmpSignatures(a, b: PSym; const relevantCols: TIntSet): int;
|
||||
var
|
||||
col, d: int;
|
||||
aa, bb: PType;
|
||||
begin
|
||||
result := 0;
|
||||
for col := 1 to sonsLen(a.typ)-1 do
|
||||
if intSetContains(relevantCols, col) then begin
|
||||
aa := skipTypes(a.typ.sons[col], skipPtrs);
|
||||
bb := skipTypes(b.typ.sons[col], skipPtrs);
|
||||
d := inheritanceDiff(aa, bb);
|
||||
if (d <> high(int)) then begin
|
||||
result := d; exit
|
||||
end
|
||||
end
|
||||
end;
|
||||
|
||||
procedure sortBucket(var a: TSymSeq; const relevantCols: TIntSet);
|
||||
// we use shellsort here; fast and simple
|
||||
var
|
||||
N, i, j, h: int;
|
||||
v: PSym;
|
||||
begin
|
||||
N := length(a);
|
||||
h := 1; repeat h := 3*h+1; until h > N;
|
||||
repeat
|
||||
h := h div 3;
|
||||
for i := h to N-1 do begin
|
||||
v := a[i]; j := i;
|
||||
while cmpSignatures(a[j-h], v, relevantCols) >= 0 do begin
|
||||
a[j] := a[j-h]; j := j - h;
|
||||
if j < h then break
|
||||
end;
|
||||
a[j] := v;
|
||||
end;
|
||||
until h = 1
|
||||
end;
|
||||
|
||||
function genDispatcher(methods: TSymSeq; const relevantCols: TIntSet): PSym;
|
||||
var
|
||||
disp, cond, call, ret, a, isn: PNode;
|
||||
base, curr, ands, iss: PSym;
|
||||
meth, col, paramLen: int;
|
||||
begin
|
||||
base := lastSon(methods[0].ast).sym;
|
||||
result := base;
|
||||
paramLen := sonsLen(base.typ);
|
||||
disp := newNodeI(nkIfStmt, base.info);
|
||||
ands := getSysSym('and');
|
||||
iss := getSysSym('is');
|
||||
for meth := 0 to high(methods) do begin
|
||||
curr := methods[meth];
|
||||
// generate condition:
|
||||
cond := nil;
|
||||
for col := 1 to paramLen-1 do begin
|
||||
if IntSetContains(relevantCols, col) then begin
|
||||
isn := newNodeIT(nkCall, base.info, getSysType(tyBool));
|
||||
addSon(isn, newSymNode(iss));
|
||||
addSon(isn, newSymNode(base.typ.n.sons[col].sym));
|
||||
addSon(isn, newNodeIT(nkType, base.info, curr.typ.sons[col]));
|
||||
if cond <> nil then begin
|
||||
a := newNodeIT(nkCall, base.info, getSysType(tyBool));
|
||||
addSon(a, newSymNode(ands));
|
||||
addSon(a, cond);
|
||||
addSon(a, isn);
|
||||
cond := a
|
||||
end
|
||||
else
|
||||
cond := isn
|
||||
end
|
||||
end;
|
||||
// generate action:
|
||||
call := newNodeI(nkCall, base.info);
|
||||
addSon(call, newSymNode(curr));
|
||||
for col := 1 to paramLen-1 do begin
|
||||
addSon(call, genConv(newSymNode(base.typ.n.sons[col].sym),
|
||||
curr.typ.sons[col], false));
|
||||
end;
|
||||
if base.typ.sons[0] <> nil then begin
|
||||
a := newNodeI(nkAsgn, base.info);
|
||||
addSon(a, newSymNode(base.ast.sons[resultPos].sym));
|
||||
addSon(a, call);
|
||||
ret := newNodeI(nkReturnStmt, base.info);
|
||||
addSon(ret, a);
|
||||
end
|
||||
else
|
||||
ret := call;
|
||||
a := newNodeI(nkElifBranch, base.info);
|
||||
addSon(a, cond);
|
||||
addSon(a, ret);
|
||||
addSon(disp, a);
|
||||
end;
|
||||
result.ast.sons[codePos] := disp;
|
||||
end;
|
||||
|
||||
function generateMethodDispatchers(): PNode;
|
||||
var
|
||||
bucket, col: int;
|
||||
relevantCols: TIntSet;
|
||||
begin
|
||||
result := newNode(nkStmtList);
|
||||
for bucket := 0 to length(gMethods)-1 do begin
|
||||
IntSetInit(relevantCols);
|
||||
for col := 1 to sonsLen(gMethods[bucket][0].typ)-1 do
|
||||
if relevantCol(gMethods[bucket], col) then IntSetIncl(relevantCols, col);
|
||||
sortBucket(gMethods[bucket], relevantCols);
|
||||
addSon(result, newSymNode(genDispatcher(gMethods[bucket], relevantCols)));
|
||||
end
|
||||
end;
|
||||
|
||||
initialization
|
||||
{@emit gMethods := @[]; }
|
||||
end.
|
||||
@@ -1036,6 +1036,7 @@ begin
|
||||
case n.kind of
|
||||
nkCommentStmt: app(d.modDesc, genComment(d, n));
|
||||
nkProcDef: genItem(d, n, n.sons[namePos], skProc);
|
||||
nkMethodDef: genItem(d, n, n.sons[namePos], skMethod);
|
||||
nkIteratorDef: genItem(d, n, n.sons[namePos], skIterator);
|
||||
nkMacroDef: genItem(d, n, n.sons[namePos], skMacro);
|
||||
nkTemplateDef: genItem(d, n, n.sons[namePos], skTemplate);
|
||||
|
||||
@@ -1717,7 +1717,7 @@ begin
|
||||
nkTypeSection, nkCommentStmt, nkIteratorDef,
|
||||
nkIncludeStmt, nkImportStmt,
|
||||
nkFromStmt, nkTemplateDef, nkMacroDef, nkPragma: begin end;
|
||||
nkProcDef, nkConverterDef: begin
|
||||
nkProcDef, nkMethodDef, nkConverterDef: begin
|
||||
if (n.sons[genericParamsPos] = nil) then begin
|
||||
prc := n.sons[namePos].sym;
|
||||
if (n.sons[codePos] <> nil) and not (lfNoDecl in prc.loc.flags) then
|
||||
|
||||
@@ -938,23 +938,6 @@ begin
|
||||
result := emptyNode;
|
||||
end;
|
||||
|
||||
function evalAppendSeqSeq(c: PEvalContext; n: PNode): PNode;
|
||||
var
|
||||
a, b: PNode;
|
||||
i: int;
|
||||
begin
|
||||
result := evalAux(c, n.sons[1]);
|
||||
if result.kind = nkExceptBranch then exit;
|
||||
a := result;
|
||||
result := evalAux(c, n.sons[2]);
|
||||
if result.kind = nkExceptBranch then exit;
|
||||
b := result;
|
||||
if a.kind = nkBracket then
|
||||
for i := 0 to sonsLen(b)-1 do addSon(a, copyTree(b.sons[i]))
|
||||
else InternalError(n.info, 'evalAppendSeqSeq');
|
||||
result := emptyNode;
|
||||
end;
|
||||
|
||||
function evalRepr(c: PEvalContext; n: PNode): PNode;
|
||||
begin
|
||||
result := evalAux(c, n.sons[1]);
|
||||
@@ -993,7 +976,6 @@ begin
|
||||
mAppendStrCh: result := evalAppendStrCh(c, n);
|
||||
mAppendStrStr: result := evalAppendStrStr(c, n);
|
||||
mAppendSeqElem: result := evalAppendSeqElem(c, n);
|
||||
mAppendSeqSeq: result := evalAppendSeqSeq(c, n);
|
||||
|
||||
mNLen: begin
|
||||
result := evalAux(c, n.sons[1]);
|
||||
@@ -1338,7 +1320,7 @@ begin
|
||||
end
|
||||
end
|
||||
end;
|
||||
nkProcDef, nkMacroDef, nkCommentStmt, nkPragma, nkTypeSection,
|
||||
nkProcDef, nkMethodDef, nkMacroDef, nkCommentStmt, nkPragma, nkTypeSection,
|
||||
nkTemplateDef, nkConstSection, nkIteratorDef, nkConverterDef,
|
||||
nkIncludeStmt, nkImportStmt, nkFromStmt: begin end;
|
||||
nkIdentDefs, nkCast, nkYieldStmt, nkAsmStmt, nkForStmt, nkPragmaExpr,
|
||||
|
||||
@@ -264,18 +264,37 @@ begin
|
||||
while not (g.buf[pos] in [#0, #10, #13]) do inc(pos);
|
||||
end;
|
||||
'a'..'z', 'A'..'Z', '_', #128..#255: begin
|
||||
if (g.buf[pos+1] = '"') and (g.buf[pos] in ['r', 'R']) then begin
|
||||
g.kind := gtRawData;
|
||||
inc(pos, 2);
|
||||
while not (g.buf[pos] in [#0, '"', #10, #13]) do inc(pos);
|
||||
if g.buf[pos] = '"' then inc(pos);
|
||||
id := '';
|
||||
while g.buf[pos] in scanner.SymChars+['_'] do begin
|
||||
addChar(id, g.buf[pos]);
|
||||
inc(pos)
|
||||
end;
|
||||
if (g.buf[pos] = '"') then begin
|
||||
if (g.buf[pos+1] = '"') and (g.buf[pos+2] = '"') then begin
|
||||
inc(pos, 3);
|
||||
g.kind := gtLongStringLit;
|
||||
while true do begin
|
||||
case g.buf[pos] of
|
||||
#0: break;
|
||||
'"': begin
|
||||
inc(pos);
|
||||
if (g.buf[pos] = '"') and (g.buf[pos+1] = '"') then begin
|
||||
inc(pos, 2);
|
||||
break
|
||||
end
|
||||
end;
|
||||
else inc(pos);
|
||||
end
|
||||
end
|
||||
end
|
||||
else begin
|
||||
g.kind := gtRawData;
|
||||
inc(pos);
|
||||
while not (g.buf[pos] in [#0, '"', #10, #13]) do inc(pos);
|
||||
if g.buf[pos] = '"' then inc(pos);
|
||||
end
|
||||
end
|
||||
else begin
|
||||
id := '';
|
||||
while g.buf[pos] in scanner.SymChars+['_'] do begin
|
||||
addChar(id, g.buf[pos]);
|
||||
inc(pos)
|
||||
end;
|
||||
g.kind := nimGetKeyword(id);
|
||||
end
|
||||
end;
|
||||
|
||||
@@ -113,7 +113,7 @@ begin
|
||||
InternalError(ident.info, 'importSymbol: 2');
|
||||
// for an enumeration we have to add all identifiers
|
||||
case s.Kind of
|
||||
skProc, skIterator, skMacro, skTemplate, skConverter: begin
|
||||
skProc, skMethod, skIterator, skMacro, skTemplate, skConverter: begin
|
||||
// for a overloadable syms add all overloaded routines
|
||||
e := InitIdentIter(it, fromMod.tab, s.name);
|
||||
while e <> nil do begin
|
||||
@@ -155,6 +155,8 @@ begin
|
||||
for i := 0 to sonsLen(n)-1 do begin
|
||||
f := getModuleFile(n.sons[i]);
|
||||
m := gImportModule(f);
|
||||
if sfDeprecated in m.flags then
|
||||
liMessage(n.sons[i].info, warnDeprecated, m.name.s);
|
||||
// ``addDecl`` needs to be done before ``importAllSymbols``!
|
||||
addDecl(c, m); // add symbol to symbol table of module
|
||||
importAllSymbols(c, m);
|
||||
|
||||
@@ -54,7 +54,7 @@ implementation
|
||||
function getSymRepr(s: PSym): string;
|
||||
begin
|
||||
case s.kind of
|
||||
skProc, skConverter, skIterator: result := getProcHeader(s);
|
||||
skProc, skMethod, skConverter, skIterator: result := getProcHeader(s);
|
||||
else result := s.name.s
|
||||
end
|
||||
end;
|
||||
@@ -72,7 +72,7 @@ begin
|
||||
liMessage(s.info, errImplOfXexpected, getSymRepr(s))
|
||||
else if ([sfUsed, sfInInterface] * s.flags = []) and
|
||||
(optHints in s.options) then // BUGFIX: check options in s!
|
||||
if not (s.kind in [skForVar, skParam, skUnknown]) then
|
||||
if not (s.kind in [skForVar, skParam, skMethod, skUnknown]) then
|
||||
liMessage(s.info, hintXDeclaredButNotUsed, getSymRepr(s));
|
||||
s := NextIter(it, tab.stack[tab.tos-1]);
|
||||
end;
|
||||
|
||||
@@ -30,6 +30,8 @@ procedure registerCompilerProc(s: PSym);
|
||||
procedure InitSystem(var tab: TSymTab);
|
||||
procedure FinishSystem(const tab: TStrTable);
|
||||
|
||||
function getSysSym(const name: string): PSym;
|
||||
|
||||
implementation
|
||||
|
||||
var
|
||||
@@ -48,14 +50,16 @@ begin
|
||||
result.align := size;
|
||||
end;
|
||||
|
||||
function sysTypeFromName(const name: string): PType;
|
||||
var
|
||||
s: PSym;
|
||||
function getSysSym(const name: string): PSym;
|
||||
begin
|
||||
s := StrTableGet(systemModule.tab, getIdent(name));
|
||||
if s = nil then rawMessage(errSystemNeeds, name);
|
||||
if s.kind = skStub then loadStub(s);
|
||||
result := s.typ;
|
||||
result := StrTableGet(systemModule.tab, getIdent(name));
|
||||
if result = nil then rawMessage(errSystemNeeds, name);
|
||||
if result.kind = skStub then loadStub(result);
|
||||
end;
|
||||
|
||||
function sysTypeFromName(const name: string): PType;
|
||||
begin
|
||||
result := getSysSym(name).typ;
|
||||
end;
|
||||
|
||||
function getSysType(const kind: TTypeKind): PType;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//
|
||||
//
|
||||
// The Nimrod Compiler
|
||||
// (c) Copyright 2008 Andreas Rumpf
|
||||
// (c) Copyright 2009 Andreas Rumpf
|
||||
//
|
||||
// See the file "copying.txt", included in this
|
||||
// distribution, for details about the copyright.
|
||||
|
||||
@@ -31,10 +31,10 @@ const
|
||||
//cog.outl('VersionMinor = %s;' % ver[1])
|
||||
//cog.outl('VersionPatch = %s;' % ver[2])
|
||||
//]]]
|
||||
VersionAsString = '0.8.0';
|
||||
VersionAsString = '0.8.1';
|
||||
VersionMajor = 0;
|
||||
VersionMinor = 8;
|
||||
VersionPatch = 0;
|
||||
VersionPatch = 1;
|
||||
//[[[[end]]]]
|
||||
|
||||
implementation
|
||||
|
||||
@@ -61,7 +61,7 @@ const
|
||||
('len', 'length'),
|
||||
('setlength', 'setlen')
|
||||
);
|
||||
nimReplacements: array [1..32] of TReplaceTuple = (
|
||||
nimReplacements: array [1..34] of TReplaceTuple = (
|
||||
('nimread', 'read'),
|
||||
('nimwrite', 'write'),
|
||||
('nimclosefile', 'close'),
|
||||
@@ -96,7 +96,10 @@ const
|
||||
('snil', 'nil'),
|
||||
('tostringf', '$'+''),
|
||||
('ttextfile', 'tfile'),
|
||||
('tbinaryfile', 'tfile') {,
|
||||
('tbinaryfile', 'tfile'),
|
||||
('strstart', '0'+''),
|
||||
('nl', '"\n"')
|
||||
{,
|
||||
('NL', '"\n"'),
|
||||
('tabulator', '''\t'''),
|
||||
('esc', '''\e'''),
|
||||
|
||||
@@ -56,7 +56,7 @@ begin
|
||||
nkStmtList: begin
|
||||
for i := 0 to sonsLen(n)-1 do {@discard} cleanup(c, n.sons[i]);
|
||||
end;
|
||||
nkProcDef: begin
|
||||
nkProcDef, nkMethodDef: begin
|
||||
if (n.sons[namePos].kind = nkSym) then begin
|
||||
s := n.sons[namePos].sym;
|
||||
if not (sfDeadCodeElim in getModule(s).flags) and
|
||||
|
||||
@@ -67,7 +67,7 @@ implementation
|
||||
|
||||
function astNeeded(s: PSym): bool;
|
||||
begin
|
||||
if (s.kind = skProc)
|
||||
if (s.kind in [skMethod, skProc])
|
||||
and ([sfCompilerProc, sfCompileTime] * s.flags = [])
|
||||
and (s.typ.callConv <> ccInline)
|
||||
and (s.ast.sons[genericParamsPos] = nil) then
|
||||
|
||||
@@ -889,7 +889,7 @@ end;
|
||||
|
||||
function parseImportStmt(var p: TParser): PNode;
|
||||
var
|
||||
a, b: PNode;
|
||||
a: PNode;
|
||||
begin
|
||||
result := newNodeP(nkImportStmt, p);
|
||||
getTok(p); // skip `import`
|
||||
@@ -1535,9 +1535,9 @@ begin
|
||||
end
|
||||
end;
|
||||
|
||||
function parseRecordPart(var p: TParser): PNode; forward;
|
||||
function parseObjectPart(var p: TParser): PNode; forward;
|
||||
|
||||
function parseRecordWhen(var p: TParser): PNode;
|
||||
function parseObjectWhen(var p: TParser): PNode;
|
||||
var
|
||||
branch: PNode;
|
||||
begin
|
||||
@@ -1549,7 +1549,7 @@ begin
|
||||
addSon(branch, parseExpr(p));
|
||||
eat(p, tkColon);
|
||||
skipComment(p, branch);
|
||||
addSon(branch, parseRecordPart(p));
|
||||
addSon(branch, parseObjectPart(p));
|
||||
skipComment(p, branch);
|
||||
addSon(result, branch);
|
||||
if p.tok.tokType <> tkElif then break
|
||||
@@ -1558,12 +1558,12 @@ begin
|
||||
branch := newNodeP(nkElse, p);
|
||||
eat(p, tkElse); eat(p, tkColon);
|
||||
skipComment(p, branch);
|
||||
addSon(branch, parseRecordPart(p));
|
||||
addSon(branch, parseObjectPart(p));
|
||||
addSon(result, branch);
|
||||
end
|
||||
end;
|
||||
|
||||
function parseRecordCase(var p: TParser): PNode;
|
||||
function parseObjectCase(var p: TParser): PNode;
|
||||
var
|
||||
a, b: PNode;
|
||||
begin
|
||||
@@ -1591,13 +1591,13 @@ begin
|
||||
else break;
|
||||
end;
|
||||
skipComment(p, b);
|
||||
addSon(b, parseRecordPart(p));
|
||||
addSon(b, parseObjectPart(p));
|
||||
addSon(result, b);
|
||||
if b.kind = nkElse then break;
|
||||
end
|
||||
end;
|
||||
|
||||
function parseRecordPart(var p: TParser): PNode;
|
||||
function parseObjectPart(var p: TParser): PNode;
|
||||
begin
|
||||
case p.tok.tokType of
|
||||
tkInd: begin
|
||||
@@ -1608,7 +1608,7 @@ begin
|
||||
case p.tok.tokType of
|
||||
tkSad: getTok(p);
|
||||
tkCase, tkWhen, tkSymbol, tkAccent, tkNil: begin
|
||||
addSon(result, parseRecordPart(p));
|
||||
addSon(result, parseObjectPart(p));
|
||||
end;
|
||||
tkDed: begin getTok(p); break end;
|
||||
tkEof: break;
|
||||
@@ -1620,8 +1620,8 @@ begin
|
||||
end;
|
||||
popInd(p.lex^);
|
||||
end;
|
||||
tkWhen: result := parseRecordWhen(p);
|
||||
tkCase: result := parseRecordCase(p);
|
||||
tkWhen: result := parseObjectWhen(p);
|
||||
tkCase: result := parseObjectCase(p);
|
||||
tkSymbol, tkAccent: begin
|
||||
result := parseIdentColonEquals(p, {@set}[withPragma]);
|
||||
skipComment(p, result);
|
||||
@@ -1634,11 +1634,11 @@ begin
|
||||
end
|
||||
end;
|
||||
|
||||
function parseRecordOrObject(var p: TParser; kind: TNodeKind): PNode;
|
||||
function parseObject(var p: TParser): PNode;
|
||||
var
|
||||
a: PNode;
|
||||
begin
|
||||
result := newNodeP(kind, p);
|
||||
result := newNodeP(nkObjectTy, p);
|
||||
getTok(p);
|
||||
if p.tok.tokType = tkCurlyDotLe then addSon(result, parsePragma(p))
|
||||
else addSon(result, nil);
|
||||
@@ -1646,14 +1646,11 @@ begin
|
||||
a := newNodeP(nkOfInherit, p);
|
||||
getTok(p);
|
||||
addSon(a, parseTypeDesc(p));
|
||||
if kind = nkObjectTy then
|
||||
addSon(result, a)
|
||||
else
|
||||
parMessage(p, errInheritanceOnlyWithNonFinalObjects);
|
||||
addSon(result, a);
|
||||
end
|
||||
else addSon(result, nil);
|
||||
skipComment(p, result);
|
||||
addSon(result, parseRecordPart(p));
|
||||
addSon(result, parseObjectPart(p));
|
||||
end;
|
||||
|
||||
function parseDistinct(var p: TParser): PNode;
|
||||
@@ -1675,7 +1672,7 @@ begin
|
||||
if p.tok.tokType = tkEquals then begin
|
||||
getTok(p); optInd(p, result);
|
||||
case p.tok.tokType of
|
||||
tkObject: a := parseRecordOrObject(p, nkObjectTy);
|
||||
tkObject: a := parseObject(p);
|
||||
tkEnum: a := parseEnum(p);
|
||||
tkDistinct: a := parseDistinct(p);
|
||||
else a := parseTypeDesc(p);
|
||||
@@ -1754,6 +1751,7 @@ begin
|
||||
tkBlock: result := parseBlock(p);
|
||||
tkAsm: result := parseAsm(p);
|
||||
tkProc: result := parseRoutine(p, nkProcDef);
|
||||
tkMethod: result := parseRoutine(p, nkMethodDef);
|
||||
tkIterator: result := parseRoutine(p, nkIteratorDef);
|
||||
tkMacro: result := parseRoutine(p, nkMacroDef);
|
||||
tkTemplate: result := parseRoutine(p, nkTemplateDef);
|
||||
|
||||
@@ -30,6 +30,7 @@ const
|
||||
wCppMethod, wDeprecated, wVarargs, wCompileTime, wMerge,
|
||||
wBorrow];
|
||||
converterPragmas = procPragmas;
|
||||
methodPragmas = procPragmas;
|
||||
macroPragmas = {@set}[FirstCallConv..LastCallConv,
|
||||
wImportc, wExportc, wNodecl, wMagic, wNosideEffect,
|
||||
wCompilerProc, wDeprecated, wTypeCheck];
|
||||
@@ -42,7 +43,7 @@ const
|
||||
wHint, wWarning, wError, wFatal, wDefine, wUndef,
|
||||
wCompile, wLink, wLinkSys, wPure,
|
||||
wPush, wPop, wBreakpoint, wCheckpoint,
|
||||
wPassL, wPassC, wDeadCodeElim];
|
||||
wPassL, wPassC, wDeadCodeElim, wDeprecated];
|
||||
lambdaPragmas = {@set}[FirstCallConv..LastCallConv,
|
||||
wImportc, wExportc, wNodecl, wNosideEffect, wSideEffect,
|
||||
wNoreturn, wDynLib, wHeader, wPure, wDeprecated];
|
||||
@@ -545,7 +546,8 @@ begin
|
||||
end;
|
||||
wDeprecated: begin
|
||||
noVal(it);
|
||||
include(sym.flags, sfDeprecated);
|
||||
if sym <> nil then include(sym.flags, sfDeprecated)
|
||||
else include(c.module.flags, sfDeprecated);
|
||||
end;
|
||||
wVarargs: begin
|
||||
noVal(it);
|
||||
|
||||
@@ -1235,6 +1235,10 @@ begin
|
||||
putWithSpace(g, tkProc, 'proc');
|
||||
gproc(g, n);
|
||||
end;
|
||||
nkMethodDef: begin
|
||||
putWithSpace(g, tkMethod, 'method');
|
||||
gproc(g, n);
|
||||
end;
|
||||
nkIteratorDef: begin
|
||||
putWithSpace(g, tkIterator, 'iterator');
|
||||
gproc(g, n);
|
||||
|
||||
@@ -519,7 +519,7 @@ begin
|
||||
s := n.sons[namePos].sym;
|
||||
addInterfaceSym(w, s);
|
||||
end;
|
||||
nkProcDef, nkIteratorDef, nkConverterDef: begin
|
||||
nkProcDef, nkMethodDef, nkIteratorDef, nkConverterDef: begin
|
||||
s := n.sons[namePos].sym;
|
||||
if s = nil then InternalError(n.info, 'rodwrite.process');
|
||||
if (n.sons[codePos] <> nil) or (s.magic <> mNone)
|
||||
|
||||
11
nim/sem.pas
11
nim/sem.pas
@@ -56,6 +56,12 @@ begin
|
||||
result.info := n.info;
|
||||
end;
|
||||
|
||||
procedure markUsed(n: PNode; s: PSym);
|
||||
begin
|
||||
include(s.flags, sfUsed);
|
||||
if sfDeprecated in s.flags then liMessage(n.info, warnDeprecated, s.name.s);
|
||||
end;
|
||||
|
||||
function semIdentVis(c: PContext; kind: TSymKind; n: PNode;
|
||||
const allowed: TSymFlags): PSym; forward;
|
||||
// identifier with visability
|
||||
@@ -130,7 +136,7 @@ var
|
||||
p: PEvalContext;
|
||||
s: PStackFrame;
|
||||
begin
|
||||
include(sym.flags, sfUsed);
|
||||
markUsed(n, sym);
|
||||
p := newEvalContext(c.module, '', false);
|
||||
s := newStackFrame();
|
||||
s.call := n;
|
||||
@@ -179,7 +185,8 @@ begin
|
||||
it := c.generics.sons[i].sons[1];
|
||||
if it.kind <> nkSym then InternalError('addCodeForGenerics');
|
||||
prc := it.sym;
|
||||
if (prc.kind in [skProc, skConverter]) and (prc.magic = mNone) then begin
|
||||
if (prc.kind in [skProc, skMethod, skConverter])
|
||||
and (prc.magic = mNone) then begin
|
||||
if (prc.ast = nil) or (prc.ast.sons[codePos] = nil) then
|
||||
InternalError(prc.info, 'no code for ' + prc.name.s);
|
||||
addSon(n, prc.ast);
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
function semTemplateExpr(c: PContext; n: PNode; s: PSym;
|
||||
semCheck: bool = true): PNode;
|
||||
begin
|
||||
include(s.flags, sfUsed);
|
||||
markUsed(n, s);
|
||||
pushInfoContext(n.info);
|
||||
result := evalTemplate(c, n, s);
|
||||
if semCheck then
|
||||
@@ -47,8 +47,6 @@ var
|
||||
diff: int;
|
||||
begin
|
||||
diff := inheritanceDiff(castDest, src);
|
||||
//if diff = 0 then
|
||||
// liMessage(info, hintConvToBaseNotNeeded)
|
||||
if diff = high(int) then
|
||||
liMessage(info, errGenerated,
|
||||
format(MsgKindToString(errIllegalConvFromXtoY),
|
||||
@@ -136,7 +134,7 @@ begin
|
||||
else begin
|
||||
for i := 0 to sonsLen(op)-1 do begin
|
||||
if sameType(result.typ, op.sons[i].typ) then begin
|
||||
include(op.sons[i].sym.flags, sfUsed);
|
||||
markUsed(n, op.sons[i].sym);
|
||||
result := op.sons[i]; exit
|
||||
end
|
||||
end;
|
||||
@@ -453,8 +451,7 @@ const
|
||||
FakeVarParams = {@set}[mNew, mNewFinalize, mInc, ast.mDec, mIncl,
|
||||
mExcl, mSetLengthStr, mSetLengthSeq,
|
||||
mAppendStrCh, mAppendStrStr, mSwap,
|
||||
mAppendSeqElem, mAppendSeqSeq,
|
||||
mNewSeq];
|
||||
mAppendSeqElem, mNewSeq];
|
||||
var
|
||||
i: int;
|
||||
t: PType;
|
||||
@@ -474,7 +471,7 @@ var
|
||||
callee: PSym;
|
||||
begin
|
||||
if not (efWantIterator in flags) then
|
||||
result := semDirectCall(c, n, {@set}[skProc, skConverter])
|
||||
result := semDirectCall(c, n, {@set}[skProc, skMethod, skConverter])
|
||||
else
|
||||
result := semDirectCall(c, n, {@set}[skIterator]);
|
||||
if result <> nil then begin
|
||||
@@ -586,17 +583,23 @@ begin
|
||||
result := n;
|
||||
end;
|
||||
|
||||
function LookUpForDefined(c: PContext; n: PNode): PSym;
|
||||
function LookUpForDefined(c: PContext; n: PNode; onlyCurrentScope: bool): PSym;
|
||||
var
|
||||
m: PSym;
|
||||
ident: PIdent;
|
||||
begin
|
||||
case n.kind of
|
||||
nkIdent: result := SymtabGet(c.Tab, n.ident); // no need for stub loading
|
||||
nkIdent: begin
|
||||
if onlyCurrentScope then
|
||||
result := SymtabLocalGet(c.tab, n.ident)
|
||||
else
|
||||
result := SymtabGet(c.Tab, n.ident); // no need for stub loading
|
||||
end;
|
||||
nkDotExpr, nkQualified: begin
|
||||
checkSonsLen(n, 2);
|
||||
result := nil;
|
||||
m := LookupForDefined(c, n.sons[0]);
|
||||
if onlyCurrentScope then exit;
|
||||
checkSonsLen(n, 2);
|
||||
m := LookupForDefined(c, n.sons[0], onlyCurrentScope);
|
||||
if (m <> nil) and (m.kind = skModule) then begin
|
||||
if (n.sons[1].kind = nkIdent) then begin
|
||||
ident := n.sons[1].ident;
|
||||
@@ -612,7 +615,7 @@ begin
|
||||
end;
|
||||
nkAccQuoted: begin
|
||||
checkSonsLen(n, 1);
|
||||
result := lookupForDefined(c, n.sons[0]);
|
||||
result := lookupForDefined(c, n.sons[0], onlyCurrentScope);
|
||||
end
|
||||
else begin
|
||||
liMessage(n.info, errIdentifierExpected, renderTree(n));
|
||||
@@ -621,14 +624,14 @@ begin
|
||||
end
|
||||
end;
|
||||
|
||||
function semDefined(c: PContext; n: PNode): PNode;
|
||||
function semDefined(c: PContext; n: PNode; onlyCurrentScope: bool): PNode;
|
||||
begin
|
||||
checkSonsLen(n, 2);
|
||||
result := newIntNode(nkIntLit, 0);
|
||||
// we replace this node by a 'true' or 'false' node
|
||||
if LookUpForDefined(c, n.sons[1]) <> nil then
|
||||
if LookUpForDefined(c, n.sons[1], onlyCurrentScope) <> nil then
|
||||
result.intVal := 1
|
||||
else if (n.sons[1].kind = nkIdent)
|
||||
else if not onlyCurrentScope and (n.sons[1].kind = nkIdent)
|
||||
and condsyms.isDefined(n.sons[1].ident) then
|
||||
result.intVal := 1;
|
||||
result.info := n.info;
|
||||
@@ -647,8 +650,8 @@ function semMagic(c: PContext; n: PNode; s: PSym; flags: TExprFlags): PNode;
|
||||
begin
|
||||
result := n;
|
||||
case s.magic of // magics that need special treatment
|
||||
mDefined: result := semDefined(c, setMs(n, s));
|
||||
mDefinedInScope: result := semDefinedInScope(c, setMs(n, s));
|
||||
mDefined: result := semDefined(c, setMs(n, s), false);
|
||||
mDefinedInScope: result := semDefined(c, setMs(n, s), true);
|
||||
mLow: result := semLowHigh(c, setMs(n, s), mLow);
|
||||
mHigh: result := semLowHigh(c, setMs(n, s), mHigh);
|
||||
mSizeOf: result := semSizeof(c, setMs(n, s));
|
||||
@@ -658,11 +661,6 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure checkDeprecated(n: PNode; s: PSym);
|
||||
begin
|
||||
if sfDeprecated in s.flags then liMessage(n.info, warnDeprecated, s.name.s);
|
||||
end;
|
||||
|
||||
function isTypeExpr(n: PNode): bool;
|
||||
begin
|
||||
case n.kind of
|
||||
@@ -795,7 +793,7 @@ begin
|
||||
result := newSymNode(f);
|
||||
result.info := n.info;
|
||||
result.typ := ty;
|
||||
checkDeprecated(n, f);
|
||||
markUsed(n, f);
|
||||
end
|
||||
else
|
||||
liMessage(n.sons[1].info, errEnumHasNoValueX, i.s);
|
||||
@@ -823,7 +821,7 @@ begin
|
||||
n.sons[0] := makeDeref(n.sons[0]);
|
||||
n.sons[1] := newSymNode(f); // we now have the correct field
|
||||
n.typ := f.typ;
|
||||
checkDeprecated(n, f);
|
||||
markUsed(n, f);
|
||||
if check = nil then result := n
|
||||
else begin
|
||||
check.sons[0] := n;
|
||||
@@ -841,7 +839,7 @@ begin
|
||||
n.sons[1] := newSymNode(f);
|
||||
n.typ := f.typ;
|
||||
result := n;
|
||||
checkDeprecated(n, f);
|
||||
markUsed(n, f);
|
||||
exit
|
||||
end
|
||||
end;
|
||||
@@ -851,7 +849,7 @@ begin
|
||||
//if (f <> nil) and (f.kind = skStub) then loadStub(f);
|
||||
// ``loadStub`` is not correct here as we don't care for ``f`` really
|
||||
if (f <> nil) then begin
|
||||
// BUGFIX: do not check for (f.kind in [skProc, skIterator]) here
|
||||
// BUGFIX: do not check for (f.kind in [skProc, skMethod, skIterator]) here
|
||||
result := newNodeI(nkDotCall, n.info);
|
||||
// This special node kind is to merge with the call handler in `semExpr`.
|
||||
addSon(result, newIdentNode(i, n.info));
|
||||
@@ -1145,7 +1143,6 @@ begin
|
||||
a := n.sons[0];
|
||||
s := qualifiedLookup(c, a, false);
|
||||
if (s <> nil) then begin
|
||||
checkDeprecated(n, s);
|
||||
case s.kind of
|
||||
skMacro: result := semMacroExpr(c, n, s, semCheck);
|
||||
skTemplate: begin
|
||||
@@ -1176,7 +1173,7 @@ begin
|
||||
if (s.kind = skType) and not (efAllowType in flags) then
|
||||
liMessage(n.info, errATypeHasNoValue);
|
||||
case s.kind of
|
||||
skProc, skIterator, skConverter: begin
|
||||
skProc, skMethod, skIterator, skConverter: begin
|
||||
if (s.magic <> mNone) then
|
||||
liMessage(n.info, errInvalidContextForBuiltinX, s.name.s);
|
||||
result := symChoice(c, n, s);
|
||||
@@ -1194,7 +1191,7 @@ begin
|
||||
copy `x`'s AST into each context, so that the type fixup phase can
|
||||
deal with two different ``[]``.
|
||||
*)
|
||||
include(s.flags, sfUsed);
|
||||
markUsed(n, s);
|
||||
if s.typ.kind in ConstAbstractTypes then begin
|
||||
result := copyTree(s.ast);
|
||||
result.info := n.info;
|
||||
@@ -1208,7 +1205,7 @@ begin
|
||||
skMacro: result := semMacroExpr(c, n, s);
|
||||
skTemplate: result := semTemplateExpr(c, n, s);
|
||||
skVar: begin
|
||||
include(s.flags, sfUsed);
|
||||
markUsed(n, s);
|
||||
// if a proc accesses a global variable, it is not side effect free
|
||||
if sfGlobal in s.flags then include(c.p.owner.flags, sfSideEffect);
|
||||
result := newSymNode(s);
|
||||
@@ -1219,12 +1216,11 @@ begin
|
||||
result := semExpr(c, s.ast);
|
||||
end
|
||||
else begin
|
||||
include(s.flags, sfUsed);
|
||||
markUsed(n, s);
|
||||
result := newSymNode(s);
|
||||
result.info := n.info;
|
||||
end
|
||||
end;
|
||||
checkDeprecated(n, s);
|
||||
end;
|
||||
|
||||
function semDotExpr(c: PContext; n: PNode; flags: TExprFlags): PNode;
|
||||
@@ -1259,7 +1255,7 @@ begin
|
||||
if (s.kind = skType) and not (efAllowType in flags) then
|
||||
liMessage(n.info, errATypeHasNoValue);
|
||||
if (s.magic <> mNone) and
|
||||
(s.kind in [skProc, skIterator, skConverter]) then
|
||||
(s.kind in [skProc, skMethod, skIterator, skConverter]) then
|
||||
liMessage(n.info, errInvalidContextForBuiltinX, s.name.s); *)
|
||||
// because of the changed symbol binding, this does not mean that we
|
||||
// don't have to check the symbol for semantics here again!
|
||||
@@ -1296,18 +1292,16 @@ begin
|
||||
checkMinSonsLen(n, 1);
|
||||
s := qualifiedLookup(c, n.sons[0], false);
|
||||
if (s <> nil) then begin
|
||||
checkDeprecated(n, s);
|
||||
case s.kind of
|
||||
skMacro: result := semMacroExpr(c, n, s);
|
||||
skTemplate: result := semTemplateExpr(c, n, s);
|
||||
skType: begin
|
||||
include(s.flags, sfUsed);
|
||||
if n.kind <> nkCall then
|
||||
liMessage(n.info, errXisNotCallable, s.name.s);
|
||||
// XXX does this check make any sense?
|
||||
result := semConv(c, n, s);
|
||||
end;
|
||||
skProc, skConverter, skIterator: begin
|
||||
skProc, skMethod, skConverter, skIterator: begin
|
||||
if s.magic = mNone then result := semDirectOp(c, n, flags)
|
||||
else result := semMagic(c, n, s, flags);
|
||||
end;
|
||||
@@ -1328,7 +1322,8 @@ begin
|
||||
nkBracketExpr: begin
|
||||
checkMinSonsLen(n, 1);
|
||||
s := qualifiedLookup(c, n.sons[0], false);
|
||||
if (s <> nil) and (s.kind in [skProc, skConverter, skIterator]) then begin
|
||||
if (s <> nil)
|
||||
and (s.kind in [skProc, skMethod, skConverter, skIterator]) then begin
|
||||
// type parameters: partial generic specialization
|
||||
// XXX: too implement!
|
||||
internalError(n.info, 'explicit generic instantation not implemented');
|
||||
|
||||
@@ -288,7 +288,7 @@ begin
|
||||
result.typ := n.typ;
|
||||
end;
|
||||
mNewString, mExit, mInc, ast.mDec, mEcho, mAssert, mSwap,
|
||||
mAppendStrCh, mAppendStrStr, mAppendSeqElem, mAppendSeqSeq,
|
||||
mAppendStrCh, mAppendStrStr, mAppendSeqElem,
|
||||
mSetLengthStr, mSetLengthSeq, mNLen..mNError: begin end;
|
||||
else InternalError(a.info, 'evalOp(' +{&} magicToStr[m] +{&} ')');
|
||||
end
|
||||
@@ -412,7 +412,7 @@ begin
|
||||
else result := copyTree(s.ast); // BUGFIX
|
||||
end
|
||||
end
|
||||
else if s.kind = skProc then // BUGFIX
|
||||
else if s.kind in [skProc, skMethod] then // BUGFIX
|
||||
result := n
|
||||
end;
|
||||
nkCharLit..nkNilLit: result := copyNode(n);
|
||||
|
||||
@@ -182,7 +182,7 @@ begin
|
||||
addDecl(c, result);
|
||||
if n.sons[codePos] <> nil then begin
|
||||
c.p := newProcCon(result);
|
||||
if result.kind in [skProc, skConverter] then begin
|
||||
if result.kind in [skProc, skMethod, skConverter] then begin
|
||||
addResult(c, result.typ.sons[0], n.info);
|
||||
addResultNode(c, n);
|
||||
end;
|
||||
|
||||
@@ -316,7 +316,7 @@ var
|
||||
begin
|
||||
result := n;
|
||||
checkSonsLen(n, 1);
|
||||
if not (c.p.owner.kind in [skConverter, skProc, skMacro]) then
|
||||
if not (c.p.owner.kind in [skConverter, skMethod, skProc, skMacro]) then
|
||||
liMessage(n.info, errXNotAllowedHere, '''return''');
|
||||
if (n.sons[0] <> nil) then begin
|
||||
n.sons[0] := SemExprWithType(c, n.sons[0]);
|
||||
@@ -970,11 +970,20 @@ begin
|
||||
result := semProcAux(c, n, skProc, procPragmas);
|
||||
end;
|
||||
|
||||
function semMethod(c: PContext; n: PNode): PNode;
|
||||
begin
|
||||
if not isTopLevel(c) then
|
||||
liMessage(n.info, errXOnlyAtModuleScope, 'method');
|
||||
result := semProcAux(c, n, skMethod, methodPragmas);
|
||||
end;
|
||||
|
||||
function semConverterDef(c: PContext; n: PNode): PNode;
|
||||
var
|
||||
t: PType;
|
||||
s: PSym;
|
||||
begin
|
||||
if not isTopLevel(c) then
|
||||
liMessage(n.info, errXOnlyAtModuleScope, 'converter');
|
||||
checkSonsLen(n, codePos+1);
|
||||
if n.sons[genericParamsPos] <> nil then
|
||||
liMessage(n.info, errNoGenericParamsAllowedForX, 'converter');
|
||||
@@ -1080,6 +1089,7 @@ begin
|
||||
nkPragma: pragma(c, c.p.owner, n, stmtPragmas);
|
||||
nkIteratorDef: result := semIterator(c, n);
|
||||
nkProcDef: result := semProc(c, n);
|
||||
nkMethodDef: result := semMethod(c, n);
|
||||
nkConverterDef: result := semConverterDef(c, n);
|
||||
nkMacroDef: result := semMacroDef(c, n);
|
||||
nkTemplateDef: result := semTemplateDef(c, n);
|
||||
|
||||
@@ -94,7 +94,7 @@ begin
|
||||
if i < a then
|
||||
arg := n.sons[i]
|
||||
else
|
||||
arg := copyTree(s.ast.sons[paramsPos].sons[i-1].sym.ast);
|
||||
arg := copyTree(s.typ.n.sons[i].sym.ast);
|
||||
if arg = nil then liMessage(n.info, errWrongNumberOfArguments);
|
||||
if not (s.typ.sons[i].kind in [tyTypeDesc, tyStmt, tyExpr]) then begin
|
||||
// concrete type means semantic checking for argument:
|
||||
@@ -132,7 +132,7 @@ begin
|
||||
if i <= 1 then begin
|
||||
result := newSymNode(s);
|
||||
result.info := n.info;
|
||||
include(s.flags, sfUsed);
|
||||
markUsed(n, s);
|
||||
end
|
||||
else begin
|
||||
// semantic checking requires a type; ``fitNode`` deals with it
|
||||
|
||||
@@ -232,7 +232,7 @@ function semTypeIdent(c: PContext; n: PNode): PSym;
|
||||
begin
|
||||
result := qualifiedLookup(c, n, true);
|
||||
if (result <> nil) then begin
|
||||
include(result.flags, sfUsed);
|
||||
markUsed(n, result);
|
||||
if result.kind <> skType then liMessage(n.info, errTypeExpected);
|
||||
end
|
||||
else
|
||||
@@ -792,7 +792,7 @@ begin
|
||||
assignType(prev, t);
|
||||
result := prev;
|
||||
end;
|
||||
include(n.sym.flags, sfUsed); // BUGFIX
|
||||
markUsed(n, n.sym);
|
||||
end
|
||||
else
|
||||
liMessage(n.info, errTypeExpected);
|
||||
|
||||
@@ -103,7 +103,7 @@ begin
|
||||
candidates := '';
|
||||
sym := initOverloadIter(o, c, n.sons[0]);
|
||||
while sym <> nil do begin
|
||||
if sym.kind in [skProc, skIterator, skConverter] then begin
|
||||
if sym.kind in [skProc, skMethod, skIterator, skConverter] then begin
|
||||
add(candidates, getProcHeader(sym));
|
||||
add(candidates, nl)
|
||||
end;
|
||||
@@ -709,7 +709,7 @@ begin
|
||||
best := -1;
|
||||
for i := 0 to sonsLen(arg)-1 do begin
|
||||
// iterators are not first class yet, so ignore them
|
||||
if arg.sons[i].sym.kind in {@set}[skProc, skConverter] then begin
|
||||
if arg.sons[i].sym.kind in {@set}[skProc, skMethod, skConverter] then begin
|
||||
copyCandidate(z, m);
|
||||
r := typeRel(z.bindings, f, arg.sons[i].typ);
|
||||
if r <> isNone then begin
|
||||
@@ -734,7 +734,7 @@ begin
|
||||
end
|
||||
else begin
|
||||
// only one valid interpretation found:
|
||||
include(arg.sons[best].sym.flags, sfUsed);
|
||||
markUsed(arg, arg.sons[best].sym);
|
||||
result := ParamTypesMatchAux(c, m, f, arg.sons[best].typ, arg.sons[best]);
|
||||
end
|
||||
end
|
||||
@@ -884,6 +884,19 @@ begin
|
||||
end
|
||||
end;
|
||||
|
||||
function sameMethodDispatcher(a, b: PSym): bool;
|
||||
var
|
||||
aa, bb: PNode;
|
||||
begin
|
||||
result := false;
|
||||
if (a.kind = skMethod) and (b.kind = skMethod) then begin
|
||||
aa := lastSon(a.ast);
|
||||
bb := lastSon(b.ast);
|
||||
if (aa.kind = nkSym) and (bb.kind = nkSym) and
|
||||
(aa.sym = bb.sym) then result := true
|
||||
end
|
||||
end;
|
||||
|
||||
function semDirectCall(c: PContext; n: PNode; filter: TSymKinds): PNode;
|
||||
var
|
||||
sym: PSym;
|
||||
@@ -923,7 +936,8 @@ begin
|
||||
// do not generate an error yet; the semantic checking will check for
|
||||
// an overloaded () operator
|
||||
end
|
||||
else if (y.state = csMatch) and (cmpCandidates(x, y) = 0) then begin
|
||||
else if (y.state = csMatch) and (cmpCandidates(x, y) = 0)
|
||||
and not sameMethodDispatcher(x.calleeSym, y.calleeSym) then begin
|
||||
if x.state <> csMatch then
|
||||
InternalError(n.info, 'x.state is not csMatch');
|
||||
//writeMatches(x);
|
||||
@@ -935,7 +949,7 @@ begin
|
||||
end
|
||||
else begin
|
||||
// only one valid interpretation found:
|
||||
include(x.calleeSym.flags, sfUsed);
|
||||
markUsed(n, x.calleeSym);
|
||||
if x.calleeSym.ast = nil then
|
||||
internalError(n.info, 'calleeSym.ast is nil'); // XXX: remove this check!
|
||||
if x.calleeSym.ast.sons[genericParamsPos] <> nil then begin
|
||||
|
||||
@@ -15,7 +15,7 @@ unit transf;
|
||||
// * inlines constants
|
||||
// * performes contant folding
|
||||
// * introduces nkHiddenDeref, nkHiddenSubConv, etc.
|
||||
// * aggressive compile-time evaluation based on the side-effect analysis
|
||||
// * introduces method dispatchers
|
||||
|
||||
interface
|
||||
|
||||
@@ -24,7 +24,7 @@ interface
|
||||
uses
|
||||
sysutils, nsystem, charsets, strutils,
|
||||
lists, options, ast, astalgo, trees, treetab, evals,
|
||||
msgs, nos, idents, rnimsyn, types, passes, semfold, magicsys;
|
||||
msgs, nos, idents, rnimsyn, types, passes, semfold, magicsys, cgmeth;
|
||||
|
||||
const
|
||||
genPrefix = ':tmp'; // prefix for generated names
|
||||
@@ -574,7 +574,7 @@ end;
|
||||
function getMagicOp(call: PNode): TMagic;
|
||||
begin
|
||||
if (call.sons[0].kind = nkSym)
|
||||
and (call.sons[0].sym.kind in [skProc, skConverter]) then
|
||||
and (call.sons[0].sym.kind in [skProc, skMethod, skConverter]) then
|
||||
result := call.sons[0].sym.magic
|
||||
else
|
||||
result := mNone
|
||||
@@ -842,6 +842,11 @@ begin
|
||||
if sonsLen(result) = 2 then
|
||||
result := result.sons[1];
|
||||
end
|
||||
else if (result.sons[0].kind = nkSym)
|
||||
and (result.sons[0].sym.kind = skMethod) then begin
|
||||
// use the dispatcher for the call:
|
||||
result := methodCall(result);
|
||||
end
|
||||
(*
|
||||
else if result.sons[0].kind = nkSym then begin
|
||||
// optimization still too aggressive
|
||||
@@ -882,9 +887,12 @@ begin
|
||||
nkLambda: result := transformLambda(c, n);
|
||||
nkForStmt: result := transformFor(c, n);
|
||||
nkCaseStmt: result := transformCase(c, n);
|
||||
nkProcDef, nkIteratorDef, nkMacroDef: begin
|
||||
if n.sons[genericParamsPos] = nil then
|
||||
nkProcDef, nkMethodDef, nkIteratorDef, nkMacroDef: begin
|
||||
if n.sons[genericParamsPos] = nil then begin
|
||||
n.sons[codePos] := transform(c, n.sons[codePos]);
|
||||
if n.kind = nkMethodDef then
|
||||
methodDef(n.sons[namePos].sym);
|
||||
end
|
||||
end;
|
||||
nkWhileStmt: begin
|
||||
if (sonsLen(n) <> 2) then InternalError(n.info, 'transform');
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
## Nimrod shall produce.
|
||||
|
||||
import
|
||||
strutils, regexprs, os, osproc, streams
|
||||
strutils, pegs, os, osproc, streams
|
||||
|
||||
const
|
||||
cmdTemplate = r"nimrod cc --hints:on $options $filename"
|
||||
@@ -38,7 +38,7 @@ type
|
||||
|
||||
proc myExec(cmd: string): string =
|
||||
#echo("Executing: " & cmd)
|
||||
result = osproc.executeProcess(cmd)
|
||||
result = osproc.execProcess(cmd)
|
||||
#echo("Received: " & result)
|
||||
|
||||
proc parseTest(filename: string): TSpec =
|
||||
@@ -49,24 +49,30 @@ proc parseTest(filename: string): TSpec =
|
||||
result.file = filename
|
||||
for s in lines(filename):
|
||||
inc(i)
|
||||
if find(s, r"\#OUT\s*(.*)", matches):
|
||||
result.outp = matches[1]
|
||||
if contains(s, peg"'#OUT' \s+ {.*}", matches):
|
||||
result.outp = matches[0]
|
||||
break
|
||||
if find(s, r"\#ERROR_IN\s*(\S*)\s*(\d+)", matches):
|
||||
result.file = matches[1]
|
||||
result.line = parseInt(matches[2])
|
||||
if contains(s, peg"'#ERROR_IN' \s* {\S*} \s* {\d+}", matches):
|
||||
result.file = matches[0]
|
||||
result.line = parseInt(matches[1])
|
||||
result.err = true
|
||||
break
|
||||
if find(s, r"\#ERROR_MSG\s*(.*)", matches):
|
||||
if contains(s, peg"'#ERROR_MSG' \s* {.*}", matches):
|
||||
result.line = i
|
||||
result.outp = matches[1]
|
||||
result.outp = matches[0]
|
||||
result.err = True
|
||||
break
|
||||
if find(s, r"\#ERROR$", matches):
|
||||
if contains(s, peg"'#ERROR' \s* !.", matches):
|
||||
result.line = i
|
||||
result.err = true
|
||||
break
|
||||
|
||||
var
|
||||
pegLineError = peg"{[^(]*} '(' {\d+} ', ' \d+ ') Error:' \s* {.*}"
|
||||
pegOtherError = peg"'Error:' \s* {.*}"
|
||||
pegSuccess = peg"'Hint: operation successful'.*"
|
||||
pegOfInterest = pegLineError / pegOtherError / pegSuccess
|
||||
|
||||
proc callCompiler(filename, options: string): TSpec =
|
||||
var c = parseCmdLine(cmdTemplate % ["filename", filename, "options", options])
|
||||
var a: seq[string] = @[] # slicing is not yet implemented :-(
|
||||
@@ -77,52 +83,50 @@ proc callCompiler(filename, options: string): TSpec =
|
||||
var s = ""
|
||||
while running(p) or not outp.atEnd(outp):
|
||||
var x = outp.readLine()
|
||||
if match(x, r"(.*)\((\d+), \d+\) Error\: (.*)") or
|
||||
match(x, r"Error\: (.*)") or
|
||||
match(x, r"Hint\: operation successful"):
|
||||
if x =~ pegOfInterest:
|
||||
# `s` should contain the last error message
|
||||
s = x
|
||||
result.outp = ""
|
||||
result.puremsg = ""
|
||||
result.file = ""
|
||||
result.err = true
|
||||
if s =~ r"(.*)\((\d+), \d+\) Error\: (.*)":
|
||||
result.file = matches[1]
|
||||
result.line = parseInt(matches[2])
|
||||
result.outp = matches[0]
|
||||
result.puremsg = matches[3]
|
||||
elif s =~ r"Error\: (.*)":
|
||||
result.puremsg = matches[1]
|
||||
result.outp = matches[0]
|
||||
if s =~ pegLineError:
|
||||
result.file = matches[0]
|
||||
result.line = parseInt(matches[1])
|
||||
result.outp = s
|
||||
result.puremsg = matches[2]
|
||||
elif s =~ pegOtherError:
|
||||
result.puremsg = matches[0]
|
||||
result.outp = s
|
||||
result.line = 1
|
||||
elif s =~ r"Hint\: operation successful":
|
||||
result.outp = matches[0]
|
||||
elif s =~ pegSuccess:
|
||||
result.outp = s
|
||||
result.err = false
|
||||
|
||||
proc cmpResults(filename: string, spec, comp: TSpec): bool =
|
||||
proc sameResults(filename: string, spec, comp: TSpec): bool =
|
||||
# short filename for messages (better readability):
|
||||
var shortfile = os.extractFilename(filename)
|
||||
|
||||
if comp.err and comp.outp == "":
|
||||
# the compiler did not say "[Error]" nor "operation sucessful"
|
||||
Echo("[Tester] $1 -- FAILED; COMPILER BROKEN" % shortfile)
|
||||
Echo("[Tester] $# -- FAILED; COMPILER BROKEN" % shortfile)
|
||||
elif spec.err != comp.err:
|
||||
Echo(("[Tester] $1 -- FAILED\n" &
|
||||
"Compiler says: $2\n" &
|
||||
"But specification says: $3") %
|
||||
Echo(("[Tester] $# -- FAILED\n" &
|
||||
"Compiler says: $#\n" &
|
||||
"But specification says: $#") %
|
||||
[shortfile, comp.outp, spec.outp])
|
||||
elif spec.err:
|
||||
if extractFilename(comp.file) != extractFilename(spec.file):
|
||||
Echo(("[Tester] $1 -- FAILED: file names do not match:\n" &
|
||||
"Compiler: $2\nSpec: $3") % [shortfile, comp.file, spec.file])
|
||||
Echo(("[Tester] $# -- FAILED: file names do not match:\n" &
|
||||
"Compiler: $#\nSpec: $#") % [shortfile, comp.file, spec.file])
|
||||
elif strip(spec.outp) notin strip(comp.puremsg):
|
||||
Echo(("[Tester] $1 -- FAILED: error messages do not match:\n" &
|
||||
"Compiler: $2\nSpec: $3") % [shortfile, comp.pureMsg, spec.outp])
|
||||
Echo(("[Tester] $# -- FAILED: error messages do not match:\n" &
|
||||
"Compiler: $#\nSpec: $#") % [shortfile, comp.pureMsg, spec.outp])
|
||||
elif comp.line != spec.line:
|
||||
Echo(("[Tester] $1 -- FAILED: line numbers do not match:\n" &
|
||||
"Compiler: $2\nSpec: $3") % [shortfile, $comp.line, $spec.line])
|
||||
Echo(("[Tester] $# -- FAILED: line numbers do not match:\n" &
|
||||
"Compiler: $#\nSpec: $#") % [shortfile, $comp.line, $spec.line])
|
||||
else:
|
||||
Echo("[Tester] $1 -- OK" % shortfile)
|
||||
Echo("[Tester] $# -- OK" % shortfile)
|
||||
result = true
|
||||
else:
|
||||
# we have to run the executable and check its output:
|
||||
@@ -131,17 +135,17 @@ proc cmpResults(filename: string, spec, comp: TSpec): bool =
|
||||
if len(spec.outp) == 0:
|
||||
# we have no output to validate against, but compilation succeeded,
|
||||
# so it's okay:
|
||||
Echo("[Tester] $1 -- OK" % shortfile)
|
||||
Echo("[Tester] $# -- OK" % shortfile)
|
||||
result = true
|
||||
else:
|
||||
var buf = myExec(exeFile)
|
||||
result = strip(buf) == strip(spec.outp)
|
||||
if result:
|
||||
Echo("[Tester] $1 -- compiled program OK" % shortfile)
|
||||
Echo("[Tester] $# -- compiled program OK" % shortfile)
|
||||
else:
|
||||
Echo("[Tester] $1 -- compiled program FAILED" % shortfile)
|
||||
Echo("[Tester] $# -- compiled program FAILED" % shortfile)
|
||||
else:
|
||||
Echo("[Tester] $1 -- FAILED; executable not found" % shortfile)
|
||||
Echo("[Tester] $# -- FAILED; executable not found" % shortfile)
|
||||
|
||||
proc main(options: string) =
|
||||
# runs the complete testsuite
|
||||
@@ -151,16 +155,17 @@ proc main(options: string) =
|
||||
if extractFilename(filename) == "tester.nim": continue
|
||||
var spec = parseTest(filename)
|
||||
var comp = callCompiler(filename, options)
|
||||
if cmpResults(filename, spec, comp): inc(passed)
|
||||
if sameResults(filename, spec, comp): inc(passed)
|
||||
inc(total)
|
||||
# ensure that the examples at least compile
|
||||
# ensure that the examples at least compiles
|
||||
for filename in os.walkFiles("examples/*.nim"):
|
||||
if executeShellCommand(cmdTemplate %
|
||||
["filename", filename, "options", options]) == 0:
|
||||
inc(passed)
|
||||
else:
|
||||
var shortfile = os.extractFilename(filename)
|
||||
var comp = callCompiler(filename, options)
|
||||
var shortfile = os.extractFilename(filename)
|
||||
if comp.err:
|
||||
Echo("[Tester] Example '$#' -- FAILED" % shortfile)
|
||||
else:
|
||||
Echo("[Tester] Example $# -- OK" % shortfile)
|
||||
inc(passed)
|
||||
inc(total)
|
||||
Echo("[Tester] $#/$# tests passed\n" % [$passed, $total])
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ Name: english; MessagesFile: compiler:Default.isl
|
||||
[Files]
|
||||
#for i in low(TFileCategory)..fcWindows:
|
||||
# for f in items(c.cat[i]):
|
||||
Source: ${expandFilename(f)}; DestDir: {app}\${extractDir(f)}; Flags: ignoreversion
|
||||
Source: ${expandFilename(f)}; DestDir: {app}\${splitFile(f).dir}; Flags: ignoreversion
|
||||
# end for
|
||||
#end for
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ if [ $# -eq 1 ] ; then
|
||||
#var createdDirs = newStringTable()
|
||||
#for cat in fcConfig..fcLib:
|
||||
# for f in items(c.cat[cat]):
|
||||
# var mk = extractDir(f.skipRoot)
|
||||
# var mk = splitFile(f.skipRoot).dir
|
||||
# if mk.len > 0:
|
||||
# mk = unixDirVars[cat] & "/" & mk
|
||||
# if not createdDirs.hasKey(mk):
|
||||
|
||||
@@ -116,7 +116,7 @@ Compile_options:
|
||||
"""
|
||||
|
||||
proc parseCmdLine(c: var TConfigData) =
|
||||
var p = init()
|
||||
var p = initOptParser()
|
||||
while true:
|
||||
next(p)
|
||||
var kind = p.kind
|
||||
@@ -132,8 +132,8 @@ proc parseCmdLine(c: var TConfigData) =
|
||||
of "inno": incl(c.actions, actionInno)
|
||||
else: quit(Usage)
|
||||
else:
|
||||
c.infile = appendFileExt(key, "ini")
|
||||
c.nimrodArgs = getRestOfCommandLine(p)
|
||||
c.infile = addFileExt(key, "ini")
|
||||
c.nimrodArgs = cmdLineRest(p)
|
||||
break
|
||||
of cmdLongOption, cmdShortOption:
|
||||
case normalize(key)
|
||||
@@ -255,7 +255,7 @@ proc parseIniFile(c: var TConfigData) =
|
||||
proc readCFiles(c: var TConfigData, osA, cpuA: int) =
|
||||
var cfg: TCfgParser
|
||||
var cfilesSection = false
|
||||
var f = extractDir(c.infile) / "mapping.txt"
|
||||
var f = splitFile(c.infile).dir / "mapping.txt"
|
||||
c.cfiles[osA][cpuA] = @[]
|
||||
var input = newFileStream(f, fmRead)
|
||||
if input != nil:
|
||||
@@ -302,7 +302,7 @@ proc srcdist(c: var TConfigData) =
|
||||
[c.oses[osA-1], c.cpus[cpuA-1], c.nimrodArgs,
|
||||
changeFileExt(c.infile, "nim")]
|
||||
echo(cmd)
|
||||
if executeShellCommand(cmd) != 0:
|
||||
if execShellCmd(cmd) != 0:
|
||||
quit("Error: call to nimrod compiler failed")
|
||||
readCFiles(c, osA, cpuA)
|
||||
for i in 0 .. c.cfiles[osA][cpuA].len-1:
|
||||
|
||||
@@ -56,7 +56,7 @@ Compile_options:
|
||||
"""
|
||||
|
||||
proc parseCmdLine(c: var TConfigData) =
|
||||
var p = init()
|
||||
var p = initOptParser()
|
||||
while true:
|
||||
next(p)
|
||||
var kind = p.kind
|
||||
@@ -64,8 +64,8 @@ proc parseCmdLine(c: var TConfigData) =
|
||||
var val = p.val
|
||||
case kind
|
||||
of cmdArgument:
|
||||
c.infile = appendFileExt(key, "ini")
|
||||
c.nimrodArgs = getRestOfCommandLine(p)
|
||||
c.infile = addFileExt(key, "ini")
|
||||
c.nimrodArgs = cmdLineRest(p)
|
||||
break
|
||||
of cmdLongOption, cmdShortOption:
|
||||
case normalize(key)
|
||||
@@ -84,7 +84,7 @@ proc walkDirRecursively(s: var seq[string], root, ext: string) =
|
||||
for k, f in walkDir(root):
|
||||
case k
|
||||
of pcFile, pcLinkToFile:
|
||||
if cmpIgnoreCase(ext, extractFileExt(f)) == 0:
|
||||
if cmpIgnoreCase(ext, splitFile(f).ext) == 0:
|
||||
add(s, f)
|
||||
of pcDirectory: walkDirRecursively(s, f, ext)
|
||||
of pcLinkToDirectory: nil
|
||||
@@ -94,7 +94,7 @@ proc addFiles(s: var seq[string], dir, ext: string, patterns: seq[string]) =
|
||||
if existsDir(dir / p):
|
||||
walkDirRecursively(s, dir / p, ext)
|
||||
else:
|
||||
add(s, dir / appendFileExt(p, ext))
|
||||
add(s, dir / addFileExt(p, ext))
|
||||
|
||||
proc parseIniFile(c: var TConfigData) =
|
||||
var
|
||||
@@ -143,7 +143,7 @@ proc parseIniFile(c: var TConfigData) =
|
||||
if c.projectName.len == 0:
|
||||
c.projectName = changeFileExt(extractFilename(c.infile), "")
|
||||
if c.outdir.len == 0:
|
||||
c.outdir = extractDir(c.infile)
|
||||
c.outdir = splitFile(c.infile).dir
|
||||
else:
|
||||
quit("cannot open: " & c.infile)
|
||||
|
||||
@@ -151,18 +151,18 @@ proc parseIniFile(c: var TConfigData) =
|
||||
|
||||
proc Exec(cmd: string) =
|
||||
echo(cmd)
|
||||
if os.executeShellCommand(cmd) != 0: quit("external program failed")
|
||||
if os.execShellCmd(cmd) != 0: quit("external program failed")
|
||||
|
||||
proc buildDoc(c: var TConfigData, destPath: string) =
|
||||
# call nim for the documentation:
|
||||
for d in items(c.doc):
|
||||
Exec("nimrod rst2html $# -o:$# --index=$#/theindex $#" %
|
||||
[c.nimrodArgs, destPath / changeFileExt(extractFileTrunk(d), "html"),
|
||||
[c.nimrodArgs, destPath / changeFileExt(splitFile(d).name, "html"),
|
||||
destpath, d])
|
||||
Exec("nimrod rst2tex $# $#" % [c.nimrodArgs, d])
|
||||
for d in items(c.srcdoc):
|
||||
Exec("nimrod doc $# -o:$# --index=$#/theindex $#" %
|
||||
[c.nimrodArgs, destPath / changeFileExt(extractFileTrunk(d), "html"),
|
||||
[c.nimrodArgs, destPath / changeFileExt(splitFile(d).name, "html"),
|
||||
destpath, d])
|
||||
Exec("nimrod rst2html $1 -o:$2/theindex.html $2/theindex" %
|
||||
[c.nimrodArgs, destPath])
|
||||
@@ -171,7 +171,7 @@ proc buildAddDoc(c: var TConfigData, destPath: string) =
|
||||
# build additional documentation (without the index):
|
||||
for d in items(c.webdoc):
|
||||
Exec("nimrod doc $# -o:$# $#" %
|
||||
[c.nimrodArgs, destPath / changeFileExt(extractFileTrunk(d), "html"), d])
|
||||
[c.nimrodArgs, destPath / changeFileExt(splitFile(d).name, "html"), d])
|
||||
|
||||
proc main(c: var TConfigData) =
|
||||
const
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
import strutils, os
|
||||
|
||||
proc newName(f: string): string =
|
||||
return extractDir(f) / "trim_" & extractFilename(f)
|
||||
proc newName(f: string): string =
|
||||
var (dir, name, ext) = splitFile(f)
|
||||
return dir / "trim_" & name & ext
|
||||
|
||||
proc walker(dir: string) =
|
||||
for kind, path in walkDir(dir):
|
||||
@@ -11,7 +12,7 @@ proc walker(dir: string) =
|
||||
of pcFile:
|
||||
moveFile(newName(path), path)
|
||||
# test if installation still works:
|
||||
if executeShellCommand(r"nimrod c --force_build tests\tlastmod") == 0:
|
||||
if execShellCmd(r"nimrod c --force_build tests\tlastmod") == 0:
|
||||
echo "Optional: ", path
|
||||
removeFile(newName(path))
|
||||
else:
|
||||
|
||||
@@ -52,6 +52,7 @@ Nimrod is efficient
|
||||
from pointers to manually managed memory.
|
||||
* Zero-overhead iterators.
|
||||
* Cross-module inlining.
|
||||
* Dynamic method binding with inlining and without virtual method table.
|
||||
* Compile time evaluation of user-defined functions.
|
||||
* Whole program dead code elimination: Only *used functions* are included in
|
||||
the executable.
|
||||
@@ -78,10 +79,8 @@ Nimrod is elegant
|
||||
Nimrod's syntax is flexible enough.
|
||||
* Yet Nimrod can be parsed with an LL(1) parser.
|
||||
* Statements are grouped by indentation but can span multiple lines.
|
||||
Indentation must not contain tabulators so **the compiler always sees
|
||||
the code the same way as you do**.
|
||||
* Nimrod is a simple language that leads to simple programs. However,
|
||||
the language is not crippled in the name of simplicity.
|
||||
Indentation must not contain tabulators so the compiler always sees
|
||||
the code the same way as you do.
|
||||
|
||||
|
||||
Nimrod plays nice with others
|
||||
@@ -97,11 +96,10 @@ Nimrod plays nice with others
|
||||
* Nimrod's documentation syntax is a subset of the wonderfully readable plaintext
|
||||
markup syntax
|
||||
`reStructuredText <http://docutils.sourceforge.net/docs/user/rst/quickref.html>`_.
|
||||
**The documentation generator is very flexible; this website has been generated
|
||||
with it!**
|
||||
The documentation generator is very flexible; this website has been generated
|
||||
with it!
|
||||
|
||||
|
||||
|
||||
Roadmap to 1.0
|
||||
==============
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ Additions
|
||||
---------
|
||||
|
||||
- implemented generic types and two phase symbol lookup in generic routines
|
||||
- template parameters can now be real types
|
||||
- template parameters can now have real types
|
||||
- implemented generalized raw string literals: ``ident"abc"`` is a shortcut for
|
||||
``ident(r"abc")``
|
||||
- in overloading resolution iterators are separated from procs; iterators now
|
||||
|
||||
@@ -21,11 +21,11 @@ FAQ: question
|
||||
file: ticker
|
||||
|
||||
[Documentation]
|
||||
doc: "endb;intern;lib;manual;tut1;tut2;nimrodc;overview"
|
||||
doc: "endb;intern;apis;lib;manual;tut1;tut2;nimrodc;overview"
|
||||
srcdoc: "system.nim;pure/os;pure/strutils;pure/regexprs;pure/math"
|
||||
srcdoc: "pure/complex;pure/times;pure/osproc"
|
||||
srcdoc: "pure/complex;pure/times;pure/osproc;pure/pegs;pure/dynlib"
|
||||
srcdoc: "pure/parseopt;pure/hashes;pure/strtabs;pure/lexbase"
|
||||
srcdoc: "pure/parsecfg;pure/parsexml;pure/parsecsv"
|
||||
srcdoc: "pure/parsecfg;pure/parsexml;pure/parsecsv;pure/parsesql"
|
||||
srcdoc: "pure/streams;pure/terminal;pure/cgi;impure/web;pure/unicode"
|
||||
srcdoc: "impure/zipfiles;pure/xmlgen;pure/macros"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user