tests and docs for call operator (#16980)
* tests and docs for call operator * fix leftover * add extra dot test
This commit is contained in:
parent
d1210a3bb9
commit
aac8f67573
4 changed files with 124 additions and 1 deletions
|
|
@ -434,6 +434,38 @@ This operator will be matched against assignments to missing fields.
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
a.b = c # becomes `.=`(a, b, c)
|
a.b = c # becomes `.=`(a, b, c)
|
||||||
|
|
||||||
|
Call operator
|
||||||
|
-------------
|
||||||
|
The call operator, `()`, matches all kinds of unresolved calls and takes
|
||||||
|
precedence over dot operators, however it does not match missing overloads
|
||||||
|
for existing routines. The experimental `callOperator` switch must be enabled
|
||||||
|
to use this operator.
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
{.experimental: "callOperator".}
|
||||||
|
|
||||||
|
template `()`(a: int, b: float): untyped = $(a, b)
|
||||||
|
|
||||||
|
block:
|
||||||
|
let a = 1.0
|
||||||
|
let b = 2
|
||||||
|
doAssert b(a) == `()`(b, a)
|
||||||
|
doAssert a.b == `()`(b, a)
|
||||||
|
|
||||||
|
block:
|
||||||
|
let a = 1.0
|
||||||
|
proc b(): int = 2
|
||||||
|
doAssert not compiles(b(a))
|
||||||
|
doAssert not compiles(a.b) # `()` not called
|
||||||
|
|
||||||
|
block:
|
||||||
|
let a = 1.0
|
||||||
|
proc b(x: float): int = int(x + 1)
|
||||||
|
let c = 3.0
|
||||||
|
|
||||||
|
doAssert not compiles(a.b(c)) # gives a type mismatch error same as b(a, c)
|
||||||
|
doAssert (a.b)(c) == `()`(a.b, c)
|
||||||
|
|
||||||
|
|
||||||
Not nil annotation
|
Not nil annotation
|
||||||
==================
|
==================
|
||||||
|
|
|
||||||
39
tests/specialops/tcallops.nim
Normal file
39
tests/specialops/tcallops.nim
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
import macros
|
||||||
|
|
||||||
|
{.experimental: "callOperator".}
|
||||||
|
|
||||||
|
type Foo[T: proc] = object
|
||||||
|
callback: T
|
||||||
|
|
||||||
|
macro `()`(foo: Foo, args: varargs[untyped]): untyped =
|
||||||
|
result = newCall(newDotExpr(foo, ident"callback"))
|
||||||
|
for a in args:
|
||||||
|
result.add(a)
|
||||||
|
|
||||||
|
var f1Calls = 0
|
||||||
|
var f = Foo[proc()](callback: proc() = inc f1Calls)
|
||||||
|
doAssert f1Calls == 0
|
||||||
|
f()
|
||||||
|
doAssert f1Calls == 1
|
||||||
|
var f2Calls = 0
|
||||||
|
f.callback = proc() = inc f2Calls
|
||||||
|
doAssert f2Calls == 0
|
||||||
|
f()
|
||||||
|
doAssert f2Calls == 1
|
||||||
|
|
||||||
|
let g = Foo[proc (x: int): int](callback: proc (x: int): int = x * 2 + 1)
|
||||||
|
doAssert g(15) == 31
|
||||||
|
|
||||||
|
proc `()`(args: varargs[string]): string =
|
||||||
|
result = "("
|
||||||
|
for a in args: result.add(a)
|
||||||
|
result.add(')')
|
||||||
|
|
||||||
|
let a = "1"
|
||||||
|
let b = "2"
|
||||||
|
let c = "3"
|
||||||
|
|
||||||
|
doAssert a(b) == "(12)"
|
||||||
|
doAssert a.b(c) == `()`(b, a, c)
|
||||||
|
doAssert (a.b)(c) == `()`(a.b, c)
|
||||||
|
doAssert `()`(a.b, c) == `()`(`()`(b, a), c)
|
||||||
44
tests/specialops/tcallprecedence.nim
Normal file
44
tests/specialops/tcallprecedence.nim
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
import macros
|
||||||
|
|
||||||
|
{.experimental: "dotOperators".}
|
||||||
|
{.experimental: "callOperator".}
|
||||||
|
|
||||||
|
block:
|
||||||
|
template `.()`(foo: int, args: varargs[untyped]): untyped {.used.} =
|
||||||
|
".()"
|
||||||
|
|
||||||
|
template `()`(foo: int, args: varargs[untyped]): untyped =
|
||||||
|
"()"
|
||||||
|
|
||||||
|
let a = (b: 1)
|
||||||
|
let c = 3
|
||||||
|
|
||||||
|
doAssert a.b(c) == "()"
|
||||||
|
doAssert not compiles(a(c))
|
||||||
|
doAssert (a.b)(c) == "()"
|
||||||
|
|
||||||
|
macro `()`(args: varargs[typed]): untyped =
|
||||||
|
result = newLit("() " & args.treeRepr)
|
||||||
|
|
||||||
|
macro `.`(args: varargs[typed]): untyped =
|
||||||
|
result = newLit(". " & args.treeRepr)
|
||||||
|
|
||||||
|
block:
|
||||||
|
let a = 1
|
||||||
|
let b = 2
|
||||||
|
doAssert a.b == `()`(b, a)
|
||||||
|
|
||||||
|
block:
|
||||||
|
let a = 1
|
||||||
|
proc b(): int {.used.} = 2
|
||||||
|
doAssert a.b == `.`(a, b)
|
||||||
|
|
||||||
|
block:
|
||||||
|
let a = 1
|
||||||
|
proc b(x: int): int = x + 1
|
||||||
|
let c = 3
|
||||||
|
|
||||||
|
doAssert a.b(c) == `.`(a, b, c)
|
||||||
|
doAssert a(b) == `()`(a, b)
|
||||||
|
doAssert (a.b)(c) == `()`(a.b, c)
|
||||||
|
doAssert a.b == b(a)
|
||||||
|
|
@ -17,6 +17,14 @@ one param call to c with 10
|
||||||
'''
|
'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
block:
|
||||||
|
type Foo = object
|
||||||
|
var a: Foo
|
||||||
|
template `.`(a: Foo, b: untyped): untyped = astToStr(b)
|
||||||
|
template callme(a, f): untyped = a.f
|
||||||
|
doAssert callme(a, f2) == "f2" # not `f`
|
||||||
|
doAssert a.callme(f3) == "f3"
|
||||||
|
|
||||||
type
|
type
|
||||||
T1 = object
|
T1 = object
|
||||||
x*: int
|
x*: int
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue