diff --git a/changelog.md b/changelog.md index 1636d125ff1f..8e70513e01e8 100644 --- a/changelog.md +++ b/changelog.md @@ -13,7 +13,36 @@ ## Language changes - +- Pragma macros on type definitions can now return `nnkTypeSection` nodes as well as `nnkTypeDef`, + allowing multiple type definitions to be injected in place of the original type definition. + + ```nim + import macros + + macro multiply(amount: static int, s: untyped): untyped = + let name = $s[0].basename + result = newNimNode(nnkTypeSection) + for i in 1 .. amount: + result.add(newTree(nnkTypeDef, ident(name & $i), s[1], s[2])) + + type + Foo = object + Bar {.multiply: 3.} = object + x, y, z: int + Baz = object + + # becomes + + type + Foo = object + Bar1 = object + x, y, z: int + Bar2 = object + x, y, z: int + Bar3 = object + x, y, z: int + Baz = object + ``` ## Compiler changes diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 4607e857aa10..36d76608e39f 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1112,7 +1112,12 @@ proc typeDefLeftSidePass(c: PContext, typeSection: PNode, i: int) = if name.kind == nkPragmaExpr: let rewritten = applyTypeSectionPragmas(c, name[1], typeDef) if rewritten != nil: - typeSection[i] = rewritten + case rewritten.kind + of nkTypeDef: + typeSection[i] = rewritten + of nkTypeSection: + typeSection.sons[i .. i] = rewritten.sons + else: illFormedAst(rewritten, c.config) typeDefLeftSidePass(c, typeSection, i) return pragma(c, s, name[1], typePragmas) @@ -1143,16 +1148,19 @@ proc typeDefLeftSidePass(c: PContext, typeSection: PNode, i: int) = proc typeSectionLeftSidePass(c: PContext, n: PNode) = # process the symbols on the left side for the whole type section, before # we even look at the type definitions on the right - for i in 0..