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