diff options
author | hlaaftana <10591326+hlaaftana@users.noreply.github.com> | 2021-02-09 14:18:16 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-02-09 12:18:16 +0100 |
commit | aac8f675732086e9573851765d6e1c5b9ff38c28 (patch) | |
tree | dc934d291fba2d73370723d1b21c8b53d03a3ca1 | |
parent | d1210a3bb9fb381c42e3f6070f1011dcf7178d29 (diff) | |
download | Nim-aac8f675732086e9573851765d6e1c5b9ff38c28.tar.gz |
tests and docs for call operator (#16980)
* tests and docs for call operator * fix leftover * add extra dot test
-rw-r--r-- | doc/manual_experimental.rst | 34 | ||||
-rw-r--r-- | tests/specialops/tcallops.nim | 39 | ||||
-rw-r--r-- | tests/specialops/tcallprecedence.nim | 44 | ||||
-rw-r--r-- | tests/specialops/tdotops.nim | 8 |
4 files changed, 124 insertions, 1 deletions
diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.rst index 63108c896..c3d221a1b 100644 --- a/doc/manual_experimental.rst +++ b/doc/manual_experimental.rst @@ -408,7 +408,7 @@ The matched dot operators can be symbols of any callable kind (procs, templates and macros), depending on the desired effect: .. code-block:: nim - template `.` (js: PJsonNode, field: untyped): JSON = js[astToStr(field)] + template `.`(js: PJsonNode, field: untyped): JSON = js[astToStr(field)] var js = parseJson("{ x: 1, y: 2}") echo js.x # outputs 1 @@ -434,6 +434,38 @@ This operator will be matched against assignments to missing fields. .. code-block:: nim 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 ================== diff --git a/tests/specialops/tcallops.nim b/tests/specialops/tcallops.nim new file mode 100644 index 000000000..0508a37a1 --- /dev/null +++ b/tests/specialops/tcallops.nim @@ -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) diff --git a/tests/specialops/tcallprecedence.nim b/tests/specialops/tcallprecedence.nim new file mode 100644 index 000000000..6116f83d5 --- /dev/null +++ b/tests/specialops/tcallprecedence.nim @@ -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) diff --git a/tests/specialops/tdotops.nim b/tests/specialops/tdotops.nim index b1c75ab33..ca5eee665 100644 --- a/tests/specialops/tdotops.nim +++ b/tests/specialops/tdotops.nim @@ -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 T1 = object x*: int |