Implement custom annotations (#6987)

This commit is contained in:
cooldome 2018-01-09 14:25:22 +00:00 • committed by Andreas Rumpf
commit 2c9e56a783
10 changed files with 254 additions and 42 deletions

View file

@ -17,6 +17,7 @@ import
const
FirstCallConv* = wNimcall
LastCallConv* = wNoconv
nkPragmaCallKinds = {nkExprColonExpr, nkCall, nkCallStrLit}
const
procPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
@ -29,7 +30,7 @@ const
converterPragmas* = procPragmas
methodPragmas* = procPragmas+{wBase}-{wImportCpp}
templatePragmas* = {wImmediate, wDeprecated, wError, wGensym, wInject, wDirty,
wDelegator, wExportNims, wUsed}
wDelegator, wExportNims, wUsed, wPragma}
macroPragmas* = {FirstCallConv..LastCallConv, wImmediate, wImportc, wExportc,
wNodecl, wMagic, wNosideeffect, wCompilerProc, wCore, wDeprecated, wExtern,
wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wDelegator,
@ -74,7 +75,7 @@ proc getPragmaVal*(procAst: PNode; name: TSpecialWord): PNode =
let p = procAst[pragmasPos]
if p.kind == nkEmpty: return nil
for it in p:
if it.kind == nkExprColonExpr and it[0].kind == nkIdent and
if it.kind in nkPragmaCallKinds and it.len == 2 and it[0].kind == nkIdent and
it[0].ident.id == ord(name):
return it[1]
@ -89,7 +90,7 @@ proc pragmaAsm*(c: PContext, n: PNode): char =
if n != nil:
for i in countup(0, sonsLen(n) - 1):
let it = n.sons[i]
if it.kind == nkExprColonExpr and it.sons[0].kind == nkIdent:
if it.kind in nkPragmaCallKinds and it.len == 2 and it.sons[0].kind == nkIdent:
case whichKeyword(it.sons[0].ident)
of wSubsChar:
if it.sons[1].kind == nkCharLit: result = chr(int(it.sons[1].intVal))
@ -151,7 +152,7 @@ proc newEmptyStrNode(n: PNode): PNode {.noinline.} =
result.strVal = ""
proc getStrLitNode(c: PContext, n: PNode): PNode =
if n.kind != nkExprColonExpr:
if n.kind notin nkPragmaCallKinds or n.len != 2:
localError(n.info, errStringLiteralExpected)
# error correction:
result = newEmptyStrNode(n)
@ -168,7 +169,7 @@ proc expectStrLit(c: PContext, n: PNode): string =
result = getStrLitNode(c, n).strVal
proc expectIntLit(c: PContext, n: PNode): int =
if n.kind != nkExprColonExpr:
if n.kind notin nkPragmaCallKinds or n.len != 2:
localError(n.info, errIntLiteralExpected)
else:
n.sons[1] = c.semConstExpr(c, n.sons[1])
@ -177,7 +178,7 @@ proc expectIntLit(c: PContext, n: PNode): int =
else: localError(n.info, errIntLiteralExpected)
proc getOptionalStr(c: PContext, n: PNode, defaultStr: string): string =
if n.kind == nkExprColonExpr: result = expectStrLit(c, n)
if n.kind in nkPragmaCallKinds: result = expectStrLit(c, n)
else: result = defaultStr
proc processCodegenDecl(c: PContext, n: PNode, sym: PSym) =
@ -186,7 +187,7 @@ proc processCodegenDecl(c: PContext, n: PNode, sym: PSym) =
proc processMagic(c: PContext, n: PNode, s: PSym) =
#if sfSystemModule notin c.module.flags:
# liMessage(n.info, errMagicOnlyInSystem)
if n.kind != nkExprColonExpr:
if n.kind notin nkPragmaCallKinds or n.len != 2:
localError(n.info, errStringLiteralExpected)
return
var v: string
@ -204,7 +205,7 @@ proc wordToCallConv(sw: TSpecialWord): TCallingConvention =
result = TCallingConvention(ord(ccDefault) + ord(sw) - ord(wNimcall))
proc isTurnedOn(c: PContext, n: PNode): bool =
if n.kind == nkExprColonExpr:
if n.kind in nkPragmaCallKinds and n.len == 2:
let x = c.semConstBoolExpr(c, n.sons[1])
n.sons[1] = x
if x.kind == nkIntLit: return x.intVal != 0
@ -223,7 +224,7 @@ proc pragmaNoForward(c: PContext, n: PNode; flag=sfNoForward) =
else: excl(c.module.flags, flag)
proc processCallConv(c: PContext, n: PNode) =
if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent):
if n.kind in nkPragmaCallKinds and n.len == 2 and n.sons[1].kind == nkIdent:
var sw = whichKeyword(n.sons[1].ident)
case sw
of FirstCallConv..LastCallConv:
@ -244,7 +245,7 @@ proc getLib(c: PContext, kind: TLibKind, path: PNode): PLib =
result.isOverriden = options.isDynlibOverride(path.strVal)
proc expectDynlibNode(c: PContext, n: PNode): PNode =
if n.kind != nkExprColonExpr:
if n.kind notin nkPragmaCallKinds or n.len != 2:
localError(n.info, errStringLiteralExpected)
# error correction:
result = newEmptyStrNode(n)
@ -264,7 +265,7 @@ proc processDynLib(c: PContext, n: PNode, sym: PSym) =
if not lib.isOverriden:
c.optionStack[^1].dynlib = lib
else:
if n.kind == nkExprColonExpr:
if n.kind in nkPragmaCallKinds:
var lib = getLib(c, libDynamic, expectDynlibNode(c, n))
if not lib.isOverriden:
addToLib(lib, sym)
@ -279,7 +280,7 @@ proc processDynLib(c: PContext, n: PNode, sym: PSym) =
sym.typ.callConv = ccCDecl
proc processNote(c: PContext, n: PNode) =
if (n.kind == nkExprColonExpr) and (sonsLen(n) == 2) and
if (n.kind in nkPragmaCallKinds) and (sonsLen(n) == 2) and
(n.sons[0].kind == nkBracketExpr) and
(n.sons[0].sons.len == 2) and
(n.sons[0].sons[1].kind == nkIdent) and
@ -307,7 +308,7 @@ proc processNote(c: PContext, n: PNode) =
invalidPragma(n)
proc processOption(c: PContext, n: PNode): bool =
if n.kind != nkExprColonExpr: result = true
if n.kind notin nkPragmaCallKinds or n.len != 2: result = true
elif n.sons[0].kind == nkBracketExpr: processNote(c, n)
elif n.sons[0].kind != nkIdent: result = true
else:
@ -355,8 +356,8 @@ proc processOption(c: PContext, n: PNode): bool =
else: result = true
proc processPush(c: PContext, n: PNode, start: int) =
if n.sons[start-1].kind == nkExprColonExpr:
localError(n.info, errGenerated, "':' after 'push' not supported")
if n.sons[start-1].kind in nkPragmaCallKinds:
localError(n.info, errGenerated, "'push' can't have arguments")
var x = newOptionEntry()
var y = c.optionStack[^1]
x.options = gOptions
@ -381,14 +382,14 @@ proc processPop(c: PContext, n: PNode) =
c.optionStack.setLen(c.optionStack.len - 1)
proc processDefine(c: PContext, n: PNode) =
if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent):
if (n.kind in nkPragmaCallKinds and n.len == 2) and (n.sons[1].kind == nkIdent):
defineSymbol(n.sons[1].ident.s)
message(n.info, warnDeprecated, "define")
else:
invalidPragma(n)
proc processUndef(c: PContext, n: PNode) =
if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent):
if (n.kind in nkPragmaCallKinds and n.len == 2) and (n.sons[1].kind == nkIdent):
undefSymbol(n.sons[1].ident.s)
message(n.info, warnDeprecated, "undef")
else:
@ -420,7 +421,7 @@ proc processCompile(c: PContext, n: PNode) =
localError(n.info, errStringLiteralExpected)
result = ""
let it = if n.kind == nkExprColonExpr: n.sons[1] else: n
let it = if n.kind in nkPragmaCallKinds and n.len == 2: n.sons[1] else: n
if it.kind == nkPar and it.len == 2:
let s = getStrLit(c, it, 0)
let dest = getStrLit(c, it, 1)
@ -453,7 +454,7 @@ proc pragmaBreakpoint(c: PContext, n: PNode) =
discard getOptionalStr(c, n, "")
proc pragmaWatchpoint(c: PContext, n: PNode) =
if n.kind == nkExprColonExpr:
if n.kind in nkPragmaCallKinds and n.len == 2:
n.sons[1] = c.semExpr(c, n.sons[1])
else:
invalidPragma(n)
@ -494,7 +495,7 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
result = newNode(nkAsmStmt, n.info)
proc pragmaEmit(c: PContext, n: PNode) =
if n.kind != nkExprColonExpr:
if n.kind notin nkPragmaCallKinds or n.len != 2:
localError(n.info, errStringLiteralExpected)
else:
let n1 = n[1]
@ -512,12 +513,12 @@ proc pragmaEmit(c: PContext, n: PNode) =
localError(n.info, errStringLiteralExpected)
proc noVal(n: PNode) =
if n.kind == nkExprColonExpr: invalidPragma(n)
if n.kind in nkPragmaCallKinds and n.len > 1: invalidPragma(n)
proc pragmaUnroll(c: PContext, n: PNode) =
if c.p.nestedLoopCounter <= 0:
invalidPragma(n)
elif n.kind == nkExprColonExpr:
elif n.kind in nkPragmaCallKinds and n.len == 2:
var unrollFactor = expectIntLit(c, n)
if unrollFactor <% 32:
n.sons[1] = newIntNode(nkIntLit, unrollFactor)
@ -525,10 +526,11 @@ proc pragmaUnroll(c: PContext, n: PNode) =
invalidPragma(n)
proc pragmaLine(c: PContext, n: PNode) =
if n.kind == nkExprColonExpr:
if n.kind in nkPragmaCallKinds and n.len == 2:
n.sons[1] = c.semConstExpr(c, n.sons[1])
let a = n.sons[1]
if a.kind == nkPar:
# unpack the tuple
var x = a.sons[0]
var y = a.sons[1]
if x.kind == nkExprColonExpr: x = x.sons[1]
@ -549,7 +551,7 @@ proc pragmaLine(c: PContext, n: PNode) =
proc processPragma(c: PContext, n: PNode, i: int) =
var it = n.sons[i]
if it.kind != nkExprColonExpr: invalidPragma(n)
if it.kind notin nkPragmaCallKinds and it.len == 2: invalidPragma(n)
elif it.sons[0].kind != nkIdent: invalidPragma(n)
elif it.sons[1].kind != nkIdent: invalidPragma(n)
@ -566,7 +568,7 @@ proc pragmaRaisesOrTags(c: PContext, n: PNode) =
localError(x.info, errGenerated, "invalid type for raises/tags list")
x.typ = t
if n.kind == nkExprColonExpr:
if n.kind in nkPragmaCallKinds and n.len == 2:
let it = n.sons[1]
if it.kind notin {nkCurly, nkBracket}:
processExc(c, it)
@ -576,7 +578,7 @@ proc pragmaRaisesOrTags(c: PContext, n: PNode) =
invalidPragma(n)
proc pragmaLockStmt(c: PContext; it: PNode) =
if it.kind != nkExprColonExpr:
if it.kind notin nkPragmaCallKinds or it.len != 2:
invalidPragma(it)
else:
let n = it[1]
@ -587,7 +589,7 @@ proc pragmaLockStmt(c: PContext; it: PNode) =
n.sons[i] = c.semExpr(c, n.sons[i])
proc pragmaLocks(c: PContext, it: PNode): TLockLevel =
if it.kind != nkExprColonExpr:
if it.kind notin nkPragmaCallKinds or it.len != 2:
invalidPragma(it)
else:
case it[1].kind
@ -604,7 +606,7 @@ proc pragmaLocks(c: PContext, it: PNode): TLockLevel =
result = TLockLevel(x)
proc typeBorrow(sym: PSym, n: PNode) =
if n.kind == nkExprColonExpr:
if n.kind in nkPragmaCallKinds and n.len == 2:
let it = n.sons[1]
if it.kind != nkAccQuoted:
localError(n.info, "a type can only borrow `.` for now")
@ -624,7 +626,7 @@ proc deprecatedStmt(c: PContext; pragma: PNode) =
if pragma.kind != nkBracket:
localError(pragma.info, "list of key:value pairs expected"); return
for n in pragma:
if n.kind in {nkExprColonExpr, nkExprEqExpr}:
if n.kind in nkPragmaCallKinds and n.len == 2:
let dest = qualifiedLookUp(c, n[1], {checkUndeclared})
if dest == nil or dest.kind in routineKinds:
localError(n.info, warnUser, "the .deprecated pragma is unreliable for routines")
@ -638,7 +640,7 @@ proc deprecatedStmt(c: PContext; pragma: PNode) =
localError(n.info, "key:value pair expected")
proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
if it.kind != nkExprColonExpr:
if it.kind notin nkPragmaCallKinds or it.len != 2:
invalidPragma(it); return
let n = it[1]
if n.kind == nkSym:
@ -655,13 +657,36 @@ proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
else:
result = qualifiedLookUp(c, n, {checkUndeclared})
proc semCustomPragma(c: PContext, n: PNode): PNode =
assert(n.kind in nkPragmaCallKinds + {nkIdent})
if n.kind == nkIdent:
result = newTree(nkCall, n)
elif n.kind == nkExprColonExpr:
# pragma: arg -> pragma(arg)
result = newTree(nkCall, n[0], n[1])
else:
result = n
result = c.semOverloadedCall(c, result, n, {skTemplate}, {})
if sfCustomPragma notin result[0].sym.flags:
invalidPragma(n)
if n.kind == nkIdent:
result = result[0]
elif n.kind == nkExprColonExpr:
result.kind = n.kind # pragma(arg) -> pragma: arg
proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
validPragmas: TSpecialWords): bool =
var it = n.sons[i]
var key = if it.kind == nkExprColonExpr: it.sons[0] else: it
var key = if it.kind in nkPragmaCallKinds and it.len > 1: it.sons[0] else: it
if key.kind == nkBracketExpr:
processNote(c, it)
return
elif key.kind notin nkIdentKinds:
n.sons[i] = semCustomPragma(c, it)
return
let ident = considerQuotedIdent(key)
var userPragma = strTableGet(c.userPragmas, ident)
if userPragma != nil:
@ -785,7 +810,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
of wExplain:
sym.flags.incl sfExplain
of wDeprecated:
if it.kind == nkExprColonExpr: deprecatedStmt(c, it)
if it.kind in nkPragmaCallKinds: deprecatedStmt(c, it)
elif sym != nil: incl(sym.flags, sfDeprecated)
else: incl(c.module.flags, sfDeprecated)
of wVarargs:
@ -864,8 +889,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
result = true
of wPop: processPop(c, it)
of wPragma:
processPragma(c, n, i)
result = true
if not sym.isNil and sym.kind == skTemplate:
sym.flags.incl sfCustomPragma
else:
processPragma(c, n, i)
result = true
of wDiscardable:
noVal(it)
if sym != nil: incl(sym.flags, sfDiscardable)
@ -939,7 +967,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
elif sym.typ == nil: invalidPragma(it)
else: sym.typ.lockLevel = pragmaLocks(c, it)
of wBitsize:
if sym == nil or sym.kind != skField or it.kind != nkExprColonExpr:
if sym == nil or sym.kind != skField:
invalidPragma(it)
else:
sym.bitsize = expectIntLit(c, it)
@ -957,7 +985,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
if sym == nil: invalidPragma(it)
else: magicsys.registerNimScriptSymbol(sym)
of wInjectStmt:
if it.kind != nkExprColonExpr:
if it.kind notin nkPragmaCallKinds or it.len != 2:
localError(it.info, errExprExpected)
else:
it.sons[1] = c.semExpr(c, it.sons[1])
@ -968,10 +996,12 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
else:
localError(it.info, "'experimental' pragma only valid as toplevel statement")
of wThis:
if it.kind == nkExprColonExpr:
if it.kind in nkPragmaCallKinds and it.len == 2:
c.selfName = considerQuotedIdent(it[1])
else:
elif it.kind == nkIdent or it.len == 1:
c.selfName = getIdent("self")
else:
localError(it.info, "'this' pragma is allowed to have zero or one arguments")
of wNoRewrite:
noVal(it)
of wBase:
@ -987,7 +1017,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
else: sym.flags.incl sfUsed
of wLiftLocals: discard
else: invalidPragma(it)
else: invalidPragma(it)
else:
n.sons[i] = semCustomPragma(c, it)
proc implicitPragmas*(c: PContext, sym: PSym, n: PNode,
validPragmas: TSpecialWords) =
@ -1015,7 +1047,7 @@ proc hasPragma*(n: PNode, pragma: TSpecialWord): bool =
return false
for p in n.sons:
var key = if p.kind == nkExprColonExpr: p[0] else: p
var key = if p.kind in nkPragmaCallKinds and p.len > 1: p[0] else: p
if key.kind == nkIdent and whichKeyword(key.ident) == pragma:
return true