documented 'immediate' templates
This commit is contained in:
parent
a6e0679aeb
commit
09499b3822
2 changed files with 56 additions and 16 deletions
|
|
@ -2688,18 +2688,46 @@ The "types" of templates can be the symbols ``expr`` (stands for *expression*),
|
||||||
``stmt`` (stands for *statement*) or ``typedesc`` (stands for *type
|
``stmt`` (stands for *statement*) or ``typedesc`` (stands for *type
|
||||||
description*). These are no real types, they just help the compiler parsing.
|
description*). These are no real types, they just help the compiler parsing.
|
||||||
Real types can be used too; this implies that expressions are expected.
|
Real types can be used too; this implies that expressions are expected.
|
||||||
However, for parameter type checking the arguments are semantically checked
|
|
||||||
before being passed to the template. Other arguments are not semantically
|
|
||||||
checked before being passed to the template.
|
Ordinary vs immediate templates
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
There are two different kinds of templates: `immediate`:idx: templates and
|
||||||
|
ordinary templates. Ordinary templates take part in overloading resolution. As
|
||||||
|
such their arguments needs to be type checked before the template is invoked.
|
||||||
|
So ordinary templates cannot receive undeclared identifiers:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
|
||||||
|
template declareInt(x: expr) =
|
||||||
|
var x: int
|
||||||
|
|
||||||
|
declareInt(x) # error: unknown identifier: 'x'
|
||||||
|
|
||||||
|
An ``immediate`` template does not participate in overload resolution and so
|
||||||
|
its arguments are not checked for semantics before invokation. So they can
|
||||||
|
receive undeclared identifiers:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
|
||||||
|
template declareInt(x: expr) {.immediate.} =
|
||||||
|
var x: int
|
||||||
|
|
||||||
|
declareInt(x) # valid
|
||||||
|
|
||||||
|
|
||||||
|
Scoping in templates
|
||||||
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
The template body does not open a new scope. To open a new scope a ``block``
|
The template body does not open a new scope. To open a new scope a ``block``
|
||||||
statement can be used:
|
statement can be used:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
template declareInScope(x: expr, t: typeDesc): stmt =
|
template declareInScope(x: expr, t: typeDesc): stmt {.immediate.} =
|
||||||
var x: t
|
var x: t
|
||||||
|
|
||||||
template declareInNewScope(x: expr, t: typeDesc): stmt =
|
template declareInNewScope(x: expr, t: typeDesc): stmt {.immediate.} =
|
||||||
# open a new scope:
|
# open a new scope:
|
||||||
block:
|
block:
|
||||||
var x: t
|
var x: t
|
||||||
|
|
@ -2711,13 +2739,16 @@ statement can be used:
|
||||||
b = 42 # does not work, `b` is unknown
|
b = 42 # does not work, `b` is unknown
|
||||||
|
|
||||||
|
|
||||||
|
Passing a code block to a template
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
If there is a ``stmt`` parameter it should be the last in the template
|
If there is a ``stmt`` parameter it should be the last in the template
|
||||||
declaration, because statements are passed to a template via a
|
declaration, because statements are passed to a template via a
|
||||||
special ``:`` syntax:
|
special ``:`` syntax:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
|
||||||
template withFile(f, fn, mode: expr, actions: stmt): stmt =
|
template withFile(f, fn, mode: expr, actions: stmt): stmt {.immediate.} =
|
||||||
block:
|
block:
|
||||||
var f: TFile
|
var f: TFile
|
||||||
if open(f, fn, mode):
|
if open(f, fn, mode):
|
||||||
|
|
@ -2793,7 +2824,7 @@ In templates identifiers can be constructed with the backticks notation:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
|
||||||
template typedef(name: expr, typ: typeDesc) =
|
template typedef(name: expr, typ: typeDesc) {.immediate.} =
|
||||||
type
|
type
|
||||||
`T name`* = typ
|
`T name`* = typ
|
||||||
`P name`* = ref `T name`
|
`P name`* = ref `T name`
|
||||||
|
|
@ -2808,8 +2839,9 @@ In the example ``name`` is instantiated with ``myint``, so \`T name\` becomes
|
||||||
Macros
|
Macros
|
||||||
------
|
------
|
||||||
|
|
||||||
`Macros`:idx: are the most powerful feature of Nimrod. They can be used
|
A `macro`:idx: is a special kind of low level template. They can be used
|
||||||
to implement `domain specific languages`:idx:.
|
to implement `domain specific languages`:idx:. Like templates, macros come in
|
||||||
|
the 2 flavors *immediate* and *ordinary*.
|
||||||
|
|
||||||
While macros enable advanced compile-time code transformations, they
|
While macros enable advanced compile-time code transformations, they
|
||||||
cannot change Nimrod's syntax. However, this is no real restriction because
|
cannot change Nimrod's syntax. However, this is no real restriction because
|
||||||
|
|
@ -3245,6 +3277,12 @@ factor.
|
||||||
**Note**: Currently the compiler recognizes but ignores this pragma.
|
**Note**: Currently the compiler recognizes but ignores this pragma.
|
||||||
|
|
||||||
|
|
||||||
|
immediate pragma
|
||||||
|
----------------
|
||||||
|
|
||||||
|
See `Ordinary vs immediate templates`_.
|
||||||
|
|
||||||
|
|
||||||
compilation option pragmas
|
compilation option pragmas
|
||||||
--------------------------
|
--------------------------
|
||||||
The listed pragmas here can be used to override the code generation options
|
The listed pragmas here can be used to override the code generation options
|
||||||
|
|
@ -3307,16 +3345,17 @@ though and for good reasons: Often they do a better job without it anyway.
|
||||||
In highly specific cases (a dispatch loop of an bytecode interpreter for
|
In highly specific cases (a dispatch loop of an bytecode interpreter for
|
||||||
example) it may provide benefits, though.
|
example) it may provide benefits, though.
|
||||||
|
|
||||||
|
|
||||||
global pragma
|
global pragma
|
||||||
---------------
|
-------------
|
||||||
The `global`:idx pragma can be applied to a variable within a proc to instruct
|
The `global`:idx: pragma can be applied to a variable within a proc to instruct
|
||||||
the compiler to store it in a global location and initialize it once at program
|
the compiler to store it in a global location and initialize it once at program
|
||||||
startup.
|
startup.
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
proc isHexNumber(s: string): bool =
|
proc isHexNumber(s: string): bool =
|
||||||
var pattern {.global.} = re"[0-9a-fA-F]+"
|
var pattern {.global.} = re"[0-9a-fA-F]+"
|
||||||
result = s.match(pattern)
|
result = s.match(pattern)
|
||||||
|
|
||||||
When used within a generic proc, a separate unique global variable will be
|
When used within a generic proc, a separate unique global variable will be
|
||||||
created for each instantiation of the proc. The order of initialization of
|
created for each instantiation of the proc. The order of initialization of
|
||||||
|
|
|
||||||
1
todo.txt
1
todo.txt
|
|
@ -10,6 +10,7 @@ New pragmas:
|
||||||
- ``hoist`` pragma for loop hoisting
|
- ``hoist`` pragma for loop hoisting
|
||||||
- implement ``byCopy`` pragma
|
- implement ``byCopy`` pragma
|
||||||
|
|
||||||
|
- ``borrow`` needs to take type classes into account
|
||||||
- complete and document optional indentation for 'case' statement
|
- complete and document optional indentation for 'case' statement
|
||||||
- make templates hygienic by default: try to gensym() everything in the 'block'
|
- make templates hygienic by default: try to gensym() everything in the 'block'
|
||||||
of a template; find a better solution for gensym instead of `*ident`
|
of a template; find a better solution for gensym instead of `*ident`
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue