Fix getCustomPragmaVal for some multi arg pragmas (#17723)

* Fix getCustomPragmaVal for some multi arg pragmas

* Bootstrap fix
This commit is contained in:
Clyybber 2021-04-15 13:55:50 +02:00 • committed by GitHub
commit 51a40c1f38
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 54 additions and 41 deletions

View file

@ -1474,23 +1474,20 @@ macro expandMacros*(body: typed): untyped =
echo body.toStrLit echo body.toStrLit
result = body result = body
proc findPragmaExprForFieldSym(arg, fieldSym: NimNode): NimNode = proc findPragmaNodeInRecList(arg, fieldSym: NimNode): NimNode =
case arg.kind case arg.kind
of nnkRecList, nnkRecCase: of nnkRecList, nnkRecCase:
for it in arg.children: for it in arg.children:
result = findPragmaExprForFieldSym(it, fieldSym) result = findPragmaNodeInRecList(it, fieldSym)
if result != nil: if result != nil: return
return
of nnkOfBranch: of nnkOfBranch:
return findPragmaExprForFieldSym(arg[1], fieldSym) return findPragmaNodeInRecList(arg[1], fieldSym)
of nnkElse: of nnkElse:
return findPragmaExprForFieldSym(arg[0], fieldSym) return findPragmaNodeInRecList(arg[0], fieldSym)
of nnkIdentDefs: of nnkIdentDefs:
for i in 0 ..< arg.len-2: for i in 0..<arg.len-2:
let child = arg[i] result = findPragmaNodeInRecList(arg[i], fieldSym)
result = findPragmaExprForFieldSym(child, fieldSym) if result != nil: return
if result != nil:
return
of nnkAccQuoted, nnkIdent, nnkSym, nnkPostfix: of nnkAccQuoted, nnkIdent, nnkSym, nnkPostfix:
return nil return nil
of nnkPragmaExpr: of nnkPragmaExpr:
@ -1502,25 +1499,15 @@ proc findPragmaExprForFieldSym(arg, fieldSym: NimNode): NimNode =
else: else:
error("illegal arg: ", arg) error("illegal arg: ", arg)
proc getPragmaByName(pragmaExpr: NimNode, name: string): NimNode = proc getPragmaNodeFromProcSym(sym: NimNode): NimNode =
if pragmaExpr.kind == nnkPragma:
for it in pragmaExpr:
if it.kind in nnkPragmaCallKinds:
if eqIdent(it[0], name):
return it
elif it.kind == nnkSym:
if eqIdent(it, name):
return it
proc getCustomPragmaNodeFromProcSym(sym: NimNode, name: string): NimNode =
sym.expectKind nnkSym sym.expectKind nnkSym
if sym.symKind != nskProc: error("expected proc sym", sym) if sym.symKind != nskProc: error("expected proc sym", sym)
let impl = sym.getImpl let impl = sym.getImpl
expectKind(impl, nnkProcDef) expectKind(impl, nnkProcDef)
result = getPragmaByName(impl[4], name) result = impl[4]
proc getCustomPragmaNodeFromObjFieldSym(sym: NimNode, name: string): NimNode = proc getPragmaNodeFromObjFieldSym(sym: NimNode): NimNode =
sym.expectKind nnkSym sym.expectKind nnkSym
if sym.symKind != nskField: error("expected field sym", sym) if sym.symKind != nskField: error("expected field sym", sym)
@ -1537,9 +1524,9 @@ proc getCustomPragmaNodeFromObjFieldSym(sym: NimNode, name: string): NimNode =
let recList = objectTy[2] let recList = objectTy[2]
recList.expectKind nnkRecList recList.expectKind nnkRecList
result = getPragmaByName(findPragmaExprForFieldSym(recList, sym), name) result = findPragmaNodeInRecList(recList, sym)
proc getCustomPragmaNodeFromTypeSym(sym: NimNode, name: string): NimNode = proc getPragmaNodeFromTypeSym(sym: NimNode): NimNode =
sym.expectKind nnkSym sym.expectKind nnkSym
if sym.symKind != nskType: error("expected type sym", sym) if sym.symKind != nskType: error("expected type sym", sym)
let impl = sym.getImpl let impl = sym.getImpl
@ -1547,9 +1534,9 @@ proc getCustomPragmaNodeFromTypeSym(sym: NimNode, name: string): NimNode =
impl.expectKind nnkTypeDef impl.expectKind nnkTypeDef
let pragmaExpr = impl[0] let pragmaExpr = impl[0]
if pragmaExpr.kind == nnkPragmaExpr: if pragmaExpr.kind == nnkPragmaExpr:
result = getPragmaByName(pragmaExpr[1], name) result = pragmaExpr[1]
proc getCustomPragmaNodeFromVarLetSym(sym: NimNode, name: string): NimNode = proc getPragmaNodeFromVarLetSym(sym: NimNode): NimNode =
sym.expectKind nnkSym sym.expectKind nnkSym
if sym.symKind notin {nskVar, nskLet}: error("expected var/let sym", sym) if sym.symKind notin {nskVar, nskLet}: error("expected var/let sym", sym)
let impl = sym.getImpl let impl = sym.getImpl
@ -1557,30 +1544,39 @@ proc getCustomPragmaNodeFromVarLetSym(sym: NimNode, name: string): NimNode =
impl.expectLen 3 impl.expectLen 3
let pragmaExpr = impl[0] let pragmaExpr = impl[0]
if pragmaExpr.kind == nnkPragmaExpr: if pragmaExpr.kind == nnkPragmaExpr:
result = getPragmaByName(pragmaExpr[1], name) result = pragmaExpr[1]
proc getPragmaByName(pragmaExpr: NimNode, name: string): NimNode =
if pragmaExpr.kind == nnkPragma:
for it in pragmaExpr:
if it.kind in nnkPragmaCallKinds:
if eqIdent(it[0], name):
return it
elif it.kind == nnkSym:
if eqIdent(it, name):
return it
proc getCustomPragmaNode(sym: NimNode, name: string): NimNode = proc getCustomPragmaNode(sym: NimNode, name: string): NimNode =
sym.expectKind nnkSym sym.expectKind nnkSym
case sym.symKind case sym.symKind
of nskField: of nskField:
result = getCustomPragmaNodeFromObjFieldSym(sym, name) result = getPragmaNodeFromObjFieldSym(sym).getPragmaByName(name)
of nskProc: of nskProc:
result = getCustomPragmaNodeFromProcSym(sym, name) result = getPragmaNodeFromProcSym(sym).getPragmaByName(name)
of nskType: of nskType:
result = getCustomPragmaNodeFromTypeSym(sym, name) result = getPragmaNodeFromTypeSym(sym).getPragmaByName(name)
of nskParam: of nskParam:
# When a typedesc parameter is passed to the macro, it will be of nskParam. # When a typedesc parameter is passed to the macro, it will be of nskParam.
let typeInst = getTypeInst(sym) let typeInst = getTypeInst(sym)
if typeInst.kind == nnkBracketExpr and eqIdent(typeInst[0], "typeDesc"): if typeInst.kind == nnkBracketExpr and eqIdent(typeInst[0], "typeDesc"):
result = getCustomPragmaNodeFromTypeSym(typeInst[1], name) result = getPragmaNodeFromTypeSym(typeInst[1]).getPragmaByName(name)
else: else:
error("illegal sym kind for argument: " & $sym.symKind, sym) error("illegal sym kind for argument: " & $sym.symKind, sym)
of nskVar, nskLet: of nskVar, nskLet:
# I think it is a bad idea to fall back to the typeSym. The API # I think it is a bad idea to fall back to the typeSym. The API
# explicity requests a var/let symbol, not a type symbol. # explicity requests a var/let symbol, not a type symbol.
result = result = getPragmaNodeFromVarLetSym(sym).getPragmaByName(name) or
getCustomPragmaNodeFromVarLetSym(sym, name) or getPragmaNodeFromTypeSym(sym.getTypeInst).getPragmaByName(name)
getCustomPragmaNodeFromTypeSym(sym.getTypeInst, name)
else: else:
error("illegal sym kind for argument: " & $sym.symKind, sym) error("illegal sym kind for argument: " & $sym.symKind, sym)
@ -1639,6 +1635,15 @@ macro hasCustomPragma*(n: typed, cp: typed{nkSym}): bool =
## assert(myProc.hasCustomPragma(myAttr)) ## assert(myProc.hasCustomPragma(myAttr))
result = newLit(getCustomPragmaNodeSmart(n, $cp) != nil) result = newLit(getCustomPragmaNodeSmart(n, $cp) != nil)
iterator iterOverFormalArgs(f: NimNode): tuple[name, typ, val: NimNode] =
f.expectKind nnkFormalParams
for i in 1..<f.len:
f[i].expectKind nnkIdentDefs
let typ = f[i][^2]
let val = f[i][^1]
for j in 0..<f[i].len-2:
yield (f[i][j], typ, val)
macro getCustomPragmaVal*(n: typed, cp: typed{nkSym}): untyped = macro getCustomPragmaVal*(n: typed, cp: typed{nkSym}): untyped =
## Expands to value of custom pragma `cp` of expression `n` which is expected ## Expands to value of custom pragma `cp` of expression `n` which is expected
## to be `nnkDotExpr`, a proc or a type. ## to be `nnkDotExpr`, a proc or a type.
@ -1664,12 +1669,11 @@ macro getCustomPragmaVal*(n: typed, cp: typed{nkSym}): untyped =
result = pragmaNode[1] result = pragmaNode[1]
else: else:
# create a named tuple expression for pragmas with multiple arguments # create a named tuple expression for pragmas with multiple arguments
let def = pragmaNode[0].getImpl[3]
result = newTree(nnkPar) result = newTree(nnkPar)
for i in 1 ..< def.len: var i = 1
let key = def[i][0] for (key, t, v) in iterOverFormalArgs(pragmaNode[0].getImpl[3]):
let val = pragmaNode[i] result.add nnkExprColonExpr.newTree(key, pragmaNode[i])
result.add nnkExprColonExpr.newTree(key, val) inc i
of nnkSym: of nnkSym:
error("The named pragma " & cp.repr & " in " & n.repr & " has no arguments and therefore no value.") error("The named pragma " & cp.repr & " in " & n.repr & " has no arguments and therefore no value.")
else: else:

View file

@ -396,3 +396,12 @@ block:
newLit(hasAttr) newLit(hasAttr)
doAssert hasMyAttr(TObj) doAssert hasMyAttr(TObj)
# misc
{.pragma: haha.}
{.pragma: hoho.}
template hehe(key, val: string, haha) {.pragma.}
type A {.haha, hoho, haha, hehe("hi", "hu", "he").} = int
assert A.getCustomPragmaVal(hehe) == (key: "hi", val: "hu", haha: "he")