summary refs log tree commit diff stats
path: root/tests
diff options
context:
space:
mode:
authormetagn <10591326+metagn@users.noreply.github.com>2022-01-20 22:57:50 +0300
committerGitHub <noreply@github.com>2022-01-20 20:57:50 +0100
commit2bd1aa186e09565b2103394bd281478fa1b10ef1 (patch)
tree3c1d9b68565f1c2f98fb3691fc4da1a81045460f /tests
parent1563cb2f6e37f07c303d095dabde74955be1e523 (diff)
downloadNim-2bd1aa186e09565b2103394bd281478fa1b10ef1.tar.gz
New/better macro pragmas, mark some as experimental (#19406)
* New/better macro pragmas, make some experimental

fix #15920, close #18212, close #14781, close #6696,
close https://github.com/nim-lang/RFCs/issues/220

Variable macro pragmas have been changed to
only take a unary section node.
They can now also be applied in sections with multiple variables,
as well as `const` sections. They also accept arguments.

Templates now support macro pragmas, mirroring other routine types.

Type and variable macro pragmas have been made experimental.
Symbols without parentheses instatiating nullary macros or templates
has also been documented in the experimental manual.

A check for a redefinition error based on the left hand side of variable
definitions when using variable macro pragmas was disabled.
This nerfs `byaddr` specifically, however this has been documented as
a consequence of the experimental features `byaddr` uses.

Given how simple these changes are I'm worried if I'm missing something.

* accomodate compiler boot

* allow weird pragmas

* add test for #10994

* remove some control flow, try remove some logic
Diffstat (limited to 'tests')
-rw-r--r--tests/pragmas/tpragmas_misc.nim24
-rw-r--r--tests/pragmas/tvar_macro.nim128
-rw-r--r--tests/stdlib/tdecls.nim66
3 files changed, 155 insertions, 63 deletions
diff --git a/tests/pragmas/tpragmas_misc.nim b/tests/pragmas/tpragmas_misc.nim
index 8cab74053..6dc2e6b80 100644
--- a/tests/pragmas/tpragmas_misc.nim
+++ b/tests/pragmas/tpragmas_misc.nim
@@ -13,8 +13,8 @@ block:
 
 block: # (partial fix) bug #15920
   block: # var template pragmas don't work in templates
-    template foo(lhs, typ, expr) =
-      let lhs = expr
+    template foo(expr) =
+      expr
     proc fun1()=
       let a {.foo.} = 1
     template fun2()=
@@ -24,23 +24,22 @@ block: # (partial fix) bug #15920
 
   template foo2() = discard # distractor (template or other symbol kind)
   block:
-    template foo2(lhs, typ, expr) =
-      let lhs = expr
+    template foo2(expr) =
+      expr
     proc fun1()=
       let a {.foo2.} = 1
     template fun2()=
       let a {.foo2.} = 1
     fun1() # ok
-    when false: # bug: Error: invalid pragma: foo2
-      fun2()
+    fun2() # bug: Error: invalid pragma: foo2
 
-  block: # proc template pragmas don't work in templates
+  block: # template pragmas don't work for templates, #18212
     # adapted from $nim/lib/std/private/since.nim
     # case without overload
     template since3(version: (int, int), body: untyped) {.dirty.} =
       when (NimMajor, NimMinor) >= version:
         body
-    when false: # bug
+    when true: # bug
       template fun3(): int {.since3: (1, 3).} = 12
 
   block: # ditto, w
@@ -51,7 +50,7 @@ block: # (partial fix) bug #15920
     template since2(version: (int, int, int), body: untyped) {.dirty.} =
       when (NimMajor, NimMinor, NimPatch) >= version:
         body
-    when false: # bug
+    when true: # bug
       template fun3(): int {.since2: (1, 3).} = 12
 
 when true: # D20210801T100514:here
@@ -62,3 +61,10 @@ when true: # D20210801T100514:here
       discard ret
     fn()
     static: discard genSym()
+
+block: # issue #10994
+  macro foo(x): untyped = x
+  template bar {.pragma.}
+
+  proc a {.bar.} = discard # works
+  proc b {.bar, foo.} = discard # doesn't
diff --git a/tests/pragmas/tvar_macro.nim b/tests/pragmas/tvar_macro.nim
new file mode 100644
index 000000000..d6a4ff983
--- /dev/null
+++ b/tests/pragmas/tvar_macro.nim
@@ -0,0 +1,128 @@
+import macros
+
+block: # test usage
+  macro modify(sec) =
+    result = copy sec
+    result[0][0] = ident(repr(result[0][0]) & "Modified")
+
+  block:
+    let foo {.modify.} = 3
+    doAssert fooModified == 3
+
+  block: # in section 
+    let
+      a = 1
+      b {.modify.} = 2
+      c = 3
+    doAssert (a, bModified, c) == (1, 2, 3)
+
+block: # with single argument
+  macro appendToName(name: static string, sec) =
+    result = sec
+    result[0][0] = ident(repr(result[0][0]) & name)
+
+  block:
+    let foo {.appendToName: "Bar".} = 3
+    doAssert fooBar == 3
+
+  block:
+    let
+      a = 1
+      b {.appendToName("").} = 2
+      c = 3
+    doAssert (a, b, c) == (1, 2, 3)
+
+macro appendToNameAndAdd(name: static string, incr: static int, sec) =
+  result = sec
+  result[0][0] = ident(repr(result[0][0]) & name)
+  result[0][2] = infix(result[0][2], "+", newLit(incr))
+
+block: # with multiple arguments
+  block:
+    let foo {.appendToNameAndAdd("Bar", 5).} = 3
+    doAssert fooBar == 8
+
+  block:
+    let
+      a = 1
+      b {.appendToNameAndAdd("", 15).} = 2
+      c = 3
+    doAssert (a, b, c) == (1, 17, 3)
+
+block: # in other kinds of sections
+  block:
+    const
+      a = 1
+      b {.appendToNameAndAdd("", 15).} = 2
+      c = 3
+    doAssert (a, b, c) == (1, 17, 3)
+    doAssert static(b) == b
+
+  block:
+    var
+      a = 1
+      b {.appendToNameAndAdd("", 15).} = 2
+      c = 3
+    doAssert (a, b, c) == (1, 17, 3)
+    b += a
+    c += b
+    doAssert (a, b, c) == (1, 18, 21)
+
+block: # with other pragmas
+  macro appendToNameAndAdd(name: static string, incr, sec) =
+    result = sec
+    result[0][0][0] = ident(repr(result[0][0][0]) & name)
+    result[0][0][1].add(ident"deprecated")
+    result[0][2] = infix(result[0][2], "+", incr)
+
+  var
+    a = 1
+    foo {.exportc: "exportedFooBar", appendToNameAndAdd("Bar", {'0'..'9'}), used.} = {'a'..'z', 'A'..'Z'}
+    b = 2
+  
+  doAssert (a, b) == (1, 2)
+
+  let importedFooBar {.importc: "exportedFooBar", nodecl.}: set[char]
+
+  doAssert importedFooBar == fooBar #[tt.Warning
+                            ^ fooBar is deprecated
+  ]#
+  
+
+block: # with stropping
+  macro `cast`(def) =
+    let def = def[0]
+    let
+      lhs = def[0]
+      typ = def[1]
+      ex = def[2]
+      addrTyp = if typ.kind == nnkEmpty: typ else: newTree(nnkPtrTy, typ)
+    result = quote do:
+      let tmp: `addrTyp` = unsafeAddr(`ex`)
+      template `lhs`: untyped = tmp[]
+  
+  macro assign(def) =
+    result = getAst(`cast`(def))
+
+  block:
+    let s = @["foo", "bar"]
+    let a {.`assign`.} = s[0]
+    doAssert a == "foo"
+    doAssert a[0].addr == s[0][0].addr
+
+  block:
+    let
+      s = @["foo", "bar"]
+      a {.`cast`.} = s[0]
+    doAssert a == "foo"
+    doAssert a[0].addr == s[0][0].addr
+
+block: # bug #15920
+  macro foo(def) =
+    result = def
+  proc fun1()=
+    let a {.foo.} = 1
+  template fun2()=
+    let a {.foo.} = 1
+  fun1() # ok
+  fun2() # BUG
diff --git a/tests/stdlib/tdecls.nim b/tests/stdlib/tdecls.nim
index c0d6f8a08..4e7407045 100644
--- a/tests/stdlib/tdecls.nim
+++ b/tests/stdlib/tdecls.nim
@@ -13,15 +13,18 @@ template fun() =
   var b {.byaddr.}: int = s[0]
   doAssert a.addr == b.addr
 
