diff --git a/compiler/sem/sem.nim b/compiler/sem/sem.nim index e729e069da6..c23e834c5ce 100644 --- a/compiler/sem/sem.nim +++ b/compiler/sem/sem.nim @@ -136,6 +136,8 @@ proc indexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode proc semStaticExpr(c: PContext, n: PNode): PNode proc semStaticType(c: PContext, childNode: PNode, prev: PType): PType proc semTypeOf(c: PContext; n: PNode): PNode +proc semAnnotation(c: PContext, pragmas: ptr PNode, n: PNode, + flags: TExprFlags): PNode proc computeRequiresInit(c: PContext, t: PType): bool proc defaultConstructionError(c: PContext, t: PType, n: PNode): PNode proc hasUnresolvedArgs(c: PContext, n: PNode): bool @@ -547,6 +549,7 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym, flags: TExprFlags = {}): PNode proc semMacroExpr(c: PContext, n: PNode, sym: PSym, flags: TExprFlags = {}): PNode +proc afterCallActions(c: PContext; n: PNode, flags: TExprFlags): PNode proc tryConstExpr(c: PContext, n: PNode): PNode = addInNimDebugUtils(c.config, "tryConstExpr", n, result) diff --git a/compiler/sem/semstmts.nim b/compiler/sem/semstmts.nim index 5e395a9cabc..85f1d117011 100644 --- a/compiler/sem/semstmts.nim +++ b/compiler/sem/semstmts.nim @@ -480,6 +480,92 @@ proc copyExcept(n: PNode, i: int): PNode {.inline.} = for j in 0..= 1 + key = + if isCallSyntax: prag[0] + else: prag + + # we only want to process macro pragmas (ast transforms) + # xxx: @saem: this dance to filter through them is another sign that pragmas + # shouldn't be associated to symbols as the syntax hints + if whichPragma(prag) == wInvalid and key.kind in nkIdentKinds: + # a custom pragma as opposed to a built-in + let (ident, err) = considerQuotedIdent(c, key) + if err != nil: + # XXX: replace with propagating ``nkError``. As it is now, an erroneous + # ``nkAccQuoted`` will not disable following macro pragmas if + # errorMax > 1! + localReport(c.config, n) + return + elif strTableGet(c.userPragmas, ident) != nil: + return # User defined pragma + else: + var amb = false + let sym = searchInScopes(c, ident, amb) + if sym != nil and sfCustomPragma in sym.flags: + return # User custom pragma + else: + return + + var x = newNodeI(nkCall, key.info) + x.add(key) + + if isCallSyntax: + # pass pragma arguments to the macro too: + for j in 1..= 0: - prag[0] - else: - prag - - # we only want to process macro pragmas (ast transforms) - # xxx: this dance to filter through them is another sign that pragmas - # shouldn't be associated to symbols as the syntax hints - if whichPragma(prag) == wInvalid and key.kind in nkIdentKinds: - # a custom pragma as opposed to a built-in - let (ident, err) = considerQuotedIdent(c, key) - - if err != nil: - # TODO convert to nkError - localReport(c.config, err) - elif strTableGet(c.userPragmas, ident) != nil: - continue # User defined pragma - else: - var amb = false - let sym = searchInScopes(c, ident, amb) - if sym != nil and sfCustomPragma in sym.flags: - continue # User custom pragma - else: - # not a custom pragma, we can ignore it - continue - - # transform `let l {.m, rest.}` to `m(do: let l {.rest.})` and let the - # semantic checker deal with the it: - var x = newNodeI(nkCall, key.info) - x.add(key) - - if prag.kind in nkPragmaCallKinds and prag.len > 1: - # pass pragma arguments to the macro too: - for j in 1..= 1: it[0] else: it - - # we only want to process macro pragmas (ast transforms) - # xxx: this dance to filter through them is another sign that pragmas - # shouldn't be associated to symbols as the syntax hints - if whichPragma(it) == wInvalid and key.kind in nkIdentKinds: - let (ident, err) = considerQuotedIdent(c, key) - if err != nil: - localReport(c.config, err) - if strTableGet(c.userPragmas, ident) != nil: - continue # User defined pragma - else: - var amb = false - let sym = searchInScopes(c, ident, amb) - if sym != nil and sfCustomPragma in sym.flags: - continue # User custom pragma - else: - # Not a custom pragma - continue - - # we transform `proc p {.m, rest.}` into `m(do: proc p {.rest.})` and - # let the semantic checker deal with it: - var x = newNodeI(nkCall, key.info) - x.add(key) - - if it.kind in nkPragmaCallKinds and it.len > 1: - # pass pragma arguments to the macro too: - for i in 1..= 1: p[0] else: p - - if p.kind == nkEmpty or whichPragma(p) != wInvalid: - discard "builtin pragma" - else: - let (ident, err) = considerQuotedIdent(c, key) - if err != nil: - # XXX: use nkError instead (or don't report an error yet and allow a - # macro to recover) - localReport(c.config, err) - elif strTableGet(c.userPragmas, ident) != nil: - discard "User-defined pragma" - else: - var amb = false - let sym = searchInScopes(c, ident, amb) - # XXX: What to do here if amb is true? - if sym != nil and sfCustomPragma in sym.flags: - discard "Custom user pragma" - else: - # we transform ``(arg1, arg2: T) {.m, rest.}`` into ``m((arg1, arg2: T) {.rest.})`` and - # let the semantic checker deal with it: - var x = newNodeI(nkCall, key.info) - x.add(key) - if p.kind in nkPragmaCallKinds and p.len > 1: - # pass pragma arguments to the macro too: - for i in 1 ..< p.len: - x.add(p[i]) - # Also pass the node the pragma has been applied to - x.add(operand.copyTreeWithoutNode(p)) - # recursion assures that this works for multiple macro annotations too: - var r = semOverloadedCall(c, x, {skMacro, skTemplate}, {efNoUndeclared}) - if r != nil: - if r.kind == nkError: - localReport(c.config, r) - return - - doAssert r[0].kind == nkSym - let m = r[0].sym - case m.kind - of skMacro: return semMacroExpr(c, r, m, {efNoSemCheck}) - of skTemplate: return semTemplateExpr(c, r, m, {efNoSemCheck}) - else: doAssert(false, "cannot happen") - proc semProcTypeWithScope(c: PContext, n: PNode, prev: PType, kind: TSymKind): PType = checkSonsLen(n, 2, c.config) if n[1].kind != nkEmpty and n[1].len > 0: - let macroEval = applyTypeSectionPragmas(c, n[1], n) + let macroEval = semAnnotation(c, addr n[1], n, {efNoSemCheck}) if macroEval != nil: return semTypeNode(c, macroEval, prev) diff --git a/tests/pragmas/tcustom_pragma.nim b/tests/pragmas/tcustom_pragma.nim index d1ab3fc219c..9222206fd53 100644 --- a/tests/pragmas/tcustom_pragma.nim +++ b/tests/pragmas/tcustom_pragma.nim @@ -354,7 +354,7 @@ ProcDef Ident "s" Ident "string" Empty - Empty + Pragma Empty StmtList ReturnStmt