pragmas.nim 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2015 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. # This module implements semantic checking for pragmas
  10. import
  11. os, platform, condsyms, ast, astalgo, idents, semdata, msgs, renderer,
  12. wordrecg, ropes, options, strutils, extccomp, math, magicsys, trees,
  13. rodread, types, lookups
  14. const
  15. FirstCallConv* = wNimcall
  16. LastCallConv* = wNoconv
  17. const
  18. procPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
  19. wMagic, wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
  20. wCompilerproc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
  21. wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
  22. wAsmNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wCodegenDecl,
  23. wGensym, wInject, wRaises, wTags, wLocks, wDelegator, wGcSafe,
  24. wOverride, wConstructor, wExportNims, wUsed}
  25. converterPragmas* = procPragmas
  26. methodPragmas* = procPragmas+{wBase}-{wImportCpp}
  27. templatePragmas* = {wImmediate, wDeprecated, wError, wGensym, wInject, wDirty,
  28. wDelegator, wExportNims, wUsed}
  29. macroPragmas* = {FirstCallConv..LastCallConv, wImmediate, wImportc, wExportc,
  30. wNodecl, wMagic, wNosideeffect, wCompilerproc, wDeprecated, wExtern,
  31. wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wDelegator,
  32. wExportNims, wUsed}
  33. iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideeffect, wSideeffect,
  34. wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
  35. wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises,
  36. wTags, wLocks, wGcSafe, wExportNims, wUsed}
  37. exprPragmas* = {wLine, wLocks, wNoRewrite, wGcSafe}
  38. stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
  39. wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
  40. wLinedir, wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError,
  41. wFatal, wDefine, wUndef, wCompile, wLink, wLinksys, wPure, wPush, wPop,
  42. wBreakpoint, wWatchPoint, wPassl, wPassc, wDeadCodeElim, wDeprecated,
  43. wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
  44. wLinearScanEnd, wPatterns, wEffects, wNoForward, wReorder, wComputedGoto,
  45. wInjectStmt, wDeprecated, wExperimental, wThis}
  46. lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
  47. wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
  48. wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame,
  49. wRaises, wLocks, wTags, wGcSafe}
  50. typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
  51. wPure, wHeader, wCompilerproc, wFinal, wSize, wExtern, wShallow,
  52. wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef,
  53. wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
  54. wBorrow, wGcSafe, wExportNims, wPartial, wUsed, wExplain}
  55. fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
  56. wImportCpp, wImportObjC, wError, wGuard, wBitsize, wUsed}
  57. varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
  58. wMagic, wHeader, wDeprecated, wCompilerproc, wDynlib, wExtern,
  59. wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal,
  60. wGensym, wInject, wCodegenDecl, wGuard, wGoto, wExportNims, wUsed}
  61. constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
  62. wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject, wExportNims,
  63. wIntDefine, wStrDefine, wUsed}
  64. letPragmas* = varPragmas
  65. procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect,
  66. wThread, wRaises, wLocks, wTags, wGcSafe}
  67. allRoutinePragmas* = methodPragmas + iteratorPragmas + lambdaPragmas
  68. proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)
  69. # implementation
  70. proc invalidPragma*(n: PNode) =
  71. localError(n.info, errInvalidPragmaX, renderTree(n, {renderNoComments}))
  72. proc pragmaAsm*(c: PContext, n: PNode): char =
  73. result = '\0'
  74. if n != nil:
  75. for i in countup(0, sonsLen(n) - 1):
  76. let it = n.sons[i]
  77. if it.kind == nkExprColonExpr and it.sons[0].kind == nkIdent:
  78. case whichKeyword(it.sons[0].ident)
  79. of wSubsChar:
  80. if it.sons[1].kind == nkCharLit: result = chr(int(it.sons[1].intVal))
  81. else: invalidPragma(it)
  82. else: invalidPragma(it)
  83. else:
  84. invalidPragma(it)
  85. proc setExternName(s: PSym, extname: string, info: TLineInfo) =
  86. # special cases to improve performance:
  87. if extname == "$1":
  88. s.loc.r = rope(s.name.s)
  89. elif '$' notin extname:
  90. s.loc.r = rope(extname)
  91. else:
  92. try:
  93. s.loc.r = rope(extname % s.name.s)
  94. except ValueError:
  95. localError(info, "invalid extern name: '" & extname & "'. (Forgot to escape '$'?)")
  96. if gCmd == cmdPretty and '$' notin extname:
  97. # note that '{.importc.}' is transformed into '{.importc: "$1".}'
  98. s.loc.flags.incl(lfFullExternalName)
  99. proc makeExternImport(s: PSym, extname: string, info: TLineInfo) =
  100. setExternName(s, extname, info)
  101. incl(s.flags, sfImportc)
  102. excl(s.flags, sfForward)
  103. proc makeExternExport(s: PSym, extname: string, info: TLineInfo) =
  104. setExternName(s, extname, info)
  105. incl(s.flags, sfExportc)
  106. proc processImportCompilerProc(s: PSym, extname: string, info: TLineInfo) =
  107. setExternName(s, extname, info)
  108. incl(s.flags, sfImportc)
  109. excl(s.flags, sfForward)
  110. incl(s.loc.flags, lfImportCompilerProc)
  111. proc processImportCpp(s: PSym, extname: string, info: TLineInfo) =
  112. setExternName(s, extname, info)
  113. incl(s.flags, sfImportc)
  114. incl(s.flags, sfInfixCall)
  115. excl(s.flags, sfForward)
  116. if gCmd == cmdCompileToC:
  117. let m = s.getModule()
  118. incl(m.flags, sfCompileToCpp)
  119. extccomp.gMixedMode = true
  120. proc processImportObjC(s: PSym, extname: string, info: TLineInfo) =
  121. setExternName(s, extname, info)
  122. incl(s.flags, sfImportc)
  123. incl(s.flags, sfNamedParamCall)
  124. excl(s.flags, sfForward)
  125. let m = s.getModule()
  126. incl(m.flags, sfCompileToObjC)
  127. proc newEmptyStrNode(n: PNode): PNode {.noinline.} =
  128. result = newNodeIT(nkStrLit, n.info, getSysType(tyString))
  129. result.strVal = ""
  130. proc getStrLitNode(c: PContext, n: PNode): PNode =
  131. if n.kind != nkExprColonExpr:
  132. localError(n.info, errStringLiteralExpected)
  133. # error correction:
  134. result = newEmptyStrNode(n)
  135. else:
  136. n.sons[1] = c.semConstExpr(c, n.sons[1])
  137. case n.sons[1].kind
  138. of nkStrLit, nkRStrLit, nkTripleStrLit: result = n.sons[1]
  139. else:
  140. localError(n.info, errStringLiteralExpected)
  141. # error correction:
  142. result = newEmptyStrNode(n)
  143. proc expectStrLit(c: PContext, n: PNode): string =
  144. result = getStrLitNode(c, n).strVal
  145. proc expectIntLit(c: PContext, n: PNode): int =
  146. if n.kind != nkExprColonExpr:
  147. localError(n.info, errIntLiteralExpected)
  148. else:
  149. n.sons[1] = c.semConstExpr(c, n.sons[1])
  150. case n.sons[1].kind
  151. of nkIntLit..nkInt64Lit: result = int(n.sons[1].intVal)
  152. else: localError(n.info, errIntLiteralExpected)
  153. proc getOptionalStr(c: PContext, n: PNode, defaultStr: string): string =
  154. if n.kind == nkExprColonExpr: result = expectStrLit(c, n)
  155. else: result = defaultStr
  156. proc processCodegenDecl(c: PContext, n: PNode, sym: PSym) =
  157. sym.constraint = getStrLitNode(c, n)
  158. proc processMagic(c: PContext, n: PNode, s: PSym) =
  159. #if sfSystemModule notin c.module.flags:
  160. # liMessage(n.info, errMagicOnlyInSystem)
  161. if n.kind != nkExprColonExpr:
  162. localError(n.info, errStringLiteralExpected)
  163. return
  164. var v: string
  165. if n.sons[1].kind == nkIdent: v = n.sons[1].ident.s
  166. else: v = expectStrLit(c, n)
  167. for m in countup(low(TMagic), high(TMagic)):
  168. if substr($m, 1) == v:
  169. s.magic = m
  170. break
  171. if s.magic == mNone: message(n.info, warnUnknownMagic, v)
  172. proc wordToCallConv(sw: TSpecialWord): TCallingConvention =
  173. # this assumes that the order of special words and calling conventions is
  174. # the same
  175. result = TCallingConvention(ord(ccDefault) + ord(sw) - ord(wNimcall))
  176. proc isTurnedOn(c: PContext, n: PNode): bool =
  177. if n.kind == nkExprColonExpr:
  178. let x = c.semConstBoolExpr(c, n.sons[1])
  179. n.sons[1] = x
  180. if x.kind == nkIntLit: return x.intVal != 0
  181. localError(n.info, errOnOrOffExpected)
  182. proc onOff(c: PContext, n: PNode, op: TOptions) =
  183. if isTurnedOn(c, n): gOptions = gOptions + op
  184. else: gOptions = gOptions - op
  185. proc pragmaDeadCodeElim(c: PContext, n: PNode) =
  186. if isTurnedOn(c, n): incl(c.module.flags, sfDeadCodeElim)
  187. else: excl(c.module.flags, sfDeadCodeElim)
  188. proc pragmaNoForward(c: PContext, n: PNode; flag=sfNoForward) =
  189. if isTurnedOn(c, n): incl(c.module.flags, flag)
  190. else: excl(c.module.flags, flag)
  191. proc processCallConv(c: PContext, n: PNode) =
  192. if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent):
  193. var sw = whichKeyword(n.sons[1].ident)
  194. case sw
  195. of FirstCallConv..LastCallConv:
  196. c.optionStack[^1].defaultCC = wordToCallConv(sw)
  197. else: localError(n.info, errCallConvExpected)
  198. else:
  199. localError(n.info, errCallConvExpected)
  200. proc getLib(c: PContext, kind: TLibKind, path: PNode): PLib =
  201. for it in c.libs:
  202. if it.kind == kind and trees.exprStructuralEquivalent(it.path, path):
  203. return it
  204. result = newLib(kind)
  205. result.path = path
  206. c.libs.add result
  207. if path.kind in {nkStrLit..nkTripleStrLit}:
  208. result.isOverriden = options.isDynlibOverride(path.strVal)
  209. proc expectDynlibNode(c: PContext, n: PNode): PNode =
  210. if n.kind != nkExprColonExpr:
  211. localError(n.info, errStringLiteralExpected)
  212. # error correction:
  213. result = newEmptyStrNode(n)
  214. else:
  215. # For the OpenGL wrapper we support:
  216. # {.dynlib: myGetProcAddr(...).}
  217. result = c.semExpr(c, n.sons[1])
  218. if result.kind == nkSym and result.sym.kind == skConst:
  219. result = result.sym.ast # look it up
  220. if result.typ == nil or result.typ.kind notin {tyPointer, tyString, tyProc}:
  221. localError(n.info, errStringLiteralExpected)
  222. result = newEmptyStrNode(n)
  223. proc processDynLib(c: PContext, n: PNode, sym: PSym) =
  224. if (sym == nil) or (sym.kind == skModule):
  225. let lib = getLib(c, libDynamic, expectDynlibNode(c, n))
  226. if not lib.isOverriden:
  227. c.optionStack[^1].dynlib = lib
  228. else:
  229. if n.kind == nkExprColonExpr:
  230. var lib = getLib(c, libDynamic, expectDynlibNode(c, n))
  231. if not lib.isOverriden:
  232. addToLib(lib, sym)
  233. incl(sym.loc.flags, lfDynamicLib)
  234. else:
  235. incl(sym.loc.flags, lfExportLib)
  236. # since we'll be loading the dynlib symbols dynamically, we must use
  237. # a calling convention that doesn't introduce custom name mangling
  238. # cdecl is the default - the user can override this explicitly
  239. if sym.kind in routineKinds and sym.typ != nil and
  240. sym.typ.callConv == ccDefault:
  241. sym.typ.callConv = ccCDecl
  242. proc processNote(c: PContext, n: PNode) =
  243. if (n.kind == nkExprColonExpr) and (sonsLen(n) == 2) and
  244. (n.sons[0].kind == nkBracketExpr) and
  245. (n.sons[0].sons.len == 2) and
  246. (n.sons[0].sons[1].kind == nkIdent) and
  247. (n.sons[0].sons[0].kind == nkIdent):
  248. #and (n.sons[1].kind == nkIdent):
  249. var nk: TNoteKind
  250. case whichKeyword(n.sons[0].sons[0].ident)
  251. of wHint:
  252. var x = findStr(msgs.HintsToStr, n.sons[0].sons[1].ident.s)
  253. if x >= 0: nk = TNoteKind(x + ord(hintMin))
  254. else: invalidPragma(n); return
  255. of wWarning:
  256. var x = findStr(msgs.WarningsToStr, n.sons[0].sons[1].ident.s)
  257. if x >= 0: nk = TNoteKind(x + ord(warnMin))
  258. else: invalidPragma(n); return
  259. else:
  260. invalidPragma(n)
  261. return
  262. let x = c.semConstBoolExpr(c, n.sons[1])
  263. n.sons[1] = x
  264. if x.kind == nkIntLit and x.intVal != 0: incl(gNotes, nk)
  265. else: excl(gNotes, nk)
  266. else:
  267. invalidPragma(n)
  268. proc processOption(c: PContext, n: PNode): bool =
  269. if n.kind != nkExprColonExpr: result = true
  270. elif n.sons[0].kind == nkBracketExpr: processNote(c, n)
  271. elif n.sons[0].kind != nkIdent: result = true
  272. else:
  273. var sw = whichKeyword(n.sons[0].ident)
  274. case sw
  275. of wChecks: onOff(c, n, ChecksOptions)
  276. of wObjChecks: onOff(c, n, {optObjCheck})
  277. of wFieldChecks: onOff(c, n, {optFieldCheck})
  278. of wRangechecks: onOff(c, n, {optRangeCheck})
  279. of wBoundchecks: onOff(c, n, {optBoundsCheck})
  280. of wOverflowchecks: onOff(c, n, {optOverflowCheck})
  281. of wNilchecks: onOff(c, n, {optNilCheck})
  282. of wFloatchecks: onOff(c, n, {optNaNCheck, optInfCheck})
  283. of wNanChecks: onOff(c, n, {optNaNCheck})
  284. of wInfChecks: onOff(c, n, {optInfCheck})
  285. of wAssertions: onOff(c, n, {optAssert})
  286. of wWarnings: onOff(c, n, {optWarns})
  287. of wHints: onOff(c, n, {optHints})
  288. of wCallconv: processCallConv(c, n)
  289. of wLinedir: onOff(c, n, {optLineDir})
  290. of wStacktrace: onOff(c, n, {optStackTrace})
  291. of wLinetrace: onOff(c, n, {optLineTrace})
  292. of wDebugger: onOff(c, n, {optEndb})
  293. of wProfiler: onOff(c, n, {optProfiler, optMemTracker})
  294. of wMemTracker: onOff(c, n, {optMemTracker})
  295. of wByRef: onOff(c, n, {optByRef})
  296. of wDynlib: processDynLib(c, n, nil)
  297. of wOptimization:
  298. if n.sons[1].kind != nkIdent:
  299. invalidPragma(n)
  300. else:
  301. case n.sons[1].ident.s.normalize
  302. of "speed":
  303. incl(gOptions, optOptimizeSpeed)
  304. excl(gOptions, optOptimizeSize)
  305. of "size":
  306. excl(gOptions, optOptimizeSpeed)
  307. incl(gOptions, optOptimizeSize)
  308. of "none":
  309. excl(gOptions, optOptimizeSpeed)
  310. excl(gOptions, optOptimizeSize)
  311. else: localError(n.info, errNoneSpeedOrSizeExpected)
  312. of wImplicitStatic: onOff(c, n, {optImplicitStatic})
  313. of wPatterns: onOff(c, n, {optPatterns})
  314. else: result = true
  315. proc processPush(c: PContext, n: PNode, start: int) =
  316. if n.sons[start-1].kind == nkExprColonExpr:
  317. localError(n.info, errGenerated, "':' after 'push' not supported")
  318. var x = newOptionEntry()
  319. var y = c.optionStack[^1]
  320. x.options = gOptions
  321. x.defaultCC = y.defaultCC
  322. x.dynlib = y.dynlib
  323. x.notes = gNotes
  324. c.optionStack.add(x)
  325. for i in countup(start, sonsLen(n) - 1):
  326. if processOption(c, n.sons[i]):
  327. # simply store it somewhere:
  328. if x.otherPragmas.isNil:
  329. x.otherPragmas = newNodeI(nkPragma, n.info)
  330. x.otherPragmas.add n.sons[i]
  331. #localError(n.info, errOptionExpected)
  332. proc processPop(c: PContext, n: PNode) =
  333. if c.optionStack.len <= 1:
  334. localError(n.info, errAtPopWithoutPush)
  335. else:
  336. gOptions = c.optionStack[^1].options
  337. gNotes = c.optionStack[^1].notes
  338. c.optionStack.setLen(c.optionStack.len - 1)
  339. proc processDefine(c: PContext, n: PNode) =
  340. if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent):
  341. defineSymbol(n.sons[1].ident.s)
  342. message(n.info, warnDeprecated, "define")
  343. else:
  344. invalidPragma(n)
  345. proc processUndef(c: PContext, n: PNode) =
  346. if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent):
  347. undefSymbol(n.sons[1].ident.s)
  348. message(n.info, warnDeprecated, "undef")
  349. else:
  350. invalidPragma(n)
  351. type
  352. TLinkFeature = enum
  353. linkNormal, linkSys
  354. proc relativeFile(c: PContext; n: PNode; ext=""): string =
  355. var s = expectStrLit(c, n)
  356. if ext.len > 0 and splitFile(s).ext == "":
  357. s = addFileExt(s, ext)
  358. result = parentDir(n.info.toFullPath) / s
  359. if not fileExists(result):
  360. if isAbsolute(s): result = s
  361. else:
  362. result = findFile(s)
  363. if result.len == 0: result = s
  364. proc processCompile(c: PContext, n: PNode) =
  365. proc getStrLit(c: PContext, n: PNode; i: int): string =
  366. n.sons[i] = c.semConstExpr(c, n.sons[i])
  367. case n.sons[i].kind
  368. of nkStrLit, nkRStrLit, nkTripleStrLit:
  369. shallowCopy(result, n.sons[i].strVal)
  370. else:
  371. localError(n.info, errStringLiteralExpected)
  372. result = ""
  373. let it = if n.kind == nkExprColonExpr: n.sons[1] else: n
  374. if it.kind == nkPar and it.len == 2:
  375. let s = getStrLit(c, it, 0)
  376. let dest = getStrLit(c, it, 1)
  377. var found = parentDir(n.info.toFullPath) / s
  378. for f in os.walkFiles(found):
  379. let nameOnly = extractFilename(f)
  380. var cf = Cfile(cname: f,
  381. obj: completeCFilePath(dest % nameOnly),
  382. flags: {CfileFlag.External})
  383. extccomp.addExternalFileToCompile(cf)
  384. else:
  385. let s = expectStrLit(c, n)
  386. var found = parentDir(n.info.toFullPath) / s
  387. if not fileExists(found):
  388. if isAbsolute(s): found = s
  389. else:
  390. found = findFile(s)
  391. if found.len == 0: found = s
  392. extccomp.addExternalFileToCompile(found)
  393. proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) =
  394. let found = relativeFile(c, n, CC[cCompiler].objExt)
  395. case feature
  396. of linkNormal: extccomp.addExternalFileToLink(found)
  397. of linkSys:
  398. extccomp.addExternalFileToLink(libpath / completeCFilePath(found, false))
  399. else: internalError(n.info, "processCommonLink")
  400. proc pragmaBreakpoint(c: PContext, n: PNode) =
  401. discard getOptionalStr(c, n, "")
  402. proc pragmaWatchpoint(c: PContext, n: PNode) =
  403. if n.kind == nkExprColonExpr:
  404. n.sons[1] = c.semExpr(c, n.sons[1])
  405. else:
  406. invalidPragma(n)
  407. proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
  408. case n.sons[1].kind
  409. of nkStrLit, nkRStrLit, nkTripleStrLit:
  410. result = newNode(if n.kind == nkAsmStmt: nkAsmStmt else: nkArgList, n.info)
  411. var str = n.sons[1].strVal
  412. if str == "":
  413. localError(n.info, errEmptyAsm)
  414. return
  415. # now parse the string literal and substitute symbols:
  416. var a = 0
  417. while true:
  418. var b = strutils.find(str, marker, a)
  419. var sub = if b < 0: substr(str, a) else: substr(str, a, b - 1)
  420. if sub != "": addSon(result, newStrNode(nkStrLit, sub))
  421. if b < 0: break
  422. var c = strutils.find(str, marker, b + 1)
  423. if c < 0: sub = substr(str, b + 1)
  424. else: sub = substr(str, b + 1, c - 1)
  425. if sub != "":
  426. var e = searchInScopes(con, getIdent(sub))
  427. if e != nil:
  428. if e.kind == skStub: loadStub(e)
  429. incl(e.flags, sfUsed)
  430. addSon(result, newSymNode(e))
  431. else:
  432. addSon(result, newStrNode(nkStrLit, sub))
  433. else:
  434. # an empty '``' produces a single '`'
  435. addSon(result, newStrNode(nkStrLit, $marker))
  436. if c < 0: break
  437. a = c + 1
  438. else:
  439. illFormedAstLocal(n)
  440. result = newNode(nkAsmStmt, n.info)
  441. proc pragmaEmit(c: PContext, n: PNode) =
  442. if n.kind != nkExprColonExpr:
  443. localError(n.info, errStringLiteralExpected)
  444. else:
  445. let n1 = n[1]
  446. if n1.kind == nkBracket:
  447. var b = newNodeI(nkBracket, n1.info, n1.len)
  448. for i in 0..<n1.len:
  449. b.sons[i] = c.semExpr(c, n1[i])
  450. n.sons[1] = b
  451. else:
  452. n.sons[1] = c.semConstExpr(c, n1)
  453. case n.sons[1].kind
  454. of nkStrLit, nkRStrLit, nkTripleStrLit:
  455. n.sons[1] = semAsmOrEmit(c, n, '`')
  456. else:
  457. localError(n.info, errStringLiteralExpected)
  458. proc noVal(n: PNode) =
  459. if n.kind == nkExprColonExpr: invalidPragma(n)
  460. proc pragmaUnroll(c: PContext, n: PNode) =
  461. if c.p.nestedLoopCounter <= 0:
  462. invalidPragma(n)
  463. elif n.kind == nkExprColonExpr:
  464. var unrollFactor = expectIntLit(c, n)
  465. if unrollFactor <% 32:
  466. n.sons[1] = newIntNode(nkIntLit, unrollFactor)
  467. else:
  468. invalidPragma(n)
  469. proc pragmaLine(c: PContext, n: PNode) =
  470. if n.kind == nkExprColonExpr:
  471. n.sons[1] = c.semConstExpr(c, n.sons[1])
  472. let a = n.sons[1]
  473. if a.kind == nkPar:
  474. var x = a.sons[0]
  475. var y = a.sons[1]
  476. if x.kind == nkExprColonExpr: x = x.sons[1]
  477. if y.kind == nkExprColonExpr: y = y.sons[1]
  478. if x.kind != nkStrLit:
  479. localError(n.info, errStringLiteralExpected)
  480. elif y.kind != nkIntLit:
  481. localError(n.info, errIntLiteralExpected)
  482. else:
  483. # XXX this produces weird paths which are not properly resolved:
  484. n.info.fileIndex = msgs.fileInfoIdx(x.strVal)
  485. n.info.line = int16(y.intVal)
  486. else:
  487. localError(n.info, errXExpected, "tuple")
  488. else:
  489. # sensible default:
  490. n.info = getInfoContext(-1)
  491. proc processPragma(c: PContext, n: PNode, i: int) =
  492. var it = n.sons[i]
  493. if it.kind != nkExprColonExpr: invalidPragma(n)
  494. elif it.sons[0].kind != nkIdent: invalidPragma(n)
  495. elif it.sons[1].kind != nkIdent: invalidPragma(n)
  496. var userPragma = newSym(skTemplate, it.sons[1].ident, nil, it.info)
  497. var body = newNodeI(nkPragma, n.info)
  498. for j in i+1 .. sonsLen(n)-1: addSon(body, n.sons[j])
  499. userPragma.ast = body
  500. strTableAdd(c.userPragmas, userPragma)
  501. proc pragmaRaisesOrTags(c: PContext, n: PNode) =
  502. proc processExc(c: PContext, x: PNode) =
  503. var t = skipTypes(c.semTypeNode(c, x, nil), skipPtrs)
  504. if t.kind != tyObject:
  505. localError(x.info, errGenerated, "invalid type for raises/tags list")
  506. x.typ = t
  507. if n.kind == nkExprColonExpr:
  508. let it = n.sons[1]
  509. if it.kind notin {nkCurly, nkBracket}:
  510. processExc(c, it)
  511. else:
  512. for e in items(it): processExc(c, e)
  513. else:
  514. invalidPragma(n)
  515. proc pragmaLockStmt(c: PContext; it: PNode) =
  516. if it.kind != nkExprColonExpr:
  517. invalidPragma(it)
  518. else:
  519. let n = it[1]
  520. if n.kind != nkBracket:
  521. localError(n.info, errGenerated, "locks pragma takes a list of expressions")
  522. else:
  523. for i in 0 .. <n.len:
  524. n.sons[i] = c.semExpr(c, n.sons[i])
  525. proc pragmaLocks(c: PContext, it: PNode): TLockLevel =
  526. if it.kind != nkExprColonExpr:
  527. invalidPragma(it)
  528. else:
  529. case it[1].kind
  530. of nkStrLit, nkRStrLit, nkTripleStrLit:
  531. if it[1].strVal == "unknown":
  532. result = UnknownLockLevel
  533. else:
  534. localError(it[1].info, "invalid string literal for locks pragma (only allowed string is \"unknown\")")
  535. else:
  536. let x = expectIntLit(c, it)
  537. if x < 0 or x > MaxLockLevel:
  538. localError(it[1].info, "integer must be within 0.." & $MaxLockLevel)
  539. else:
  540. result = TLockLevel(x)
  541. proc typeBorrow(sym: PSym, n: PNode) =
  542. if n.kind == nkExprColonExpr:
  543. let it = n.sons[1]
  544. if it.kind != nkAccQuoted:
  545. localError(n.info, "a type can only borrow `.` for now")
  546. incl(sym.typ.flags, tfBorrowDot)
  547. proc markCompilerProc(s: PSym) =
  548. # minor hack ahead: FlowVar is the only generic .compilerProc type which
  549. # should not have an external name set:
  550. if s.kind != skType or s.name.s != "FlowVar":
  551. makeExternExport(s, "$1", s.info)
  552. incl(s.flags, sfCompilerProc)
  553. incl(s.flags, sfUsed)
  554. registerCompilerProc(s)
  555. proc deprecatedStmt(c: PContext; pragma: PNode) =
  556. let pragma = pragma[1]
  557. if pragma.kind != nkBracket:
  558. localError(pragma.info, "list of key:value pairs expected"); return
  559. for n in pragma:
  560. if n.kind in {nkExprColonExpr, nkExprEqExpr}:
  561. let dest = qualifiedLookUp(c, n[1], {checkUndeclared})
  562. assert dest != nil
  563. let src = considerQuotedIdent(n[0])
  564. let alias = newSym(skAlias, src, dest, n[0].info)
  565. incl(alias.flags, sfExported)
  566. if sfCompilerProc in dest.flags: markCompilerProc(alias)
  567. addInterfaceDecl(c, alias)
  568. n.sons[1] = newSymNode(dest)
  569. else:
  570. localError(n.info, "key:value pair expected")
  571. proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
  572. if it.kind != nkExprColonExpr:
  573. invalidPragma(it); return
  574. let n = it[1]
  575. if n.kind == nkSym:
  576. result = n.sym
  577. elif kind == skField:
  578. # First check if the guard is a global variable:
  579. result = qualifiedLookUp(c, n, {})
  580. if result.isNil or result.kind notin {skLet, skVar} or
  581. sfGlobal notin result.flags:
  582. # We return a dummy symbol; later passes over the type will repair it.
  583. # Generic instantiation needs to know about this too. But we're lazy
  584. # and perform the lookup on demand instead.
  585. result = newSym(skUnknown, considerQuotedIdent(n), nil, n.info)
  586. else:
  587. result = qualifiedLookUp(c, n, {checkUndeclared})
  588. proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
  589. validPragmas: TSpecialWords): bool =
  590. var it = n.sons[i]
  591. var key = if it.kind == nkExprColonExpr: it.sons[0] else: it
  592. if key.kind == nkBracketExpr:
  593. processNote(c, it)
  594. return
  595. let ident = considerQuotedIdent(key)
  596. var userPragma = strTableGet(c.userPragmas, ident)
  597. if userPragma != nil:
  598. inc c.instCounter
  599. if c.instCounter > 100:
  600. globalError(it.info, errRecursiveDependencyX, userPragma.name.s)
  601. pragma(c, sym, userPragma.ast, validPragmas)
  602. # ensure the pragma is also remember for generic instantiations in other
  603. # modules:
  604. n.sons[i] = userPragma.ast
  605. dec c.instCounter
  606. else:
  607. var k = whichKeyword(ident)
  608. if k in validPragmas:
  609. case k
  610. of wExportc:
  611. makeExternExport(sym, getOptionalStr(c, it, "$1"), it.info)
  612. incl(sym.flags, sfUsed) # avoid wrong hints
  613. of wImportc:
  614. let name = getOptionalStr(c, it, "$1")
  615. cppDefine(c.graph.config, name)
  616. makeExternImport(sym, name, it.info)
  617. of wImportCompilerProc:
  618. let name = getOptionalStr(c, it, "$1")
  619. cppDefine(c.graph.config, name)
  620. processImportCompilerProc(sym, name, it.info)
  621. of wExtern: setExternName(sym, expectStrLit(c, it), it.info)
  622. of wImmediate:
  623. if sym.kind in {skTemplate, skMacro}:
  624. incl(sym.flags, sfImmediate)
  625. incl(sym.flags, sfAllUntyped)
  626. message(n.info, warnDeprecated, "use 'untyped' parameters instead; immediate")
  627. else: invalidPragma(it)
  628. of wDirty:
  629. if sym.kind == skTemplate: incl(sym.flags, sfDirty)
  630. else: invalidPragma(it)
  631. of wImportCpp:
  632. processImportCpp(sym, getOptionalStr(c, it, "$1"), it.info)
  633. of wImportObjC:
  634. processImportObjC(sym, getOptionalStr(c, it, "$1"), it.info)
  635. of wAlign:
  636. if sym.typ == nil: invalidPragma(it)
  637. var align = expectIntLit(c, it)
  638. if (not isPowerOfTwo(align) and align != 0) or align >% high(int16):
  639. localError(it.info, errPowerOfTwoExpected)
  640. else:
  641. sym.typ.align = align.int16
  642. of wSize:
  643. if sym.typ == nil: invalidPragma(it)
  644. var size = expectIntLit(c, it)
  645. if not isPowerOfTwo(size) or size <= 0 or size > 8:
  646. localError(it.info, errPowerOfTwoExpected)
  647. else:
  648. sym.typ.size = size
  649. of wNodecl:
  650. noVal(it)
  651. incl(sym.loc.flags, lfNoDecl)
  652. of wPure, wAsmNoStackFrame:
  653. noVal(it)
  654. if sym != nil:
  655. if k == wPure and sym.kind in routineKinds: invalidPragma(it)
  656. else: incl(sym.flags, sfPure)
  657. of wVolatile:
  658. noVal(it)
  659. incl(sym.flags, sfVolatile)
  660. of wRegister:
  661. noVal(it)
  662. incl(sym.flags, sfRegister)
  663. of wThreadVar:
  664. noVal(it)
  665. incl(sym.flags, sfThread)
  666. of wDeadCodeElim: pragmaDeadCodeElim(c, it)
  667. of wNoForward: pragmaNoForward(c, it)
  668. of wReorder: pragmaNoForward(c, it, sfReorder)
  669. of wMagic: processMagic(c, it, sym)
  670. of wCompileTime:
  671. noVal(it)
  672. incl(sym.flags, sfCompileTime)
  673. incl(sym.loc.flags, lfNoDecl)
  674. of wGlobal:
  675. noVal(it)
  676. incl(sym.flags, sfGlobal)
  677. incl(sym.flags, sfPure)
  678. of wMerge:
  679. # only supported for backwards compat, doesn't do anything anymore
  680. noVal(it)
  681. of wConstructor:
  682. noVal(it)
  683. incl(sym.flags, sfConstructor)
  684. of wHeader:
  685. var lib = getLib(c, libHeader, getStrLitNode(c, it))
  686. addToLib(lib, sym)
  687. incl(sym.flags, sfImportc)
  688. incl(sym.loc.flags, lfHeader)
  689. incl(sym.loc.flags, lfNoDecl)
  690. # implies nodecl, because otherwise header would not make sense
  691. if sym.loc.r == nil: sym.loc.r = rope(sym.name.s)
  692. of wDestructor:
  693. sym.flags.incl sfOverriden
  694. if sym.name.s.normalize != "destroy":
  695. localError(n.info, errGenerated, "destructor has to be named 'destroy'")
  696. of wOverride:
  697. sym.flags.incl sfOverriden
  698. of wNosideeffect:
  699. noVal(it)
  700. incl(sym.flags, sfNoSideEffect)
  701. if sym.typ != nil: incl(sym.typ.flags, tfNoSideEffect)
  702. of wSideeffect:
  703. noVal(it)
  704. incl(sym.flags, sfSideEffect)
  705. of wNoreturn:
  706. noVal(it)
  707. incl(sym.flags, sfNoReturn)
  708. of wDynlib:
  709. processDynLib(c, it, sym)
  710. of wCompilerproc:
  711. noVal(it) # compilerproc may not get a string!
  712. cppDefine(c.graph.config, sym.name.s)
  713. if sfFromGeneric notin sym.flags: markCompilerProc(sym)
  714. of wProcVar:
  715. noVal(it)
  716. incl(sym.flags, sfProcvar)
  717. of wExplain:
  718. sym.flags.incl sfExplain
  719. of wDeprecated:
  720. if it.kind == nkExprColonExpr: deprecatedStmt(c, it)
  721. elif sym != nil: incl(sym.flags, sfDeprecated)
  722. else: incl(c.module.flags, sfDeprecated)
  723. of wVarargs:
  724. noVal(it)
  725. if sym.typ == nil: invalidPragma(it)
  726. else: incl(sym.typ.flags, tfVarargs)
  727. of wBorrow:
  728. if sym.kind == skType:
  729. typeBorrow(sym, it)
  730. else:
  731. noVal(it)
  732. incl(sym.flags, sfBorrow)
  733. of wFinal:
  734. noVal(it)
  735. if sym.typ == nil: invalidPragma(it)
  736. else: incl(sym.typ.flags, tfFinal)
  737. of wInheritable:
  738. noVal(it)
  739. if sym.typ == nil or tfFinal in sym.typ.flags: invalidPragma(it)
  740. else: incl(sym.typ.flags, tfInheritable)
  741. of wAcyclic:
  742. noVal(it)
  743. if sym.typ == nil: invalidPragma(it)
  744. else: incl(sym.typ.flags, tfAcyclic)
  745. of wShallow:
  746. noVal(it)
  747. if sym.typ == nil: invalidPragma(it)
  748. else: incl(sym.typ.flags, tfShallow)
  749. of wThread:
  750. noVal(it)
  751. incl(sym.flags, sfThread)
  752. incl(sym.flags, sfProcvar)
  753. if sym.typ != nil:
  754. incl(sym.typ.flags, tfThread)
  755. if sym.typ.callConv == ccClosure: sym.typ.callConv = ccDefault
  756. of wGcSafe:
  757. noVal(it)
  758. if sym != nil:
  759. if sym.kind != skType: incl(sym.flags, sfThread)
  760. if sym.typ != nil: incl(sym.typ.flags, tfGcSafe)
  761. else: invalidPragma(it)
  762. else:
  763. discard "no checking if used as a code block"
  764. of wPacked:
  765. noVal(it)
  766. if sym.typ == nil: invalidPragma(it)
  767. else: incl(sym.typ.flags, tfPacked)
  768. of wHint: message(it.info, hintUser, expectStrLit(c, it))
  769. of wWarning: message(it.info, warnUser, expectStrLit(c, it))
  770. of wError:
  771. if sym != nil and sym.isRoutine:
  772. # This is subtle but correct: the error *statement* is only
  773. # allowed for top level statements. Seems to be easier than
  774. # distinguishing properly between
  775. # ``proc p() {.error}`` and ``proc p() = {.error: "msg".}``
  776. noVal(it)
  777. incl(sym.flags, sfError)
  778. else:
  779. localError(it.info, errUser, expectStrLit(c, it))
  780. of wFatal: fatal(it.info, errUser, expectStrLit(c, it))
  781. of wDefine: processDefine(c, it)
  782. of wUndef: processUndef(c, it)
  783. of wCompile: processCompile(c, it)
  784. of wLink: processCommonLink(c, it, linkNormal)
  785. of wLinksys: processCommonLink(c, it, linkSys)
  786. of wPassl: extccomp.addLinkOption(expectStrLit(c, it))
  787. of wPassc: extccomp.addCompileOption(expectStrLit(c, it))
  788. of wBreakpoint: pragmaBreakpoint(c, it)
  789. of wWatchPoint: pragmaWatchpoint(c, it)
  790. of wPush:
  791. processPush(c, n, i + 1)
  792. result = true
  793. of wPop: processPop(c, it)
  794. of wPragma:
  795. processPragma(c, n, i)
  796. result = true
  797. of wDiscardable:
  798. noVal(it)
  799. if sym != nil: incl(sym.flags, sfDiscardable)
  800. of wNoInit:
  801. noVal(it)
  802. if sym != nil: incl(sym.flags, sfNoInit)
  803. of wCodegenDecl: processCodegenDecl(c, it, sym)
  804. of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks,
  805. wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
  806. wLinedir, wStacktrace, wLinetrace, wOptimization,
  807. wCallconv,
  808. wDebugger, wProfiler, wFloatchecks, wNanChecks, wInfChecks,
  809. wPatterns:
  810. if processOption(c, it):
  811. # calling conventions (boring...):
  812. localError(it.info, errOptionExpected)
  813. of FirstCallConv..LastCallConv:
  814. assert(sym != nil)
  815. if sym.typ == nil: invalidPragma(it)
  816. else: sym.typ.callConv = wordToCallConv(k)
  817. of wEmit: pragmaEmit(c, it)
  818. of wUnroll: pragmaUnroll(c, it)
  819. of wLinearScanEnd, wComputedGoto: noVal(it)
  820. of wEffects:
  821. # is later processed in effect analysis:
  822. noVal(it)
  823. of wIncompleteStruct:
  824. noVal(it)
  825. if sym.typ == nil: invalidPragma(it)
  826. else: incl(sym.typ.flags, tfIncompleteStruct)
  827. of wUnchecked:
  828. noVal(it)
  829. if sym.typ == nil: invalidPragma(it)
  830. else: incl(sym.typ.flags, tfUncheckedArray)
  831. of wUnion:
  832. noVal(it)
  833. if sym.typ == nil: invalidPragma(it)
  834. else: incl(sym.typ.flags, tfUnion)
  835. of wRequiresInit:
  836. noVal(it)
  837. if sym.typ == nil: invalidPragma(it)
  838. else: incl(sym.typ.flags, tfNeedsInit)
  839. of wByRef:
  840. noVal(it)
  841. if sym == nil or sym.typ == nil:
  842. if processOption(c, it): localError(it.info, errOptionExpected)
  843. else:
  844. incl(sym.typ.flags, tfByRef)
  845. of wByCopy:
  846. noVal(it)
  847. if sym.kind != skType or sym.typ == nil: invalidPragma(it)
  848. else: incl(sym.typ.flags, tfByCopy)
  849. of wPartial:
  850. noVal(it)
  851. if sym.kind != skType or sym.typ == nil: invalidPragma(it)
  852. else:
  853. incl(sym.typ.flags, tfPartial)
  854. # .partial types can only work with dead code elimination
  855. # to prevent the codegen from doing anything before we compiled
  856. # the whole program:
  857. incl gGlobalOptions, optDeadCodeElim
  858. of wInject, wGensym:
  859. # We check for errors, but do nothing with these pragmas otherwise
  860. # as they are handled directly in 'evalTemplate'.
  861. noVal(it)
  862. if sym == nil: invalidPragma(it)
  863. of wLine: pragmaLine(c, it)
  864. of wRaises, wTags: pragmaRaisesOrTags(c, it)
  865. of wLocks:
  866. if sym == nil: pragmaLockStmt(c, it)
  867. elif sym.typ == nil: invalidPragma(it)
  868. else: sym.typ.lockLevel = pragmaLocks(c, it)
  869. of wBitsize:
  870. if sym == nil or sym.kind != skField or it.kind != nkExprColonExpr:
  871. invalidPragma(it)
  872. else:
  873. sym.bitsize = expectIntLit(c, it)
  874. of wGuard:
  875. if sym == nil or sym.kind notin {skVar, skLet, skField}:
  876. invalidPragma(it)
  877. else:
  878. sym.guard = pragmaGuard(c, it, sym.kind)
  879. of wGoto:
  880. if sym == nil or sym.kind notin {skVar, skLet}:
  881. invalidPragma(it)
  882. else:
  883. sym.flags.incl sfGoto
  884. of wExportNims:
  885. if sym == nil: invalidPragma(it)
  886. else: magicsys.registerNimScriptSymbol(sym)
  887. of wInjectStmt:
  888. if it.kind != nkExprColonExpr:
  889. localError(it.info, errExprExpected)
  890. else:
  891. it.sons[1] = c.semExpr(c, it.sons[1])
  892. of wExperimental:
  893. noVal(it)
  894. if isTopLevel(c):
  895. c.module.flags.incl sfExperimental
  896. else:
  897. localError(it.info, "'experimental' pragma only valid as toplevel statement")
  898. of wThis:
  899. if it.kind == nkExprColonExpr:
  900. c.selfName = considerQuotedIdent(it[1])
  901. else:
  902. c.selfName = getIdent("self")
  903. of wNoRewrite:
  904. noVal(it)
  905. of wBase:
  906. noVal(it)
  907. sym.flags.incl sfBase
  908. of wIntDefine:
  909. sym.magic = mIntDefine
  910. of wStrDefine:
  911. sym.magic = mStrDefine
  912. of wUsed:
  913. noVal(it)
  914. if sym == nil: invalidPragma(it)
  915. else: sym.flags.incl sfUsed
  916. else: invalidPragma(it)
  917. else: invalidPragma(it)
  918. proc implicitPragmas*(c: PContext, sym: PSym, n: PNode,
  919. validPragmas: TSpecialWords) =
  920. if sym != nil and sym.kind != skModule:
  921. for it in c.optionStack:
  922. let o = it.otherPragmas
  923. if not o.isNil:
  924. pushInfoContext(n.info)
  925. for i in countup(0, sonsLen(o) - 1):
  926. if singlePragma(c, sym, o, i, validPragmas):
  927. internalError(n.info, "implicitPragmas")
  928. popInfoContext()
  929. if lfExportLib in sym.loc.flags and sfExportc notin sym.flags:
  930. localError(n.info, errDynlibRequiresExportc)
  931. var lib = c.optionStack[^1].dynlib
  932. if {lfDynamicLib, lfHeader} * sym.loc.flags == {} and
  933. sfImportc in sym.flags and lib != nil:
  934. incl(sym.loc.flags, lfDynamicLib)
  935. addToLib(lib, sym)
  936. if sym.loc.r == nil: sym.loc.r = rope(sym.name.s)
  937. proc hasPragma*(n: PNode, pragma: TSpecialWord): bool =
  938. if n == nil or n.sons == nil:
  939. return false
  940. for p in n.sons:
  941. var key = if p.kind == nkExprColonExpr: p[0] else: p
  942. if key.kind == nkIdent and whichKeyword(key.ident) == pragma:
  943. return true
  944. return false
  945. proc pragmaRec(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
  946. if n == nil: return
  947. for i in countup(0, sonsLen(n) - 1):
  948. if n.sons[i].kind == nkPragma: pragmaRec(c, sym, n.sons[i], validPragmas)
  949. elif singlePragma(c, sym, n, i, validPragmas): break
  950. proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
  951. if n == nil: return
  952. pragmaRec(c, sym, n, validPragmas)
  953. implicitPragmas(c, sym, n, validPragmas)