summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rwxr-xr-xcompiler/ast.nim4
-rwxr-xr-xcompiler/ccgutils.nim6
-rwxr-xr-xcompiler/evals.nim2
-rwxr-xr-xcompiler/msgs.nim6
-rwxr-xr-xcompiler/parser.nim11
-rwxr-xr-xcompiler/pragmas.nim19
-rwxr-xr-xcompiler/renderer.nim11
-rw-r--r--compiler/semmagic.nim18
-rwxr-xr-xcompiler/semstmts.nim14
-rwxr-xr-xcompiler/trees.nim4
10 files changed, 88 insertions, 7 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index db5d8b9f0..76260b586 100755
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -139,6 +139,7 @@ type
     nkMacroStmt,          # a macro statement
     nkAsmStmt,            # an assembler block
     nkPragma,             # a pragma statement
+    nkPragmaBlock,        # a pragma with a block
     nkIfStmt,             # an if statement
     nkWhenStmt,           # a when statement
     nkForStmt,            # a for statement
@@ -390,7 +391,8 @@ type
     mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal, 
     mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNLineInfo,
     mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr, 
-    mEqIdent, mEqNimrodNode, mNHint, mNWarning, mNError, mGetTypeInfo
+    mEqIdent, mEqNimrodNode, mNHint, mNWarning, mNError, 
+    mInstantiationInfo, mGetTypeInfo
 
 type 
   PNode* = ref TNode
diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim
index 578512bb0..610fcb39b 100755
--- a/compiler/ccgutils.nim
+++ b/compiler/ccgutils.nim
@@ -11,11 +11,7 @@
 
 import 
   ast, astalgo, ropes, lists, hashes, strutils, types, msgs, wordrecg, 
-  platform
-
-proc whichPragma*(n: PNode): TSpecialWord = 
-  var key = if n.kind == nkExprColonExpr: n.sons[0] else: n
-  if key.kind == nkIdent: result = whichKeyword(key.ident)
+  platform, trees
 
 proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
   case n.kind
diff --git a/compiler/evals.nim b/compiler/evals.nim
index d4602aa24..311b01b84 100755
--- a/compiler/evals.nim
+++ b/compiler/evals.nim
@@ -1213,6 +1213,8 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
   of nkMetaNode:
     result = copyTree(n.sons[0])
     result.typ = n.typ
+  of nkPragmaBlock:
+    result = evalAux(c, n.sons[1], flags)
   of nkIdentDefs, nkCast, nkYieldStmt, nkAsmStmt, nkForStmt, nkPragmaExpr, 
      nkLambda, nkContinueStmt, nkIdent: 
     result = raiseCannotEval(c, n.info)
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 6cb2fedcd..e1deb6e35 100755
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -476,6 +476,12 @@ proc pushInfoContext*(info: TLineInfo) =
 proc popInfoContext*() = 
   setlen(msgContext, len(msgContext) - 1)
 
+proc getInfoContext*(index: int): TLineInfo =
+  let L = msgContext.len
+  let i = if index < 0: L + index else: index
+  if i >=% L: result = UnknownLineInfo()
+  else: result = msgContext[i]
+
 proc ToFilename*(info: TLineInfo): string =
   if info.fileIndex < 0: result = "???"
   else: result = fileInfos[info.fileIndex].projPath
diff --git a/compiler/parser.nim b/compiler/parser.nim
index 118b96736..12184a097 100755
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -1316,6 +1316,15 @@ proc parseBind(p: var TParser): PNode =
     optInd(p, a)
   expectNl(p)
   
+proc parseStmtPragma(p: var TParser): PNode =
+  result = parsePragma(p)
+  if p.tok.tokType == tkColon:
+    let a = result
+    result = newNodeI(nkPragmaBlock, a.info)
+    getTok(p)
+    result.add a
+    result.add parseStmt(p)
+
 proc simpleStmt(p: var TParser): PNode = 
   case p.tok.tokType
   of tkReturn: result = parseReturnOrRaise(p, nkReturnStmt)
@@ -1324,7 +1333,7 @@ proc simpleStmt(p: var TParser): PNode =
   of tkDiscard: result = parseYieldOrDiscard(p, nkDiscardStmt)
   of tkBreak: result = parseBreakOrContinue(p, nkBreakStmt)
   of tkContinue: result = parseBreakOrContinue(p, nkContinueStmt)
-  of tkCurlyDotLe: result = parsePragma(p)
+  of tkCurlyDotLe: result = parseStmtPragma(p)
   of tkImport: result = parseImportOrIncludeStmt(p, nkImportStmt)
   of tkFrom: result = parseFromStmt(p)
   of tkInclude: result = parseImportOrIncludeStmt(p, nkIncludeStmt)
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 762bfa5bf..4c38dcb1a 100755
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -32,6 +32,7 @@ const
   iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideEffect, wSideEffect, 
     wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
     wImportcpp, wImportobjc, wError, wDiscardable}
+  exprPragmas* = {wLine}
   stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
     wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
     wLinedir, wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError,
@@ -394,6 +395,23 @@ proc PragmaUnroll(c: PContext, n: PNode) =
 proc PragmaLinearScanEnd(c: PContext, n: PNode) =
   noVal(n)
 
