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
This commit is contained in:
parent
1563cb2f6e
commit
2bd1aa186e
8 changed files with 435 additions and 205 deletions
|
|
@ -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
|
||||
|
|
|
|||
128
tests/pragmas/tvar_macro.nim
Normal file
128
tests/pragmas/tvar_macro.nim
Normal file
|
|
@ -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
|
||||
Loading…
Add table
Add a link
Reference in a new issue