-  doAssert not compiles(block:
-    # redeclaration not allowed
-    var foo = 0
-    var foo {.byaddr.} = s[0])
-
-  doAssert not compiles(block:
-    # ditto
-    var foo {.byaddr.} = s[0]
-    var foo {.byaddr.} = s[0])
+  when false:
+    # template specific redeclaration issue
+    # see https://github.com/nim-lang/Nim/issues/8275
+    doAssert not compiles(block:
+      # redeclaration not allowed
+      var foo = 0
+      var foo {.byaddr.} = s[0])
+
+    doAssert not compiles(block:
+      # ditto
+      var foo {.byaddr.} = s[0]
+      var foo {.byaddr.} = s[0])
 
   block:
     var b {.byaddr.} = s[1] # redeclaration ok in sub scope
@@ -44,48 +47,3 @@ fun2()
 static: fun2()
 when false: # pending bug #13887
   static: fun()
-
-## We can define custom pragmas in user code
-template byUnsafeAddr(lhs, typ, expr) =
-  when typ is type(nil):
-    let tmp = addr(expr)
-  else:
-    let tmp: ptr typ = addr(expr)
-  template lhs: untyped = tmp[]
-
-block:
-  let s = @["foo", "bar"]
-  let a {.byUnsafeAddr.} = s[0]
-  doAssert a == "foo"
-  doAssert a[0].addr == s[0][0].addr
-
-block: # nkAccQuoted
-  # shows using a keyword, which requires nkAccQuoted
-  template `cast`(lhs, typ, expr) =
-    when typ is type(nil):
-      let tmp = addr(expr)
-    else:
-      let tmp: ptr typ = addr(expr)
-    template lhs: untyped = tmp[]
-
-  block:
-    let s = @["foo", "bar"]
-    let a {.`byUnsafeAddr`.} = s[0]
-    doAssert a == "foo"
-    doAssert a[0].addr == s[0][0].addr
-
-  block:
-    let s = @["foo", "bar"]
-    let a {.`cast`.} = s[0]
-    doAssert a == "foo"
-    doAssert a[0].addr == s[0][0].addr
-
-block: # bug #15920
-  template foo(lhs, typ, expr) =
-    let lhs = expr
-  proc fun1()=
-    let a {.foo.} = 1
-  template fun2()=
-    let a {.foo.} = 1
-  fun1() # ok
-  fun2() # BUG