+proc PragmaLine(c: PContext, n: PNode) =
+  if n.kind == nkExprColonExpr:
+    n.sons[1] = c.semConstExpr(c, n.sons[1])
+    let a = n.sons[1]
+    if a.kind != nkPar: GlobalError(n.info, errXExpected, "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: GlobalError(n.info, errStringLiteralExpected)
+    if y.kind != nkIntLit: GlobalError(n.info, errIntLiteralExpected)
+    n.info.fileIndex = msgs.fileInfoIdx(x.strVal)
+    n.info.line = int16(y.intVal)
+  else:
+    # sensible default:
+    n.info = getInfoContext(-1)
+
 proc processPragma(c: PContext, n: PNode, i: int) = 
   var it = n.sons[i]
   if it.kind != nkExprColonExpr: invalidPragma(n)
@@ -575,6 +593,7 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
             noVal(it)
             if sym.typ == nil: invalidPragma(it)
             incl(sym.typ.flags, tfIncompleteStruct)
+          of wLine: PragmaLine(c, it)
           else: invalidPragma(it)
         else: invalidPragma(it)
     else: processNote(c, it)
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index 04cff007b..d26896b8e 100755
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -537,6 +537,16 @@ proc gwhile(g: var TSrcGen, n: PNode) =
   gcoms(g)                    # a good place for comments
   gstmts(g, n.sons[1], c)
 
+proc gpragmaBlock(g: var TSrcGen, n: PNode) = 
+  var c: TContext
+  gsub(g, n.sons[0])
+  putWithSpace(g, tkColon, ":")
+  initContext(c)
+  if longMode(n) or (lsub(n.sons[1]) + g.lineLen > maxLineLen):
+    incl(c.flags, rfLongMode)
+  gcoms(g)                    # a good place for comments
+  gstmts(g, n.sons[1], c)
+
 proc gtry(g: var TSrcGen, n: PNode) = 
   var c: TContext
   put(g, tkTry, "try")
@@ -933,6 +943,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     putWithSpace(g, tkWhen, "when")
     gif(g, n)
   of nkWhileStmt: gwhile(g, n)
+  of nkPragmaBlock: gpragmaBlock(g, n)
   of nkCaseStmt, nkRecCase: gcase(g, n)
   of nkMacroStmt: gmacro(g, n)
   of nkTryStmt: gtry(g, n)
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index 6b868d19b..932f36c2f 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -26,6 +26,23 @@ proc semSlurp(c: PContext, n: PNode, flags: TExprFlags): PNode =
   except EIO:
     GlobalError(a.info, errCannotOpenFile, a.strVal)
 
+proc expectIntLit(c: PContext, n: PNode): int =
+  let x = c.semConstExpr(c, n)
+  case x.kind
+  of nkIntLit..nkInt64Lit: result = int(x.intVal)
+  else: GlobalError(n.info, errIntLiteralExpected)
+
+proc semInstantiationInfo(c: PContext, n: PNode): PNode =
+  result = newNodeIT(nkPar, n.info, n.typ)
+  let idx = expectIntLit(c, n.sons[1])
+  let info = getInfoContext(idx)
+  var filename = newNodeIT(nkStrLit, n.info, getSysType(tyString))
+  filename.strVal = ToFilename(info)
+  var line = newNodeIT(nkIntLit, n.info, getSysType(tyInt))
+  line.intVal = ToLinenumber(info)
+  result.add(filename)
+  result.add(line)
+
 proc magicsAfterOverloadResolution(c: PContext, n: PNode, 
                                    flags: TExprFlags): PNode =
   case n[0].sym.magic
@@ -34,5 +51,6 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
   of mAstToStr:
     result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
     result.typ = getSysType(tyString)
+  of mInstantiationInfo: result = semInstantiationInfo(c, n)
   else: result = n
 
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 6208f6bc9..54625b46e 100755
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -827,6 +827,18 @@ proc evalInclude(c: PContext, n: PNode): PNode =
     addSon(result, semStmt(c, gIncludeFile(f)))
     Excl(c.includedFiles, fileIndex)
   
+proc setLine(n: PNode, info: TLineInfo) =
+  for i in 0 .. <safeLen(n): setLine(n.sons[i], info)
+  n.info = info
+  
+proc semPragmaBlock(c: PContext, n: PNode): PNode =
+  let pragmaList = n.sons[0]
+  pragma(c, nil, pragmaList, exprPragmas)
+  result = semStmt(c, n.sons[1])
+  for i in 0 .. <pragmaList.len:
+    if whichPragma(pragmaList.sons[i]) == wLine:
+      setLine(result, pragmaList.sons[i].info)
+
 proc SemStmt(c: PContext, n: PNode): PNode = 
   const                       # must be last statements in a block:
     LastBlockStmts = {nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt}
@@ -881,6 +893,8 @@ proc SemStmt(c: PContext, n: PNode): PNode =
   of nkIncludeStmt: 
     if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "include")
     result = evalInclude(c, n)
+  of nkPragmaBlock:
+    result = semPragmaBlock(c, n)
   else: 
     # in interactive mode, we embed the expression in an 'echo':
     if gCmd == cmdInteractive:
diff --git a/compiler/trees.nim b/compiler/trees.nim
index 3b35b2ff6..f393bfc66 100755
--- a/compiler/trees.nim
+++ b/compiler/trees.nim
@@ -146,3 +146,7 @@ proc IsRange*(n: PNode): bool {.inline.} =
         n[0].kind == nkSymChoice and n[0][1].sym.name.id == ord(wDotDot):
       result = true
 
+proc whichPragma*(n: PNode): TSpecialWord = 
+  let key = if n.kind == nkExprColonExpr: n.sons[0] else: n
+  if key.kind == nkIdent: result = whichKeyword(key.ident)
+