implemented multi methods

This commit is contained in:
Andreas Rumpf
2009-09-23 23:38:00 +02:00
parent 66a7e3d37c
commit 3f3dda5a77
65 changed files with 11086 additions and 1258 deletions

View File

@@ -182,6 +182,7 @@
'nkModule', # the syntax tree of a module
'nkProcDef', # a proc
'nkMethodDef', # a method
'nkConverterDef', # a converter
'nkMacroDef', # a macro
'nkTemplateDef', # a template
@@ -258,6 +259,7 @@
'skConst', # a constant
'skVar', # a variable
'skProc', # a proc
'skMethod', # a method
'skIterator', # an iterator
'skConverter', # a type converter
'skMacro', # a macro

View File

@@ -165,7 +165,6 @@
'AppendStrCh',
'AppendStrStr',
'AppendSeqElem',
'AppendSeqSeq',
'InRange',
'InSet',
'Repr',

View File

@@ -8,6 +8,8 @@
.. contents::
Abstraction is layering ignorance on top of reality. -- unknown
Directory structure
===================
@@ -72,18 +74,6 @@ the same::
./boot [-d:release]
Coding Guidelines
=================
* Use CamelCase, not underscored_identifiers.
* Indent with two spaces.
* Max line length is 80 characters.
* Provide spaces around binary operators if that enhances readability.
* Use a space after a colon, but not before it.
* Start types with a capital ``T``, unless they are pointers which start with
``P``.
Pascal annotations
==================
There are some annotations that the Pascal sources use so that they can

View File

@@ -5,6 +5,10 @@ Nimrod Standard Library
:Author: Andreas Rumpf
:Version: |nimrodversion|
..
The good thing about reinventing the wheel is that you can get a round one.
Though the Nimrod Standard Library is still evolving, it is already quite
usable. It is divided into *pure libraries*, *impure libraries* and *wrappers*.
@@ -12,10 +16,15 @@ Pure libraries do not depend on any external ``*.dll`` or ``lib*.so`` binary
while impure libraries do. A wrapper is an impure library that is a very
low-level interface to a C library.
Read this `document <apis.html>`_ for a quick overview of the API design.
Pure libraries
==============
Core
----
* `system <system.html>`_
Basic procs and operators that every program needs. It also provides IO
facilities for reading and writing text and binary files. It is imported
@@ -25,11 +34,35 @@ Pure libraries
* `macros <macros.html>`_
Contains the AST API and documentation of Nimrod for writing macros.
String handling
---------------
* `strutils <strutils.html>`_
This module contains common string handling operations like converting a
string into uppercase, splitting a string into substrings, searching for
substrings, replacing substrings.
* `strtabs <strtabs.html>`_
The ``strtabs`` module implements an efficient hash table that is a mapping
from strings to strings. Supports a case-sensitive, case-insensitive and
style-insensitive mode. An efficient string substitution operator ``%``
for the string table is also provided.
* `unicode <unicode.html>`_
This module provides support to handle the Unicode UTF-8 encoding.
* `regexprs <regexprs.html>`_
This module contains procedures and operators for handling regular
expressions. Consider using `pegs` instead.
* `pegs <pegs.html>`_
This module contains procedures and operators for handling PEGs.
Generic Operating System Services
---------------------------------
* `os <os.html>`_
Basic operating system facilities like retrieving environment variables,
reading command line arguments, working with directories, running shell
@@ -37,7 +70,28 @@ Pure libraries
platform independant.
* `osproc <osproc.html>`_
Module for process communication beyond ``os.executeShellCommand``.
Module for process communication beyond ``os.execShellCmd``.
* `times <times.html>`_
The ``times`` module contains basic support for working with time.
* `dynlib <dynlib.html>`_
This module implements the ability to access symbols from shared libraries.
* `streams <streams.html>`_
This module provides a stream interface and two implementations thereof:
the `PFileStream` and the `PStringStream` which implement the stream
interface for Nimrod file objects (`TFile`) and strings. Other modules
may provide other implementations for this standard stream interface.
* `terminal <terminal.html>`_
This module contains a few procedures to control the *terminal*
(also called *console*). The implementation simply uses ANSI escape
sequences and does not depend on any other module.
Math libraries
--------------
* `math <math.html>`_
Mathematical operations like cosine, square root.
@@ -45,11 +99,17 @@ Pure libraries
* `complex <complex.html>`_
This module implements complex numbers and their mathematical operations.
* `times <times.html>`_
The ``times`` module contains basic support for working with time.
* `dynlib <dynlib.html>`_
This module implements the ability to access symbols from shared libraries.
Internet Protocols and Support
------------------------------
* `cgi <cgi.html>`_
This module implements helpers for CGI applictions.
Parsers
-------
* `parseopt <parseopt.html>`_
The ``parseopt`` module implements a command line option parser. This
@@ -71,48 +131,32 @@ Pure libraries
* `parsecsv <parsecsv.html>`_
The ``parsecsv`` module implements a simple high performance CSV parser.
* `parsesql <parsesql.html>`_
The ``parsesql`` module implements a simple high performance SQL parser.
* `strtabs <strtabs.html>`_
The ``strtabs`` module implements an efficient hash table that is a mapping
from strings to strings. Supports a case-sensitive, case-insensitive and
style-insensitive mode. An efficient string substitution operator ``%``
for the string table is also provided.
* `lexbase <lexbase.html>`_
This is a low level module that implements an extremely efficient buffering
scheme for lexers and parsers. This is used by the diverse parsing modules.
* `streams <streams.html>`_
This module provides a stream interface and two implementations thereof:
the `PFileStream` and the `PStringStream` which implement the stream
interface for Nimrod file objects (`TFile`) and strings. Other modules
may provide other implementations for this standard stream interface.
Code generation
---------------
* `xmlgen <xmlgen.html>`_
This module implements macros for XML/HTML code generation.
Cryptography and Hashing
------------------------
* `hashes <hashes.html>`_
This module implements efficient computations of hash values for diverse
Nimrod types.
* `lexbase <lexbase.html>`_
This is a low level module that implements an extremely efficient buffering
scheme for lexers and parsers. This is used by the ``parsecfg`` module.
* `terminal <terminal.html>`_
This module contains a few procedures to control the *terminal*
(also called *console*). The implementation simply uses ANSI escape
sequences and does not depend on any other module.
* `cgi <cgi.html>`_
This module implements helper procs for CGI applictions.
* `unicode <unicode.html>`_
This module provides support to handle the Unicode UTF-8 encoding.
* `regexprs <regexprs.html>`_
This module contains procedures and operators for handling regular
expressions.
* `md5 <md5.html>`_
This module implements the MD5 checksum algorithm.
* `xmlgen <xmlgen.html>`_
This module implements macros for HTML code generation.
Impure libraries

View File

@@ -1357,7 +1357,7 @@ given *slicelist* the ``else`` part is executed. If there is no ``else``
part and not all possible values that ``expr`` can hold occur in a ``vallist``,
a static error is given. This holds only for expressions of ordinal types.
If the expression is not of an ordinal type, and no ``else`` part is
given, control just passes after the ``case`` statement.
given, control passes after the ``case`` statement.
To suppress the static error in the ordinal case an ``else`` part with a ``nil``
statement can be used.
@@ -1604,7 +1604,9 @@ statement is syntactic sugar for a nested block:
continue
stmt2
# is equivalent to:
Is equivalent to:
.. code-block:: nimrod
while expr1:
block myBlockName:
stmt1
@@ -1669,7 +1671,7 @@ object on the stack and can thus reference a non-existing object.
Procedures
~~~~~~~~~~
What most programming languages call `methods`:idx: or `funtions`:idx: are
What most programming languages call `methods`:idx: or `functions`:idx: are
called `procedures`:idx: in Nimrod (which is the correct terminology). A
procedure declaration defines an identifier and associates it with a block
of code. A procedure may call itself recursively. The syntax is::

View File

@@ -51,8 +51,8 @@ that its extension should be ``.cfg``.
Command line settings have priority over configuration file settings.
Nimrod's directory structure
----------------------------
Generated C code directory
--------------------------
The generated files that Nimrod produces all go into a subdirectory called
``nimcache`` in your project directory. This makes it easy to delete all
generated files.
@@ -116,7 +116,7 @@ No_decl Pragma
The `no_decl`:idx: pragma can be applied to almost any symbol (variable, proc,
type, etc.) and is sometimes useful for interoperability with C:
It tells Nimrod that it should not generate a declaration for the symbol in
the C code. Thus it makes the following possible, for example:
the C code. For example:
.. code-block:: Nimrod
var
@@ -129,12 +129,12 @@ However, the ``header`` pragma is often the better alternative.
Header Pragma
~~~~~~~~~~~~~
The `header`:idx: pragma is very similar to the ``no_decl`` pragma: It can be
applied to almost any symbol and specifies that not only it should not be
declared but also that it leads to the inclusion of a given header file:
applied to almost any symbol and specifies that it should not be declared
and instead the generated code should contain an ``#include``:
.. code-block:: Nimrod
type
PFile {.importc: "FILE*", header: "<stdio.h>".} = pointer
PFile {.importc: "FILE*", header: "<stdio.h>".} = distinct pointer
# import C's FILE* type; Nimrod will treat it as a new pointer type
The ``header`` pragma expects always a string constant. The string contant
@@ -159,7 +159,7 @@ strings automatically:
Line_dir Option
~~~~~~~~~~~~~~~
The `line_dir`:idx: option can be turned on or off. If on the generated C code
contains ``#line`` directives.
contains ``#line`` directives. This may be helpful for debugging with GDB.
Stack_trace Option
@@ -198,7 +198,7 @@ Register Pragma
The `register`:idx: pragma is for variables only. It declares the variable as
``register``, giving the compiler a hint that the variable should be placed
in a hardware register for faster access. C compilers usually ignore this
though and for good reason: Often they do a better job without it anyway.
though and for good reasons: Often they do a better job without it anyway.
In highly specific cases (a dispatch loop of an bytecode interpreter for
example) it may provide benefits, though.
@@ -228,7 +228,7 @@ memory, but nothing worse happens.
Dead_code_elim Pragma
~~~~~~~~~~~~~~~~~~~~~
The `dead_code_elim`:idx: pragma only applies to whole modules: It tells the
compiler to active (or deactivate) dead code elimination for the module the
compiler to activate (or deactivate) dead code elimination for the module the
pragma appers in.
The ``--dead_code_elim:on`` command line switch has the same effect as marking
@@ -288,9 +288,9 @@ Optimizing string handling
String assignments are sometimes expensive in Nimrod: They are required to
copy the whole string. However, the compiler is often smart enough to not copy
strings. Due to the argument passing semantics, strings are never copied when
passed to subroutines. The compiler does not copy strings that are returned by
a routine, because a routine returns a new string anyway. Thus it is efficient
to do:
passed to subroutines. The compiler does not copy strings that are result from
a procedure call, because the called procedure returns a new string anyway.
Thus it is efficient to do:
.. code-block:: Nimrod
var s = procA() # assignment will not copy the string; procA allocates a new

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
============================
The Nimrod Tutorial (Part I)
============================
========================
Nimrod Tutorial (Part I)
========================
:Author: Andreas Rumpf
:Version: |nimrodversion|
@@ -63,7 +63,8 @@ Nimrod: It is a good compromise between brevity and readability.
The "hallo world" program contains several identifiers that are already
known to the compiler: ``echo``, ``readLine``, etc. These built-in items are
declared in the system_ module which is implicitly imported by any other module.
declared in the system_ module which is implicitly imported by any other
module.
Lexical elements
@@ -173,7 +174,7 @@ to a storage location:
var x = "abc" # introduces a new variable `x` and assigns a value to it
x = "xyz" # assigns a new value to `x`
The ``=`` is called the *assignment operator*. The assignment operator cannot
``=`` is the *assignment operator*. The assignment operator cannot
be overloaded, overwritten or forbidden, but this might change in a future
version of Nimrod.
@@ -196,7 +197,7 @@ constants:
x = 1
# a comment can occur here too
y = 2
z = y + 5 # simple computations are possible
z = y + 5 # computations are possible
Control flow statements
@@ -277,14 +278,13 @@ the compiler that for every other value nothing should be done:
The ``nil`` statement is a *do nothing* statement. The compiler knows that a
case statement with an else part cannot fail and thus the error disappers. Note
that it is impossible to cover any possible string value: That is why there is
no such compiler check for string cases.
no such check for string cases.
In general the case statement is used for subrange types or enumerations where
it is of great help that the compiler checks that you covered any possible
value.
While statement
---------------
@@ -327,7 +327,7 @@ the same:
Echo($i)
inc(i) # increment i by 1
Counting down can be achieved as easily (but is much less needed):
Counting down can be achieved as easily (but is less often needed):
.. code-block:: nimrod
Echo("Counting down from 10 to 1: ")
@@ -372,7 +372,7 @@ Break statement
---------------
A block can be left prematurely with a ``break`` statement. The break statement
can leave a while, for, or a block statement. It leaves the innermost construct,
unless the label of a block is given:
unless a label of a block is given:
.. code-block:: nimrod
block myblock:
@@ -392,7 +392,7 @@ unless the label of a block is given:
Continue statement
------------------
Like in many other programming languages, a ``continue`` statement leads to
Like in many other programming languages, a ``continue`` statement starts
the next iteration immediately:
.. code-block:: nimrod
@@ -512,7 +512,7 @@ the procedure (and therefore the while loop) immediately. The
parameter named ``question`` of type ``string`` and returns a value of type
``bool``. ``Bool`` is a built-in type: The only valid values for ``bool`` are
``true`` and ``false``.
The conditions in if or while statements need to have the type ``bool``.
The conditions in if or while statements should be of the type ``bool``.
Some terminology: In the example ``question`` is called a (formal) *parameter*,
``"Should I..."`` is called an *argument* that is passed to this parameter.
@@ -614,7 +614,7 @@ Now the call to ``createWindow`` only needs to set the values that differ
from the defaults.
Note that type inference works for parameters with default values, there is
no need to specify ``title: string = "unknown"``, for example.
no need to write ``title: string = "unknown"``, for example.
Overloaded procedures
@@ -857,7 +857,6 @@ loses information, the `EOutOfRange`:idx: exception is raised (if the error
cannot be detected at compile time).
Floats
------
Nimrod has these floating point types built-in: ``float float32 float64``.
@@ -1232,7 +1231,7 @@ mysterious crashes.
**Note**: The example only works because the memory is initialized with zero
(``alloc0`` instead of ``alloc`` does this): ``d.s`` is thus initialized to
``nil`` which the string assignment can handle. You need to know low level
details like this when mixing garbage collected data with unmanaged memory!
details like this when mixing garbage collected data with unmanaged memory.
Procedural type
@@ -1240,8 +1239,7 @@ Procedural type
A `procedural type`:idx: is a (somewhat abstract) pointer to a procedure.
``nil`` is an allowed value for a variable of a procedural type.
Nimrod uses procedural types to achieve `functional`:idx: programming
techniques. Dynamic dispatch for OOP constructs can also be implemented with
procedural types (details follow in the OOP section).
techniques.
Example:
@@ -1303,9 +1301,9 @@ because then one module cannot be reused without the other.
The algorithm for compiling modules is:
- Compile the whole module as usual, following import statements recursively
- if there is a cycle only import the already parsed symbols (that are
exported); if an unknown identifier occurs then abort
- Compile the whole module as usual, following import statements recursively.
- If there is a cycle only import the already parsed symbols (that are
exported); if an unknown identifier occurs then abort.
This is best illustrated by an example:

View File

