parent
0880f118d3
commit
f50377986a
3 changed files with 198 additions and 171 deletions
170
doc/manual.rst
170
doc/manual.rst
|
|
@ -1734,22 +1734,9 @@ dereferencing operations for reference types:
|
||||||
n.data = 9
|
n.data = 9
|
||||||
# no need to write n[].data; in fact n[].data is highly discouraged!
|
# no need to write n[].data; in fact n[].data is highly discouraged!
|
||||||
|
|
||||||
Automatic dereferencing is also performed for the first argument of a routine
|
Automatic dereferencing can be performed for the first argument of a routine
|
||||||
call. But currently this feature has to be only enabled
|
call, but this is an experimental feature and is described `here
|
||||||
via ``{.experimental: "implicitDeref".}``:
|
<manual_experimental.html#type-bound-operations>`_.
|
||||||
|
|
||||||
.. code-block:: nim
|
|
||||||
{.experimental: "implicitDeref".}
|
|
||||||
|
|
||||||
proc depth(x: NodeObj): int = ...
|
|
||||||
|
|
||||||
var
|
|
||||||
n: Node
|
|
||||||
new(n)
|
|
||||||
echo n.depth
|
|
||||||
# no need to write n[].depth either
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
In order to simplify structural type checking, recursive tuples are not valid:
|
In order to simplify structural type checking, recursive tuples are not valid:
|
||||||
|
|
||||||
|
|
@ -5341,52 +5328,6 @@ powerful programming construct that still suffices. So the "check list" is:
|
||||||
(4) Else: Use a macro.
|
(4) Else: Use a macro.
|
||||||
|
|
||||||
|
|
||||||
For Loop Macro
|
|
||||||
--------------
|
|
||||||
|
|
||||||
A macro that takes as its only input parameter an expression of the special
|
|
||||||
type ``system.ForLoopStmt`` can rewrite the entirety of a ``for`` loop:
|
|
||||||
|
|
||||||
.. code-block:: nim
|
|
||||||
:test: "nim c $1"
|
|
||||||
|
|
||||||
import macros
|
|
||||||
{.experimental: "forLoopMacros".}
|
|
||||||
|
|
||||||
macro enumerate(x: ForLoopStmt): untyped =
|
|
||||||
expectKind x, nnkForStmt
|
|
||||||
# we strip off the first for loop variable and use
|
|
||||||
# it as an integer counter:
|
|
||||||
result = newStmtList()
|
|
||||||
result.add newVarStmt(x[0], newLit(0))
|
|
||||||
var body = x[^1]
|
|
||||||
if body.kind != nnkStmtList:
|
|
||||||
body = newTree(nnkStmtList, body)
|
|
||||||
body.add newCall(bindSym"inc", x[0])
|
|
||||||
var newFor = newTree(nnkForStmt)
|
|
||||||
for i in 1..x.len-3:
|
|
||||||
newFor.add x[i]
|
|
||||||
# transform enumerate(X) to 'X'
|
|
||||||
newFor.add x[^2][1]
|
|
||||||
newFor.add body
|
|
||||||
result.add newFor
|
|
||||||
# now wrap the whole macro in a block to create a new scope
|
|
||||||
result = quote do:
|
|
||||||
block: `result`
|
|
||||||
|
|
||||||
for a, b in enumerate(items([1, 2, 3])):
|
|
||||||
echo a, " ", b
|
|
||||||
|
|
||||||
# without wrapping the macro in a block, we'd need to choose different
|
|
||||||
# names for `a` and `b` here to avoid redefinition errors
|
|
||||||
for a, b in enumerate([1, 2, 3, 5]):
|
|
||||||
echo a, " ", b
|
|
||||||
|
|
||||||
|
|
||||||
Currently for loop macros must be enabled explicitly
|
|
||||||
via ``{.experimental: "forLoopMacros".}``.
|
|
||||||
|
|
||||||
|
|
||||||
Special Types
|
Special Types
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
|
@ -5822,111 +5763,6 @@ iterator in which case the overloading resolution takes place:
|
||||||
var x = 4
|
var x = 4
|
||||||
write(stdout, x) # not ambiguous: uses the module C's x
|
write(stdout, x) # not ambiguous: uses the module C's x
|
||||||
|
|
||||||
Code reordering
|
|
||||||
~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
**Note**: Code reordering is experimental and must be enabled via the
|
|
||||||
``{.experimental.}`` pragma.
|
|
||||||
|
|
||||||
The code reordering feature can implicitly rearrange procedure, template, and
|
|
||||||
macro definitions along with variable declarations and initializations at the top
|
|
||||||
level scope so that, to a large extent, a programmer should not have to worry
|
|
||||||
about ordering definitions correctly or be forced to use forward declarations to
|
|
||||||
preface definitions inside a module.
|
|
||||||
|
|
||||||
..
|
|
||||||
NOTE: The following was documentation for the code reordering precursor,
|
|
||||||
which was {.noForward.}.
|
|
||||||
|
|
||||||
In this mode, procedure definitions may appear out of order and the compiler
|
|
||||||
will postpone their semantic analysis and compilation until it actually needs
|
|
||||||
to generate code using the definitions. In this regard, this mode is similar
|
|
||||||
to the modus operandi of dynamic scripting languages, where the function
|
|
||||||
calls are not resolved until the code is executed. Here is the detailed
|
|
||||||
algorithm taken by the compiler:
|
|
||||||
|
|
||||||
1. When a callable symbol is first encountered, the compiler will only note
|
|
||||||
the symbol callable name and it will add it to the appropriate overload set
|
|
||||||
in the current scope. At this step, it won't try to resolve any of the type
|
|
||||||
expressions used in the signature of the symbol (so they can refer to other
|
|
||||||
not yet defined symbols).
|
|
||||||
|
|
||||||
2. When a top level call is encountered (usually at the very end of the
|
|
||||||
module), the compiler will try to determine the actual types of all of the
|
|
||||||
symbols in the matching overload set. This is a potentially recursive process
|
|
||||||
as the signatures of the symbols may include other call expressions, whose
|
|
||||||
types will be resolved at this point too.
|
|
||||||
|
|
||||||
3. Finally, after the best overload is picked, the compiler will start
|
|
||||||
compiling the body of the respective symbol. This in turn will lead the
|
|
||||||
compiler to discover more call expressions that need to be resolved and steps
|
|
||||||
2 and 3 will be repeated as necessary.
|
|
||||||
|
|
||||||
Please note that if a callable symbol is never used in this scenario, its
|
|
||||||
body will never be compiled. This is the default behavior leading to best
|
|
||||||
compilation times, but if exhaustive compilation of all definitions is
|
|
||||||
required, using ``nim check`` provides this option as well.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
.. code-block:: nim
|
|
||||||
|
|
||||||
{.experimental: "codeReordering".}
|
|
||||||
|
|
||||||
proc foo(x: int) =
|
|
||||||
bar(x)
|
|
||||||
|
|
||||||
proc bar(x: int) =
|
|
||||||
echo(x)
|
|
||||||
|
|
||||||
foo(10)
|
|
||||||
|
|
||||||
Variables can also be reordered as well. Variables that are *initialized* (i.e.
|
|
||||||
variables that have their declaration and assignment combined in a single
|
|
||||||
statement) can have their entire initialization statement reordered. Be wary of
|
|
||||||
what code is executed at the top level:
|
|
||||||
|
|
||||||
.. code-block:: nim
|
|
||||||
{.experimental: "codeReordering".}
|
|
||||||
|
|
||||||
proc a() =
|
|
||||||
echo(foo)
|
|
||||||
|
|
||||||
var foo = 5
|
|
||||||
|
|
||||||
a() # outputs: "5"
|
|
||||||
|
|
||||||
..
|
|
||||||
TODO: Let's table this for now. This is an *experimental feature* and so the
|
|
||||||
specific manner in which ``declared`` operates with it can be decided in
|
|
||||||
eventuality, because right now it works a bit weirdly.
|
|
||||||
|
|
||||||
The values of expressions involving ``declared`` are decided *before* the
|
|
||||||
code reordering process, and not after. As an example, the output of this
|
|
||||||
code is the same as it would be with code reordering disabled.
|
|
||||||
|
|
||||||
.. code-block:: nim
|
|
||||||
{.experimental: "codeReordering".}
|
|
||||||
|
|
||||||
proc x() =
|
|
||||||
echo(declared(foo))
|
|
||||||
|
|
||||||
var foo = 4
|
|
||||||
|
|
||||||
x() # "false"
|
|
||||||
|
|
||||||
It is important to note that reordering *only* works for symbols at top level
|
|
||||||
scope. Therefore, the following will *fail to compile:*
|
|
||||||
|
|
||||||
.. code-block:: nim
|
|
||||||
{.experimental: "codeReordering".}
|
|
||||||
|
|
||||||
proc a() =
|
|
||||||
b()
|
|
||||||
proc b() =
|
|
||||||
echo("Hello!")
|
|
||||||
|
|
||||||
a()
|
|
||||||
|
|
||||||
Compiler Messages
|
Compiler Messages
|
||||||
=================
|
=================
|
||||||
|
|
|
||||||
|
|
@ -203,10 +203,122 @@ useful only when interfacing with imported types having such semantics.
|
||||||
Automatic dereferencing
|
Automatic dereferencing
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
If the `experimental mode <manual.html#pragmas-experimental-pragma>`_ is active
|
Automatic dereferencing is performed for the first argument of a routine call.
|
||||||
and no other match is found, the first argument ``a`` is dereferenced
|
This feature has to be only enabled via ``{.experimental: "implicitDeref".}``:
|
||||||
automatically if it's a pointer type and overloading resolution is tried
|
|
||||||
with ``a[]`` instead.
|
.. code-block:: nim
|
||||||
|
{.experimental: "implicitDeref".}
|
||||||
|
|
||||||
|
proc depth(x: NodeObj): int = ...
|
||||||
|
|
||||||
|
var
|
||||||
|
n: Node
|
||||||
|
new(n)
|
||||||
|
echo n.depth
|
||||||
|
# no need to write n[].depth either
|
||||||
|
|
||||||
|
Code reordering
|
||||||
|
===============
|
||||||
|
|
||||||
|
The code reordering feature can implicitly rearrange procedure, template, and
|
||||||
|
macro definitions along with variable declarations and initializations at the top
|
||||||
|
level scope so that, to a large extent, a programmer should not have to worry
|
||||||
|
about ordering definitions correctly or be forced to use forward declarations to
|
||||||
|
preface definitions inside a module.
|
||||||
|
|
||||||
|
..
|
||||||
|
NOTE: The following was documentation for the code reordering precursor,
|
||||||
|
which was {.noForward.}.
|
||||||
|
|
||||||
|
In this mode, procedure definitions may appear out of order and the compiler
|
||||||
|
will postpone their semantic analysis and compilation until it actually needs
|
||||||
|
to generate code using the definitions. In this regard, this mode is similar
|
||||||
|
to the modus operandi of dynamic scripting languages, where the function
|
||||||
|
calls are not resolved until the code is executed. Here is the detailed
|
||||||
|
algorithm taken by the compiler:
|
||||||
|
|
||||||
|
1. When a callable symbol is first encountered, the compiler will only note
|
||||||
|
the symbol callable name and it will add it to the appropriate overload set
|
||||||
|
in the current scope. At this step, it won't try to resolve any of the type
|
||||||
|
expressions used in the signature of the symbol (so they can refer to other
|
||||||
|
not yet defined symbols).
|
||||||
|
|
||||||
|
2. When a top level call is encountered (usually at the very end of the
|
||||||
|
module), the compiler will try to determine the actual types of all of the
|
||||||
|
symbols in the matching overload set. This is a potentially recursive process
|
||||||
|
as the signatures of the symbols may include other call expressions, whose
|
||||||
|
types will be resolved at this point too.
|
||||||
|
|
||||||
|
3. Finally, after the best overload is picked, the compiler will start
|
||||||
|
compiling the body of the respective symbol. This in turn will lead the
|
||||||
|
compiler to discover more call expressions that need to be resolved and steps
|
||||||
|
2 and 3 will be repeated as necessary.
|
||||||
|
|
||||||
|
Please note that if a callable symbol is never used in this scenario, its
|
||||||
|
body will never be compiled. This is the default behavior leading to best
|
||||||
|
compilation times, but if exhaustive compilation of all definitions is
|
||||||
|
required, using ``nim check`` provides this option as well.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
|
||||||
|
{.experimental: "codeReordering".}
|
||||||
|
|
||||||
|
proc foo(x: int) =
|
||||||
|
bar(x)
|
||||||
|
|
||||||
|
proc bar(x: int) =
|
||||||
|
echo(x)
|
||||||
|
|
||||||
|
foo(10)
|
||||||
|
|
||||||
|
Variables can also be reordered as well. Variables that are *initialized* (i.e.
|
||||||
|
variables that have their declaration and assignment combined in a single
|
||||||
|
statement) can have their entire initialization statement reordered. Be wary of
|
||||||
|
what code is executed at the top level:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
{.experimental: "codeReordering".}
|
||||||
|
|
||||||
|
proc a() =
|
||||||
|
echo(foo)
|
||||||
|
|
||||||
|
var foo = 5
|
||||||
|
|
||||||
|
a() # outputs: "5"
|
||||||
|
|
||||||
|
..
|
||||||
|
TODO: Let's table this for now. This is an *experimental feature* and so the
|
||||||
|
specific manner in which ``declared`` operates with it can be decided in
|
||||||
|
eventuality, because right now it works a bit weirdly.
|
||||||
|
|
||||||
|
The values of expressions involving ``declared`` are decided *before* the
|
||||||
|
code reordering process, and not after. As an example, the output of this
|
||||||
|
code is the same as it would be with code reordering disabled.
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
{.experimental: "codeReordering".}
|
||||||
|
|
||||||
|
proc x() =
|
||||||
|
echo(declared(foo))
|
||||||
|
|
||||||
|
var foo = 4
|
||||||
|
|
||||||
|
x() # "false"
|
||||||
|
|
||||||
|
It is important to note that reordering *only* works for symbols at top level
|
||||||
|
scope. Therefore, the following will *fail to compile:*
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
{.experimental: "codeReordering".}
|
||||||
|
|
||||||
|
proc a() =
|
||||||
|
b()
|
||||||
|
proc b() =
|
||||||
|
echo("Hello!")
|
||||||
|
|
||||||
|
a()
|
||||||
|
|
||||||
|
|
||||||
Automatic self insertions
|
Automatic self insertions
|
||||||
|
|
@ -245,6 +357,25 @@ if no other interpretation of the call is possible:
|
||||||
echo self, self.childField, " ", sumFields(self)
|
echo self, self.childField, " ", sumFields(self)
|
||||||
|
|
||||||
|
|
||||||
|
Named argument overloading
|
||||||
|
==========================
|
||||||
|
|
||||||
|
Routines with the same type signature can be called differently if a parameter
|
||||||
|
has different names. This does not need an ``experimental`` switch, but is an
|
||||||
|
unstable feature.
|
||||||
|
|
||||||
|
.. code-block::nim
|
||||||
|
proc foo(x: int) =
|
||||||
|
echo "Using x: ", x
|
||||||
|
proc foo(y: int) =
|
||||||
|
echo "Using y: ", y
|
||||||
|
|
||||||
|
foo(x = 2)
|
||||||
|
# Using x: 2
|
||||||
|
foo(y = 2)
|
||||||
|
# Using y: 2
|
||||||
|
|
||||||
|
|
||||||
Do notation
|
Do notation
|
||||||
===========
|
===========
|
||||||
|
|
||||||
|
|
@ -899,6 +1030,52 @@ but only the statement's selector expression is used to determine which
|
||||||
macro to call.
|
macro to call.
|
||||||
|
|
||||||
|
|
||||||
|
For loop macros
|
||||||
|
---------------
|
||||||
|
|
||||||
|
A macro that takes as its only input parameter an expression of the special
|
||||||
|
type ``system.ForLoopStmt`` can rewrite the entirety of a ``for`` loop:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
:test: "nim c $1"
|
||||||
|
|
||||||
|
import macros
|
||||||
|
{.experimental: "forLoopMacros".}
|
||||||
|
|
||||||
|
macro enumerate(x: ForLoopStmt): untyped =
|
||||||
|
expectKind x, nnkForStmt
|
||||||
|
# we strip off the first for loop variable and use
|
||||||
|
# it as an integer counter:
|
||||||
|
result = newStmtList()
|
||||||
|
result.add newVarStmt(x[0], newLit(0))
|
||||||
|
var body = x[^1]
|
||||||
|
if body.kind != nnkStmtList:
|
||||||
|
body = newTree(nnkStmtList, body)
|
||||||
|
body.add newCall(bindSym"inc", x[0])
|
||||||
|
var newFor = newTree(nnkForStmt)
|
||||||
|
for i in 1..x.len-3:
|
||||||
|
newFor.add x[i]
|
||||||
|
# transform enumerate(X) to 'X'
|
||||||
|
newFor.add x[^2][1]
|
||||||
|
newFor.add body
|
||||||
|
result.add newFor
|
||||||
|
# now wrap the whole macro in a block to create a new scope
|
||||||
|
result = quote do:
|
||||||
|
block: `result`
|
||||||
|
|
||||||
|
for a, b in enumerate(items([1, 2, 3])):
|
||||||
|
echo a, " ", b
|
||||||
|
|
||||||
|
# without wrapping the macro in a block, we'd need to choose different
|
||||||
|
# names for `a` and `b` here to avoid redefinition errors
|
||||||
|
for a, b in enumerate([1, 2, 3, 5]):
|
||||||
|
echo a, " ", b
|
||||||
|
|
||||||
|
|
||||||
|
Currently for loop macros must be enabled explicitly
|
||||||
|
via ``{.experimental: "forLoopMacros".}``.
|
||||||
|
|
||||||
|
|
||||||
Term rewriting macros
|
Term rewriting macros
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
|
|
|
||||||
14
tests/overload/tnamedparamoverloading.nim
Normal file
14
tests/overload/tnamedparamoverloading.nim
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
discard """
|
||||||
|
output: '''
|
||||||
|
Using x: 2
|
||||||
|
Using y: 2
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
proc foo(x: int) =
|
||||||
|
echo "Using x: ", x
|
||||||
|
proc foo(y: int) =
|
||||||
|
echo "Using y: ", y
|
||||||
|
|
||||||
|
foo(x = 2)
|
||||||
|
foo(y = 2)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue