summary refs log blame commit diff stats
path: root/compiler/pragmas.nim
blob: a067f2074a04dcd08a2f66f056ad60d66040dab0 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11

 
                            
                                         






                                                      

                                                                        
                                                                      
                           
 
     


                           
     

                                                                           
                                                                                
                                                                            
                                                                  

                                                                             
                                 
                                                   
                                                                                
                                            
                                                                               
                                                                               
                                                                                
                       
                                                                              
                                                                       
                                                                             
                                               
                                                     
                                                                  

                                                                        
                                                                              
                                                                           


                                                 
                                                                  
                                                                             
                                                   

                                                                             
                                                                             
                                    
                                                                             
                                                                           
                                                                        
                                                                               
                                                                       
                                                            
                                                             
                                                                               
                                                                         
                                                                    
                                                                      
                                                                             
                                                                            
                                                        
                          
                                                                           
                                                               
                                                                      
 



                                                               
                                                                                 


                                    
                                                                           
 






                                                                       





                                                                                      
 
                                              
               

                                        
                        
                                                                                     
                                           
                     
                                                                               

                                    
           
                            
 
                                                                            








                                         
                                                                                                   
                                                     

                                                                     
 

                                                                               


                          

                                                                               

                          

                                                                                        



                                         

                                                                               


                            
                                   

                                 
                                           
 

                                                                                


                                 

                                
 

                                                                             

                    
                                                  
                                                  
                                                          
                       
                                  
       

                                            
                                                              
         
                                                            
                         
                                    
 
                                                  
                                     
 
                                               
                                                  
                                                       
       


                                                           
                                                             
 
                                                                        
                                                             
                           



                                                           
                                                   

                                            
                                                  
                                                          
          
               

                                                     

                                              
                 
           
                                                                     
 
                                                           



                                                                           
                                              
                                                


                                               
                                                        
 


                                                                           
 


                                                               
 
                                             
                                                                              
                                          
           
                                   
                                                      
                                                                     
       
                                                               

                                                             


                                                                         
 

                       
                   
                                             
                                                                        
 
                                                     
                                                  
                                                          
                       
                                  
       

                                        
                                    

                                                           
                                                                                

                                                            

                                                      
                                            

                                                           
                                    
       
                                   
                                                             


                                         



                                                                        
                                                                  
                                                      
                                      

                                
                                         



                                                          
                     
                                    
             
                                                  
                                                 
                                       
                
                                                     
                                                 
                                       
         
                         

            
                                       
                 

                                                                     
       
                       
 





























                                                                              
                                                         
                                                
       
                                          



























                                                                                  

                                                     
                                               

                                                                
                           
                              

                           
                          
                      
                                          
                                                            
                                  


                                                   
                                                    
 



                                                              
                                        
                            
                                                                            
       
                                                
                                            
                                               
 
                                           


                                                                             
       
                       

                                          


                                                                             
       
                       


                     

                       
                                                          
                            

                                            
                                                      

                                
         
                                    
                                    

                                            



                                                                      

                                                         

                                       
                                           
                                      
         
                                                            

                 
                                                                           
                                                       

                                  
                                                           
                                 

                                                                      
       
                              
                                                           


                                 
                                     
                                    
                                                                            
                                
 
                                                                      
                                                               
              


                                                   
             


                                                                           
                                                            

                                              

                                  
                                              
                                                

                                       
                       
 

                                                                  

                                                                               
                              
                 
                                                             
            

                                                          
               
                                           
                                                                    
                                                             
                     
                                               

                                           
                   
                                                             
                    

                                            
                               
                                       
             
                                                   


                                                     
                     
               
       
                                    
                                       

                                        
                                                  
                                                          












                                                  
                                                              
 

                                                                   
 

                                          
                       
                                                  
                                         
                          
                                                    
         
                         
 
                                        
                                                

                                            
                                        
                        



                                                 
                            
                                                              
                              
                                                           
           
                                                                        
                                                               
                                      
         
                                                    

                       
                                         
 
                                                   
               


                                                                         
 
                                                                                  
                                                             
                                        
 
                                                


                                                         
                                                                                     
             
 
                                                





                                          
                       
 
                                             
                                                    
                        


                           
                                                                                            
         
                           

                                           
                                                      
                                                    
                        
       




                                           
                                                                                                                        
         
                                 
                                   
                                                                                      
           
                              
 
                                                   
                                                

                              
                                                                        

                                  
                                             


                                                                          
                                        

                               
                                  
 





                                                       
                              
                                                                                 
                  
                                                  
                                                            
                                                  
                                                                                                   
                                            
                                                                         
                                   
                                                                 
                                
                                  
         
                                                             
 
                                                                
                                                    
                                



                       






                                                                            
                                                                        
                         
       
                                                     
 
                                                    




                                        
                                               
              
       
                       
            
 

                                                             
                       





                                                       
 

                                                          
                                                                                          








                                                       
                                                                       
         
                                                            
 
                                                               

                                                      
                                                                               


                               


                                      
                                         

                                                    
                                                                    

                           
                                                                                  
 
                                                

                                                                            

                     
                               


                         
                                                                      
                                                   

                                              
                                 
                                              
                                               
                             
                                              
                                 
                                              

                                                                     
                    


                                             

                                                                                                  

                                                           
                                  
                    
                                                                      
                     
                                                                       
                
                                               

                                                                            
                                                                


                                     
                                               

                                                           
                                                                


                             
                    

                                     
                    
                      
                                                                          

                                       
                    

                                   
                    

                                   
                    
                                             
                                                                             
                                           
                                                    

                                         
                    


                                      
                    



                                                                          
                    
                      
                    








                                                                       


                                  
                    


                                                              
                    

                                     
                    
                                   
                             

                                                          

                                 
                              
                                                                   
                                             
                                                    
                                                                  
                  
                    
                                  

                                
                     



                                                                       


                                                      

                                               


                                            
                                
             
                      

                                   

                                               

                                          

                                                                           
                                                
                  

                                               
                                        
                  

                                               

                                            

                                               

                                            
                    

                                  


                                                                        
                 
                    


                                                          
                                    

                                                       
                 

                                               
                                           







                                               





                                                                     
                      

                                  


                                                   
                                                                       




                                                    







                                              






                                             




                                                    
                      
                    

                                                     
                    



                                                                       







                                                                               

                                     
                                               


                                                  
                                                    

                                                
                    
                           

                                               

                                                     

                                               

                                                   

                                               

                                          

                                               

                                              
                    
                                        
                                                


                                      

                                                                     
                                           
                  

                                                                     

                                        


                                                                          

                                           



                                                  
                                                 
                                                    
                  
                                             
                              

                                           

                                                                
                              



                                                       
                              

                               
                     

                                                            
                     
                                                          
                                                              


                                               
                                       
               
                                                        
                                                    
                                                                         
                                               
                                                
                                                                         
             
                                                                                                 
                    
                    
               
                    
                             


                              
                              
               

                                           
                                   
                             
                                
         

                                        
 

                                                       
                                         
                            

                             
                                         

                          
                                                      
                                                              
               
                                
 
                                                                  
                                                               
                                      

                                                         

                                       
                                                       
 
                                                       
                           
 
             
                                                                        

                                                                 
 

              
                                                                               
                     
           
                  

                                                      



                                                                            
                                          
#
#
#           The Nim Compiler
#        (c) Copyright 2015 Andreas Rumpf
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

# This module implements semantic checking for pragmas

import
  os, platform, condsyms, ast, astalgo, idents, semdata, msgs, renderer,
  wordrecg, ropes, options, strutils, extccomp, math, magicsys, trees,
  types, lookups, lineinfos

const
  FirstCallConv* = wNimcall
  LastCallConv* = wNoconv

const
  procPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
    wMagic, wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
    wCompilerProc, wCore, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
    wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
    wAsmNoStackFrame, wError, wDiscardable, wNoInit, wCodegenDecl,
    wGensym, wInject, wRaises, wTags, wLocks, wDelegator, wGcSafe, wOverride,
    wConstructor, wExportNims, wUsed, wLiftLocals, wStacktrace, wLinetrace}
  converterPragmas* = procPragmas
  methodPragmas* = procPragmas+{wBase}-{wImportCpp}
  templatePragmas* = {wImmediate, wDeprecated, wError, wGensym, wInject, wDirty,
    wDelegator, wExportNims, wUsed, wPragma}
  macroPragmas* = {FirstCallConv..LastCallConv, wImmediate, wImportc, wExportc,
    wNodecl, wMagic, wNosideeffect, wCompilerProc, wCore, wDeprecated, wExtern,
    wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wDelegator,
    wExportNims, wUsed}
  iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideeffect, wSideeffect,
    wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
    wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises,
    wTags, wLocks, wGcSafe, wExportNims, wUsed}
  exprPragmas* = {wLine, wLocks, wNoRewrite, wGcSafe}
  stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
    wBoundchecks, wOverflowchecks, wNilchecks, wMovechecks, wAssertions,
    wWarnings, wHints,
    wLinedir, wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError,
    wFatal, wDefine, wUndef, wCompile, wLink, wLinksys, wPure, wPush, wPop,
    wBreakpoint, wWatchPoint, wPassl, wPassc,
    wDeadCodeElimUnused,  # deprecated, always on
    wDeprecated,
    wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
    wLinearScanEnd, wPatterns, wEffects, wNoForward, wReorder, wComputedGoto,
    wInjectStmt, wDeprecated, wExperimental, wThis}
  lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
    wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
    wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame,
    wRaises, wLocks, wTags, wGcSafe}
  typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
    wPure, wHeader, wCompilerProc, wCore, wFinal, wSize, wExtern, wShallow,
    wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef,
    wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
    wBorrow, wGcSafe, wExportNims, wPartial, wUsed, wExplain, wPackage}
  fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
    wImportCpp, wImportObjC, wError, wGuard, wBitsize, wUsed}
  varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
    wMagic, wHeader, wDeprecated, wCompilerProc, wCore, wDynlib, wExtern,
    wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal,
    wGensym, wInject, wCodegenDecl, wGuard, wGoto, wExportNims, wUsed}
  constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
    wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject, wExportNims,
    wIntDefine, wStrDefine, wUsed, wCompilerProc, wCore}
  letPragmas* = varPragmas
  procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect,
                      wThread, wRaises, wLocks, wTags, wGcSafe}
  allRoutinePragmas* = methodPragmas + iteratorPragmas + lambdaPragmas

proc getPragmaVal*(procAst: PNode; name: TSpecialWord): PNode =
  let p = procAst[pragmasPos]
  if p.kind == nkEmpty: return nil
  for it in p:
    if it.kind in nkPragmaCallKinds and it.len == 2 and it[0].kind == nkIdent and
        it[0].ident.id == ord(name):
      return it[1]

proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)

proc recordPragma(c: PContext; n: PNode; key, val: string; val2 = "") =
  var recorded = newNodeI(nkCommentStmt, n.info)
  recorded.add newStrNode(key, n.info)
  recorded.add newStrNode(val, n.info)
  if val2.len > 0: recorded.add newStrNode(val2, n.info)
  c.graph.recordStmt(c.graph, c.module, recorded)

const
  errStringLiteralExpected = "string literal expected"
  errIntLiteralExpected = "integer literal expected"

proc invalidPragma*(c: PContext; n: PNode) =
  localError(c.config, n.info, "invalid pragma: " % renderTree(n, {renderNoComments}))

proc pragmaAsm*(c: PContext, n: PNode): char =
  result = '\0'
  if n != nil:
    for i in countup(0, sonsLen(n) - 1):
      let it = n.sons[i]
      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))
          else: invalidPragma(c, it)
        else: invalidPragma(c, it)
      else:
        invalidPragma(c, it)

proc setExternName(c: PContext; s: PSym, extname: string, info: TLineInfo) =
  # special cases to improve performance:
  if extname == "$1":
    s.loc.r = rope(s.name.s)
  elif '$' notin extname:
    s.loc.r = rope(extname)
  else:
    try:
      s.loc.r = rope(extname % s.name.s)
    except ValueError:
      localError(c.config, info, "invalid extern name: '" & extname & "'. (Forgot to escape '$'?)")
  if c.config.cmd == cmdPretty and '$' notin extname:
    # note that '{.importc.}' is transformed into '{.importc: "$1".}'
    s.loc.flags.incl(lfFullExternalName)

proc makeExternImport(c: PContext; s: PSym, extname: string, info: TLineInfo) =
  setExternName(c, s, extname, info)
  incl(s.flags, sfImportc)
  excl(s.flags, sfForward)

proc makeExternExport(c: PContext; s: PSym, extname: string, info: TLineInfo) =
  setExternName(c, s, extname, info)
  incl(s.flags, sfExportc)

proc processImportCompilerProc(c: PContext; s: PSym, extname: string, info: TLineInfo) =
  setExternName(c, s, extname, info)
  incl(s.flags, sfImportc)
  excl(s.flags, sfForward)
  incl(s.loc.flags, lfImportCompilerProc)

proc processImportCpp(c: PContext; s: PSym, extname: string, info: TLineInfo) =
  setExternName(c, s, extname, info)
  incl(s.flags, sfImportc)
  incl(s.flags, sfInfixCall)
  excl(s.flags, sfForward)
  if c.config.cmd == cmdCompileToC:
    let m = s.getModule()
    incl(m.flags, sfCompileToCpp)
  incl c.config.globalOptions, optMixedMode

proc processImportObjC(c: PContext; s: PSym, extname: string, info: TLineInfo) =
  setExternName(c, s, extname, info)
  incl(s.flags, sfImportc)
  incl(s.flags, sfNamedParamCall)
  excl(s.flags, sfForward)
  let m = s.getModule()
  incl(m.flags, sfCompileToObjC)

proc newEmptyStrNode(c: PContext; n: PNode): PNode {.noinline.} =
  result = newNodeIT(nkStrLit, n.info, getSysType(c.graph, n.info, tyString))
  result.strVal = ""

proc getStrLitNode(c: PContext, n: PNode): PNode =
  if n.kind notin nkPragmaCallKinds or n.len != 2:
    localError(c.config, n.info, errStringLiteralExpected)
    # error correction:
    result = newEmptyStrNode(c, n)
  else:
    n.sons[1] = c.semConstExpr(c, n.sons[1])
    case n.sons[1].kind
    of nkStrLit, nkRStrLit, nkTripleStrLit: result = n.sons[1]
    else:
      localError(c.config, n.info, errStringLiteralExpected)
      # error correction:
      result = newEmptyStrNode(c, n)

proc expectStrLit(c: PContext, n: PNode): string =
  result = getStrLitNode(c, n).strVal

proc expectIntLit(c: PContext, n: PNode): int =
  if n.kind notin nkPragmaCallKinds or n.len != 2:
    localError(c.config, n.info, errIntLiteralExpected)
  else:
    n.sons[1] = c.semConstExpr(c, n.sons[1])
    case n.sons[1].kind
    of nkIntLit..nkInt64Lit: result = int(n.sons[1].intVal)
    else: localError(c.config, n.info, errIntLiteralExpected)

proc getOptionalStr(c: PContext, n: PNode, defaultStr: string): string =
  if n.kind in nkPragmaCallKinds: result = expectStrLit(c, n)
  else: result = defaultStr

proc processCodegenDecl(c: PContext, n: PNode, sym: PSym) =
  sym.constraint = getStrLitNode(c, n)

proc processMagic(c: PContext, n: PNode, s: PSym) =
  #if sfSystemModule notin c.module.flags:
  #  liMessage(n.info, errMagicOnlyInSystem)
  if n.kind notin nkPragmaCallKinds or n.len != 2:
    localError(c.config, n.info, errStringLiteralExpected)
    return
  var v: string
  if n.sons[1].kind == nkIdent: v = n.sons[1].ident.s
  else: v = expectStrLit(c, n)
  for m in countup(low(TMagic), high(TMagic)):
    if substr($m, 1) == v:
      s.magic = m
      break
  if s.magic == mNone: message(c.config, n.info, warnUnknownMagic, v)

proc wordToCallConv(sw: TSpecialWord): TCallingConvention =
  # this assumes that the order of special words and calling conventions is
  # the same
  result = TCallingConvention(ord(ccDefault) + ord(sw) - ord(wNimcall))

proc isTurnedOn(c: PContext, n: PNode): bool =
  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
  localError(c.config, n.info, "'on' or 'off' expected")

proc onOff(c: PContext, n: PNode, op: TOptions, resOptions: var TOptions) =
  if isTurnedOn(c, n): resOptions = resOptions + op
  else: resOptions = resOptions - op

proc pragmaNoForward(c: PContext, n: PNode; flag=sfNoForward) =
  if isTurnedOn(c, n): incl(c.module.flags, flag)
  else: excl(c.module.flags, flag)

proc processCallConv(c: PContext, n: PNode) =
  if n.kind in nkPragmaCallKinds and n.len == 2 and n.sons[1].kind == nkIdent:
    let sw = whichKeyword(n.sons[1].ident)
    case sw
    of FirstCallConv..LastCallConv:
      c.optionStack[^1].defaultCC = wordToCallConv(sw)
    else: localError(c.config, n.info, "calling convention expected")
  else:
    localError(c.config, n.info, "calling convention expected")

proc getLib(c: PContext, kind: TLibKind, path: PNode): PLib =
  for it in c.libs:
    if it.kind == kind and trees.exprStructuralEquivalent(it.path, path):
      return it

  result = newLib(kind)
  result.path = path
  c.libs.add result
  if path.kind in {nkStrLit..nkTripleStrLit}:
    result.isOverriden = options.isDynlibOverride(c.config, path.strVal)

proc expectDynlibNode(c: PContext, n: PNode): PNode =
  if n.kind notin nkPragmaCallKinds or n.len != 2:
    localError(c.config, n.info, errStringLiteralExpected)
    # error correction:
    result = newEmptyStrNode(c, n)
  else:
    # For the OpenGL wrapper we support:
    # {.dynlib: myGetProcAddr(...).}
    result = c.semExpr(c, n.sons[1])
    if result.kind == nkSym and result.sym.kind == skConst:
      result = result.sym.ast # look it up
    if result.typ == nil or result.typ.kind notin {tyPointer, tyString, tyProc}:
      localError(c.config, n.info, errStringLiteralExpected)
      result = newEmptyStrNode(c, n)

proc processDynLib(c: PContext, n: PNode, sym: PSym) =
  if (sym == nil) or (sym.kind == skModule):
    let lib = getLib(c, libDynamic, expectDynlibNode(c, n))
    if not lib.isOverriden:
      c.optionStack[^1].dynlib = lib
  else:
    if n.kind in nkPragmaCallKinds:
      var lib = getLib(c, libDynamic, expectDynlibNode(c, n))
      if not lib.isOverriden:
        addToLib(lib, sym)
        incl(sym.loc.flags, lfDynamicLib)
    else:
      incl(sym.loc.flags, lfExportLib)
    # since we'll be loading the dynlib symbols dynamically, we must use
    # a calling convention that doesn't introduce custom name mangling
    # cdecl is the default - the user can override this explicitly
    if sym.kind in routineKinds and sym.typ != nil and
        sym.typ.callConv == ccDefault:
      sym.typ.callConv = ccCDecl

proc processNote(c: PContext, n: PNode) =
  if n.kind in nkPragmaCallKinds and len(n) == 2 and
      n[0].kind == nkBracketExpr and
      n[0].len == 2 and
      n[0][1].kind == nkIdent and n[0][0].kind == nkIdent:
    var nk: TNoteKind
    case whichKeyword(n[0][0].ident)
    of wHint:
      var x = findStr(HintsToStr, n[0][1].ident.s)
      if x >= 0: nk = TNoteKind(x + ord(hintMin))
      else: invalidPragma(c, n); return
    of wWarning:
      var x = findStr(WarningsToStr, n[0][1].ident.s)
      if x >= 0: nk = TNoteKind(x + ord(warnMin))
      else: invalidPragma(c, n); return
    else:
      invalidPragma(c, n)
      return

    let x = c.semConstBoolExpr(c, n[1])
    n.sons[1] = x
    if x.kind == nkIntLit and x.intVal != 0: incl(c.config.notes, nk)
    else: excl(c.config.notes, nk)
  else:
    invalidPragma(c, n)

proc pragmaToOptions(w: TSpecialWord): TOptions {.inline.} =
  case w
  of wChecks: ChecksOptions
  of wObjChecks: {optObjCheck}
  of wFieldChecks: {optFieldCheck}
  of wRangechecks: {optRangeCheck}
  of wBoundchecks: {optBoundsCheck}
  of wOverflowchecks: {optOverflowCheck}
  of wNilchecks: {optNilCheck}
  of wFloatchecks: {optNaNCheck, optInfCheck}
  of wNanChecks: {optNaNCheck}
  of wInfChecks: {optInfCheck}
  of wMovechecks: {optMoveCheck}
  of wAssertions: {optAssert}
  of wWarnings: {optWarns}
  of wHints: {optHints}
  of wLinedir: {optLineDir}
  of wStacktrace: {optStackTrace}
  of wLinetrace: {optLineTrace}
  of wDebugger: {optEndb}
  of wProfiler: {optProfiler, optMemTracker}
  of wMemTracker: {optMemTracker}
  of wByRef: {optByRef}
  of wImplicitStatic: {optImplicitStatic}
  of wPatterns: {optPatterns}
  else: {}

proc tryProcessOption(c: PContext, n: PNode, resOptions: var TOptions): bool =
  result = true
  if n.kind notin nkPragmaCallKinds or n.len != 2: result = false
  elif n.sons[0].kind == nkBracketExpr: processNote(c, n)
  elif n.sons[0].kind != nkIdent: result = false
  else:
    let sw = whichKeyword(n.sons[0].ident)
    let opts = pragmaToOptions(sw)
    if opts != {}:
      onOff(c, n, opts, resOptions)
    else:
      case sw
      of wCallconv: processCallConv(c, n)
      of wDynlib: processDynLib(c, n, nil)
      of wOptimization:
        if n.sons[1].kind != nkIdent:
          invalidPragma(c, n)
        else:
          case n.sons[1].ident.s.normalize
          of "speed":
            incl(resOptions, optOptimizeSpeed)
            excl(resOptions, optOptimizeSize)
          of "size":
            excl(resOptions, optOptimizeSpeed)
            incl(resOptions, optOptimizeSize)
          of "none":
            excl(resOptions, optOptimizeSpeed)
            excl(resOptions, optOptimizeSize)
          else: localError(c.config, n.info, "'none', 'speed' or 'size' expected")
      else: result = false

proc processOption(c: PContext, n: PNode, resOptions: var TOptions) =
  if not tryProcessOption(c, n, resOptions):
    # calling conventions (boring...):
    localError(c.config, n.info, "option expected")

proc processPush(c: PContext, n: PNode, start: int) =
  if n.sons[start-1].kind in nkPragmaCallKinds:
    localError(c.config, n.info, "'push' cannot have arguments")
  var x = newOptionEntry(c.config)
  var y = c.optionStack[^1]
  x.options = c.config.options
  x.defaultCC = y.defaultCC
  x.dynlib = y.dynlib
  x.notes = c.config.notes
  c.optionStack.add(x)
  for i in countup(start, sonsLen(n) - 1):
    if not tryProcessOption(c, n.sons[i], c.config.options):
      # simply store it somewhere:
      if x.otherPragmas.isNil:
        x.otherPragmas = newNodeI(nkPragma, n.info)
      x.otherPragmas.add n.sons[i]
    #localError(c.config, n.info, errOptionExpected)

  # If stacktrace is disabled globally we should not enable it
  if optStackTrace notin c.optionStack[0].options:
    c.config.options.excl(optStackTrace)

proc processPop(c: PContext, n: PNode) =
  if c.optionStack.len <= 1:
    localError(c.config, n.info, "{.pop.} without a corresponding {.push.}")
  else:
    c.config.options = c.optionStack[^1].options
    c.config.notes = c.optionStack[^1].notes
    c.optionStack.setLen(c.optionStack.len - 1)

proc processDefine(c: PContext, n: PNode) =
  if (n.kind in nkPragmaCallKinds and n.len == 2) and (n[1].kind == nkIdent):
    defineSymbol(c.config.symbols, n[1].ident.s)
    message(c.config, n.info, warnDeprecated, "define")
  else:
    invalidPragma(c, n)

proc processUndef(c: PContext, n: PNode) =
  if (n.kind in nkPragmaCallKinds and n.len == 2) and (n[1].kind == nkIdent):
    undefSymbol(c.config.symbols, n[1].ident.s)
    message(c.config, n.info, warnDeprecated, "undef")
  else:
    invalidPragma(c, n)

type
  TLinkFeature = enum
    linkNormal, linkSys

proc relativeFile(c: PContext; n: PNode; ext=""): string =
  var s = expectStrLit(c, n)
  if ext.len > 0 and splitFile(s).ext == "":
    s = addFileExt(s, ext)
  result = parentDir(toFullPath(c.config, n.info)) / s
  if not fileExists(result):
    if isAbsolute(s): result = s
    else:
      result = findFile(c.config, s)
      if result.len == 0: result = s

proc processCompile(c: PContext, n: PNode) =
  proc docompile(c: PContext; it: PNode; src, dest: string) =
    var cf = Cfile(cname: src, obj: dest, flags: {CfileFlag.External})
    extccomp.addExternalFileToCompile(c.config, cf)
    recordPragma(c, it, "compile", src, dest)

  proc getStrLit(c: PContext, n: PNode; i: int): string =
    n.sons[i] = c.semConstExpr(c, n[i])
    case n[i].kind
    of nkStrLit, nkRStrLit, nkTripleStrLit:
      shallowCopy(result, n[i].strVal)
    else:
      localError(c.config, n.info, errStringLiteralExpected)
      result = ""

  let it = if n.kind in nkPragmaCallKinds and n.len == 2: n.sons[1] else: n
  if it.kind in {nkPar, nkTupleConstr} and it.len == 2:
    let s = getStrLit(c, it, 0)
    let dest = getStrLit(c, it, 1)
    var found = parentDir(toFullPath(c.config, n.info)) / s
    for f in os.walkFiles(found):
      let obj = completeCFilePath(c.config, dest % extractFilename(f))
      docompile(c, it, f, obj)
  else:
    let s = expectStrLit(c, n)
    var found = parentDir(toFullPath(c.config, n.info)) / s
    if not fileExists(found):
      if isAbsolute(s): found = s
      else:
        found = findFile(c.config, s)
        if found.len == 0: found = s
    let obj = toObjFile(c.config, completeCFilePath(c.config, found, false))
    docompile(c, it, found, obj)

proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) =
  let found = relativeFile(c, n, CC[c.config.cCompiler].objExt)
  case feature
  of linkNormal:
    extccomp.addExternalFileToLink(c.config, found)
    recordPragma(c, n, "link", found)
  of linkSys:
    let dest = c.config.libpath / completeCFilePath(c.config, found, false)
    extccomp.addExternalFileToLink(c.config, dest)
    recordPragma(c, n, "link", dest)
  else: internalError(c.config, n.info, "processCommonLink")

proc pragmaBreakpoint(c: PContext, n: PNode) =
  discard getOptionalStr(c, n, "")

proc pragmaWatchpoint(c: PContext, n: PNode) =
  if n.kind in nkPragmaCallKinds and n.len == 2:
    n.sons[1] = c.semExpr(c, n.sons[1])
  else:
    invalidPragma(c, n)

proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
  case n.sons[1].kind
  of nkStrLit, nkRStrLit, nkTripleStrLit:
    result = newNode(if n.kind == nkAsmStmt: nkAsmStmt else: nkArgList, n.info)
    var str = n.sons[1].strVal
    if str == "":
      localError(con.config, n.info, "empty 'asm' statement")
      return
    # now parse the string literal and substitute symbols:
    var a = 0
    while true:
      var b = strutils.find(str, marker, a)
      var sub = if b < 0: substr(str, a) else: substr(str, a, b - 1)
      if sub != "": addSon(result, newStrNode(nkStrLit, sub))
      if b < 0: break
      var c = strutils.find(str, marker, b + 1)
      if c < 0: sub = substr(str, b + 1)
      else: sub = substr(str, b + 1, c - 1)
      if sub != "":
        var e = searchInScopes(con, getIdent(con.cache, sub))
        if e != nil:
          when false:
            if e.kind == skStub: loadStub(e)
          incl(e.flags, sfUsed)
          addSon(result, newSymNode(e))
        else:
          addSon(result, newStrNode(nkStrLit, sub))
      else:
        # an empty '``' produces a single '`'
        addSon(result, newStrNode(nkStrLit, $marker))
      if c < 0: break
      a = c + 1
  else:
    illFormedAstLocal(n, con.config)
    result = newNode(nkAsmStmt, n.info)

proc pragmaEmit(c: PContext, n: PNode) =
  if n.kind notin nkPragmaCallKinds or n.len != 2:
    localError(c.config, n.info, errStringLiteralExpected)
  else:
    let n1 = n[1]
    if n1.kind == nkBracket:
      var b = newNodeI(nkBracket, n1.info, n1.len)
      for i in 0..<n1.len:
        b.sons[i] = c.semExpr(c, n1[i])
      n.sons[1] = b
    else:
      n.sons[1] = c.semConstExpr(c, n1)
      case n.sons[1].kind
      of nkStrLit, nkRStrLit, nkTripleStrLit:
        n.sons[1] = semAsmOrEmit(c, n, '`')
      else:
        localError(c.config, n.info, errStringLiteralExpected)

proc noVal(c: PContext; n: PNode) =
  if n.kind in nkPragmaCallKinds and n.len > 1: invalidPragma(c, n)

proc pragmaUnroll(c: PContext, n: PNode) =
  if c.p.nestedLoopCounter <= 0:
    invalidPragma(c, n)
  elif n.kind in nkPragmaCallKinds and n.len == 2:
    var unrollFactor = expectIntLit(c, n)
    if unrollFactor <% 32:
      n.sons[1] = newIntNode(nkIntLit, unrollFactor)
    else:
      invalidPragma(c, n)

proc pragmaLine(c: PContext, n: PNode) =
  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 in {nkPar, nkTupleConstr}:
      # unpack the tuple
      var x = a.sons[0]
      var y = a.sons[1]
      if x.kind == nkExprColonExpr: x = x.sons[1]
      if y.kind == nkExprColonExpr: y = y.sons[1]
      if x.kind != nkStrLit:
        localError(c.config, n.info, errStringLiteralExpected)
      elif y.kind != nkIntLit:
        localError(c.config, n.info, errIntLiteralExpected)
      else:
        # XXX this produces weird paths which are not properly resolved:
        n.info.fileIndex = msgs.fileInfoIdx(c.config, x.strVal)
        n.info.line = uint16(y.intVal)
    else:
      localError(c.config, n.info, "tuple expected")
  else:
    # sensible default:
    n.info = getInfoContext(c.config, -1)

proc processPragma(c: PContext, n: PNode, i: int) =
  let it = n[i]
  if it.kind notin nkPragmaCallKinds and it.len == 2: invalidPragma(c, n)
  elif it[0].kind != nkIdent: invalidPragma(c, n)
  elif it[1].kind != nkIdent: invalidPragma(c, n)

  var userPragma = newSym(skTemplate, it[1].ident, nil, it.info, c.config.options)
  userPragma.ast = newNode(nkPragma, n.info, n.sons[i+1..^1])
  strTableAdd(c.userPragmas, userPragma)

proc pragmaRaisesOrTags(c: PContext, n: PNode) =
  proc processExc(c: PContext, x: PNode) =
    var t = skipTypes(c.semTypeNode(c, x, nil), skipPtrs)
    if t.kind != tyObject:
      localError(c.config, x.info, errGenerated, "invalid type for raises/tags list")
    x.typ = t

  if n.kind in nkPragmaCallKinds and n.len == 2:
    let it = n.sons[1]
    if it.kind notin {nkCurly, nkBracket}:
      processExc(c, it)
    else:
      for e in items(it): processExc(c, e)
  else:
    invalidPragma(c, n)

proc pragmaLockStmt(c: PContext; it: PNode) =
  if it.kind notin nkPragmaCallKinds or it.len != 2:
    invalidPragma(c, it)
  else:
    let n = it[1]
    if n.kind != nkBracket:
      localError(c.config, n.info, errGenerated, "locks pragma takes a list of expressions")
    else:
      for i in 0 ..< n.len:
        n.sons[i] = c.semExpr(c, n.sons[i])

proc pragmaLocks(c: PContext, it: PNode): TLockLevel =
  if it.kind notin nkPragmaCallKinds or it.len != 2:
    invalidPragma(c, it)
  else:
    case it[1].kind
    of nkStrLit, nkRStrLit, nkTripleStrLit:
      if it[1].strVal == "unknown":
        result = UnknownLockLevel
      else:
        localError(c.config, it[1].info, "invalid string literal for locks pragma (only allowed string is \"unknown\")")
    else:
      let x = expectIntLit(c, it)
      if x < 0 or x > MaxLockLevel:
        localError(c.config, it[1].info, "integer must be within 0.." & $MaxLockLevel)
      else:
        result = TLockLevel(x)

proc typeBorrow(c: PContext; sym: PSym, n: PNode) =
  if n.kind in nkPragmaCallKinds and n.len == 2:
    let it = n.sons[1]
    if it.kind != nkAccQuoted:
      localError(c.config, n.info, "a type can only borrow `.` for now")
  incl(sym.typ.flags, tfBorrowDot)

proc markCompilerProc(c: PContext; s: PSym) =
  # minor hack ahead: FlowVar is the only generic .compilerProc type which
  # should not have an external name set:
  if s.kind != skType or s.name.s != "FlowVar":
    makeExternExport(c, s, "$1", s.info)
  incl(s.flags, sfCompilerProc)
  incl(s.flags, sfUsed)
  registerCompilerProc(c.graph, s)

proc deprecatedStmt(c: PContext; outerPragma: PNode) =
  let pragma = outerPragma[1]
  if pragma.kind in {nkStrLit..nkTripleStrLit}:
    incl(c.module.flags, sfDeprecated)
    c.module.constraint = getStrLitNode(c, outerPragma)
    return
  if pragma.kind != nkBracket:
    localError(c.config, pragma.info, "list of key:value pairs expected"); return
  for n in pragma:
    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(c.config, n.info, warnUser, "the .deprecated pragma is unreliable for routines")
      let src = considerQuotedIdent(c, n[0])
      let alias = newSym(skAlias, src, dest, n[0].info, c.config.options)
      incl(alias.flags, sfExported)
      if sfCompilerProc in dest.flags: markCompilerProc(c, alias)
      addInterfaceDecl(c, alias)
      n.sons[1] = newSymNode(dest)
    else:
      localError(c.config, n.info, "key:value pair expected")

proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
  if it.kind notin nkPragmaCallKinds or it.len != 2:
    invalidPragma(c, it); return
  let n = it[1]
  if n.kind == nkSym:
    result = n.sym
  elif kind == skField:
    # First check if the guard is a global variable:
    result = qualifiedLookUp(c, n, {})
    if result.isNil or result.kind notin {skLet, skVar} or
        sfGlobal notin result.flags:
      # We return a dummy symbol; later passes over the type will repair it.
      # Generic instantiation needs to know about this too. But we're lazy
      # and perform the lookup on demand instead.
      result = newSym(skUnknown, considerQuotedIdent(c, n), nil, n.info,
        c.config.options)
  else:
    result = qualifiedLookUp(c, n, {checkUndeclared})

proc semCustomPragma(c: PContext, n: PNode): PNode =
  if n.kind == nkIdent:
    result = newTree(nkCall, n)
  elif n.kind == nkExprColonExpr:
    # pragma: arg -> pragma(arg)
    result = newTree(nkCall, n[0], n[1])
  elif n.kind in nkPragmaCallKinds + {nkIdent}:
    result = n
  else:
    invalidPragma(c, n)
    return n

  let r = c.semOverloadedCall(c, result, n, {skTemplate}, {})
  if r.isNil or sfCustomPragma notin r[0].sym.flags:
    invalidPragma(c, n)
  else:
    result = r
    if n.kind == nkIdent:
      result = result[0]
    elif n.kind == nkExprColonExpr:
      result.kind = n.kind # pragma(arg) -> pragma: arg

proc processExperimental(c: PContext; n: PNode; s: PSym) =
  if not isTopLevel(c):
    localError(c.config, n.info, "'experimental' pragma only valid as toplevel statement")
  if n.kind notin nkPragmaCallKinds or n.len != 2:
    c.features.incl oldExperimentalFeatures
  else:
    n[1] = c.semConstExpr(c, n[1])
    case n[1].kind
    of nkStrLit, nkRStrLit, nkTripleStrLit:
      try:
        c.features.incl parseEnum[Feature](n[1].strVal)
      except ValueError:
        localError(c.config, n[1].info, "unknown experimental feature")
    else:
      localError(c.config, n.info, errStringLiteralExpected)

proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
                  validPragmas: TSpecialWords): bool =
  var it = n.sons[i]
  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(c, key)
  var userPragma = strTableGet(c.userPragmas, ident)
  if userPragma != nil:
    # number of pragmas increase/decrease with user pragma expansion
    inc c.instCounter
    if c.instCounter > 100:
      globalError(c.config, it.info, "recursive dependency: " & userPragma.name.s)

    pragma(c, sym, userPragma.ast, validPragmas)
    n.sons[i..i] = userPragma.ast.sons # expand user pragma with its content
    i.inc(userPragma.ast.len - 1) # inc by -1 is ok, user pragmas was empty
    dec c.instCounter
  else:
    let k = whichKeyword(ident)
    if k in validPragmas:
      case k
      of wExportc:
        makeExternExport(c, sym, getOptionalStr(c, it, "$1"), it.info)
        incl(sym.flags, sfUsed) # avoid wrong hints
      of wImportc:
        let name = getOptionalStr(c, it, "$1")
        cppDefine(c.config, name)
        recordPragma(c, it, "cppdefine", name)
        makeExternImport(c, sym, name, it.info)
      of wImportCompilerProc:
        let name = getOptionalStr(c, it, "$1")
        cppDefine(c.config, name)
        recordPragma(c, it, "cppdefine", name)
        processImportCompilerProc(c, sym, name, it.info)
      of wExtern: setExternName(c, sym, expectStrLit(c, it), it.info)
      of wImmediate:
        if sym.kind in {skTemplate, skMacro}:
          incl(sym.flags, sfImmediate)
          incl(sym.flags, sfAllUntyped)
          message(c.config, n.info, warnDeprecated, "use 'untyped' parameters instead; immediate")
        else: invalidPragma(c, it)
      of wDirty:
        if sym.kind == skTemplate: incl(sym.flags, sfDirty)
        else: invalidPragma(c, it)
      of wImportCpp:
        processImportCpp(c, sym, getOptionalStr(c, it, "$1"), it.info)
      of wImportObjC:
        processImportObjC(c, sym, getOptionalStr(c, it, "$1"), it.info)
      of wAlign:
        if sym.typ == nil: invalidPragma(c, it)
        var align = expectIntLit(c, it)
        if (not isPowerOfTwo(align) and align != 0) or align >% high(int16):
          localError(c.config, it.info, "power of two expected")
        else:
          sym.typ.align = align.int16
      of wSize:
        if sym.typ == nil: invalidPragma(c, it)
        var size = expectIntLit(c, it)
        if not isPowerOfTwo(size) or size <= 0 or size > 8:
          localError(c.config, it.info, "power of two expected")
        else:
          sym.typ.size = size
      of wNodecl:
        noVal(c, it)
        incl(sym.loc.flags, lfNoDecl)
      of wPure, wAsmNoStackFrame:
        noVal(c, it)
        if sym != nil:
          if k == wPure and sym.kind in routineKinds: invalidPragma(c, it)
          else: incl(sym.flags, sfPure)
      of wVolatile:
        noVal(c, it)
        incl(sym.flags, sfVolatile)
      of wRegister:
        noVal(c, it)
        incl(sym.flags, sfRegister)
      of wThreadVar:
        noVal(c, it)
        incl(sym.flags, {sfThread, sfGlobal})
      of wDeadCodeElimUnused: discard  # deprecated, dead code elim always on
      of wNoForward: pragmaNoForward(c, it)
      of wReorder: pragmaNoForward(c, it, sfReorder)
      of wMagic: processMagic(c, it, sym)
      of wCompileTime:
        noVal(c, it)
        incl(sym.flags, sfCompileTime)
        incl(sym.loc.flags, lfNoDecl)
      of wGlobal:
        noVal(c, it)
        incl(sym.flags, sfGlobal)
        incl(sym.flags, sfPure)
      of wMerge:
        # only supported for backwards compat, doesn't do anything anymore
        noVal(c, it)
      of wConstructor:
        noVal(c, it)
        incl(sym.flags, sfConstructor)
      of wHeader:
        var lib = getLib(c, libHeader, getStrLitNode(c, it))
        addToLib(lib, sym)
        incl(sym.flags, sfImportc)
        incl(sym.loc.flags, lfHeader)
        incl(sym.loc.flags, lfNoDecl)
        # implies nodecl, because otherwise header would not make sense
        if sym.loc.r == nil: sym.loc.r = rope(sym.name.s)
      of wOverride:
        sym.flags.incl sfOverriden
      of wNosideeffect:
        noVal(c, it)
        incl(sym.flags, sfNoSideEffect)
        if sym.typ != nil: incl(sym.typ.flags, tfNoSideEffect)
      of wSideeffect:
        noVal(c, it)
        incl(sym.flags, sfSideEffect)
      of wNoreturn:
        noVal(c, it)
        incl(sym.flags, sfNoReturn)
        if sym.typ[0] != nil:
          localError(c.config, sym.ast[paramsPos][0].info,
            ".noreturn with return type not allowed")
      of wDynlib:
        processDynLib(c, it, sym)
      of wCompilerProc, wCore:
        noVal(c, it)           # compilerproc may not get a string!
        cppDefine(c.graph.config, sym.name.s)
        recordPragma(c, it, "cppdefine", sym.name.s)
        if sfFromGeneric notin sym.flags: markCompilerProc(c, sym)
      of wProcVar:
        noVal(c, it)
        incl(sym.flags, sfProcvar)
      of wExplain:
        sym.flags.incl sfExplain
      of wDeprecated:
        if sym != nil and sym.kind in routineKinds:
          if it.kind in nkPragmaCallKinds: discard getStrLitNode(c, it)
          incl(sym.flags, sfDeprecated)
        elif it.kind in nkPragmaCallKinds: deprecatedStmt(c, it)
        elif sym != nil: incl(sym.flags, sfDeprecated)
        else: incl(c.module.flags, sfDeprecated)
      of wVarargs:
        noVal(c, it)
        if sym.typ == nil: invalidPragma(c, it)
        else: incl(sym.typ.flags, tfVarargs)
      of wBorrow:
        if sym.kind == skType:
          typeBorrow(c, sym, it)
        else:
          noVal(c, it)
          incl(sym.flags, sfBorrow)
      of wFinal:
        noVal(c, it)
        if sym.typ == nil: invalidPragma(c, it)
        else: incl(sym.typ.flags, tfFinal)
      of wInheritable:
        noVal(c, it)
        if sym.typ == nil or tfFinal in sym.typ.flags: invalidPragma(c, it)
        else: incl(sym.typ.flags, tfInheritable)
      of wPackage:
        noVal(c, it)
        if sym.typ == nil: invalidPragma(c, it)
        else: incl(sym.flags, sfForward)
      of wAcyclic:
        noVal(c, it)
        if sym.typ == nil: invalidPragma(c, it)
        else: incl(sym.typ.flags, tfAcyclic)
      of wShallow:
        noVal(c, it)
        if sym.typ == nil: invalidPragma(c, it)
        else: incl(sym.typ.flags, tfShallow)
      of wThread:
        noVal(c, it)
        incl(sym.flags, sfThread)
        incl(sym.flags, sfProcvar)
        if sym.typ != nil:
          incl(sym.typ.flags, tfThread)
          if sym.typ.callConv == ccClosure: sym.typ.callConv = ccDefault
      of wGcSafe:
        noVal(c, it)
        if sym != nil:
          if sym.kind != skType: incl(sym.flags, sfThread)
          if sym.typ != nil: incl(sym.typ.flags, tfGcSafe)
          else: invalidPragma(c, it)
        else:
          discard "no checking if used as a code block"
      of wPacked:
        noVal(c, it)
        if sym.typ == nil: invalidPragma(c, it)
        else: incl(sym.typ.flags, tfPacked)
      of wHint:
        let s = expectStrLit(c, it)
        recordPragma(c, it, "hint", s)
        message(c.config, it.info, hintUser, s)
      of wWarning:
        let s = expectStrLit(c, it)
        recordPragma(c, it, "warning", s)
        message(c.config, it.info, warnUser, s)
      of wError:
        if sym != nil and sym.isRoutine:
          # This is subtle but correct: the error *statement* is only
          # allowed for top level statements. Seems to be easier than
          # distinguishing properly between
          # ``proc p() {.error}`` and ``proc p() = {.error: "msg".}``
          noVal(c, it)
          incl(sym.flags, sfError)
        else:
          let s = expectStrLit(c, it)
          recordPragma(c, it, "error", s)
          localError(c.config, it.info, errUser, s)
      of wFatal: fatal(c.config, it.info, errUser, expectStrLit(c, it))
      of wDefine: processDefine(c, it)
      of wUndef: processUndef(c, it)
      of wCompile: processCompile(c, it)
      of wLink: processCommonLink(c, it, linkNormal)
      of wLinksys: processCommonLink(c, it, linkSys)
      of wPassl:
        let s = expectStrLit(c, it)
        extccomp.addLinkOption(c.config, s)
        recordPragma(c, it, "passl", s)
      of wPassc:
        let s = expectStrLit(c, it)
        extccomp.addCompileOption(c.config, s)
        recordPragma(c, it, "passc", s)
      of wBreakpoint: pragmaBreakpoint(c, it)
      of wWatchPoint: pragmaWatchpoint(c, it)
      of wPush:
        processPush(c, n, i + 1)
        result = true
      of wPop: processPop(c, it)
      of wPragma:
        if not sym.isNil and sym.kind == skTemplate:
          sym.flags.incl sfCustomPragma
        else:
          processPragma(c, n, i)
          result = true
      of wDiscardable:
        noVal(c, it)
        if sym != nil: incl(sym.flags, sfDiscardable)
      of wNoInit:
        noVal(c, it)
        if sym != nil: incl(sym.flags, sfNoInit)
      of wCodegenDecl: processCodegenDecl(c, it, sym)
      of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks,
         wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
         wLinedir, wOptimization, wMovechecks, wCallconv, wDebugger, wProfiler,
         wFloatchecks, wNanChecks, wInfChecks, wPatterns:
        processOption(c, it, c.config.options)
      of wStacktrace, wLinetrace:
        if sym.kind in {skProc, skMethod, skConverter}:
          processOption(c, it, sym.options)
        else:
          processOption(c, it, c.config.options)
      of FirstCallConv..LastCallConv:
        assert(sym != nil)
        if sym.typ == nil: invalidPragma(c, it)
        else: sym.typ.callConv = wordToCallConv(k)
      of wEmit: pragmaEmit(c, it)
      of wUnroll: pragmaUnroll(c, it)
      of wLinearScanEnd, wComputedGoto: noVal(c, it)
      of wEffects:
        # is later processed in effect analysis:
        noVal(c, it)
      of wIncompleteStruct:
        noVal(c, it)
        if sym.typ == nil: invalidPragma(c, it)
        else: incl(sym.typ.flags, tfIncompleteStruct)
      of wUnchecked:
        noVal(c, it)
        if sym.typ == nil: invalidPragma(c, it)
        else: incl(sym.typ.flags, tfUncheckedArray)
      of wUnion:
        noVal(c, it)
        if sym.typ == nil: invalidPragma(c, it)
        else: incl(sym.typ.flags, tfUnion)
      of wRequiresInit:
        noVal(c, it)
        if sym.typ == nil: invalidPragma(c, it)
        else: incl(sym.typ.flags, tfNeedsInit)
      of wByRef:
        noVal(c, it)
        if sym == nil or sym.typ == nil:
          processOption(c, it, c.config.options)
        else:
          incl(sym.typ.flags, tfByRef)
      of wByCopy:
        noVal(c, it)
        if sym.kind != skType or sym.typ == nil: invalidPragma(c, it)
        else: incl(sym.typ.flags, tfByCopy)
      of wPartial:
        noVal(c, it)
        if sym.kind != skType or sym.typ == nil: invalidPragma(c, it)
        else:
          incl(sym.typ.flags, tfPartial)
      of wInject, wGensym:
        # We check for errors, but do nothing with these pragmas otherwise
        # as they are handled directly in 'evalTemplate'.
        noVal(c, it)
        if sym == nil: invalidPragma(c, it)
      of wLine: pragmaLine(c, it)
      of wRaises, wTags: pragmaRaisesOrTags(c, it)
      of wLocks:
        if sym == nil: pragmaLockStmt(c, it)
        elif sym.typ == nil: invalidPragma(c, it)
        else: sym.typ.lockLevel = pragmaLocks(c, it)
      of wBitsize:
        if sym == nil or sym.kind != skField:
          invalidPragma(c, it)
        else:
          sym.bitsize = expectIntLit(c, it)
      of wGuard:
        if sym == nil or sym.kind notin {skVar, skLet, skField}:
          invalidPragma(c, it)
        else:
          sym.guard = pragmaGuard(c, it, sym.kind)
      of wGoto:
        if sym == nil or sym.kind notin {skVar, skLet}:
          invalidPragma(c, it)
        else:
          sym.flags.incl sfGoto
      of wExportNims:
        if sym == nil: invalidPragma(c, it)
        else: magicsys.registerNimScriptSymbol(c.graph, sym)
      of wInjectStmt:
        if it.kind notin nkPragmaCallKinds or it.len != 2:
          localError(c.config, it.info, "expression expected")
        else:
          it.sons[1] = c.semExpr(c, it.sons[1])
      of wExperimental:
        processExperimental(c, it, sym)
      of wThis:
        if it.kind in nkPragmaCallKinds and it.len == 2:
          c.selfName = considerQuotedIdent(c, it[1])
          message(c.config, n.info, warnDeprecated, "the '.this' pragma")
        elif it.kind == nkIdent or it.len == 1:
          c.selfName = getIdent(c.cache, "self")
          message(c.config, n.info, warnDeprecated, "the '.this' pragma")
        else:
          localError(c.config, it.info, "'this' pragma is allowed to have zero or one arguments")
      of wNoRewrite:
        noVal(c, it)
      of wBase:
        noVal(c, it)
        sym.flags.incl sfBase
      of wIntDefine:
        sym.magic = mIntDefine
      of wStrDefine:
        sym.magic = mStrDefine
      of wUsed:
        noVal(c, it)
        if sym == nil: invalidPragma(c, it)
        else: sym.flags.incl sfUsed
      of wLiftLocals: discard
      else: invalidPragma(c, it)
    else:
      n.sons[i] = semCustomPragma(c, it)


proc implicitPragmas*(c: PContext, sym: PSym, n: PNode,
                      validPragmas: TSpecialWords) =
  if sym != nil and sym.kind != skModule:
    for it in c.optionStack:
      let o = it.otherPragmas
      if not o.isNil:
        pushInfoContext(c.config, n.info)
        var i = 0
        while i < o.len():
          if singlePragma(c, sym, o, i, validPragmas):
            internalError(c.config, n.info, "implicitPragmas")
          inc i
        popInfoContext(c.config)

    if lfExportLib in sym.loc.flags and sfExportc notin sym.flags:
      localError(c.config, n.info, ".dynlib requires .exportc")
    var lib = c.optionStack[^1].dynlib
    if {lfDynamicLib, lfHeader} * sym.loc.flags == {} and
        sfImportc in sym.flags and lib != nil:
      incl(sym.loc.flags, lfDynamicLib)
      addToLib(lib, sym)
      if sym.loc.r == nil: sym.loc.r = rope(sym.name.s)

proc hasPragma*(n: PNode, pragma: TSpecialWord): bool =
  if n == nil: return false

  for p in n:
    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

  return false

proc pragmaRec(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
  if n == nil: return
  var i = 0
  while i < n.len:
    if singlePragma(c, sym, n, i, validPragmas): break
    inc i

proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
  if n == nil: return
  pragmaRec(c, sym, n, validPragmas)
  implicitPragmas(c, sym, n, validPragmas)