@@ -1,6 +1,6 @@
=============================
The Nimrod Tutorial (Part II)
=============================
=========================
Nimrod Tutorial (Part II)
=========================
:Author: Andreas Rumpf
:Version: |nimrodversion|
@@ -73,9 +73,9 @@ section.
Inheritance is done with the ``object of`` syntax. Multiple inheritance is
currently not supported. If an object type has no suitable ancestor, ``TObject``
should be used as its ancestor, but this is only a convention.
can be used as its ancestor, but this is only a convention.
Note that aggregation (*has-a* relation) is often preferable to inheritance
**Note**: Aggregation (*has-a* relation) is often preferable to inheritance
(*is-a* relation) for simple code reuse. Since objects are value types in
Nimrod, aggregation is as efficient as inheritance.
@@ -84,9 +84,9 @@ Mutually recursive types
------------------------
Objects, tuples and references can model quite complex data structures which
depend on each other. This is called *mutually recursive types*. In Nimrod
these types need to be declared within a single type section. Anything else
would require arbitrary symbol lookahead which slows down compilation.
depend on each other; they are *mutually recursive*. In Nimrod
these types can only be declared within a single type section. (Anything else
would require arbitrary symbol lookahead which slows down compilation.)
Example:
@@ -147,7 +147,7 @@ An example:
TNode = object
case kind: TNodeKind # the ``kind`` field is the discriminator
of nkInt: intVal: int
of nkFloat: floavVal: float
of nkFloat: floatVal: float
of nkString: strVal: string
of nkAdd, nkSub:
leftOp, rightOp: PNode
@@ -176,18 +176,25 @@ bound to a class. This has disadvantages:
* Adding a method to a class the programmer has no control over is
impossible or needs ugly workarounds.
* Often it is unclear where the procedure should belong to: Is
* Often it is unclear where the method should belong to: Is
``join`` a string method or an array method? Should the complex
``vertexCover`` algorithm really be a method of the ``graph`` class?
Nimrod avoids these problems by not distinguishing between methods and
procedures. Methods are just ordinary procedures. However, there is a special
syntactic sugar for calling procedures: The syntax ``obj.method(args)`` can be
used instead of ``method(obj, args)``. If there are no remaining arguments, the
parentheses can be omitted: ``obj.len`` (instead of ``len(obj)``).
Nimrod avoids these problems by not assigning methods to a class. All methods
in Nimrod are `multi-methods`:idx:. As we will see later, multi-methods are
distinguished from procs only for dynamic binding purposes.
Method call syntax
------------------
There is a syntactic sugar for calling routines:
The syntax ``obj.method(args)`` can be used instead of ``method(obj, args)``.
If there are no remaining arguments, the parentheses can be omitted:
``obj.len`` (instead of ``len(obj)``).
This `method call syntax`:idx: is not restricted to objects, it can be used
for any type:
for any type:
.. code-block:: nimrod
@@ -196,9 +203,17 @@ for any type:
echo({'a', 'b', 'c'}.card)
stdout.writeln("Hallo") # the same as write(stdout, "Hallo")
If it gives you warm fuzzy feelings, you can even write ``1.`+`(2)`` instead of
``1 + 2`` and claim that Nimrod is a pure object oriented language. (But
that's not true. :-)
(Another way to look at the method call syntax is that it provides the missing
postfix notation.)
So code that looks "pure object oriented" is easy to write:
.. code-block:: nimrod
import strutils
stdout.writeln("Give a list of numbers (separated by spaces): ")
stdout.write(stdin.readLine.split.each(parseInt).max.`$`)
stdout.writeln(" is the maximum!")
Properties
@@ -261,60 +276,75 @@ already provides ``v[]`` access.
Dynamic dispatch
----------------
In Nimrod procedural types are used to implement dynamic dispatch. The
following example also shows some more conventions: The ``self`` or ``this``
object is named ``my`` (because it is shorter than the alternatives), each
class provides a constructor, etc.
Procedures always use static dispatch. To get dynamic dispatch, replace the
``proc`` keyword by ``method``:
.. code-block:: nimrod
type
TFigure = object of TObject # abstract base class:
fDraw: proc (my: var TFigure) # concrete classes implement this proc
TExpr = object ## abstract base class for an expression
TLiteral = object of TExpr
x: int
TPlusExpr = object of TExpr
a, b: ref TExpr
method eval(e: ref TExpr): int =
# override this base method
quit "to override!"
method eval(e: ref TLiteral): int = return e.x
method eval(e: ref TPlusExpr): int =
# watch out: relies on dynamic binding
return eval(e.a) + eval(e.b)
proc newLit(x: int): ref TLiteral =
new(result)
result.x = x
proc init(f: var TFigure) =
f.fDraw = nil
proc newPlus(a, b: ref TExpr): ref TPlusExpr =
new(result)
result.a = a
result.b = b
proc draw(f: var TFigure) =
# ``draw`` dispatches dynamically:
f.fDraw(f)
echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4)))
type
TCircle = object of TFigure
radius: int
proc drawCircle(my: var TCircle) = echo("o " & $my.radius)
proc init(my: var TCircle) =
init(TFigure(my)) # call base constructor
my.radius = 5
my.fdraw = drawCircle
Note that in the example the constructors ``newLit`` and ``newPlus`` are procs
because they should use static binding, but ``eval`` is a method because it
requires dynamic binding.
In a multi-method all parameters that have an object type are used for the
dispatching:
.. code-block:: nimrod
type
TRectangle = object of TFigure
width, height: int
TThing = object
TUnit = object of TThing
x: int
method collide(a, b: TThing) {.inline.} =
quit "to override!"
method collide(a: TThing, b: TUnit) {.inline.} =
echo "1"
proc drawRectangle(my: var TRectangle) = echo("[]")
method collide(a: TUnit, b: TThing) {.inline.} =
echo "2"
proc init(my: var TRectangle) =
init(TFigure(my)) # call base constructor
my.width = 5
my.height = 10
my.fdraw = drawRectangle
# now use these classes:
var
r: TRectangle
c: TCircle
init(r)
init(c)
r.draw()
c.draw()
a, b: TUnit
collide(a, b) # output: 2
The code uses a ``draw`` procedure that is bound statically, but inside it
the dynamic dispatch happens with the help of the ``fdraw`` field. Even though
this solution has its advantages compared to traditional OOP-languages, it is
a **preliminary** solution. Multimethods are a planned language feature that
provide a more flexible and efficient mechanism.
As the example demonstrates, invokation of a multi-method cannot be ambiguous:
Collide 2 is prefered over collide 1 because the resolution works from left to
right. Thus ``TUnit, TThing`` is prefered over ``TThing, TUnit``.
**Perfomance note**: Nimrod does not produce a virtual method table, but
generates dispatch trees. This avoids the expensive indirect branch for method
calls and enables inlining. However, other optimizations like compile time
evaluation or dead code elimination do not work with methods.
Exceptions
@@ -497,8 +527,7 @@ simple proc for logging:
debug = True
proc log(msg: string) {.inline.} =
if debug:
stdout.writeln(msg)
if debug: stdout.writeln(msg)
var
x = 4
@@ -506,7 +535,7 @@ simple proc for logging:
This code has a shortcoming: If ``debug`` is set to false someday, the quite
expensive ``$`` and ``&`` operations are still performed! (The argument
evaluation for procedures is said to be *eager*).
evaluation for procedures is *eager*).
Turning the ``log`` proc into a template solves this problem:
@@ -514,21 +543,20 @@ Turning the ``log`` proc into a template solves this problem:
const
debug = True
template log(msg: expr): stmt =
if debug:
stdout.writeln(msg)
template log(msg: string) =
if debug: stdout.writeln(msg)
var
x = 4
log("x has the value: " & $x)
The "types" of templates can be the symbols ``expr`` (stands for *expression*),
``stmt`` (stands for *statement*) or ``typedesc`` (stands for *type
description*). These are no real types, they just help the compiler parsing.
However, real types are supported too.
The parameters' types can be ordinary types or the meta types ``expr``
(stands for *expression*), ``stmt`` (stands for *statement*) or ``typedesc``
(stands for *type description*). If the template has no explicit return type,
``stmt`` is used for consistency with procs and methods.
The template body does not open a new scope. To open a new scope
use a ``block`` statement:
The template body does not open a new scope. To open a new scope use a ``block``
statement:
.. code-block:: nimrod
template declareInScope(x: expr, t: typeDesc): stmt =
@@ -573,7 +601,7 @@ In the example the two ``writeln`` statements are bound to the ``actions``
parameter. The ``withFile`` template contains boilerplate code and helps to
avoid a common bug: To forget to close the file. Note how the
``var fn = filename`` statement ensures that ``filename`` is evaluated only
once.
once.
Macros

View File

@@ -51,20 +51,21 @@ type
nnkObjDownConv, nnkObjUpConv, nnkChckRangeF, nnkChckRange64,
nnkChckRange, nnkStringToCString, nnkCStringToString, nnkPassAsOpenArray,
nnkAsgn, nnkFastAsgn, nnkGenericParams, nnkFormalParams,
nnkOfInherit, nnkModule, nnkProcDef, nnkConverterDef,
nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch,
nnkElifBranch, nnkExceptBranch, nnkElse, nnkMacroStmt,
nnkAsmStmt, nnkPragma, nnkIfStmt, nnkWhenStmt,
nnkForStmt, nnkWhileStmt, nnkCaseStmt, nnkVarSection,
nnkConstSection, nnkConstDef, nnkTypeSection, nnkTypeDef,
nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt,
nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt,
nnkDiscardStmt, nnkStmtList, nnkImportStmt, nnkFromStmt,
nnkIncludeStmt, nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr,
nnkStmtListType, nnkBlockType, nnkTypeOfExpr, nnkObjectTy,
nnkTupleTy, nnkRecList, nnkRecCase, nnkRecWhen,
nnkRefTy, nnkPtrTy, nnkVarTy, nnkDistinctTy,
nnkProcTy, nnkEnumTy, nnkEnumFieldDef, nnkReturnToken
nnkOfInherit, nnkModule, nnkProcDef, nnkMethodDef,
nnkConverterDef, nnkMacroDef, nnkTemplateDef, nnkIteratorDef,
nnkOfBranch, nnkElifBranch, nnkExceptBranch, nnkElse,
nnkMacroStmt, nnkAsmStmt, nnkPragma, nnkIfStmt,
nnkWhenStmt, nnkForStmt, nnkWhileStmt, nnkCaseStmt,
nnkVarSection, nnkConstSection, nnkConstDef, nnkTypeSection,
nnkTypeDef, nnkYieldStmt, nnkTryStmt, nnkFinally,
nnkRaiseStmt, nnkReturnStmt, nnkBreakStmt, nnkContinueStmt,
nnkBlockStmt, nnkDiscardStmt, nnkStmtList, nnkImportStmt,
nnkFromStmt, nnkIncludeStmt, nnkCommentStmt, nnkStmtListExpr,
nnkBlockExpr, nnkStmtListType, nnkBlockType, nnkTypeOfExpr,
nnkObjectTy, nnkTupleTy, nnkRecList, nnkRecCase,
nnkRecWhen, nnkRefTy, nnkPtrTy, nnkVarTy,
nnkDistinctTy, nnkProcTy, nnkEnumTy, nnkEnumFieldDef,
nnkReturnToken
TNimNodeKinds* = set[TNimrodNodeKind]
TNimrodTypeKind* = enum
ntyNone, ntyBool, ntyChar, ntyEmpty,
@@ -81,9 +82,10 @@ type
TNimrodSymKind* = enum
nskUnknown, nskConditional, nskDynLib, nskParam,
nskGenericParam, nskTemp, nskType, nskConst,
nskVar, nskProc, nskIterator, nskConverter,
nskMacro, nskTemplate, nskField, nskEnumField,
nskForVar, nskModule, nskLabel, nskStub
nskVar, nskProc, nskMethod, nskIterator,
nskConverter, nskMacro, nskTemplate, nskField,
nskEnumField, nskForVar, nskModule, nskLabel,
nskStub
TNimSymKinds* = set[TNimrodSymKind]
#[[[end]]]

View File

@@ -363,7 +363,24 @@ proc `/` * (head, tail: string): string {.noSideEffect.} =
## The same as ``joinPath(head, tail)``
return joinPath(head, tail)
proc SplitPath*(path: string, head, tail: var string) {.noSideEffect.} =
proc SplitPath*(path: string, head, tail: var string) {.noSideEffect,
deprecated.} =
## **Deprecated since version 0.8.2**: use the version that returns a tuple
## instead
var
sepPos = -1
for i in countdown(len(path)-1, 0):
if path[i] in {dirsep, altsep}:
sepPos = i
break
if sepPos >= 0:
head = copy(path, 0, sepPos-1)
tail = copy(path, sepPos+1)
else:
head = ""
tail = path # make a string copy here
proc SplitPath*(path: string): tuple[head, tail: string] {.noSideEffect.} =
## Splits a directory into (head, tail), so that
## ``JoinPath(head, tail) == path``.
##
@@ -378,11 +395,11 @@ proc SplitPath*(path: string, head, tail: var string) {.noSideEffect.} =
sepPos = i
break
if sepPos >= 0:
head = copy(path, 0, sepPos-1)
tail = copy(path, sepPos+1)
result.head = copy(path, 0, sepPos-1)
result.tail = copy(path, sepPos+1)
else:
head = ""
tail = path # make a string copy here
result.head = ""
result.tail = path
proc parentDir*(path: string): string {.noSideEffect.} =
## Returns the parent directory of `path`.
@@ -422,25 +439,50 @@ proc searchExtPos(s: string): int =
elif s[i] in {dirsep, altsep}:
break # do not skip over path
proc extractDir*(path: string): string {.noSideEffect.} =
proc splitFile*(path: string): tuple[dir, name, ext: string] {.noSideEffect.} =
## Splits a filename into (dir, filename, extension).
## `dir` does not end in `DirSep`.
## `extension` includes the leading dot.
##
## Example:
##
## .. code-block:: nimrod
## var (dir, name, ext) = splitFile("usr/local/nimrodc.html")
## assert dir == "usr/local"
## assert name == "nimrodc"
## assert ext == ".html"
## If `path` has no extension, `ext` is the empty string.
## If `path` has no directory component, `dir` is the empty string.
## If `path` has no filename component, `name` and `ext` are empty strings.
if path.len == 0 or path[path.len-1] in {dirSep, altSep}:
result = (path, "", "")
else:
var sepPos = -1
var dotPos = path.len
for i in countdown(len(path)-1, 0):
if path[i] == ExtSep:
if dotPos == path.len: dotPos = i
elif path[i] in {dirsep, altsep}:
sepPos = i
break
result.dir = copy(path, 0, sepPos-1)
result.name = copy(path, sepPos+1, dotPos-1)
result.ext = copy(path, dotPos)
proc extractDir*(path: string): string {.noSideEffect, deprecated.} =
## Extracts the directory of a given path. This is almost the
## same as the `head` result of `splitPath`, except that
## ``extractDir("/usr/lib/") == "/usr/lib/"``.
if path.len == 0 or path[path.len-1] in {dirSep, altSep}:
result = path
else:
var tail: string
splitPath(path, result, tail)
## **Deprecated since version 0.8.2**: Use ``splitFile(path).dir`` instead.
result = splitFile(path).dir
proc extractFilename*(path: string): string {.noSideEffect.} =
## Extracts the filename of a given `path`. This is almost the
## same as the `tail` result of `splitPath`, except that
## ``extractFilename("/usr/lib/") == ""``.
## Extracts the filename of a given `path`. This is the same as
## ``name & ext`` from ``splitFile(path)``.
if path.len == 0 or path[path.len-1] in {dirSep, altSep}:
result = ""
else:
var head: string
splitPath(path, head, result)
result = splitPath(path).tail
proc expandFilename*(filename: string): string =
## Returns the full path of `filename`, raises EOS in case of an error.
@@ -457,13 +499,14 @@ proc expandFilename*(filename: string): string =
c_free(res)
proc SplitFilename*(filename: string, name, extension: var string) {.
noSideEffect.} =
noSideEffect, deprecated.} =
## Splits a filename into (name, extension), so that
## ``name & extension == filename``.
##
## Example: After ``SplitFilename("usr/local/nimrodc.html", name, ext)``,
## `name` is "usr/local/nimrodc" and `ext` is ".html".
## It the file has no extension, extention is the empty string.
## If the file has no extension, extension is the empty string.
## **Deprecated since version 0.8.2**: Use ``splitFile(filename)`` instead.
var extPos = searchExtPos(filename)
if extPos >= 0:
name = copy(filename, 0, extPos-1)
@@ -472,18 +515,19 @@ proc SplitFilename*(filename: string, name, extension: var string) {.
name = filename # make a string copy here
extension = ""
proc extractFileExt*(filename: string): string {.noSideEffect.} =
proc extractFileExt*(filename: string): string {.noSideEffect, deprecated.} =
## Extracts the file extension of a given `filename`. This is the
## same as the `extension` result of `splitFilename`.
var dummy: string
splitFilename(filename, dummy, result)
## **Deprecated since version 0.8.2**: Use ``splitFile(filename).ext``
## instead.
result = splitFile(filename).ext
proc extractFileTrunk*(filename: string): string {.noSideEffect.} =
proc extractFileTrunk*(filename: string): string {.noSideEffect, deprecated.} =
## Extracts the file name of a given `filename`. This removes any
## directory information and the file extension.
var dummy: string
splitFilename(extractFilename(filename), result, dummy)
## **Deprecated since version 0.8.2**: Use ``splitFile(path).name`` instead.
result = splitFile(filename).name
proc ChangeFileExt*(filename, ext: string): string {.noSideEffect.} =
## Changes the file extension to `ext`.
##
@@ -496,8 +540,8 @@ proc ChangeFileExt*(filename, ext: string): string {.noSideEffect.} =
if extPos < 0: result = filename & normExt(ext)
else: result = copy(filename, 0, extPos-1) & normExt(ext)
proc AppendFileExt*(filename, ext: string): string {.noSideEffect.} =
## Appends the file extension `ext` to `filename`, unless
proc addFileExt*(filename, ext: string): string {.noSideEffect.} =
## Adds the file extension `ext` to `filename`, unless
## `filename` already has an extension.
##
## `Ext` should be given without the leading '.', because some
@@ -505,7 +549,12 @@ proc AppendFileExt*(filename, ext: string): string {.noSideEffect.} =
## (Although I know of none such beast.)
var extPos = searchExtPos(filename)
if extPos < 0: result = filename & normExt(ext)
else: result = filename #make a string copy here
else: result = filename
proc AppendFileExt*(filename, ext: string): string {.
noSideEffect, deprecated.} =
## **Deprecated since version 0.8.2**: Use `addFileExt` instead.
result = addFileExt(filename, ext)
proc cmpPaths*(pathA, pathB: string): int {.noSideEffect.} =
## Compares two paths.
@@ -610,14 +659,18 @@ proc removeFile*(file: string) =
## Removes the `file`. If this fails, `EOS` is raised.
if cremove(file) != 0'i32: OSError()
proc executeShellCommand*(command: string): int =
proc executeShellCommand*(command: string): int {.deprecated.} =
## **Deprecated since version 0.8.2**: Use `execShellCmd` instead.
result = csystem(command)
proc execShellCmd*(command: string): int =
## Executes a shell command.
##
## Command has the form 'program args' where args are the command
## line arguments given to program. The proc returns the error code
## of the shell when it has finished. The proc does not return until
## the process has finished. To execute a program without having a
## shell involved, use the `executeProcess` proc of the `osproc`
## shell involved, use the `execProcess` proc of the `osproc`
## module.
result = csystem(command)
@@ -707,7 +760,16 @@ proc putEnv*(key, val: string) =
if SetEnvironmentVariableA(key, val) == 0'i32:
OSError()
iterator iterOverEnvironment*(): tuple[key, value: string] =
iterator iterOverEnvironment*(): tuple[key, value: string] {.deprecated.} =
## Iterate over all environments variables. In the first component of the
## tuple is the name of the current variable stored, in the second its value.
## **Deprecated since version 0.8.2**: Use `envPairs` instead.
getEnvVarsC()
for i in 0..high(environment):
var p = find(environment[i], '=')
yield (copy(environment[i], 0, p-1), copy(environment[i], p+1))
iterator envPairs*(): tuple[key, value: string] =
## Iterate over all environments variables. In the first component of the
## tuple is the name of the current variable stored, in the second its value.
getEnvVarsC()
@@ -1039,7 +1101,6 @@ proc getApplicationFilename*(): string =
proc getApplicationDir*(): string =
## Returns the directory of the application's executable.
var tail: string
splitPath(getApplicationFilename(), result, tail)
result = splitFile(getApplicationFilename()).dir
{.pop.}

View File

@@ -36,16 +36,28 @@ type
## often creates a security whole!
poStdErrToStdOut ## merge stdout and stderr to the stdout stream
proc executeProcess*(command: string,
options: set[TProcessOption] = {poStdErrToStdOut,
poUseShell}): string
proc execProcess*(command: string,
options: set[TProcessOption] = {poStdErrToStdOut,
poUseShell}): string
## A convience procedure that executes ``command`` with ``startProcess``
## and returns its output as a string.
proc executeCommand*(command: string): int
proc executeProcess*(command: string,
options: set[TProcessOption] = {poStdErrToStdOut,
poUseShell}): string {.
deprecated.} =
## **Deprecated since version 0.8.2**: Use `execProcess` instead.
result = execProcess(command, options)
proc execCmd*(command: string): int
## Executes ``command`` and returns its error code. Standard input, output,
## error streams are inherited from the calling process.
proc executeCommand*(command: string): int {.deprecated.} =
## **Deprecated since version 0.8.2**: Use `execCmd` instead.
result = execCmd(command)
proc startProcess*(command: string,
workingDir: string = "",
args: openarray[string] = [],
@@ -56,11 +68,12 @@ proc startProcess*(command: string,
## is used. `args` are the command line arguments that are passed to the
## process. On many operating systems, the first command line argument is the
## name of the executable. `args` should not contain this argument!
## `startProcess` takes care of that. `env` is the environment that will be
## passed to the process. If ``env == nil`` the environment is inherited of
## `env` is the environment that will be passed to the process.
## If ``env == nil`` the environment is inherited of
## the parent process. `options` are additional flags that may be passed
## to `startProcess`. See the documentation of ``TProcessOption`` for the
## meaning of these flags.
##
## Return value: The newly created process object. Nil is never returned,
## but ``EOS`` is raised in case of an error.
@@ -104,9 +117,9 @@ proc outputStream*(p: PProcess): PStream
proc errorStream*(p: PProcess): PStream
## returns ``p``'s output stream for reading from
proc executeProcess*(command: string,
options: set[TProcessOption] = {poStdErrToStdOut,
poUseShell}): string =
proc execProcess(command: string,
options: set[TProcessOption] = {poStdErrToStdOut,
poUseShell}): string =
var c = parseCmdLine(command)
var a: seq[string] = @[] # slicing is not yet implemented :-(
for i in 1 .. c.len-1: add(a, c[i])
@@ -208,24 +221,24 @@ when defined(Windows):
SI.dwFlags = STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES
CreatePipeHandles(SI.hStdInput, HI)
CreatePipeHandles(HO, Si.hStdOutput)
#SI.hStdInput = GetStdHandle(STD_INPUT_HANDLE())
#SI.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE())
if poStdErrToStdOut in options:
SI.hStdError = SI.hStdOutput
HE = HO
else:
CreatePipeHandles(HE, Si.hStdError)
#SI.hStdError = GetStdHandle(STD_ERROR_HANDLE())
#result.inputHandle = open_osfhandle(HI, O_WRONLY)
#if result.inputHandle == -1'i32: OSError()
result.inputHandle = hi
result.outputHandle = ho
result.errorHandle = he
#result.outputHandle = open_osfhandle(HO, O_RDONLY)
#if result.outputHandle == -1'i32: OSError()
#result.errorHandle = open_osfhandle(HE, O_RDONLY)
#if result.errorHandle == -1'i32: OSError()
var cmdl = buildCommandLine(command, args)
var cmdl: cstring
if poUseShell in options:
var comspec = getEnv("COMSPEC")
var a: seq[string] = @[]
add(a, "/c")
add(a, command)
add(a, args)
cmdl = buildCommandLine(comspec, a)
else:
cmdl = buildCommandLine(command, args)
var wd: cstring = nil
if len(workingDir) > 0: wd = workingDir
if env == nil:
@@ -239,6 +252,9 @@ when defined(Windows):
dealloc(cmdl)
if success == 0:
OSError()
# NEW:
# Close the handles now so anyone waiting is woken.
discard closeHandle(procInfo.hThread)
result.FProcessHandle = procInfo.hProcess
result.FThreadHandle = procInfo.hThread
result.id = procInfo.dwProcessID
@@ -258,7 +274,7 @@ when defined(Windows):
discard TerminateProcess(p.FProcessHandle, 0)
proc waitForExit(p: PProcess): int =
discard CloseHandle(p.FThreadHandle)
#CloseHandle(p.FThreadHandle)
discard WaitForSingleObject(p.FProcessHandle, Infinite)
var res: int32
discard GetExitCodeProcess(p.FProcessHandle, res)
@@ -274,7 +290,7 @@ when defined(Windows):
proc errorStream(p: PProcess): PStream =
result = newFileHandleStream(p.errorHandle)
proc executeCommand(command: string): int =
proc execCmd(command: string): int =
var
SI: TStartupInfo
ProcInfo: TProcessInformation
@@ -420,8 +436,8 @@ else:
proc csystem(cmd: cstring): cint {.nodecl, importc: "system".}
proc executeCommand(command: string): int =
proc execCmd(command: string): int =
result = csystem(command)
when isMainModule:
echo executeCommand("gcc -v")
echo execCmd("gcc -v")

View File

@@ -138,7 +138,7 @@ proc getEscapedChar(c: var TCfgParser, tok: var TToken) =
inc(c.bufpos) # skip '\'
case c.buf[c.bufpos]
of 'n', 'N':
add(tok.literal, nl)
add(tok.literal, "\n")
Inc(c.bufpos)
of 'r', 'R', 'c', 'C':
add(tok.literal, '\c')
@@ -208,7 +208,7 @@ proc getString(c: var TCfgParser, tok: var TToken, rawMode: bool) =
of '\c', '\L':
pos = HandleCRLF(c, pos)
buf = c.buf
add(tok.literal, nl)
add(tok.literal, "\n")
of lexbase.EndOfFile:
tok.kind = tkInvalid
break
@@ -302,7 +302,7 @@ proc rawGetTok(c: var TCfgParser, tok: var TToken) =
proc errorStr(c: TCfgParser, msg: string): string =
result = `%`("$1($2, $3) Error: $4",
[c.filename, toString(getLine(c)), toString(getColumn(c)), msg])
[c.filename, $getLine(c), $getColumn(c), msg])
proc getKeyValPair(c: var TCfgParser, kind: TCfgEventKind): TCfgEvent =
if c.tok.kind == tkSymbol:

View File

@@ -32,21 +32,10 @@ type
## or the argument, ``value`` is not "" if
## the option was given a value
proc init*(cmdline: string = ""): TOptParser
proc initOptParser*(cmdline = ""): TOptParser =
## inits the option parser. If ``cmdline == ""``, the real command line
## (as provided by the ``OS`` module) is taken.
proc next*(p: var TOptParser)
## parses the first or next option; ``p.kind`` describes what token has been
## parsed. ``p.key`` and ``p.val`` are set accordingly.
proc getRestOfCommandLine*(p: TOptParser): string
## retrieves the rest of the command line that has not been parsed yet.
# implementation
proc init(cmdline: string = ""): TOptParser =
result.pos = strStart
result.pos = 0
result.inShortState = false
if cmdline != "":
result.cmd = cmdline
@@ -58,6 +47,10 @@ proc init(cmdline: string = ""): TOptParser =
result.key = ""
result.val = ""
proc init*(cmdline: string = ""): TOptParser {.deprecated.} =
## **Deprecated since version 0.8.2**: Use `initOptParser` instead.
result = initOptParser(cmdline)
proc parseWord(s: string, i: int, w: var string,
delim: TCharSet = {'\x09', ' ', '\0'}): int =
result = i
@@ -89,7 +82,9 @@ proc handleShortOption(p: var TOptParser) =
if p.cmd[i] == '\0': p.inShortState = false
p.pos = i
proc next(p: var TOptParser) =
proc next*(p: var TOptParser) =
## parses the first or next option; ``p.kind`` describes what token has been
## parsed. ``p.key`` and ``p.val`` are set accordingly.
var i = p.pos
while p.cmd[i] in {'\x09', ' '}: inc(i)
p.pos = i
@@ -121,12 +116,17 @@ proc next(p: var TOptParser) =
p.kind = cmdArgument
p.pos = parseWord(p.cmd, i, p.key)
proc getRestOfCommandLine(p: TOptParser): string =
result = strip(copy(p.cmd, p.pos + strStart, len(p.cmd) - 1))
proc cmdLineRest*(p: TOptParser): string =
## retrieves the rest of the command line that has not been parsed yet.
result = strip(copy(p.cmd, p.pos, len(p.cmd) - 1))
proc getRestOfCommandLine*(p: TOptParser): string {.deprecated.} =
## **Deprecated since version 0.8.2**: Use `cmdLineRest` instead.
result = cmdLineRest(p)
iterator getopt*(): tuple[kind: TCmdLineKind, key, val: string] =
##this is an convenience iterator for iterating over the command line.
##This uses the TOptParser object. Example:
## This is an convenience iterator for iterating over the command line.
## This uses the TOptParser object. Example:
##
## .. code-block:: nimrod
## var
@@ -143,7 +143,7 @@ iterator getopt*(): tuple[kind: TCmdLineKind, key, val: string] =
## if filename == "":
## # no filename has been given, so we show the help:
## writeHelp()
var p = init()
var p = initOptParser()
while true:
next(p)
if p.kind == cmdEnd: break

View File

@@ -483,7 +483,7 @@ proc errorStr(L: TSqlLexer, msg: string): string =
# OR left logical disjunction
type
TSqlNodeKind* = enum
TSqlNodeKind* = enum ## kind of SQL abstract syntax tree
nkNone,
nkIdent,
nkStringLit,
@@ -536,17 +536,18 @@ type
nkEnumDef
type
EInvalidSql* = object of EBase
PSqlNode* = ref TSqlNode
TSqlNode* = object
case kind*: TSqlNodeKind
EInvalidSql* = object of EBase ## Invalid SQL encountered
PSqlNode* = ref TSqlNode ## an SQL abstract syntax tree node
TSqlNode* = object ## an SQL abstract syntax tree node
case kind*: TSqlNodeKind ## kind of syntax tree
of nkIdent, nkStringLit, nkBitStringLit, nkHexStringLit,
nkIntegerLit, nkNumericLit:
strVal*: string
strVal*: string ## AST leaf: the identifier, numeric literal
## string literal, etc.
else:
sons*: seq[PSqlNode]
sons*: seq[PSqlNode] ## the node's children
TSqlParser = object of TSqlLexer
TSqlParser* = object of TSqlLexer ## SQL parser object
tok: TToken
proc newNode(k: TSqlNodeKind): PSqlNode =
@@ -1070,7 +1071,17 @@ proc parseStmt(p: var TSqlParser): PSqlNode =
else:
sqlError(p, "CREATE expected")
proc parse*(p: var TSqlParser): PSqlNode =
proc open(p: var TSqlParser, input: PStream, filename: string) =
## opens the parser `p` and assigns the input stream `input` to it.
## `filename` is only used for error messages.
open(TSqlLexer(p), input, filename)
p.tok.kind = tkInvalid
p.tok.literal = ""
getTok(p)
proc parse(p: var TSqlParser): PSqlNode =
## parses the content of `p`'s input stream and returns the SQL AST.
## Syntax errors raise an `EInvalidSql` exception.
result = newNode(nkStmtList)
while p.tok.kind != tkEof:
var s = parseStmt(p)
@@ -1078,21 +1089,21 @@ proc parse*(p: var TSqlParser): PSqlNode =
result.add(s)
if result.len == 1:
result = result.sons[0]
proc open*(p: var TSqlParser, input: PStream, filename: string) =
open(TSqlLexer(p), input, filename)
p.tok.kind = tkInvalid
p.tok.literal = ""
getTok(p)
proc close*(p: var TSqlParser) =
proc close(p: var TSqlParser) =
## closes the parser `p`. The associated input stream is closed too.
close(TSqlLexer(p))
proc parseSQL*(input: PStream, filename: string): PSqlNode =
## parses the SQL from `input` into an AST and returns the AST.
## `filename` is only used for error messages.
## Syntax errors raise an `EInvalidSql` exception.
var p: TSqlParser
open(p, input, filename)
result = parse(p)
close(p)
try:
result = parse(p)
finally:
close(p)
proc ra(n: PSqlNode, s: var string, indent: int)
@@ -1114,7 +1125,7 @@ proc ra(n: PSqlNode, s: var string, indent: int) =
if allCharsInSet(n.strVal, {'\33'..'\127'}):
s.add(n.strVal)
else:
s.add("\"" & replaceStr(n.strVal, "\"", "\"\"") & "\"")
s.add("\"" & replace(n.strVal, "\"", "\"\"") & "\"")
of nkStringLit:
s.add(escape(n.strVal, "e'", "'"))
of nkBitStringLit:

View File

@@ -297,7 +297,7 @@ proc parseEntity(my: var TXmlParser, dest: var string) =
var buf = my.buf
my.kind = xmlCharData
if buf[pos] == '#':
var r: TRune
var r: int
inc(pos)
if buf[pos] == 'x':
inc(pos)
@@ -312,7 +312,7 @@ proc parseEntity(my: var TXmlParser, dest: var string) =
while buf[pos] in {'0'..'9'}:
r = r * 10 + (ord(buf[pos]) - ord('0'))
inc(pos)
add(dest, toUTF8(r))
add(dest, toUTF8(TRune(r)))
elif buf[pos] == 'l' and buf[pos+1] == 't':
add(dest, '<')
inc(pos, 2)

View File

@@ -8,6 +8,9 @@
#
## Regular expression support for Nimrod.
## **Deprecated** since version 0.8.2. Use the module `re` instead.
{.deprecated.}
## Currently this module is implemented by providing a wrapper around the
## `PRCE (Perl-Compatible Regular Expressions) <http://www.pcre.org>`_
## C library. This means that your application will depend on the PRCE
@@ -131,13 +134,14 @@ template `=~` *(s, pattern: expr): expr =
## echo("comment: ", matches[1])
## else:
## echo("syntax error")
##
var matches: array[0..maxSubPatterns-1, string]
##
when not definedInScope(matches):
var matches: array[0..maxSubPatterns-1, string]
match(s, pattern, matches)
const ## common regular expressions
reIdentifier* = r"\b[a-zA-Z_]+[a-zA-Z_0-9]*\b" ## describes an identifier
reIdentifier* = r"\b[a-zA-Z_][a-zA-Z_0-9]*\b" ## describes an identifier
reNatural* = r"\b\d+\b" ## describes a natural number
reInteger* = r"\b[-+]?\d+\b" ## describes an integer
reHex* = r"\b0[xX][0-9a-fA-F]+\b" ## describes a hexadecimal number

View File

@@ -45,9 +45,9 @@ const
IdentStartChars* = {'a'..'z', 'A'..'Z', '_'}
## the set of characters an identifier can start with
strStart* = 0 ## this is only for bootstraping
## XXX: remove this someday
nl* = "\n" ## this is only for bootstraping XXX: remove this somehow
# strStart* = 0 ## this is only for bootstraping
# ## XXX: remove this someday
# nl* = "\n" ## this is only for bootstraping XXX: remove this someday
proc `%` *(formatstr: string, a: openarray[string]): string {.noSideEffect.}
## The `substitution`:idx: operator performs string substitutions in
@@ -272,43 +272,39 @@ iterator splitLines*(s: string): string =
else: break # was '\0'
first = last
template iterToProc(iter: expr): stmt =
result = @[]
for x in iter: add(result, x)
proc splitLinesSeq*(s: string): seq[string] {.noSideEffect, deprecated.} =
## The same as `splitLines`, but is a proc that returns a sequence
## of substrings.
## **Deprecated since version 0.8.0**: Use `splitLines` instead.
iterToProc(splitLines(s))
accumulateResult(splitLines(s))
proc splitSeq*(s: string, seps: set[char] = Whitespace): seq[string] {.
noSideEffect, deprecated.} =
## The same as `split`, but is a proc that returns a sequence of substrings.
## **Deprecated since version 0.8.0**: Use `split` instead.
iterToProc(split(s, seps))
accumulateResult(split(s, seps))
proc splitSeq*(s: string, sep: char): seq[string] {.noSideEffect,
deprecated.} =
## The same as `split`, but is a proc that returns a sequence of substrings.
## **Deprecated since version 0.8.0**: Use `split` instead.
iterToProc(split(s, sep))
accumulateResult(split(s, sep))
proc splitLines*(s: string): seq[string] {.noSideEffect.} =
## The same as the `splitLines` iterator, but is a proc that returns a
## sequence of substrings.
iterToProc(splitLines(s))
accumulateResult(splitLines(s))
proc split*(s: string, seps: set[char] = Whitespace): seq[string] {.
noSideEffect.} =
## The same as the `split` iterator, but is a proc that returns a
## sequence of substrings.
iterToProc(split(s, seps))
accumulateResult(split(s, seps))
proc split*(s: string, sep: char): seq[string] {.noSideEffect.} =
## The same as the `split` iterator, but is a proc that returns a sequence
## of substrings.
iterToProc(split(s, sep))
accumulateResult(split(s, sep))
proc cmpIgnoreCase*(a, b: string): int {.noSideEffect.}
## Compares two strings in a case insensitive manner. Returns:
@@ -358,8 +354,10 @@ proc ParseFloat*(s: string): float {.noSideEffect.}
## ``INF``, ``-INF`` are also supported (case insensitive comparison).
# the stringify and format operators:
proc toString*[Ty](x: Ty): string
proc toString*[Ty](x: Ty): string {.deprecated.}
## This generic proc is the same as the stringify operator `$`.
##
## **Deprecated since version 0.8.2:** Use `$` instead.
proc repeatChar*(count: int, c: Char = ' '): string
## Returns a string of length `count` consisting only of

View File

@@ -12,9 +12,14 @@
{.deadCodeElim: on.}
type
TRune* = int ## type that can hold any Unicode character
TRune16* = int16 ## 16 bit Unicode character
irune = int # underlying type of TRune
TRune* = distinct irune ## type that can hold any Unicode character
TRune16* = distinct int16 ## 16 bit Unicode character
proc `<=%`*(a, b: TRune): bool {.borrow.}
proc `<%`*(a, b: TRune): bool {.borrow.}
proc `==`*(a, b: TRune): bool {.borrow.}
template ones(n: expr): expr = ((1 shl n)-1)
proc runeLen*(s: string): int =
@@ -28,77 +33,71 @@ proc runeLen*(s: string): int =
else: assert(false)
inc(result)
proc runeLenAt*(s: string, i: int): int =
## returns the number of bytes the rune starting at ``s[i]`` takes.
if ord(s[i]) <=% 127: result = 1
elif ord(s[i]) shr 5 == 0b110: result = 2
elif ord(s[i]) shr 4 == 0b1110: result = 3
elif ord(s[i]) shr 3 == 0b11110: result = 4
else: assert(false)
template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
## Returns the unicode character ``s[i]`` in `result`. If ``doInc == true``
## `i` is incremented by the number of bytes that have been processed.
when not defined(ones):
template ones(n: expr): expr = ((1 shl n)-1)
if ord(s[i]) <=% 127:
result = TRune(ord(s[i]))
when doInc: inc(i)
elif ord(s[i]) shr 5 == 0b110:
assert(ord(s[i+1]) shr 6 == 0b10)
result = TRune((ord(s[i]) and ones(5)) shl 6 or (ord(s[i+1]) and ones(6)))
when doInc: inc(i, 2)
elif ord(s[i]) shr 4 == 0b1110:
assert(ord(s[i+1]) shr 6 == 0b10)
assert(ord(s[i+2]) shr 6 == 0b10)
result = TRune((ord(s[i]) and ones(4)) shl 12 or
(ord(s[i+1]) and ones(6)) shl 6 or
(ord(s[i+2]) and ones(6)))
when doInc: inc(i, 3)
elif ord(s[i]) shr 3 == 0b11110:
assert(ord(s[i+1]) shr 6 == 0b10)
assert(ord(s[i+2]) shr 6 == 0b10)
assert(ord(s[i+3]) shr 6 == 0b10)
result = TRune((ord(s[i]) and ones(3)) shl 18 or
(ord(s[i+1]) and ones(6)) shl 12 or
(ord(s[i+2]) and ones(6)) shl 6 or
(ord(s[i+3]) and ones(6)))
when doInc: inc(i, 4)
else:
assert(false)
proc runeAt*(s: string, i: int): TRune =
## returns the unicode character in `s` at byte index `i`
if ord(s[i]) <=% 127:
result = ord(s[i])
elif ord(s[i]) shr 5 == 0b110:
assert(ord(s[i+1]) shr 6 == 0b10)
result = (ord(s[i]) and ones(5)) shl 6 or (ord(s[i+1]) and ones(6))
elif ord(s[i]) shr 4 == 0b1110:
assert(ord(s[i+1]) shr 6 == 0b10)
assert(ord(s[i+2]) shr 6 == 0b10)
result = (ord(s[i]) and ones(4)) shl 12 or
(ord(s[i+1]) and ones(6)) shl 6 or
(ord(s[i+2]) and ones(6))
elif ord(s[i]) shr 3 == 0b11110:
assert(ord(s[i+1]) shr 6 == 0b10)
assert(ord(s[i+2]) shr 6 == 0b10)
assert(ord(s[i+3]) shr 6 == 0b10)
result = (ord(s[i]) and ones(3)) shl 18 or
(ord(s[i+1]) and ones(6)) shl 12 or
(ord(s[i+2]) and ones(6)) shl 6 or
(ord(s[i+3]) and ones(6))
else:
assert(false)
template fastRuneAt(s, i, result: expr): stmt =
if ord(s[i]) <=% 127:
result = ord(s[i])
inc(i)
elif ord(s[i]) shr 5 == 0b110:
assert(ord(s[i+1]) shr 6 == 0b10)
result = (ord(s[i]) and ones(5)) shl 6 or (ord(s[i+1]) and ones(6))
inc(i, 2)
elif ord(s[i]) shr 4 == 0b1110:
assert(ord(s[i+1]) shr 6 == 0b10)
assert(ord(s[i+2]) shr 6 == 0b10)
result = (ord(s[i]) and ones(4)) shl 12 or
(ord(s[i+1]) and ones(6)) shl 6 or
(ord(s[i+2]) and ones(6))
inc(i, 3)
elif ord(s[i]) shr 3 == 0b11110:
assert(ord(s[i+1]) shr 6 == 0b10)
assert(ord(s[i+2]) shr 6 == 0b10)
assert(ord(s[i+3]) shr 6 == 0b10)
result = (ord(s[i]) and ones(3)) shl 18 or
(ord(s[i+1]) and ones(6)) shl 12 or
(ord(s[i+2]) and ones(6)) shl 6 or
(ord(s[i+3]) and ones(6))
inc(i, 4)
else:
assert(false)
fastRuneAt(s, i, result, false)
proc toUTF8*(c: TRune): string =
## converts a character into its UTF8 representation
if c <=% 127:
## converts a rune into its UTF8 representation
var i = irune(c)
if i <=% 127:
result = newString(1)
result[0] = chr(c)
elif c <=% 0x07FF:
result[0] = chr(i)
elif i <=% 0x07FF:
result = newString(2)
result[0] = chr(c shr 6 or 0b110_0000)
result[1] = chr(c and ones(6) or 0b10_000000)
elif c <=% 0xFFFF:
result[0] = chr(i shr 6 or 0b110_0000)
result[1] = chr(i and ones(6) or 0b10_000000)
elif i <=% 0xFFFF:
result = newString(3)
result[0] = chr(c shr 12 or 0b1110_0000)
result[1] = chr(c shr 6 and ones(6) or 0b10_0000_00)
result[2] = chr(c and ones(6) or 0b10_0000_00)
elif c <=% 0x0010FFFF:
result[0] = chr(i shr 12 or 0b1110_0000)
result[1] = chr(i shr 6 and ones(6) or 0b10_0000_00)
result[2] = chr(i and ones(6) or 0b10_0000_00)
elif i <=% 0x0010FFFF:
result = newString(4)
result[0] = chr(c shr 18 or 0b1111_0000)
result[1] = chr(c shr 12 and ones(6) or 0b10_0000_00)
result[2] = chr(c shr 6 and ones(6) or 0b10_0000_00)
result[3] = chr(c and ones(6) or 0b10_0000_00)
result[0] = chr(i shr 18 or 0b1111_0000)
result[1] = chr(i shr 12 and ones(6) or 0b10_0000_00)
result[2] = chr(i shr 6 and ones(6) or 0b10_0000_00)
result[3] = chr(i and ones(6) or 0b10_0000_00)
else:
assert false
@@ -1061,7 +1060,7 @@ const
0x01f1, 501, # DZ Dz
0x01f3, 499] # dz Dz
proc binarySearch(c: TRune, tab: openArray[TRune], len, stride: int): int =
proc binarySearch(c: irune, tab: openArray[iRune], len, stride: int): int =
var n = len
var t = 0
while n > 1:
@@ -1078,32 +1077,39 @@ proc binarySearch(c: TRune, tab: openArray[TRune], len, stride: int): int =
proc toLower*(c: TRune): TRune =
## Converts `c` into lower case. This works for any Unicode character.
## If possible, prefer `toLower` over `toUpper`.
var c = irune(c)
var p = binarySearch(c, tolowerRanges, len(toLowerRanges) div 3, 3)
if p >= 0 and c >= tolowerRanges[p] and c <= tolowerRanges[p+1]:
return c + tolowerRanges[p+2] - 500
return TRune(c + tolowerRanges[p+2] - 500)
p = binarySearch(c, toLowerSinglets, len(toLowerSinglets) div 2, 2)
if p >= 0 and c == toLowerSinglets[p]:
return c + toLowerSinglets[p+1] - 500
return c
return TRune(c + toLowerSinglets[p+1] - 500)
return TRune(c)
proc toUpper*(c: TRune): TRune =
## Converts `c` into upper case. This works for any Unicode character.
## If possible, prefer `toLower` over `toUpper`.
var c = irune(c)
var p = binarySearch(c, toUpperRanges, len(toUpperRanges) div 3, 3)
if p >= 0 and c >= toUpperRanges[p] and c <= toUpperRanges[p+1]:
return c + toUpperRanges[p+2] - 500
return TRune(c + toUpperRanges[p+2] - 500)
p = binarySearch(c, toUpperSinglets, len(toUpperSinglets) div 2, 2)
if p >= 0 and c == toUpperSinglets[p]:
return c + toUpperSinglets[p+1] - 500
return c
return TRune(c + toUpperSinglets[p+1] - 500)
return TRune(c)
proc toTitle*(c: TRune): TRune =
var c = irune(c)
var p = binarySearch(c, toTitleSinglets, len(toTitleSinglets) div 2, 2)
if p >= 0 and c == toTitleSinglets[p]:
return c + toTitleSinglets[p+1] - 500
return c
return TRune(c + toTitleSinglets[p+1] - 500)
return TRune(c)
proc isLower*(c: TRune): bool =
## returns true iff `c` is a lower case Unicode character
## If possible, prefer `isLower` over `isUpper`.
var c = irune(c)
# Note: toUpperRanges is correct here!
var p = binarySearch(c, toUpperRanges, len(toUpperRanges) div 3, 3)
if p >= 0 and c >= toUpperRanges[p] and c <= toUpperRanges[p+1]:
@@ -1114,6 +1120,8 @@ proc isLower*(c: TRune): bool =
proc isUpper*(c: TRune): bool =
## returns true iff `c` is a upper case Unicode character
## If possible, prefer `isLower` over `isUpper`.
var c = irune(c)
# Note: toLowerRanges is correct here!
var p = binarySearch(c, toLowerRanges, len(toLowerRanges) div 3, 3)
if p >= 0 and c >= toLowerRanges[p] and c <= toLowerRanges[p+1]:
@@ -1126,6 +1134,7 @@ proc isAlpha*(c: TRune): bool =
## returns true iff `c` is an *alpha* Unicode character (i.e. a letter)
if isUpper(c) or isLower(c):
return true
var c = irune(c)
var p = binarySearch(c, alphaRanges, len(alphaRanges) div 2, 2)
if p >= 0 and c >= alphaRanges[p] and c <= alphaRanges[p+1]:
return true
@@ -1138,6 +1147,7 @@ proc isTitle*(c: TRune): bool =
proc isWhiteSpace*(c: TRune): bool =
## returns true iff `c` is a Unicode whitespace character
var c = irune(c)
var p = binarySearch(c, spaceRanges, len(spaceRanges) div 2, 2)
if p >= 0 and c >= spaceRanges[p] and c <= spaceRanges[p+1]:
return true
@@ -1148,7 +1158,7 @@ iterator runes*(s: string): TRune =
i = 0
result: TRune
while i < len(s):
fastRuneAt(s, i, result)
fastRuneAt(s, i, result, true)
yield result
proc cmpRunesIgnoreCase*(a, b: string): int =
@@ -1164,7 +1174,7 @@ proc cmpRunesIgnoreCase*(a, b: string): int =
# slow path:
fastRuneAt(a, i, ar)
fastRuneAt(b, j, br)
result = toLower(ar) - toLower(br)
result = irune(toLower(ar)) - irune(toLower(br))
if result != 0: return
result = a.len - b.len

View File

@@ -13,9 +13,6 @@
## Each module implicitly imports the System module; it may not be listed
## explicitly. Because of this there can not be a user-defined module named
## ``system``.
##
## *The good thing about reinventing the wheel is that you can get a
## round one.*
{.push hints: off.}
@@ -58,11 +55,10 @@ proc defined*[T](x: T): bool {.magic: "Defined", noSideEffect.}
## # provide our own toUpper proc here, because strutils is
## # missing it.
proc definedInScope*[T](x: T, scope=0): bool {.
proc definedInScope*[T](x: T): bool {.
magic: "DefinedInScope", noSideEffect.}
## Special comile-time procedure that checks whether `x` is
## defined in the scope `scope`. `x` has to be an identifier.
## 0 means the current scope, 1 means the scope above the current scope, etc.
## defined in the current scope. `x` has to be an identifier.
# these require compiler magic:
proc `not` *(x: bool): bool {.magic: "Not", noSideEffect.}
@@ -617,6 +613,27 @@ proc `@` * [IDX, T](a: array[IDX, T]): seq[T] {.
## sequences with the array constructor: ``@[1, 2, 3]`` has the type
## ``seq[int]``, while ``[1, 2, 3]`` has the type ``array[0..2, int]``.
proc setLen*[T](s: var seq[T], newlen: int) {.
magic: "SetLengthSeq", noSideEffect.}
## sets the length of `s` to `newlen`.
## ``T`` may be any sequence type.
## If the current length is greater than the new length,
## ``s`` will be truncated.
proc setLen*(s: var string, newlen: int) {.
magic: "SetLengthStr", noSideEffect.}
## sets the length of `s` to `newlen`.
## If the current length is greater than the new length,
## ``s`` will be truncated.
proc newString*(len: int): string {.
magic: "NewString", importc: "mnewString", noSideEffect.}
## returns a new string of length ``len`` but with uninitialized
## content. One needs to fill the string character after character
## with the index operator ``s[i]``. This procedure exists only for
## optimization purposes; the same effect can be achieved with the
## ``&`` operator.
# concat operator:
proc `&` * (x: string, y: char): string {.
magic: "ConStrStr", noSideEffect, merge.}
@@ -651,12 +668,15 @@ else:
"""
proc add *[T](x: var seq[T], y: T) {.magic: "AppendSeqElem", noSideEffect.}
proc add *[T](x: var seq[T], y: seq[T]) {.magic: "AppendSeqSeq", noSideEffect.}
proc add *[T](x: var seq[T], y: seq[T]) {.noSideEffect.} =
## Generic proc for adding a data item `y` to a container `x`.
## For containers that have an order, `add` means *append*. New generic
## containers should also call their adding proc `add` for consistency.
## Generic code becomes much easier to write if the Nimrod naming scheme is
## respected.
var xl = x.len
setLen(x, xl + y.len)
for i in 0..high(y): x[xl+i] = y[i]
proc repr*[T](x: T): string {.magic: "Repr", noSideEffect.}
## takes any Nimrod variable and returns its string representation. It
@@ -798,20 +818,6 @@ proc copy*(s: string, first, last: int): string {.
## the first and last characters that shall be copied. If ``last``
## is omitted, it is treated as ``high(s)``.
proc setLen*(s: var string, newlen: int) {.
magic: "SetLengthStr", noSideEffect.}
## sets the length of `s` to `newlen`.
## If the current length is greater than the new length,
## ``s`` will be truncated.
proc newString*(len: int): string {.
magic: "NewString", importc: "mnewString", noSideEffect.}
## returns a new string of length ``len`` but with uninitialized
## content. One needs to fill the string character after character
## with the index operator ``s[i]``. This procedure exists only for
## optimization purposes; the same effect can be achieved with the
## ``&`` operator.
proc zeroMem*(p: Pointer, size: int) {.importc, noDecl.}
## overwrites the contents of the memory at ``p`` with the value 0.
## Exactly ``size`` bytes will be overwritten. Like any procedure
@@ -861,13 +867,6 @@ proc dealloc*(p: Pointer) {.noconv.}
## or other memory may be corrupted. So this procedure is really
## *unsafe*.
proc setLen*[T](s: var seq[T], newlen: int) {.
magic: "SetLengthSeq", noSideEffect.}
## sets the length of `s` to `newlen`.
## ``T`` may be any sequence type.
## If the current length is greater than the new length,
## ``s`` will be truncated.
proc assert*(cond: bool) {.magic: "Assert", noSideEffect.}
## provides a means to implement `programming by contracts` in Nimrod.
## ``assert`` evaluates expression ``cond`` and if ``cond`` is false, it
@@ -1195,6 +1194,10 @@ proc GC_unref*[T](x: seq[T]) {.magic: "GCunref".}
proc GC_unref*(x: string) {.magic: "GCunref".}
## see the documentation of `GC_ref`.
template accumulateResult*(iter: expr) =
## helps to convert an iterator to a proc.
result = @[]
for x in iter: add(result, x)
{.push checks: off, line_dir: off, debugger: off.}
# obviously we cannot generate checking operations here :-)

View File

@@ -74,26 +74,16 @@ proc hashString(s: string): int {.compilerproc.} =
h = h +% h shl 15
result = h
# copy(s: string, start = 0): string
# {.extern: "copyStr", noDecl, noSideEffect.}
# copy(s: string, start, len: int): string
# {.extern: "copyStrLen", noDecl, noSideEffect.}
#
# setLength(var s: string, newlen: int)
# {.extern: "setLengthStr", noDecl, noSideEffect.}
proc copyStrLast(s: NimString, start, last: int): NimString {.exportc.} =
var
len: int
if start >= s.len: return mnewString(0) # BUGFIX
if last >= s.len:
len = s.len - start # - 1 + 1
var start = max(start, 0)
var len = min(last, s.len-1) - start + 1
if len > 0:
result = rawNewString(len)
result.len = len
c_memcpy(result.data, addr(s.data[start]), len * sizeof(Char))
result.data[len] = '\0'
else:
len = last - start + 1
result = rawNewString(len)
result.len = len
c_memcpy(result.data, addr(s.data[start]), len * sizeof(Char))
result.data[len] = '\0'
result = mnewString(0)
proc copyStr(s: NimString, start: int): NimString {.exportc.} =
return copyStrLast(s, start, s.len-1)

View File

@@ -1,110 +1,110 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2009 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements a small wrapper for some needed Win API procedures,
## so that the Nimrod compiler does not depend on the huge Windows module.
type
THandle* = int
WINBOOL* = int32
TSECURITY_ATTRIBUTES* {.final, pure.} = object
nLength*: int32
lpSecurityDescriptor*: pointer
bInheritHandle*: WINBOOL
TSTARTUPINFO* {.final, pure.} = object
cb*: int32
lpReserved*: cstring
lpDesktop*: cstring
lpTitle*: cstring
dwX*: int32
dwY*: int32
dwXSize*: int32
dwYSize*: int32
dwXCountChars*: int32
dwYCountChars*: int32
dwFillAttribute*: int32
dwFlags*: int32
wShowWindow*: int16
cbReserved2*: int16
lpReserved2*: pointer
hStdInput*: THANDLE
hStdOutput*: THANDLE
hStdError*: THANDLE
TPROCESS_INFORMATION* {.final, pure.} = object
hProcess*: THANDLE
hThread*: THANDLE
dwProcessId*: int32
dwThreadId*: int32
const
STARTF_USESHOWWINDOW* = 1'i32
STARTF_USESTDHANDLES* = 256'i32
HIGH_PRIORITY_CLASS* = 128'i32
IDLE_PRIORITY_CLASS* = 64'i32
NORMAL_PRIORITY_CLASS* = 32'i32
REALTIME_PRIORITY_CLASS* = 256'i32
WAIT_TIMEOUT* = 0x00000102'i32
INFINITE* = -1'i32
STD_INPUT_HANDLE* = -10'i32
STD_OUTPUT_HANDLE* = -11'i32
STD_ERROR_HANDLE* = -12'i32
proc CloseHandle*(hObject: THANDLE): WINBOOL {.stdcall, dynlib: "kernel32",
importc: "CloseHandle".}
proc ReadFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToRead: int32,
lpNumberOfBytesRead: var int32, lpOverlapped: pointer): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "ReadFile".}
proc WriteFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToWrite: int32,
lpNumberOfBytesWritten: var int32,
lpOverlapped: pointer): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "WriteFile".}
proc CreatePipe*(hReadPipe, hWritePipe: var THandle,
lpPipeAttributes: var TSECURITY_ATTRIBUTES,
nSize: int32): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "CreatePipe".}
proc CreateProcess*(lpApplicationName, lpCommandLine: cstring,
lpProcessAttributes: ptr TSECURITY_ATTRIBUTES,
lpThreadAttributes: ptr TSECURITY_ATTRIBUTES,
bInheritHandles: WINBOOL, dwCreationFlags: int32,
lpEnvironment: pointer, lpCurrentDirectory: cstring,
lpStartupInfo: var TSTARTUPINFO,
lpProcessInformation: var TPROCESS_INFORMATION): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "CreateProcessA".}
proc SuspendThread*(hThread: THANDLE): int32 {.stdcall, dynlib: "kernel32",
importc: "SuspendThread".}
proc ResumeThread*(hThread: THANDLE): int32 {.stdcall, dynlib: "kernel32",
importc: "ResumeThread".}
proc WaitForSingleObject*(hHandle: THANDLE, dwMilliseconds: int32): int32 {.
stdcall, dynlib: "kernel32", importc: "WaitForSingleObject".}
proc TerminateProcess*(hProcess: THANDLE, uExitCode: int): WINBOOL {.stdcall,
dynlib: "kernel32", importc: "TerminateProcess".}
proc GetExitCodeProcess*(hProcess: THANDLE, lpExitCode: var int32): WINBOOL {.
stdcall, dynlib: "kernel32", importc: "GetExitCodeProcess".}
proc GetStdHandle*(nStdHandle: int32): THANDLE {.stdcall, dynlib: "kernel32",
importc: "GetStdHandle".}
proc SetStdHandle*(nStdHandle: int32, hHandle: THANDLE): WINBOOL {.stdcall,
dynlib: "kernel32", importc: "SetStdHandle".}
proc FlushFileBuffers*(hFile: THANDLE): WINBOOL {.stdcall, dynlib: "kernel32",
importc: "FlushFileBuffers".}
#
#
# Nimrod's Runtime Library
# (c) Copyright 2009 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements a small wrapper for some needed Win API procedures,
## so that the Nimrod compiler does not depend on the huge Windows module.
type
THandle* = int
WINBOOL* = int32
TSECURITY_ATTRIBUTES* {.final, pure.} = object
nLength*: int32
lpSecurityDescriptor*: pointer
bInheritHandle*: WINBOOL
TSTARTUPINFO* {.final, pure.} = object
cb*: int32
lpReserved*: cstring
lpDesktop*: cstring
lpTitle*: cstring
dwX*: int32
dwY*: int32
dwXSize*: int32
dwYSize*: int32
dwXCountChars*: int32
dwYCountChars*: int32
dwFillAttribute*: int32
dwFlags*: int32
wShowWindow*: int16
cbReserved2*: int16
lpReserved2*: pointer
hStdInput*: THANDLE
hStdOutput*: THANDLE
hStdError*: THANDLE
TPROCESS_INFORMATION* {.final, pure.} = object
hProcess*: THANDLE
hThread*: THANDLE
dwProcessId*: int32
dwThreadId*: int32
const
STARTF_USESHOWWINDOW* = 1'i32
STARTF_USESTDHANDLES* = 256'i32
HIGH_PRIORITY_CLASS* = 128'i32
IDLE_PRIORITY_CLASS* = 64'i32
NORMAL_PRIORITY_CLASS* = 32'i32
REALTIME_PRIORITY_CLASS* = 256'i32
WAIT_TIMEOUT* = 0x00000102'i32
INFINITE* = -1'i32
STD_INPUT_HANDLE* = -10'i32
STD_OUTPUT_HANDLE* = -11'i32
STD_ERROR_HANDLE* = -12'i32
proc CloseHandle*(hObject: THANDLE): WINBOOL {.stdcall, dynlib: "kernel32",
importc: "CloseHandle".}
proc ReadFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToRead: int32,
lpNumberOfBytesRead: var int32, lpOverlapped: pointer): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "ReadFile".}
proc WriteFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToWrite: int32,
lpNumberOfBytesWritten: var int32,
lpOverlapped: pointer): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "WriteFile".}
proc CreatePipe*(hReadPipe, hWritePipe: var THandle,
lpPipeAttributes: var TSECURITY_ATTRIBUTES,
nSize: int32): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "CreatePipe".}
proc CreateProcess*(lpApplicationName, lpCommandLine: cstring,
lpProcessAttributes: ptr TSECURITY_ATTRIBUTES,
lpThreadAttributes: ptr TSECURITY_ATTRIBUTES,
bInheritHandles: WINBOOL, dwCreationFlags: int32,
lpEnvironment: pointer, lpCurrentDirectory: cstring,
lpStartupInfo: var TSTARTUPINFO,
lpProcessInformation: var TPROCESS_INFORMATION): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "CreateProcessA".}
proc SuspendThread*(hThread: THANDLE): int32 {.stdcall, dynlib: "kernel32",
importc: "SuspendThread".}
proc ResumeThread*(hThread: THANDLE): int32 {.stdcall, dynlib: "kernel32",
importc: "ResumeThread".}
proc WaitForSingleObject*(hHandle: THANDLE, dwMilliseconds: int32): int32 {.
stdcall, dynlib: "kernel32", importc: "WaitForSingleObject".}
proc TerminateProcess*(hProcess: THANDLE, uExitCode: int): WINBOOL {.stdcall,
dynlib: "kernel32", importc: "TerminateProcess".}
proc GetExitCodeProcess*(hProcess: THANDLE, lpExitCode: var int32): WINBOOL {.
stdcall, dynlib: "kernel32", importc: "GetExitCodeProcess".}
proc GetStdHandle*(nStdHandle: int32): THANDLE {.stdcall, dynlib: "kernel32",
importc: "GetStdHandle".}
proc SetStdHandle*(nStdHandle: int32, hHandle: THANDLE): WINBOOL {.stdcall,
dynlib: "kernel32", importc: "SetStdHandle".}
proc FlushFileBuffers*(hFile: THANDLE): WINBOOL {.stdcall, dynlib: "kernel32",
importc: "FlushFileBuffers".}
proc GetLastError*(): int32 {.importc, stdcall, dynlib: "kernel32".}
proc FormatMessageA*(dwFlags: int32, lpSource: pointer,

259
lib/wrappers/tre/config.h Normal file
View 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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
0.7.6

View File

@@ -84,20 +84,21 @@ type
nkObjDownConv, nkObjUpConv, nkChckRangeF, nkChckRange64,
nkChckRange, nkStringToCString, nkCStringToString, nkPassAsOpenArray,
nkAsgn, nkFastAsgn, nkGenericParams, nkFormalParams,
nkOfInherit, nkModule, nkProcDef, nkConverterDef,
nkMacroDef, nkTemplateDef, nkIteratorDef, nkOfBranch,
nkElifBranch, nkExceptBranch, nkElse, nkMacroStmt,
nkAsmStmt, nkPragma, nkIfStmt, nkWhenStmt,
nkForStmt, nkWhileStmt, nkCaseStmt, nkVarSection,
nkConstSection, nkConstDef, nkTypeSection, nkTypeDef,
nkYieldStmt, nkTryStmt, nkFinally, nkRaiseStmt,
nkReturnStmt, nkBreakStmt, nkContinueStmt, nkBlockStmt,
nkDiscardStmt, nkStmtList, nkImportStmt, nkFromStmt,
nkIncludeStmt, nkCommentStmt, nkStmtListExpr, nkBlockExpr,
nkStmtListType, nkBlockType, nkTypeOfExpr, nkObjectTy,
nkTupleTy, nkRecList, nkRecCase, nkRecWhen,
nkRefTy, nkPtrTy, nkVarTy, nkDistinctTy,
nkProcTy, nkEnumTy, nkEnumFieldDef, nkReturnToken);
nkOfInherit, nkModule, nkProcDef, nkMethodDef,
nkConverterDef, nkMacroDef, nkTemplateDef, nkIteratorDef,
nkOfBranch, nkElifBranch, nkExceptBranch, nkElse,
nkMacroStmt, nkAsmStmt, nkPragma, nkIfStmt,
nkWhenStmt, nkForStmt, nkWhileStmt, nkCaseStmt,
nkVarSection, nkConstSection, nkConstDef, nkTypeSection,
nkTypeDef, nkYieldStmt, nkTryStmt, nkFinally,
nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt,
nkBlockStmt, nkDiscardStmt, nkStmtList, nkImportStmt,
nkFromStmt, nkIncludeStmt, nkCommentStmt, nkStmtListExpr,
nkBlockExpr, nkStmtListType, nkBlockType, nkTypeOfExpr,
nkObjectTy, nkTupleTy, nkRecList, nkRecCase,
nkRecWhen, nkRefTy, nkPtrTy, nkVarTy,
nkDistinctTy, nkProcTy, nkEnumTy, nkEnumFieldDef,
nkReturnToken);
TNodeKinds = set of TNodeKind;
const
NodeKindToStr: array [TNodeKind] of string = (
@@ -118,20 +119,21 @@ const
'nkObjDownConv', 'nkObjUpConv', 'nkChckRangeF', 'nkChckRange64',
'nkChckRange', 'nkStringToCString', 'nkCStringToString', 'nkPassAsOpenArray',
'nkAsgn', 'nkFastAsgn', 'nkGenericParams', 'nkFormalParams',
'nkOfInherit', 'nkModule', 'nkProcDef', 'nkConverterDef',
'nkMacroDef', 'nkTemplateDef', 'nkIteratorDef', 'nkOfBranch',
'nkElifBranch', 'nkExceptBranch', 'nkElse', 'nkMacroStmt',
'nkAsmStmt', 'nkPragma', 'nkIfStmt', 'nkWhenStmt',
'nkForStmt', 'nkWhileStmt', 'nkCaseStmt', 'nkVarSection',
'nkConstSection', 'nkConstDef', 'nkTypeSection', 'nkTypeDef',
'nkYieldStmt', 'nkTryStmt', 'nkFinally', 'nkRaiseStmt',
'nkReturnStmt', 'nkBreakStmt', 'nkContinueStmt', 'nkBlockStmt',
'nkDiscardStmt', 'nkStmtList', 'nkImportStmt', 'nkFromStmt',
'nkIncludeStmt', 'nkCommentStmt', 'nkStmtListExpr', 'nkBlockExpr',
'nkStmtListType', 'nkBlockType', 'nkTypeOfExpr', 'nkObjectTy',
'nkTupleTy', 'nkRecList', 'nkRecCase', 'nkRecWhen',
'nkRefTy', 'nkPtrTy', 'nkVarTy', 'nkDistinctTy',
'nkProcTy', 'nkEnumTy', 'nkEnumFieldDef', 'nkReturnToken');
'nkOfInherit', 'nkModule', 'nkProcDef', 'nkMethodDef',
'nkConverterDef', 'nkMacroDef', 'nkTemplateDef', 'nkIteratorDef',
'nkOfBranch', 'nkElifBranch', 'nkExceptBranch', 'nkElse',
'nkMacroStmt', 'nkAsmStmt', 'nkPragma', 'nkIfStmt',
'nkWhenStmt', 'nkForStmt', 'nkWhileStmt', 'nkCaseStmt',
'nkVarSection', 'nkConstSection', 'nkConstDef', 'nkTypeSection',
'nkTypeDef', 'nkYieldStmt', 'nkTryStmt', 'nkFinally',
'nkRaiseStmt', 'nkReturnStmt', 'nkBreakStmt', 'nkContinueStmt',
'nkBlockStmt', 'nkDiscardStmt', 'nkStmtList', 'nkImportStmt',
'nkFromStmt', 'nkIncludeStmt', 'nkCommentStmt', 'nkStmtListExpr',
'nkBlockExpr', 'nkStmtListType', 'nkBlockType', 'nkTypeOfExpr',
'nkObjectTy', 'nkTupleTy', 'nkRecList', 'nkRecCase',
'nkRecWhen', 'nkRefTy', 'nkPtrTy', 'nkVarTy',
'nkDistinctTy', 'nkProcTy', 'nkEnumTy', 'nkEnumFieldDef',
'nkReturnToken');
type
TSymFlag = (
sfUsed, sfStar, sfMinus, sfInInterface,
@@ -200,17 +202,19 @@ type
TSymKind = (
skUnknown, skConditional, skDynLib, skParam,
skGenericParam, skTemp, skType, skConst,
skVar, skProc, skIterator, skConverter,
skMacro, skTemplate, skField, skEnumField,
skForVar, skModule, skLabel, skStub);
skVar, skProc, skMethod, skIterator,
skConverter, skMacro, skTemplate, skField,
skEnumField, skForVar, skModule, skLabel,
skStub);
TSymKinds = set of TSymKind;
const
SymKindToStr: array [TSymKind] of string = (
'skUnknown', 'skConditional', 'skDynLib', 'skParam',
'skGenericParam', 'skTemp', 'skType', 'skConst',
'skVar', 'skProc', 'skIterator', 'skConverter',
'skMacro', 'skTemplate', 'skField', 'skEnumField',
'skForVar', 'skModule', 'skLabel', 'skStub');
'skVar', 'skProc', 'skMethod', 'skIterator',
'skConverter', 'skMacro', 'skTemplate', 'skField',
'skEnumField', 'skForVar', 'skModule', 'skLabel',
'skStub');
{[[[end]]]}
type
@@ -223,9 +227,9 @@ type
// if (i+1) % 6 == 0: cog.outl("")
//cog.outl("m" + magics[-1])
//]]]
mNone, mDefined, mLow, mHigh, mSizeOf, mIs,
mEcho, mSucc, mPred, mInc, mDec, mOrd,
mNew, mNewFinalize, mNewSeq, mRegisterFinalizer, mLengthOpenArray, mLengthStr,
mNone, mDefined, mDefinedInScope, mLow, mHigh, mSizeOf,
mIs, mEcho, mSucc, mPred, mInc, mDec,
mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray, mLengthStr,
mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr,
mGCref, mGCunref, mAddI, mSubI, mMulI, mDivI,
mModI, mAddI64, mSubI64, mMulI64, mDivI64, mModI64,
@@ -247,21 +251,20 @@ type
mStrToStr, mEnumToStr, mAnd, mOr, mEqStr, mLeStr,
mLtStr, mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet,
mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT, mConTArr,
mConTT, mSlice, mAppendStrCh, mAppendStrStr, mAppendSeqElem, mAppendSeqSeq,
mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq,
mAssert, mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast,
mNewString, mArray, mOpenArray, mRange, mSet, mSeq,
mOrdinal, mInt, mInt8, mInt16, mInt32, mInt64,
mFloat, mFloat32, mFloat64, mBool, mChar, mString,
mCstring, mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr,
mStmt, mTypeDesc, mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion,
mNimrodMajor, mNimrodMinor, mNimrodPatch, mCpuEndian, mHostOS, mHostCPU,
mNaN, mInf, mNegInf, mNLen, mNChild, mNSetChild,
mNAdd, mNAddMultiple, mNDel, mNKind, mNIntVal, mNFloatVal,
mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal, mNSetFloatVal,
mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNNewNimNode, mNCopyNimNode,
mNCopyNimTree, mStrToIdent, mIdentToStr, mEqIdent, mNHint, mNWarning,
mNError
mConTT, mSlice, mAppendStrCh, mAppendStrStr, mAppendSeqElem, mInRange,
mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq, mAssert,
mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast, mNewString,
mArray, mOpenArray, mRange, mSet, mSeq, mOrdinal,
mInt, mInt8, mInt16, mInt32, mInt64, mFloat,
mFloat32, mFloat64, mBool, mChar, mString, mCstring,
mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt,
mTypeDesc, mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion, mNimrodMajor,
mNimrodMinor, mNimrodPatch, mCpuEndian, mHostOS, mHostCPU, mNaN,
mInf, mNegInf, mNLen, mNChild, mNSetChild, mNAdd,
mNAddMultiple, mNDel, mNKind, mNIntVal, mNFloatVal, mNSymbol,
mNIdent, mNGetType, mNStrVal, mNSetIntVal, mNSetFloatVal, mNSetSymbol,
mNSetIdent, mNSetType, mNSetStrVal, mNNewNimNode, mNCopyNimNode, mNCopyNimTree,
mStrToIdent, mIdentToStr, mEqIdent, mNHint, mNWarning, mNError
//[[[end]]]
);
@@ -472,7 +475,7 @@ type
end;
const
OverloadableSyms = {@set}[skProc, skIterator, skConverter];
OverloadableSyms = {@set}[skProc, skMethod, skIterator, skConverter];
const // "MagicToStr" array:
MagicToStr: array [TMagic] of string = (
@@ -482,9 +485,9 @@ const // "MagicToStr" array:
// if (i+1) % 6 == 0: cog.outl("")
//cog.outl("'%s'" % magics[-1])
//]]]
'None', 'Defined', 'Low', 'High', 'SizeOf', 'Is',
'Echo', 'Succ', 'Pred', 'Inc', 'Dec', 'Ord',
'New', 'NewFinalize', 'NewSeq', 'RegisterFinalizer', 'LengthOpenArray', 'LengthStr',
'None', 'Defined', 'DefinedInScope', 'Low', 'High', 'SizeOf',
'Is', 'Echo', 'Succ', 'Pred', 'Inc', 'Dec',
'Ord', 'New', 'NewFinalize', 'NewSeq', 'LengthOpenArray', 'LengthStr',
'LengthArray', 'LengthSeq', 'Incl', 'Excl', 'Card', 'Chr',
'GCref', 'GCunref', 'AddI', 'SubI', 'MulI', 'DivI',
'ModI', 'AddI64', 'SubI64', 'MulI64', 'DivI64', 'ModI64',
@@ -506,21 +509,20 @@ const // "MagicToStr" array:
'StrToStr', 'EnumToStr', 'And', 'Or', 'EqStr', 'LeStr',
'LtStr', 'EqSet', 'LeSet', 'LtSet', 'MulSet', 'PlusSet',
'MinusSet', 'SymDiffSet', 'ConStrStr', 'ConArrArr', 'ConArrT', 'ConTArr',
'ConTT', 'Slice', 'AppendStrCh', 'AppendStrStr', 'AppendSeqElem', 'AppendSeqSeq',
'InRange', 'InSet', 'Repr', 'Exit', 'SetLengthStr', 'SetLengthSeq',
'Assert', 'Swap', 'IsNil', 'ArrToSeq', 'CopyStr', 'CopyStrLast',
'NewString', 'Array', 'OpenArray', 'Range', 'Set', 'Seq',
'Ordinal', 'Int', 'Int8', 'Int16', 'Int32', 'Int64',
'Float', 'Float32', 'Float64', 'Bool', 'Char', 'String',
'Cstring', 'Pointer', 'EmptySet', 'IntSetBaseType', 'Nil', 'Expr',
'Stmt', 'TypeDesc', 'IsMainModule', 'CompileDate', 'CompileTime', 'NimrodVersion',
'NimrodMajor', 'NimrodMinor', 'NimrodPatch', 'CpuEndian', 'HostOS', 'HostCPU',
'NaN', 'Inf', 'NegInf', 'NLen', 'NChild', 'NSetChild',
'NAdd', 'NAddMultiple', 'NDel', 'NKind', 'NIntVal', 'NFloatVal',
'NSymbol', 'NIdent', 'NGetType', 'NStrVal', 'NSetIntVal', 'NSetFloatVal',
'NSetSymbol', 'NSetIdent', 'NSetType', 'NSetStrVal', 'NNewNimNode', 'NCopyNimNode',
'NCopyNimTree', 'StrToIdent', 'IdentToStr', 'EqIdent', 'NHint', 'NWarning',
'NError'
'ConTT', 'Slice', 'AppendStrCh', 'AppendStrStr', 'AppendSeqElem', 'InRange',
'InSet', 'Repr', 'Exit', 'SetLengthStr', 'SetLengthSeq', 'Assert',
'Swap', 'IsNil', 'ArrToSeq', 'CopyStr', 'CopyStrLast', 'NewString',
'Array', 'OpenArray', 'Range', 'Set', 'Seq', 'Ordinal',
'Int', 'Int8', 'Int16', 'Int32', 'Int64', 'Float',
'Float32', 'Float64', 'Bool', 'Char', 'String', 'Cstring',
'Pointer', 'EmptySet', 'IntSetBaseType', 'Nil', 'Expr', 'Stmt',
'TypeDesc', 'IsMainModule', 'CompileDate', 'CompileTime', 'NimrodVersion', 'NimrodMajor',
'NimrodMinor', 'NimrodPatch', 'CpuEndian', 'HostOS', 'HostCPU', 'NaN',
'Inf', 'NegInf', 'NLen', 'NChild', 'NSetChild', 'NAdd',
'NAddMultiple', 'NDel', 'NKind', 'NIntVal', 'NFloatVal', 'NSymbol',
'NIdent', 'NGetType', 'NStrVal', 'NSetIntVal', 'NSetFloatVal', 'NSetSymbol',
'NSetIdent', 'NSetType', 'NSetStrVal', 'NNewNimNode', 'NCopyNimNode', 'NCopyNimTree',
'StrToIdent', 'IdentToStr', 'EqIdent', 'NHint', 'NWarning', 'NError'
//[[[end]]]
);
@@ -553,7 +555,7 @@ const
tyFloat..tyFloat128
];
ConstantDataTypes: TTypeKinds = {@set}[tyArray, tySet, tyTuple];
ExportableSymKinds = {@set}[skVar, skConst, skProc, skType,
ExportableSymKinds = {@set}[skVar, skConst, skProc, skMethod, skType,
skIterator, skMacro, skTemplate, skConverter,
skStub];
PersistentNodeFlags: TNodeFlags = {@set}[
@@ -564,6 +566,7 @@ const
pragmasPos = 3;
codePos = 4;
resultPos = 5;
dispatcherPos = 6;
var
gId: int;

View File

@@ -1285,14 +1285,14 @@ begin
genAssignment(p, a, c, {@set}[]);
end;
procedure genIs(p: BProc; n: PNode; var d: TLoc);
procedure genIs(p: BProc; x: PNode; typ: PType; var d: TLoc); overload;
var
a: TLoc;
dest, t: PType;
r, nilcheck: PRope;
begin
initLocExpr(p, n.sons[1], a);
dest := skipTypes(n.sons[2].typ, abstractPtrs);
initLocExpr(p, x, a);
dest := skipTypes(typ, abstractPtrs);
useMagic(p.module, 'isObj');
r := rdLoc(a);
nilCheck := nil;
@@ -1313,7 +1313,12 @@ begin
else
r := ropef('isObj($1.m_type, $2)',
[r, genTypeInfo(p.module, dest)]);
putIntoDest(p, d, n.typ, r);
putIntoDest(p, d, getSysType(tyBool), r);
end;
procedure genIs(p: BProc; n: PNode; var d: TLoc); overload;
begin
genIs(p, n.sons[1], n.sons[2].typ, d);
end;
procedure genNewFinalize(p: BProc; e: PNode);
@@ -1330,14 +1335,14 @@ begin
// This is a little hack:
// XXX this is also a bug, if the finalizer expression produces side-effects
oldModule := p.module;
p.module := gmti;
p.module := gNimDat;
InitLocExpr(p, e.sons[2], f);
p.module := oldModule;
initLoc(b, locExpr, a.t, OnHeap);
ti := genTypeInfo(p.module, refType);
appf(gmti.s[cfsTypeInit3], '$1->finalizer = (void*)$2;$n', [
appf(gNimDat.s[cfsTypeInit3], '$1->finalizer = (void*)$2;$n', [
ti, rdLoc(f)]);
b.r := ropef('($1) newObj($2, sizeof($3))',
[getTypeDesc(p.module, refType), ti,
@@ -2164,6 +2169,16 @@ begin
nkSym: begin
sym := e.sym;
case sym.Kind of
skMethod: begin
if sym.ast.sons[codePos] = nil then begin
// we cannot produce code for the dispatcher yet:
fillProcLoc(sym);
genProcPrototype(p.module, sym);
end
else
genProc(p.module, sym);
putLocIntoDest(p, d, sym.loc);
end;
skProc, skConverter: begin
genProc(p.module, sym);
if ((sym.loc.r = nil) or (sym.loc.t = nil)) then

View File

@@ -326,7 +326,7 @@ begin
nkStrLit..nkTripleStrLit: app(s, t.sons[i].strVal);
nkSym: begin
sym := t.sons[i].sym;
if sym.kind = skProc then begin
if sym.kind in [skProc, skMethod] then begin
initLocExpr(p, t.sons[i], a);
app(s, rdLoc(a));
end
@@ -970,12 +970,13 @@ begin
nkCommentStmt, nkNilLit, nkIteratorDef, nkIncludeStmt, nkImportStmt,
nkFromStmt, nkTemplateDef, nkMacroDef: begin end;
nkPragma: genPragma(p, t);
nkProcDef, nkConverterDef: begin
nkProcDef, nkMethodDef, nkConverterDef: begin
if (t.sons[genericParamsPos] = nil) then begin
prc := t.sons[namePos].sym;
if not (optDeadCodeElim in gGlobalOptions) and
not (sfDeadCodeElim in getModule(prc).flags)
or ([sfExportc, sfCompilerProc] * prc.flags = [sfExportc]) then begin
or ([sfExportc, sfCompilerProc] * prc.flags = [sfExportc])
or (prc.kind = skMethod) then begin
if (t.sons[codePos] <> nil) or (lfDynamicLib in prc.loc.flags) then begin
genProc(p.module, prc)
end

View File

@@ -47,7 +47,7 @@ begin
if result = nil then begin
if gCmd = cmdCompileToLLVM then begin
case s.kind of
skProc, skConverter, skConst: result := toRope('@'+'');
skProc, skMethod, skConverter, skConst: result := toRope('@'+'');
skVar: begin
if (sfGlobal in s.flags) then result := toRope('@'+'')
else result := toRope('%'+'');
@@ -1026,15 +1026,15 @@ begin
tyEmpty: result := toRope('0'+'');
tyPointer, tyProc, tyBool, tyChar, tyCString, tyString,
tyInt..tyFloat128, tyVar:
genTypeInfoAuxBase(gmti, t, result, toRope('0'+''));
tyRef, tyPtr, tySequence, tyRange: genTypeInfoAux(gmti, t, result);
tyArrayConstr, tyArray: genArrayInfo(gmti, t, result);
tySet: genSetInfo(gmti, t, result);
tyEnum: genEnumInfo(gmti, t, result);
tyObject: genObjectInfo(gmti, t, result);
genTypeInfoAuxBase(gNimDat, t, result, toRope('0'+''));
tyRef, tyPtr, tySequence, tyRange: genTypeInfoAux(gNimDat, t, result);
tyArrayConstr, tyArray: genArrayInfo(gNimDat, t, result);
tySet: genSetInfo(gNimDat, t, result);
tyEnum: genEnumInfo(gNimDat, t, result);
tyObject: genObjectInfo(gNimDat, t, result);
tyTuple: begin
if t.n <> nil then genObjectInfo(gmti, t, result)
else genTupleInfo(gmti, t, result);
if t.n <> nil then genObjectInfo(gNimDat, t, result)
else genTupleInfo(gNimDat, t, result);
end;
else InternalError('genTypeInfo(' + typekindToStr[t.kind] + ')');
end

View File

@@ -19,7 +19,7 @@ uses
nsystem, ast, astalgo, strutils, nhashes, trees, platform, magicsys,
extccomp, options, nversion, nimsets, msgs, crc, bitsets, idents,
lists, types, ccgutils, nos, ntime, ropes, nmath, passes, rodread,
wordrecg, rnimsyn, treetab;
wordrecg, rnimsyn, treetab, cgmeth;
function cgenPass(): TPass;
@@ -131,7 +131,7 @@ var
gPendingModules: array of BModule = {@ignore} nil {@emit @[]};
// list of modules that are not finished with code generation
gForwardedProcsCounter: int = 0;
gmti: BModule; // generated type info: no need to initialize: defaults fit
gNimDat: BModule; // generated global data
function ropeff(const cformat, llvmformat: string;
const args: array of PRope): PRope;
@@ -557,7 +557,7 @@ begin
sym := magicsys.getCompilerProc(name);
if sym <> nil then
case sym.kind of
skProc, skConverter: genProc(m, sym);
skProc, skMethod, skConverter: genProc(m, sym);
skVar: genVarPrototype(m, sym);
skType: {@discard} getTypeDesc(m, sym.typ);
else InternalError('useMagic: ' + name)
@@ -730,6 +730,7 @@ begin
app(generatedProc, '}' + tnl);
end;
app(m.s[cfsProcs], generatedProc);
//if prc.kind = skMethod then addMethodToCompile(gNimDat, prc);
end;
procedure genProcPrototype(m: BModule; sym: PSym);
@@ -746,8 +747,9 @@ begin
end
end
else begin
if not IntSetContainsOrIncl(m.declaredProtos, sym.id) then
if not IntSetContainsOrIncl(m.declaredProtos, sym.id) then begin
appf(m.s[cfsProcHeaders], '$1;$n', [genProcHeader(m, sym)]);
end
end
end;
@@ -836,18 +838,18 @@ function getFileHeader(const cfilenoext: string): PRope;
begin
if optCompileOnly in gGlobalOptions then
result := ropeff(
'/* Generated by the Nimrod Compiler v$1 */$n' +
'/* Generated by Nimrod Compiler v$1 */$n' +
'/* (c) 2009 Andreas Rumpf */$n',
'; Generated by the Nimrod Compiler v$1$n' +
'; Generated by Nimrod Compiler v$1$n' +
'; (c) 2009 Andreas Rumpf$n',
[toRope(versionAsString)])
else
result := ropeff(
'/* Generated by the Nimrod Compiler v$1 */$n' +
'/* Generated by Nimrod Compiler v$1 */$n' +
'/* (c) 2009 Andreas Rumpf */$n' +
'/* Compiled for: $2, $3, $4 */$n' +
'/* Command for C compiler:$n $5 */$n',
'; Generated by the Nimrod Compiler v$1$n' +
'; Generated by Nimrod Compiler v$1$n' +
'; (c) 2009 Andreas Rumpf$n' +
'; Compiled for: $2, $3, $4$n' +
'; Command for LLVM compiler:$n $5$n',
@@ -1115,15 +1117,15 @@ var
s: PSym;
begin
s := NewSym(skModule, getIdent(moduleName), nil);
gmti := rawNewModule(s, joinPath(options.projectPath, moduleName)+'.nim');
addPendingModule(gmti);
gNimDat := rawNewModule(s, joinPath(options.projectPath, moduleName)+'.nim');
addPendingModule(gNimDat);
appff(mainModProcs, 'N_NOINLINE(void, $1)(void);$n',
'declare void $1() noinline$n', [getInitName(s)]);
end;
function myOpen(module: PSym; const filename: string): PPassContext;
begin
if gmti = nil then registerTypeInfoModule();
if gNimDat = nil then registerTypeInfoModule();
result := newModule(module, filename);
end;
@@ -1132,7 +1134,7 @@ function myOpenCached(module: PSym; const filename: string;
var
cfile, cfilenoext, objFile: string;
begin
if gmti = nil then registerTypeInfoModule();
if gNimDat = nil then registerTypeInfoModule();
//MessageOut('cgen.myOpenCached has been called ' + filename);
cfile := changeFileExt(completeCFilePath(filename), cExt);
cfilenoext := changeFileExt(cfile, '');
@@ -1177,7 +1179,7 @@ begin
i := 0;
while i <= high(m.forwardedProcs) do begin
// Note: ``genProc`` may add to ``m.forwardedProcs``, so we cannot use
// a for loop here
// a ``for`` loop here
prc := m.forwardedProcs[i];
if sfForward in prc.flags then InternalError(prc.info, 'still forwarded');
genProcNoForward(m, prc);
@@ -1214,6 +1216,7 @@ function myClose(b: PPassContext; n: PNode): PNode;
var
m: BModule;
i: int;
disp: PNode;
begin
result := n;
if b = nil then exit;
@@ -1227,6 +1230,8 @@ begin
not (sfDeadCodeElim in m.module.flags) then
finishModule(m);
if sfMainModule in m.module.flags then begin
disp := generateMethodDispatchers();
for i := 0 to sonsLen(disp)-1 do genProcAux(gNimDat, disp.sons[i].sym);
genMainProc(m);
// we need to process the transitive closure because recursive module
// deps are allowed (and the system module is processed in the wrong
@@ -1241,7 +1246,7 @@ begin
not (sfDeadCodeElim in m.module.flags) then
writeModule(m);
if sfMainModule in m.module.flags then
writeMapping(gMapping);
writeMapping(gMapping);
end;
function cgenPass(): TPass;

269
nim/cgmeth.pas Normal file
View 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.

View File

@@ -1036,6 +1036,7 @@ begin
case n.kind of
nkCommentStmt: app(d.modDesc, genComment(d, n));
nkProcDef: genItem(d, n, n.sons[namePos], skProc);
nkMethodDef: genItem(d, n, n.sons[namePos], skMethod);
nkIteratorDef: genItem(d, n, n.sons[namePos], skIterator);
nkMacroDef: genItem(d, n, n.sons[namePos], skMacro);
nkTemplateDef: genItem(d, n, n.sons[namePos], skTemplate);

View File

@@ -1717,7 +1717,7 @@ begin
nkTypeSection, nkCommentStmt, nkIteratorDef,
nkIncludeStmt, nkImportStmt,
nkFromStmt, nkTemplateDef, nkMacroDef, nkPragma: begin end;
nkProcDef, nkConverterDef: begin
nkProcDef, nkMethodDef, nkConverterDef: begin
if (n.sons[genericParamsPos] = nil) then begin
prc := n.sons[namePos].sym;
if (n.sons[codePos] <> nil) and not (lfNoDecl in prc.loc.flags) then

View File

@@ -938,23 +938,6 @@ begin
result := emptyNode;
end;
function evalAppendSeqSeq(c: PEvalContext; n: PNode): PNode;
var
a, b: PNode;
i: int;
begin
result := evalAux(c, n.sons[1]);
if result.kind = nkExceptBranch then exit;
a := result;
result := evalAux(c, n.sons[2]);
if result.kind = nkExceptBranch then exit;
b := result;
if a.kind = nkBracket then
for i := 0 to sonsLen(b)-1 do addSon(a, copyTree(b.sons[i]))
else InternalError(n.info, 'evalAppendSeqSeq');
result := emptyNode;
end;
function evalRepr(c: PEvalContext; n: PNode): PNode;
begin
result := evalAux(c, n.sons[1]);
@@ -993,7 +976,6 @@ begin
mAppendStrCh: result := evalAppendStrCh(c, n);
mAppendStrStr: result := evalAppendStrStr(c, n);
mAppendSeqElem: result := evalAppendSeqElem(c, n);
mAppendSeqSeq: result := evalAppendSeqSeq(c, n);
mNLen: begin
result := evalAux(c, n.sons[1]);
@@ -1338,7 +1320,7 @@ begin
end
end
end;
nkProcDef, nkMacroDef, nkCommentStmt, nkPragma, nkTypeSection,
nkProcDef, nkMethodDef, nkMacroDef, nkCommentStmt, nkPragma, nkTypeSection,
nkTemplateDef, nkConstSection, nkIteratorDef, nkConverterDef,
nkIncludeStmt, nkImportStmt, nkFromStmt: begin end;
nkIdentDefs, nkCast, nkYieldStmt, nkAsmStmt, nkForStmt, nkPragmaExpr,

View File

@@ -264,18 +264,37 @@ begin
while not (g.buf[pos] in [#0, #10, #13]) do inc(pos);
end;
'a'..'z', 'A'..'Z', '_', #128..#255: begin
if (g.buf[pos+1] = '"') and (g.buf[pos] in ['r', 'R']) then begin
g.kind := gtRawData;
inc(pos, 2);
while not (g.buf[pos] in [#0, '"', #10, #13]) do inc(pos);
if g.buf[pos] = '"' then inc(pos);
id := '';
while g.buf[pos] in scanner.SymChars+['_'] do begin
addChar(id, g.buf[pos]);
inc(pos)
end;
if (g.buf[pos] = '"') then begin
if (g.buf[pos+1] = '"') and (g.buf[pos+2] = '"') then begin
inc(pos, 3);
g.kind := gtLongStringLit;
while true do begin
case g.buf[pos] of
#0: break;
'"': begin
inc(pos);
if (g.buf[pos] = '"') and (g.buf[pos+1] = '"') then begin
inc(pos, 2);
break
end
end;
else inc(pos);
end
end
end
else begin
g.kind := gtRawData;
inc(pos);
while not (g.buf[pos] in [#0, '"', #10, #13]) do inc(pos);
if g.buf[pos] = '"' then inc(pos);
end
end
else begin
id := '';
while g.buf[pos] in scanner.SymChars+['_'] do begin
addChar(id, g.buf[pos]);
inc(pos)
end;
g.kind := nimGetKeyword(id);
end
end;

View File

@@ -113,7 +113,7 @@ begin
InternalError(ident.info, 'importSymbol: 2');
// for an enumeration we have to add all identifiers
case s.Kind of
skProc, skIterator, skMacro, skTemplate, skConverter: begin
skProc, skMethod, skIterator, skMacro, skTemplate, skConverter: begin
// for a overloadable syms add all overloaded routines
e := InitIdentIter(it, fromMod.tab, s.name);
while e <> nil do begin
@@ -155,6 +155,8 @@ begin
for i := 0 to sonsLen(n)-1 do begin
f := getModuleFile(n.sons[i]);
m := gImportModule(f);
if sfDeprecated in m.flags then
liMessage(n.sons[i].info, warnDeprecated, m.name.s);
// ``addDecl`` needs to be done before ``importAllSymbols``!
addDecl(c, m); // add symbol to symbol table of module
importAllSymbols(c, m);

View File

@@ -54,7 +54,7 @@ implementation
function getSymRepr(s: PSym): string;
begin
case s.kind of
skProc, skConverter, skIterator: result := getProcHeader(s);
skProc, skMethod, skConverter, skIterator: result := getProcHeader(s);
else result := s.name.s
end
end;
@@ -72,7 +72,7 @@ begin
liMessage(s.info, errImplOfXexpected, getSymRepr(s))
else if ([sfUsed, sfInInterface] * s.flags = []) and
(optHints in s.options) then // BUGFIX: check options in s!
if not (s.kind in [skForVar, skParam, skUnknown]) then
if not (s.kind in [skForVar, skParam, skMethod, skUnknown]) then
liMessage(s.info, hintXDeclaredButNotUsed, getSymRepr(s));
s := NextIter(it, tab.stack[tab.tos-1]);
end;

View File

@@ -30,6 +30,8 @@ procedure registerCompilerProc(s: PSym);
procedure InitSystem(var tab: TSymTab);
procedure FinishSystem(const tab: TStrTable);
function getSysSym(const name: string): PSym;
implementation
var
@@ -48,14 +50,16 @@ begin
result.align := size;
end;
function sysTypeFromName(const name: string): PType;
var
s: PSym;
function getSysSym(const name: string): PSym;
begin
s := StrTableGet(systemModule.tab, getIdent(name));
if s = nil then rawMessage(errSystemNeeds, name);
if s.kind = skStub then loadStub(s);
result := s.typ;
result := StrTableGet(systemModule.tab, getIdent(name));
if result = nil then rawMessage(errSystemNeeds, name);
if result.kind = skStub then loadStub(result);
end;
function sysTypeFromName(const name: string): PType;
begin
result := getSysSym(name).typ;
end;
function getSysType(const kind: TTypeKind): PType;

View File

@@ -1,7 +1,7 @@
//
//
// The Nimrod Compiler
// (c) Copyright 2008 Andreas Rumpf
// (c) Copyright 2009 Andreas Rumpf
//
// See the file "copying.txt", included in this
// distribution, for details about the copyright.

View File

@@ -31,10 +31,10 @@ const
//cog.outl('VersionMinor = %s;' % ver[1])
//cog.outl('VersionPatch = %s;' % ver[2])
//]]]
VersionAsString = '0.8.0';
VersionAsString = '0.8.1';
VersionMajor = 0;
VersionMinor = 8;
VersionPatch = 0;
VersionPatch = 1;
//[[[[end]]]]
implementation

View File

@@ -61,7 +61,7 @@ const
('len', 'length'),
('setlength', 'setlen')
);
nimReplacements: array [1..32] of TReplaceTuple = (
nimReplacements: array [1..34] of TReplaceTuple = (
('nimread', 'read'),
('nimwrite', 'write'),
('nimclosefile', 'close'),
@@ -96,7 +96,10 @@ const
('snil', 'nil'),
('tostringf', '$'+''),
('ttextfile', 'tfile'),
('tbinaryfile', 'tfile') {,
('tbinaryfile', 'tfile'),
('strstart', '0'+''),
('nl', '"\n"')
{,
('NL', '"\n"'),
('tabulator', '''\t'''),
('esc', '''\e'''),

View File

@@ -56,7 +56,7 @@ begin
nkStmtList: begin
for i := 0 to sonsLen(n)-1 do {@discard} cleanup(c, n.sons[i]);
end;
nkProcDef: begin
nkProcDef, nkMethodDef: begin
if (n.sons[namePos].kind = nkSym) then begin
s := n.sons[namePos].sym;
if not (sfDeadCodeElim in getModule(s).flags) and

View File

@@ -67,7 +67,7 @@ implementation
function astNeeded(s: PSym): bool;
begin
if (s.kind = skProc)
if (s.kind in [skMethod, skProc])
and ([sfCompilerProc, sfCompileTime] * s.flags = [])
and (s.typ.callConv <> ccInline)
and (s.ast.sons[genericParamsPos] = nil) then

View File

@@ -889,7 +889,7 @@ end;
function parseImportStmt(var p: TParser): PNode;
var
a, b: PNode;
a: PNode;
begin
result := newNodeP(nkImportStmt, p);
getTok(p); // skip `import`
@@ -1535,9 +1535,9 @@ begin
end
end;
function parseRecordPart(var p: TParser): PNode; forward;
function parseObjectPart(var p: TParser): PNode; forward;
function parseRecordWhen(var p: TParser): PNode;
function parseObjectWhen(var p: TParser): PNode;
var
branch: PNode;
begin
@@ -1549,7 +1549,7 @@ begin
addSon(branch, parseExpr(p));
eat(p, tkColon);
skipComment(p, branch);
addSon(branch, parseRecordPart(p));
addSon(branch, parseObjectPart(p));
skipComment(p, branch);
addSon(result, branch);
if p.tok.tokType <> tkElif then break
@@ -1558,12 +1558,12 @@ begin
branch := newNodeP(nkElse, p);
eat(p, tkElse); eat(p, tkColon);
skipComment(p, branch);
addSon(branch, parseRecordPart(p));
addSon(branch, parseObjectPart(p));
addSon(result, branch);
end
end;
function parseRecordCase(var p: TParser): PNode;
function parseObjectCase(var p: TParser): PNode;
var
a, b: PNode;
begin
@@ -1591,13 +1591,13 @@ begin
else break;
end;
skipComment(p, b);
addSon(b, parseRecordPart(p));
addSon(b, parseObjectPart(p));
addSon(result, b);
if b.kind = nkElse then break;
end
end;
function parseRecordPart(var p: TParser): PNode;
function parseObjectPart(var p: TParser): PNode;
begin
case p.tok.tokType of
tkInd: begin
@@ -1608,7 +1608,7 @@ begin
case p.tok.tokType of
tkSad: getTok(p);
tkCase, tkWhen, tkSymbol, tkAccent, tkNil: begin
addSon(result, parseRecordPart(p));
addSon(result, parseObjectPart(p));
end;
tkDed: begin getTok(p); break end;
tkEof: break;
@@ -1620,8 +1620,8 @@ begin
end;
popInd(p.lex^);
end;
tkWhen: result := parseRecordWhen(p);
tkCase: result := parseRecordCase(p);
tkWhen: result := parseObjectWhen(p);
tkCase: result := parseObjectCase(p);
tkSymbol, tkAccent: begin
result := parseIdentColonEquals(p, {@set}[withPragma]);
skipComment(p, result);
@@ -1634,11 +1634,11 @@ begin
end
end;
function parseRecordOrObject(var p: TParser; kind: TNodeKind): PNode;
function parseObject(var p: TParser): PNode;
var
a: PNode;
begin
result := newNodeP(kind, p);
result := newNodeP(nkObjectTy, p);
getTok(p);
if p.tok.tokType = tkCurlyDotLe then addSon(result, parsePragma(p))
else addSon(result, nil);
@@ -1646,14 +1646,11 @@ begin
a := newNodeP(nkOfInherit, p);
getTok(p);
addSon(a, parseTypeDesc(p));
if kind = nkObjectTy then
addSon(result, a)
else
parMessage(p, errInheritanceOnlyWithNonFinalObjects);
addSon(result, a);
end
else addSon(result, nil);
skipComment(p, result);
addSon(result, parseRecordPart(p));
addSon(result, parseObjectPart(p));
end;
function parseDistinct(var p: TParser): PNode;
@@ -1675,7 +1672,7 @@ begin
if p.tok.tokType = tkEquals then begin
getTok(p); optInd(p, result);
case p.tok.tokType of
tkObject: a := parseRecordOrObject(p, nkObjectTy);
tkObject: a := parseObject(p);
tkEnum: a := parseEnum(p);
tkDistinct: a := parseDistinct(p);
else a := parseTypeDesc(p);
@@ -1754,6 +1751,7 @@ begin
tkBlock: result := parseBlock(p);
tkAsm: result := parseAsm(p);
tkProc: result := parseRoutine(p, nkProcDef);
tkMethod: result := parseRoutine(p, nkMethodDef);
tkIterator: result := parseRoutine(p, nkIteratorDef);
tkMacro: result := parseRoutine(p, nkMacroDef);
tkTemplate: result := parseRoutine(p, nkTemplateDef);

View File

@@ -30,6 +30,7 @@ const
wCppMethod, wDeprecated, wVarargs, wCompileTime, wMerge,
wBorrow];
converterPragmas = procPragmas;
methodPragmas = procPragmas;
macroPragmas = {@set}[FirstCallConv..LastCallConv,
wImportc, wExportc, wNodecl, wMagic, wNosideEffect,
wCompilerProc, wDeprecated, wTypeCheck];
@@ -42,7 +43,7 @@ const
wHint, wWarning, wError, wFatal, wDefine, wUndef,
wCompile, wLink, wLinkSys, wPure,
wPush, wPop, wBreakpoint, wCheckpoint,
wPassL, wPassC, wDeadCodeElim];
wPassL, wPassC, wDeadCodeElim, wDeprecated];
lambdaPragmas = {@set}[FirstCallConv..LastCallConv,
wImportc, wExportc, wNodecl, wNosideEffect, wSideEffect,
wNoreturn, wDynLib, wHeader, wPure, wDeprecated];
@@ -545,7 +546,8 @@ begin
end;
wDeprecated: begin
noVal(it);
include(sym.flags, sfDeprecated);
if sym <> nil then include(sym.flags, sfDeprecated)
else include(c.module.flags, sfDeprecated);
end;
wVarargs: begin
noVal(it);

View File

@@ -1235,6 +1235,10 @@ begin
putWithSpace(g, tkProc, 'proc');
gproc(g, n);
end;
nkMethodDef: begin
putWithSpace(g, tkMethod, 'method');
gproc(g, n);
end;
nkIteratorDef: begin
putWithSpace(g, tkIterator, 'iterator');
gproc(g, n);

View File

@@ -519,7 +519,7 @@ begin
s := n.sons[namePos].sym;
addInterfaceSym(w, s);
end;
nkProcDef, nkIteratorDef, nkConverterDef: begin
nkProcDef, nkMethodDef, nkIteratorDef, nkConverterDef: begin
s := n.sons[namePos].sym;
if s = nil then InternalError(n.info, 'rodwrite.process');
if (n.sons[codePos] <> nil) or (s.magic <> mNone)

View File

@@ -56,6 +56,12 @@ begin
result.info := n.info;
end;
procedure markUsed(n: PNode; s: PSym);
begin
include(s.flags, sfUsed);
if sfDeprecated in s.flags then liMessage(n.info, warnDeprecated, s.name.s);
end;
function semIdentVis(c: PContext; kind: TSymKind; n: PNode;
const allowed: TSymFlags): PSym; forward;
// identifier with visability
@@ -130,7 +136,7 @@ var
p: PEvalContext;
s: PStackFrame;
begin
include(sym.flags, sfUsed);
markUsed(n, sym);
p := newEvalContext(c.module, '', false);
s := newStackFrame();
s.call := n;
@@ -179,7 +185,8 @@ begin
it := c.generics.sons[i].sons[1];
if it.kind <> nkSym then InternalError('addCodeForGenerics');
prc := it.sym;
if (prc.kind in [skProc, skConverter]) and (prc.magic = mNone) then begin
if (prc.kind in [skProc, skMethod, skConverter])
and (prc.magic = mNone) then begin
if (prc.ast = nil) or (prc.ast.sons[codePos] = nil) then
InternalError(prc.info, 'no code for ' + prc.name.s);
addSon(n, prc.ast);

View File

@@ -13,7 +13,7 @@
function semTemplateExpr(c: PContext; n: PNode; s: PSym;
semCheck: bool = true): PNode;
begin
include(s.flags, sfUsed);
markUsed(n, s);
pushInfoContext(n.info);
result := evalTemplate(c, n, s);
if semCheck then
@@ -47,8 +47,6 @@ var
diff: int;
begin
diff := inheritanceDiff(castDest, src);
//if diff = 0 then
// liMessage(info, hintConvToBaseNotNeeded)
if diff = high(int) then
liMessage(info, errGenerated,
format(MsgKindToString(errIllegalConvFromXtoY),
@@ -136,7 +134,7 @@ begin
else begin
for i := 0 to sonsLen(op)-1 do begin
if sameType(result.typ, op.sons[i].typ) then begin
include(op.sons[i].sym.flags, sfUsed);
markUsed(n, op.sons[i].sym);
result := op.sons[i]; exit
end
end;
@@ -453,8 +451,7 @@ const
FakeVarParams = {@set}[mNew, mNewFinalize, mInc, ast.mDec, mIncl,
mExcl, mSetLengthStr, mSetLengthSeq,
mAppendStrCh, mAppendStrStr, mSwap,
mAppendSeqElem, mAppendSeqSeq,
mNewSeq];
mAppendSeqElem, mNewSeq];
var
i: int;
t: PType;
@@ -474,7 +471,7 @@ var
callee: PSym;
begin
if not (efWantIterator in flags) then
result := semDirectCall(c, n, {@set}[skProc, skConverter])
result := semDirectCall(c, n, {@set}[skProc, skMethod, skConverter])
else
result := semDirectCall(c, n, {@set}[skIterator]);
if result <> nil then begin
@@ -586,17 +583,23 @@ begin
result := n;
end;
function LookUpForDefined(c: PContext; n: PNode): PSym;
function LookUpForDefined(c: PContext; n: PNode; onlyCurrentScope: bool): PSym;
var
m: PSym;
ident: PIdent;
begin
case n.kind of
nkIdent: result := SymtabGet(c.Tab, n.ident); // no need for stub loading
nkIdent: begin
if onlyCurrentScope then
result := SymtabLocalGet(c.tab, n.ident)
else
result := SymtabGet(c.Tab, n.ident); // no need for stub loading
end;
nkDotExpr, nkQualified: begin
checkSonsLen(n, 2);
result := nil;
m := LookupForDefined(c, n.sons[0]);
if onlyCurrentScope then exit;
checkSonsLen(n, 2);
m := LookupForDefined(c, n.sons[0], onlyCurrentScope);
if (m <> nil) and (m.kind = skModule) then begin
if (n.sons[1].kind = nkIdent) then begin
ident := n.sons[1].ident;
@@ -612,7 +615,7 @@ begin
end;
nkAccQuoted: begin
checkSonsLen(n, 1);
result := lookupForDefined(c, n.sons[0]);
result := lookupForDefined(c, n.sons[0], onlyCurrentScope);
end
else begin
liMessage(n.info, errIdentifierExpected, renderTree(n));
@@ -621,14 +624,14 @@ begin
end
end;
function semDefined(c: PContext; n: PNode): PNode;
function semDefined(c: PContext; n: PNode; onlyCurrentScope: bool): PNode;
begin
checkSonsLen(n, 2);
result := newIntNode(nkIntLit, 0);
// we replace this node by a 'true' or 'false' node
if LookUpForDefined(c, n.sons[1]) <> nil then
if LookUpForDefined(c, n.sons[1], onlyCurrentScope) <> nil then
result.intVal := 1
else if (n.sons[1].kind = nkIdent)
else if not onlyCurrentScope and (n.sons[1].kind = nkIdent)
and condsyms.isDefined(n.sons[1].ident) then
result.intVal := 1;
result.info := n.info;
@@ -647,8 +650,8 @@ function semMagic(c: PContext; n: PNode; s: PSym; flags: TExprFlags): PNode;
begin
result := n;
case s.magic of // magics that need special treatment
mDefined: result := semDefined(c, setMs(n, s));
mDefinedInScope: result := semDefinedInScope(c, setMs(n, s));
mDefined: result := semDefined(c, setMs(n, s), false);
mDefinedInScope: result := semDefined(c, setMs(n, s), true);
mLow: result := semLowHigh(c, setMs(n, s), mLow);
mHigh: result := semLowHigh(c, setMs(n, s), mHigh);
mSizeOf: result := semSizeof(c, setMs(n, s));
@@ -658,11 +661,6 @@ begin
end;
end;
procedure checkDeprecated(n: PNode; s: PSym);
begin
if sfDeprecated in s.flags then liMessage(n.info, warnDeprecated, s.name.s);
end;
function isTypeExpr(n: PNode): bool;
begin
case n.kind of
@@ -795,7 +793,7 @@ begin
result := newSymNode(f);
result.info := n.info;
result.typ := ty;
checkDeprecated(n, f);
markUsed(n, f);
end
else
liMessage(n.sons[1].info, errEnumHasNoValueX, i.s);
@@ -823,7 +821,7 @@ begin
n.sons[0] := makeDeref(n.sons[0]);
n.sons[1] := newSymNode(f); // we now have the correct field
n.typ := f.typ;
checkDeprecated(n, f);
markUsed(n, f);
if check = nil then result := n
else begin
check.sons[0] := n;
@@ -841,7 +839,7 @@ begin
n.sons[1] := newSymNode(f);
n.typ := f.typ;
result := n;
checkDeprecated(n, f);
markUsed(n, f);
exit
end
end;
@@ -851,7 +849,7 @@ begin
//if (f <> nil) and (f.kind = skStub) then loadStub(f);
// ``loadStub`` is not correct here as we don't care for ``f`` really
if (f <> nil) then begin
// BUGFIX: do not check for (f.kind in [skProc, skIterator]) here
// BUGFIX: do not check for (f.kind in [skProc, skMethod, skIterator]) here
result := newNodeI(nkDotCall, n.info);
// This special node kind is to merge with the call handler in `semExpr`.
addSon(result, newIdentNode(i, n.info));
@@ -1145,7 +1143,6 @@ begin
a := n.sons[0];
s := qualifiedLookup(c, a, false);
if (s <> nil) then begin
checkDeprecated(n, s);
case s.kind of
skMacro: result := semMacroExpr(c, n, s, semCheck);
skTemplate: begin
@@ -1176,7 +1173,7 @@ begin
if (s.kind = skType) and not (efAllowType in flags) then
liMessage(n.info, errATypeHasNoValue);
case s.kind of
skProc, skIterator, skConverter: begin
skProc, skMethod, skIterator, skConverter: begin
if (s.magic <> mNone) then
liMessage(n.info, errInvalidContextForBuiltinX, s.name.s);
result := symChoice(c, n, s);
@@ -1194,7 +1191,7 @@ begin
copy `x`'s AST into each context, so that the type fixup phase can
deal with two different ``[]``.
*)
include(s.flags, sfUsed);
markUsed(n, s);
if s.typ.kind in ConstAbstractTypes then begin
result := copyTree(s.ast);
result.info := n.info;
@@ -1208,7 +1205,7 @@ begin
skMacro: result := semMacroExpr(c, n, s);
skTemplate: result := semTemplateExpr(c, n, s);
skVar: begin
include(s.flags, sfUsed);
markUsed(n, s);
// if a proc accesses a global variable, it is not side effect free
if sfGlobal in s.flags then include(c.p.owner.flags, sfSideEffect);
result := newSymNode(s);
@@ -1219,12 +1216,11 @@ begin
result := semExpr(c, s.ast);
end
else begin
include(s.flags, sfUsed);
markUsed(n, s);
result := newSymNode(s);
result.info := n.info;
end
end;
checkDeprecated(n, s);
end;
function semDotExpr(c: PContext; n: PNode; flags: TExprFlags): PNode;
@@ -1259,7 +1255,7 @@ begin
if (s.kind = skType) and not (efAllowType in flags) then
liMessage(n.info, errATypeHasNoValue);
if (s.magic <> mNone) and
(s.kind in [skProc, skIterator, skConverter]) then
(s.kind in [skProc, skMethod, skIterator, skConverter]) then
liMessage(n.info, errInvalidContextForBuiltinX, s.name.s); *)
// because of the changed symbol binding, this does not mean that we
// don't have to check the symbol for semantics here again!
@@ -1296,18 +1292,16 @@ begin
checkMinSonsLen(n, 1);
s := qualifiedLookup(c, n.sons[0], false);
if (s <> nil) then begin
checkDeprecated(n, s);
case s.kind of
skMacro: result := semMacroExpr(c, n, s);
skTemplate: result := semTemplateExpr(c, n, s);
skType: begin
include(s.flags, sfUsed);
if n.kind <> nkCall then
liMessage(n.info, errXisNotCallable, s.name.s);
// XXX does this check make any sense?
result := semConv(c, n, s);
end;
skProc, skConverter, skIterator: begin
skProc, skMethod, skConverter, skIterator: begin
if s.magic = mNone then result := semDirectOp(c, n, flags)
else result := semMagic(c, n, s, flags);
end;
@@ -1328,7 +1322,8 @@ begin
nkBracketExpr: begin
checkMinSonsLen(n, 1);
s := qualifiedLookup(c, n.sons[0], false);
if (s <> nil) and (s.kind in [skProc, skConverter, skIterator]) then begin
if (s <> nil)
and (s.kind in [skProc, skMethod, skConverter, skIterator]) then begin
// type parameters: partial generic specialization
// XXX: too implement!
internalError(n.info, 'explicit generic instantation not implemented');

View File

@@ -288,7 +288,7 @@ begin
result.typ := n.typ;
end;
mNewString, mExit, mInc, ast.mDec, mEcho, mAssert, mSwap,
mAppendStrCh, mAppendStrStr, mAppendSeqElem, mAppendSeqSeq,
mAppendStrCh, mAppendStrStr, mAppendSeqElem,
mSetLengthStr, mSetLengthSeq, mNLen..mNError: begin end;
else InternalError(a.info, 'evalOp(' +{&} magicToStr[m] +{&} ')');
end
@@ -412,7 +412,7 @@ begin
else result := copyTree(s.ast); // BUGFIX
end
end
else if s.kind = skProc then // BUGFIX
else if s.kind in [skProc, skMethod] then // BUGFIX
result := n
end;
nkCharLit..nkNilLit: result := copyNode(n);

View File

@@ -182,7 +182,7 @@ begin
addDecl(c, result);
if n.sons[codePos] <> nil then begin
c.p := newProcCon(result);
if result.kind in [skProc, skConverter] then begin
if result.kind in [skProc, skMethod, skConverter] then begin
addResult(c, result.typ.sons[0], n.info);
addResultNode(c, n);
end;

View File

@@ -316,7 +316,7 @@ var
begin
result := n;
checkSonsLen(n, 1);
if not (c.p.owner.kind in [skConverter, skProc, skMacro]) then
if not (c.p.owner.kind in [skConverter, skMethod, skProc, skMacro]) then
liMessage(n.info, errXNotAllowedHere, '''return''');
if (n.sons[0] <> nil) then begin
n.sons[0] := SemExprWithType(c, n.sons[0]);
@@ -970,11 +970,20 @@ begin
result := semProcAux(c, n, skProc, procPragmas);
end;
function semMethod(c: PContext; n: PNode): PNode;
begin
if not isTopLevel(c) then
liMessage(n.info, errXOnlyAtModuleScope, 'method');
result := semProcAux(c, n, skMethod, methodPragmas);
end;
function semConverterDef(c: PContext; n: PNode): PNode;
var
t: PType;
s: PSym;
begin
if not isTopLevel(c) then
liMessage(n.info, errXOnlyAtModuleScope, 'converter');
checkSonsLen(n, codePos+1);
if n.sons[genericParamsPos] <> nil then
liMessage(n.info, errNoGenericParamsAllowedForX, 'converter');
@@ -1080,6 +1089,7 @@ begin
nkPragma: pragma(c, c.p.owner, n, stmtPragmas);
nkIteratorDef: result := semIterator(c, n);
nkProcDef: result := semProc(c, n);
nkMethodDef: result := semMethod(c, n);
nkConverterDef: result := semConverterDef(c, n);
nkMacroDef: result := semMacroDef(c, n);
nkTemplateDef: result := semTemplateDef(c, n);

View File

@@ -94,7 +94,7 @@ begin
if i < a then
arg := n.sons[i]
else
arg := copyTree(s.ast.sons[paramsPos].sons[i-1].sym.ast);
arg := copyTree(s.typ.n.sons[i].sym.ast);
if arg = nil then liMessage(n.info, errWrongNumberOfArguments);
if not (s.typ.sons[i].kind in [tyTypeDesc, tyStmt, tyExpr]) then begin
// concrete type means semantic checking for argument:
@@ -132,7 +132,7 @@ begin
if i <= 1 then begin
result := newSymNode(s);
result.info := n.info;
include(s.flags, sfUsed);
markUsed(n, s);
end
else begin
// semantic checking requires a type; ``fitNode`` deals with it

View File

@@ -232,7 +232,7 @@ function semTypeIdent(c: PContext; n: PNode): PSym;
begin
result := qualifiedLookup(c, n, true);
if (result <> nil) then begin
include(result.flags, sfUsed);
markUsed(n, result);
if result.kind <> skType then liMessage(n.info, errTypeExpected);
end
else
@@ -792,7 +792,7 @@ begin
assignType(prev, t);
result := prev;
end;
include(n.sym.flags, sfUsed); // BUGFIX
markUsed(n, n.sym);
end
else
liMessage(n.info, errTypeExpected);

View File

@@ -103,7 +103,7 @@ begin
candidates := '';
sym := initOverloadIter(o, c, n.sons[0]);
while sym <> nil do begin
if sym.kind in [skProc, skIterator, skConverter] then begin
if sym.kind in [skProc, skMethod, skIterator, skConverter] then begin
add(candidates, getProcHeader(sym));
add(candidates, nl)
end;
@@ -709,7 +709,7 @@ begin
best := -1;
for i := 0 to sonsLen(arg)-1 do begin
// iterators are not first class yet, so ignore them
if arg.sons[i].sym.kind in {@set}[skProc, skConverter] then begin
if arg.sons[i].sym.kind in {@set}[skProc, skMethod, skConverter] then begin
copyCandidate(z, m);
r := typeRel(z.bindings, f, arg.sons[i].typ);
if r <> isNone then begin
@@ -734,7 +734,7 @@ begin
end
else begin
// only one valid interpretation found:
include(arg.sons[best].sym.flags, sfUsed);
markUsed(arg, arg.sons[best].sym);
result := ParamTypesMatchAux(c, m, f, arg.sons[best].typ, arg.sons[best]);
end
end
@@ -884,6 +884,19 @@ begin
end
end;
function sameMethodDispatcher(a, b: PSym): bool;
var
aa, bb: PNode;
begin
result := false;
if (a.kind = skMethod) and (b.kind = skMethod) then begin
aa := lastSon(a.ast);
bb := lastSon(b.ast);
if (aa.kind = nkSym) and (bb.kind = nkSym) and
(aa.sym = bb.sym) then result := true
end
end;
function semDirectCall(c: PContext; n: PNode; filter: TSymKinds): PNode;
var
sym: PSym;
@@ -923,7 +936,8 @@ begin
// do not generate an error yet; the semantic checking will check for
// an overloaded () operator
end
else if (y.state = csMatch) and (cmpCandidates(x, y) = 0) then begin
else if (y.state = csMatch) and (cmpCandidates(x, y) = 0)
and not sameMethodDispatcher(x.calleeSym, y.calleeSym) then begin
if x.state <> csMatch then
InternalError(n.info, 'x.state is not csMatch');
//writeMatches(x);
@@ -935,7 +949,7 @@ begin
end
else begin
// only one valid interpretation found:
include(x.calleeSym.flags, sfUsed);
markUsed(n, x.calleeSym);
if x.calleeSym.ast = nil then
internalError(n.info, 'calleeSym.ast is nil'); // XXX: remove this check!
if x.calleeSym.ast.sons[genericParamsPos] <> nil then begin

View File

@@ -15,7 +15,7 @@ unit transf;
// * inlines constants
// * performes contant folding
// * introduces nkHiddenDeref, nkHiddenSubConv, etc.
// * aggressive compile-time evaluation based on the side-effect analysis
// * introduces method dispatchers
interface
@@ -24,7 +24,7 @@ interface
uses
sysutils, nsystem, charsets, strutils,
lists, options, ast, astalgo, trees, treetab, evals,
msgs, nos, idents, rnimsyn, types, passes, semfold, magicsys;
msgs, nos, idents, rnimsyn, types, passes, semfold, magicsys, cgmeth;
const
genPrefix = ':tmp'; // prefix for generated names
@@ -574,7 +574,7 @@ end;
function getMagicOp(call: PNode): TMagic;
begin
if (call.sons[0].kind = nkSym)
and (call.sons[0].sym.kind in [skProc, skConverter]) then
and (call.sons[0].sym.kind in [skProc, skMethod, skConverter]) then
result := call.sons[0].sym.magic
else
result := mNone
@@ -842,6 +842,11 @@ begin
if sonsLen(result) = 2 then
result := result.sons[1];
end
else if (result.sons[0].kind = nkSym)
and (result.sons[0].sym.kind = skMethod) then begin
// use the dispatcher for the call:
result := methodCall(result);
end
(*
else if result.sons[0].kind = nkSym then begin
// optimization still too aggressive
@@ -882,9 +887,12 @@ begin
nkLambda: result := transformLambda(c, n);
nkForStmt: result := transformFor(c, n);
nkCaseStmt: result := transformCase(c, n);
nkProcDef, nkIteratorDef, nkMacroDef: begin
if n.sons[genericParamsPos] = nil then
nkProcDef, nkMethodDef, nkIteratorDef, nkMacroDef: begin
if n.sons[genericParamsPos] = nil then begin
n.sons[codePos] := transform(c, n.sons[codePos]);
if n.kind = nkMethodDef then
methodDef(n.sons[namePos].sym);
end
end;
nkWhileStmt: begin
if (sonsLen(n) <> 2) then InternalError(n.info, 'transform');

View File

@@ -23,7 +23,7 @@
## Nimrod shall produce.
import
strutils, regexprs, os, osproc, streams
strutils, pegs, os, osproc, streams
const
cmdTemplate = r"nimrod cc --hints:on $options $filename"
@@ -38,7 +38,7 @@ type
proc myExec(cmd: string): string =
#echo("Executing: " & cmd)
result = osproc.executeProcess(cmd)
result = osproc.execProcess(cmd)
#echo("Received: " & result)
proc parseTest(filename: string): TSpec =
@@ -49,24 +49,30 @@ proc parseTest(filename: string): TSpec =
result.file = filename
for s in lines(filename):
inc(i)
if find(s, r"\#OUT\s*(.*)", matches):
result.outp = matches[1]
if contains(s, peg"'#OUT' \s+ {.*}", matches):
result.outp = matches[0]
break
if find(s, r"\#ERROR_IN\s*(\S*)\s*(\d+)", matches):
result.file = matches[1]
result.line = parseInt(matches[2])
if contains(s, peg"'#ERROR_IN' \s* {\S*} \s* {\d+}", matches):
result.file = matches[0]
result.line = parseInt(matches[1])
result.err = true
break
if find(s, r"\#ERROR_MSG\s*(.*)", matches):
if contains(s, peg"'#ERROR_MSG' \s* {.*}", matches):
result.line = i
result.outp = matches[1]
result.outp = matches[0]
result.err = True
break
if find(s, r"\#ERROR$", matches):
if contains(s, peg"'#ERROR' \s* !.", matches):
result.line = i
result.err = true
break
var
pegLineError = peg"{[^(]*} '(' {\d+} ', ' \d+ ') Error:' \s* {.*}"
pegOtherError = peg"'Error:' \s* {.*}"
pegSuccess = peg"'Hint: operation successful'.*"
pegOfInterest = pegLineError / pegOtherError / pegSuccess
proc callCompiler(filename, options: string): TSpec =
var c = parseCmdLine(cmdTemplate % ["filename", filename, "options", options])
var a: seq[string] = @[] # slicing is not yet implemented :-(
@@ -77,52 +83,50 @@ proc callCompiler(filename, options: string): TSpec =
var s = ""
while running(p) or not outp.atEnd(outp):
var x = outp.readLine()
if match(x, r"(.*)\((\d+), \d+\) Error\: (.*)") or
match(x, r"Error\: (.*)") or
match(x, r"Hint\: operation successful"):
if x =~ pegOfInterest:
# `s` should contain the last error message
s = x
result.outp = ""
result.puremsg = ""
result.file = ""
result.err = true
if s =~ r"(.*)\((\d+), \d+\) Error\: (.*)":
result.file = matches[1]
result.line = parseInt(matches[2])
result.outp = matches[0]
result.puremsg = matches[3]
elif s =~ r"Error\: (.*)":
result.puremsg = matches[1]
result.outp = matches[0]
if s =~ pegLineError:
result.file = matches[0]
result.line = parseInt(matches[1])
result.outp = s
result.puremsg = matches[2]
elif s =~ pegOtherError:
result.puremsg = matches[0]
result.outp = s
result.line = 1
elif s =~ r"Hint\: operation successful":
result.outp = matches[0]
elif s =~ pegSuccess:
result.outp = s
result.err = false
proc cmpResults(filename: string, spec, comp: TSpec): bool =
proc sameResults(filename: string, spec, comp: TSpec): bool =
# short filename for messages (better readability):
var shortfile = os.extractFilename(filename)
if comp.err and comp.outp == "":
# the compiler did not say "[Error]" nor "operation sucessful"
Echo("[Tester] $1 -- FAILED; COMPILER BROKEN" % shortfile)
Echo("[Tester] $# -- FAILED; COMPILER BROKEN" % shortfile)
elif spec.err != comp.err:
Echo(("[Tester] $1 -- FAILED\n" &
"Compiler says: $2\n" &
"But specification says: $3") %
Echo(("[Tester] $# -- FAILED\n" &
"Compiler says: $#\n" &
"But specification says: $#") %
[shortfile, comp.outp, spec.outp])
elif spec.err:
if extractFilename(comp.file) != extractFilename(spec.file):
Echo(("[Tester] $1 -- FAILED: file names do not match:\n" &
"Compiler: $2\nSpec: $3") % [shortfile, comp.file, spec.file])
Echo(("[Tester] $# -- FAILED: file names do not match:\n" &
"Compiler: $#\nSpec: $#") % [shortfile, comp.file, spec.file])
elif strip(spec.outp) notin strip(comp.puremsg):
Echo(("[Tester] $1 -- FAILED: error messages do not match:\n" &
"Compiler: $2\nSpec: $3") % [shortfile, comp.pureMsg, spec.outp])
Echo(("[Tester] $# -- FAILED: error messages do not match:\n" &
"Compiler: $#\nSpec: $#") % [shortfile, comp.pureMsg, spec.outp])
elif comp.line != spec.line:
Echo(("[Tester] $1 -- FAILED: line numbers do not match:\n" &
"Compiler: $2\nSpec: $3") % [shortfile, $comp.line, $spec.line])
Echo(("[Tester] $# -- FAILED: line numbers do not match:\n" &
"Compiler: $#\nSpec: $#") % [shortfile, $comp.line, $spec.line])
else:
Echo("[Tester] $1 -- OK" % shortfile)
Echo("[Tester] $# -- OK" % shortfile)
result = true
else:
# we have to run the executable and check its output:
@@ -131,17 +135,17 @@ proc cmpResults(filename: string, spec, comp: TSpec): bool =
if len(spec.outp) == 0:
# we have no output to validate against, but compilation succeeded,
# so it's okay:
Echo("[Tester] $1 -- OK" % shortfile)
Echo("[Tester] $# -- OK" % shortfile)
result = true
else:
var buf = myExec(exeFile)
result = strip(buf) == strip(spec.outp)
if result:
Echo("[Tester] $1 -- compiled program OK" % shortfile)
Echo("[Tester] $# -- compiled program OK" % shortfile)
else:
Echo("[Tester] $1 -- compiled program FAILED" % shortfile)
Echo("[Tester] $# -- compiled program FAILED" % shortfile)
else:
Echo("[Tester] $1 -- FAILED; executable not found" % shortfile)
Echo("[Tester] $# -- FAILED; executable not found" % shortfile)
proc main(options: string) =
# runs the complete testsuite
@@ -151,16 +155,17 @@ proc main(options: string) =
if extractFilename(filename) == "tester.nim": continue
var spec = parseTest(filename)
var comp = callCompiler(filename, options)
if cmpResults(filename, spec, comp): inc(passed)
if sameResults(filename, spec, comp): inc(passed)
inc(total)
# ensure that the examples at least compile
# ensure that the examples at least compiles
for filename in os.walkFiles("examples/*.nim"):
if executeShellCommand(cmdTemplate %
["filename", filename, "options", options]) == 0:
inc(passed)
else:
var shortfile = os.extractFilename(filename)
var comp = callCompiler(filename, options)
var shortfile = os.extractFilename(filename)
if comp.err:
Echo("[Tester] Example '$#' -- FAILED" % shortfile)
else:
Echo("[Tester] Example $# -- OK" % shortfile)
inc(passed)
inc(total)
Echo("[Tester] $#/$# tests passed\n" % [$passed, $total])

View File

@@ -20,7 +20,7 @@ Name: english; MessagesFile: compiler:Default.isl
[Files]
#for i in low(TFileCategory)..fcWindows:
# for f in items(c.cat[i]):
Source: ${expandFilename(f)}; DestDir: {app}\${extractDir(f)}; Flags: ignoreversion
Source: ${expandFilename(f)}; DestDir: {app}\${splitFile(f).dir}; Flags: ignoreversion
# end for
#end for

View File

@@ -58,7 +58,7 @@ if [ $# -eq 1 ] ; then
#var createdDirs = newStringTable()
#for cat in fcConfig..fcLib:
# for f in items(c.cat[cat]):
# var mk = extractDir(f.skipRoot)
# var mk = splitFile(f.skipRoot).dir
# if mk.len > 0:
# mk = unixDirVars[cat] & "/" & mk
# if not createdDirs.hasKey(mk):

View File

@@ -116,7 +116,7 @@ Compile_options:
"""
proc parseCmdLine(c: var TConfigData) =
var p = init()
var p = initOptParser()
while true:
next(p)
var kind = p.kind
@@ -132,8 +132,8 @@ proc parseCmdLine(c: var TConfigData) =
of "inno": incl(c.actions, actionInno)
else: quit(Usage)
else:
c.infile = appendFileExt(key, "ini")
c.nimrodArgs = getRestOfCommandLine(p)
c.infile = addFileExt(key, "ini")
c.nimrodArgs = cmdLineRest(p)
break
of cmdLongOption, cmdShortOption:
case normalize(key)
@@ -255,7 +255,7 @@ proc parseIniFile(c: var TConfigData) =
proc readCFiles(c: var TConfigData, osA, cpuA: int) =
var cfg: TCfgParser
var cfilesSection = false
var f = extractDir(c.infile) / "mapping.txt"
var f = splitFile(c.infile).dir / "mapping.txt"
c.cfiles[osA][cpuA] = @[]
var input = newFileStream(f, fmRead)
if input != nil:
@@ -302,7 +302,7 @@ proc srcdist(c: var TConfigData) =
[c.oses[osA-1], c.cpus[cpuA-1], c.nimrodArgs,
changeFileExt(c.infile, "nim")]
echo(cmd)
if executeShellCommand(cmd) != 0:
if execShellCmd(cmd) != 0:
quit("Error: call to nimrod compiler failed")
readCFiles(c, osA, cpuA)
for i in 0 .. c.cfiles[osA][cpuA].len-1:

View File

@@ -56,7 +56,7 @@ Compile_options:
"""
proc parseCmdLine(c: var TConfigData) =
var p = init()
var p = initOptParser()
while true:
next(p)
var kind = p.kind
@@ -64,8 +64,8 @@ proc parseCmdLine(c: var TConfigData) =
var val = p.val
case kind
of cmdArgument:
c.infile = appendFileExt(key, "ini")
c.nimrodArgs = getRestOfCommandLine(p)
c.infile = addFileExt(key, "ini")
c.nimrodArgs = cmdLineRest(p)
break
of cmdLongOption, cmdShortOption:
case normalize(key)
@@ -84,7 +84,7 @@ proc walkDirRecursively(s: var seq[string], root, ext: string) =
for k, f in walkDir(root):
case k
of pcFile, pcLinkToFile:
if cmpIgnoreCase(ext, extractFileExt(f)) == 0:
if cmpIgnoreCase(ext, splitFile(f).ext) == 0:
add(s, f)
of pcDirectory: walkDirRecursively(s, f, ext)
of pcLinkToDirectory: nil
@@ -94,7 +94,7 @@ proc addFiles(s: var seq[string], dir, ext: string, patterns: seq[string]) =
if existsDir(dir / p):
walkDirRecursively(s, dir / p, ext)
else:
add(s, dir / appendFileExt(p, ext))
add(s, dir / addFileExt(p, ext))
proc parseIniFile(c: var TConfigData) =
var
@@ -143,7 +143,7 @@ proc parseIniFile(c: var TConfigData) =
if c.projectName.len == 0:
c.projectName = changeFileExt(extractFilename(c.infile), "")
if c.outdir.len == 0:
c.outdir = extractDir(c.infile)
c.outdir = splitFile(c.infile).dir
else:
quit("cannot open: " & c.infile)
@@ -151,18 +151,18 @@ proc parseIniFile(c: var TConfigData) =
proc Exec(cmd: string) =
echo(cmd)
if os.executeShellCommand(cmd) != 0: quit("external program failed")
if os.execShellCmd(cmd) != 0: quit("external program failed")
proc buildDoc(c: var TConfigData, destPath: string) =
# call nim for the documentation:
for d in items(c.doc):
Exec("nimrod rst2html $# -o:$# --index=$#/theindex $#" %
[c.nimrodArgs, destPath / changeFileExt(extractFileTrunk(d), "html"),
[c.nimrodArgs, destPath / changeFileExt(splitFile(d).name, "html"),
destpath, d])
Exec("nimrod rst2tex $# $#" % [c.nimrodArgs, d])
for d in items(c.srcdoc):
Exec("nimrod doc $# -o:$# --index=$#/theindex $#" %
[c.nimrodArgs, destPath / changeFileExt(extractFileTrunk(d), "html"),
[c.nimrodArgs, destPath / changeFileExt(splitFile(d).name, "html"),
destpath, d])
Exec("nimrod rst2html $1 -o:$2/theindex.html $2/theindex" %
[c.nimrodArgs, destPath])
@@ -171,7 +171,7 @@ proc buildAddDoc(c: var TConfigData, destPath: string) =
# build additional documentation (without the index):
for d in items(c.webdoc):
Exec("nimrod doc $# -o:$# $#" %
[c.nimrodArgs, destPath / changeFileExt(extractFileTrunk(d), "html"), d])
[c.nimrodArgs, destPath / changeFileExt(splitFile(d).name, "html"), d])
proc main(c: var TConfigData) =
const

View File

@@ -2,8 +2,9 @@
import strutils, os
proc newName(f: string): string =
return extractDir(f) / "trim_" & extractFilename(f)
proc newName(f: string): string =
var (dir, name, ext) = splitFile(f)
return dir / "trim_" & name & ext
proc walker(dir: string) =
for kind, path in walkDir(dir):
@@ -11,7 +12,7 @@ proc walker(dir: string) =
of pcFile:
moveFile(newName(path), path)
# test if installation still works:
if executeShellCommand(r"nimrod c --force_build tests\tlastmod") == 0:
if execShellCmd(r"nimrod c --force_build tests\tlastmod") == 0:
echo "Optional: ", path
removeFile(newName(path))
else:

View File

@@ -52,6 +52,7 @@ Nimrod is efficient
from pointers to manually managed memory.
* Zero-overhead iterators.
* Cross-module inlining.
* Dynamic method binding with inlining and without virtual method table.
* Compile time evaluation of user-defined functions.
* Whole program dead code elimination: Only *used functions* are included in
the executable.
@@ -78,10 +79,8 @@ Nimrod is elegant
Nimrod's syntax is flexible enough.
* Yet Nimrod can be parsed with an LL(1) parser.
* Statements are grouped by indentation but can span multiple lines.
Indentation must not contain tabulators so **the compiler always sees
the code the same way as you do**.
* Nimrod is a simple language that leads to simple programs. However,
the language is not crippled in the name of simplicity.
Indentation must not contain tabulators so the compiler always sees
the code the same way as you do.
Nimrod plays nice with others
@@ -97,11 +96,10 @@ Nimrod plays nice with others
* Nimrod's documentation syntax is a subset of the wonderfully readable plaintext
markup syntax
`reStructuredText <http://docutils.sourceforge.net/docs/user/rst/quickref.html>`_.
**The documentation generator is very flexible; this website has been generated
with it!**
The documentation generator is very flexible; this website has been generated
with it!
Roadmap to 1.0
==============

View File

@@ -21,7 +21,7 @@ Additions
---------
- implemented generic types and two phase symbol lookup in generic routines
- template parameters can now be real types
- template parameters can now have real types
- implemented generalized raw string literals: ``ident"abc"`` is a shortcut for
``ident(r"abc")``
- in overloading resolution iterators are separated from procs; iterators now

View File

@@ -21,11 +21,11 @@ FAQ: question
file: ticker
[Documentation]
doc: "endb;intern;lib;manual;tut1;tut2;nimrodc;overview"
doc: "endb;intern;apis;lib;manual;tut1;tut2;nimrodc;overview"
srcdoc: "system.nim;pure/os;pure/strutils;pure/regexprs;pure/math"
srcdoc: "pure/complex;pure/times;pure/osproc"
srcdoc: "pure/complex;pure/times;pure/osproc;pure/pegs;pure/dynlib"
srcdoc: "pure/parseopt;pure/hashes;pure/strtabs;pure/lexbase"
srcdoc: "pure/parsecfg;pure/parsexml;pure/parsecsv"
srcdoc: "pure/parsecfg;pure/parsexml;pure/parsecsv;pure/parsesql"
srcdoc: "pure/streams;pure/terminal;pure/cgi;impure/web;pure/unicode"
srcdoc: "impure/zipfiles;pure/xmlgen;pure/macros"