pragma blocks; fixed line information issue with user defined assertions
This commit is contained in:
parent
42dad650e0
commit
78f4aacde9
17 changed files with 133 additions and 23 deletions
|
|
@ -139,6 +139,7 @@ type
|
||||||
nkMacroStmt, # a macro statement
|
nkMacroStmt, # a macro statement
|
||||||
nkAsmStmt, # an assembler block
|
nkAsmStmt, # an assembler block
|
||||||
nkPragma, # a pragma statement
|
nkPragma, # a pragma statement
|
||||||
|
nkPragmaBlock, # a pragma with a block
|
||||||
nkIfStmt, # an if statement
|
nkIfStmt, # an if statement
|
||||||
nkWhenStmt, # a when statement
|
nkWhenStmt, # a when statement
|
||||||
nkForStmt, # a for statement
|
nkForStmt, # a for statement
|
||||||
|
|
@ -390,7 +391,8 @@ type
|
||||||
mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal,
|
mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal,
|
||||||
mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNLineInfo,
|
mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNLineInfo,
|
||||||
mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr,
|
mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr,
|
||||||
mEqIdent, mEqNimrodNode, mNHint, mNWarning, mNError, mGetTypeInfo
|
mEqIdent, mEqNimrodNode, mNHint, mNWarning, mNError,
|
||||||
|
mInstantiationInfo, mGetTypeInfo
|
||||||
|
|
||||||
type
|
type
|
||||||
PNode* = ref TNode
|
PNode* = ref TNode
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
ast, astalgo, ropes, lists, hashes, strutils, types, msgs, wordrecg,
|
ast, astalgo, ropes, lists, hashes, strutils, types, msgs, wordrecg,
|
||||||
platform
|
platform, trees
|
||||||
|
|
||||||
proc whichPragma*(n: PNode): TSpecialWord =
|
|
||||||
var key = if n.kind == nkExprColonExpr: n.sons[0] else: n
|
|
||||||
if key.kind == nkIdent: result = whichKeyword(key.ident)
|
|
||||||
|
|
||||||
proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
|
proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
|
||||||
case n.kind
|
case n.kind
|
||||||
|
|
|
||||||
|
|
@ -1213,6 +1213,8 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
|
||||||
of nkMetaNode:
|
of nkMetaNode:
|
||||||
result = copyTree(n.sons[0])
|
result = copyTree(n.sons[0])
|
||||||
result.typ = n.typ
|
result.typ = n.typ
|
||||||
|
of nkPragmaBlock:
|
||||||
|
result = evalAux(c, n.sons[1], flags)
|
||||||
of nkIdentDefs, nkCast, nkYieldStmt, nkAsmStmt, nkForStmt, nkPragmaExpr,
|
of nkIdentDefs, nkCast, nkYieldStmt, nkAsmStmt, nkForStmt, nkPragmaExpr,
|
||||||
nkLambda, nkContinueStmt, nkIdent:
|
nkLambda, nkContinueStmt, nkIdent:
|
||||||
result = raiseCannotEval(c, n.info)
|
result = raiseCannotEval(c, n.info)
|
||||||
|
|
|
||||||
|
|
@ -476,6 +476,12 @@ proc pushInfoContext*(info: TLineInfo) =
|
||||||
proc popInfoContext*() =
|
proc popInfoContext*() =
|
||||||
setlen(msgContext, len(msgContext) - 1)
|
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 =
|
proc ToFilename*(info: TLineInfo): string =
|
||||||
if info.fileIndex < 0: result = "???"
|
if info.fileIndex < 0: result = "???"
|
||||||
else: result = fileInfos[info.fileIndex].projPath
|
else: result = fileInfos[info.fileIndex].projPath
|
||||||
|
|
|
||||||
|
|
@ -1316,6 +1316,15 @@ proc parseBind(p: var TParser): PNode =
|
||||||
optInd(p, a)
|
optInd(p, a)
|
||||||
expectNl(p)
|
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 =
|
proc simpleStmt(p: var TParser): PNode =
|
||||||
case p.tok.tokType
|
case p.tok.tokType
|
||||||
of tkReturn: result = parseReturnOrRaise(p, nkReturnStmt)
|
of tkReturn: result = parseReturnOrRaise(p, nkReturnStmt)
|
||||||
|
|
@ -1324,7 +1333,7 @@ proc simpleStmt(p: var TParser): PNode =
|
||||||
of tkDiscard: result = parseYieldOrDiscard(p, nkDiscardStmt)
|
of tkDiscard: result = parseYieldOrDiscard(p, nkDiscardStmt)
|
||||||
of tkBreak: result = parseBreakOrContinue(p, nkBreakStmt)
|
of tkBreak: result = parseBreakOrContinue(p, nkBreakStmt)
|
||||||
of tkContinue: result = parseBreakOrContinue(p, nkContinueStmt)
|
of tkContinue: result = parseBreakOrContinue(p, nkContinueStmt)
|
||||||
of tkCurlyDotLe: result = parsePragma(p)
|
of tkCurlyDotLe: result = parseStmtPragma(p)
|
||||||
of tkImport: result = parseImportOrIncludeStmt(p, nkImportStmt)
|
of tkImport: result = parseImportOrIncludeStmt(p, nkImportStmt)
|
||||||
of tkFrom: result = parseFromStmt(p)
|
of tkFrom: result = parseFromStmt(p)
|
||||||
of tkInclude: result = parseImportOrIncludeStmt(p, nkIncludeStmt)
|
of tkInclude: result = parseImportOrIncludeStmt(p, nkIncludeStmt)
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ const
|
||||||
iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideEffect, wSideEffect,
|
iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideEffect, wSideEffect,
|
||||||
wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
|
wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
|
||||||
wImportcpp, wImportobjc, wError, wDiscardable}
|
wImportcpp, wImportobjc, wError, wDiscardable}
|
||||||
|
exprPragmas* = {wLine}
|
||||||
stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
|
stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
|
||||||
wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
|
wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
|
||||||
wLinedir, wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError,
|
wLinedir, wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError,
|
||||||
|
|
@ -394,6 +395,23 @@ proc PragmaUnroll(c: PContext, n: PNode) =
|
||||||
proc PragmaLinearScanEnd(c: PContext, n: PNode) =
|
proc PragmaLinearScanEnd(c: PContext, n: PNode) =
|
||||||
noVal(n)
|
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) =
|
proc processPragma(c: PContext, n: PNode, i: int) =
|
||||||
var it = n.sons[i]
|
var it = n.sons[i]
|
||||||
if it.kind != nkExprColonExpr: invalidPragma(n)
|
if it.kind != nkExprColonExpr: invalidPragma(n)
|
||||||
|
|
@ -575,6 +593,7 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
|
||||||
noVal(it)
|
noVal(it)
|
||||||
if sym.typ == nil: invalidPragma(it)
|
if sym.typ == nil: invalidPragma(it)
|
||||||
incl(sym.typ.flags, tfIncompleteStruct)
|
incl(sym.typ.flags, tfIncompleteStruct)
|
||||||
|
of wLine: PragmaLine(c, it)
|
||||||
else: invalidPragma(it)
|
else: invalidPragma(it)
|
||||||
else: invalidPragma(it)
|
else: invalidPragma(it)
|
||||||
else: processNote(c, it)
|
else: processNote(c, it)
|
||||||
|
|
|
||||||
|
|
@ -537,6 +537,16 @@ proc gwhile(g: var TSrcGen, n: PNode) =
|
||||||
gcoms(g) # a good place for comments
|
gcoms(g) # a good place for comments
|
||||||
gstmts(g, n.sons[1], c)
|
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) =
|
proc gtry(g: var TSrcGen, n: PNode) =
|
||||||
var c: TContext
|
var c: TContext
|
||||||
put(g, tkTry, "try")
|
put(g, tkTry, "try")
|
||||||
|
|
@ -933,6 +943,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||||
putWithSpace(g, tkWhen, "when")
|
putWithSpace(g, tkWhen, "when")
|
||||||
gif(g, n)
|
gif(g, n)
|
||||||
of nkWhileStmt: gwhile(g, n)
|
of nkWhileStmt: gwhile(g, n)
|
||||||
|
of nkPragmaBlock: gpragmaBlock(g, n)
|
||||||
of nkCaseStmt, nkRecCase: gcase(g, n)
|
of nkCaseStmt, nkRecCase: gcase(g, n)
|
||||||
of nkMacroStmt: gmacro(g, n)
|
of nkMacroStmt: gmacro(g, n)
|
||||||
of nkTryStmt: gtry(g, n)
|
of nkTryStmt: gtry(g, n)
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,23 @@ proc semSlurp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
except EIO:
|
except EIO:
|
||||||
GlobalError(a.info, errCannotOpenFile, a.strVal)
|
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,
|
proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||||
flags: TExprFlags): PNode =
|
flags: TExprFlags): PNode =
|
||||||
case n[0].sym.magic
|
case n[0].sym.magic
|
||||||
|
|
@ -34,5 +51,6 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||||
of mAstToStr:
|
of mAstToStr:
|
||||||
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
|
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
|
||||||
result.typ = getSysType(tyString)
|
result.typ = getSysType(tyString)
|
||||||
|
of mInstantiationInfo: result = semInstantiationInfo(c, n)
|
||||||
else: result = n
|
else: result = n
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -827,6 +827,18 @@ proc evalInclude(c: PContext, n: PNode): PNode =
|
||||||
addSon(result, semStmt(c, gIncludeFile(f)))
|
addSon(result, semStmt(c, gIncludeFile(f)))
|
||||||
Excl(c.includedFiles, fileIndex)
|
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 =
|
proc SemStmt(c: PContext, n: PNode): PNode =
|
||||||
const # must be last statements in a block:
|
const # must be last statements in a block:
|
||||||
LastBlockStmts = {nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt}
|
LastBlockStmts = {nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt}
|
||||||
|
|
@ -881,6 +893,8 @@ proc SemStmt(c: PContext, n: PNode): PNode =
|
||||||
of nkIncludeStmt:
|
of nkIncludeStmt:
|
||||||
if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "include")
|
if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "include")
|
||||||
result = evalInclude(c, n)
|
result = evalInclude(c, n)
|
||||||
|
of nkPragmaBlock:
|
||||||
|
result = semPragmaBlock(c, n)
|
||||||
else:
|
else:
|
||||||
# in interactive mode, we embed the expression in an 'echo':
|
# in interactive mode, we embed the expression in an 'echo':
|
||||||
if gCmd == cmdInteractive:
|
if gCmd == cmdInteractive:
|
||||||
|
|
|
||||||
|
|
@ -146,3 +146,7 @@ proc IsRange*(n: PNode): bool {.inline.} =
|
||||||
n[0].kind == nkSymChoice and n[0][1].sym.name.id == ord(wDotDot):
|
n[0].kind == nkSymChoice and n[0][1].sym.name.id == ord(wDotDot):
|
||||||
result = true
|
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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# Configuration file for the Nimrod Compiler.
|
# Configuration file for the Nimrod Compiler.
|
||||||
# (c) 2011 Andreas Rumpf
|
# (c) 2012 Andreas Rumpf
|
||||||
|
|
||||||
# Feel free to edit the default values as you need.
|
# Feel free to edit the default values as you need.
|
||||||
|
|
||||||
|
|
@ -77,6 +77,7 @@ icc.options.linker = "-cxxlib"
|
||||||
gcc.options.debug = "-g3 -O0"
|
gcc.options.debug = "-g3 -O0"
|
||||||
|
|
||||||
@if macosx:
|
@if macosx:
|
||||||
|
tlsEmulation:on
|
||||||
@if not release:
|
@if not release:
|
||||||
gcc.options.always = "-w -fasm-blocks -O1"
|
gcc.options.always = "-w -fasm-blocks -O1"
|
||||||
@else:
|
@else:
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@ primarySuffix ::= '.' optInd symbol [generalizedLit]
|
||||||
| '(' optInd namedExprList optPar ')'
|
| '(' optInd namedExprList optPar ')'
|
||||||
| '[' optInd [indexExpr (comma indexExpr)* [comma]] optPar ']'
|
| '[' optInd [indexExpr (comma indexExpr)* [comma]] optPar ']'
|
||||||
| '{' optInd [indexExpr (comma indexExpr)* [comma]] optPar '}'
|
| '{' optInd [indexExpr (comma indexExpr)* [comma]] optPar '}'
|
||||||
| pragma
|
|
||||||
|
|
||||||
primary ::= primaryPrefix* (symbol [generalizedLit] |
|
primary ::= primaryPrefix* (symbol [generalizedLit] |
|
||||||
constructor | castExpr | addrExpr)
|
constructor | castExpr | addrExpr)
|
||||||
|
|
@ -84,13 +83,15 @@ macroStmt ::= ':' [stmt] ('of' [exprList] ':' stmt
|
||||||
|'except' exceptList ':' stmt )*
|
|'except' exceptList ':' stmt )*
|
||||||
['else' ':' stmt]
|
['else' ':' stmt]
|
||||||
|
|
||||||
|
pragmaBlock ::= pragma [':' stmt]
|
||||||
|
|
||||||
simpleStmt ::= returnStmt
|
simpleStmt ::= returnStmt
|
||||||
| yieldStmt
|
| yieldStmt
|
||||||
| discardStmt
|
| discardStmt
|
||||||
| raiseStmt
|
| raiseStmt
|
||||||
| breakStmt
|
| breakStmt
|
||||||
| continueStmt
|
| continueStmt
|
||||||
| pragma
|
| pragmaBlock
|
||||||
| importStmt
|
| importStmt
|
||||||
| fromStmt
|
| fromStmt
|
||||||
| includeStmt
|
| includeStmt
|
||||||
|
|
|
||||||
|
|
@ -2570,10 +2570,11 @@ occuring in a generic:
|
||||||
|
|
||||||
echo a == b # works!
|
echo a == b # works!
|
||||||
|
|
||||||
In the example the generic ``==`` for tuples uses the ``==`` operators of the
|
In the example the generic ``==`` for tuples (as defined in the system module)
|
||||||
tuple's components. However, the ``==`` for the ``TIndex`` type is
|
uses the ``==`` operators of the tuple's components. However, the ``==`` for
|
||||||
defined *after* the ``==`` for tuples; yet the example compiles as the
|
the ``TIndex`` type is defined *after* the ``==`` for tuples; yet the example
|
||||||
instantiation takes the currently defined symbols into account too.
|
compiles as the instantiation takes the currently defined symbols into account
|
||||||
|
too.
|
||||||
|
|
||||||
|
|
||||||
Templates
|
Templates
|
||||||
|
|
@ -2679,7 +2680,8 @@ Syntax::
|
||||||
|
|
||||||
bindStmt ::= 'bind' IDENT (comma IDENT)*
|
bindStmt ::= 'bind' IDENT (comma IDENT)*
|
||||||
|
|
||||||
Exporting a template is a often a leaky abstraction. However, to compensate for
|
Exporting a template is a often a leaky abstraction as it can depend on
|
||||||
|
symbols that are not visible from a client module. However, to compensate for
|
||||||
this case, a `bind`:idx: statement can be used: It declares all identifiers
|
this case, a `bind`:idx: statement can be used: It declares all identifiers
|
||||||
that should be bound early (i.e. when the template is parsed):
|
that should be bound early (i.e. when the template is parsed):
|
||||||
|
|
||||||
|
|
@ -3096,6 +3098,23 @@ hint pragma
|
||||||
The `hint`:idx: pragma is used to make the compiler output a hint message with
|
The `hint`:idx: pragma is used to make the compiler output a hint message with
|
||||||
the given content. Compilation continues after the hint.
|
the given content. Compilation continues after the hint.
|
||||||
|
|
||||||
|
line pragma
|
||||||
|
-----------
|
||||||
|
The `line`:idx: pragma can be used to affect line information of the annotated
|
||||||
|
statement as seen in stack backtraces:
|
||||||
|
|
||||||
|
.. code-bock:: nimrod
|
||||||
|
|
||||||
|
template myassert*(cond: expr, msg = "") =
|
||||||
|
if not cond:
|
||||||
|
# change run-time line information of the 'raise' statement:
|
||||||
|
{.line: InstantiationInfo().}:
|
||||||
|
raise newException(EAssertionFailed, msg)
|
||||||
|
|
||||||
|
If the ``line`` pragma is used with a parameter, the parameter needs be a
|
||||||
|
``tuple[filename: string, line: int]``. If it is used without a parameter,
|
||||||
|
``system.InstantiationInfo()`` is used.
|
||||||
|
|
||||||
|
|
||||||
linearScanEnd pragma
|
linearScanEnd pragma
|
||||||
--------------------
|
--------------------
|
||||||
|
|
@ -3315,6 +3334,7 @@ Dynlib pragma for import
|
||||||
With the `dynlib`:idx: pragma a procedure can be imported from
|
With the `dynlib`:idx: pragma a procedure can be imported from
|
||||||
|
|
||||||
a dynamic library (``.dll`` files for Windows, ``lib*.so`` files for UNIX). The
|
a dynamic library (``.dll`` files for Windows, ``lib*.so`` files for UNIX). The
|
||||||
|
|
||||||
non-optional argument has to be the name of the dynamic library:
|
non-optional argument has to be the name of the dynamic library:
|
||||||
|
|
||||||
.. code-block:: Nimrod
|
.. code-block:: Nimrod
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ type
|
||||||
nnkModule, nnkProcDef, nnkMethodDef, nnkConverterDef,
|
nnkModule, nnkProcDef, nnkMethodDef, nnkConverterDef,
|
||||||
nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch,
|
nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch,
|
||||||
nnkElifBranch, nnkExceptBranch, nnkElse, nnkMacroStmt,
|
nnkElifBranch, nnkExceptBranch, nnkElse, nnkMacroStmt,
|
||||||
nnkAsmStmt, nnkPragma, nnkIfStmt, nnkWhenStmt,
|
nnkAsmStmt, nnkPragma, nnkPragmaBlock, nnkIfStmt, nnkWhenStmt,
|
||||||
nnkForStmt, nnkWhileStmt, nnkCaseStmt,
|
nnkForStmt, nnkWhileStmt, nnkCaseStmt,
|
||||||
nnkTypeSection, nnkVarSection, nnkLetSection, nnkConstSection,
|
nnkTypeSection, nnkVarSection, nnkLetSection, nnkConstSection,
|
||||||
nnkConstDef, nnkTypeDef,
|
nnkConstDef, nnkTypeDef,
|
||||||
|
|
|
||||||
|
|
@ -2080,6 +2080,12 @@ proc astToStr*[T](x: T): string {.magic: "AstToStr", noSideEffect.}
|
||||||
## converts the AST of `x` into a string representation. This is very useful
|
## converts the AST of `x` into a string representation. This is very useful
|
||||||
## for debugging.
|
## for debugging.
|
||||||
|
|
||||||
|
proc InstantiationInfo*(index = -1): tuple[filename: string, line: int] {.
|
||||||
|
magic: "InstantiationInfo", noSideEffect.}
|
||||||
|
## provides access to the compiler's instantiation stack line information.
|
||||||
|
## This is only useful for advanced meta programming. See the implementation
|
||||||
|
## of `assert` for an example.
|
||||||
|
|
||||||
proc raiseAssert(msg: string) {.noinline.} =
|
proc raiseAssert(msg: string) {.noinline.} =
|
||||||
raise newException(EAssertionFailed, msg)
|
raise newException(EAssertionFailed, msg)
|
||||||
|
|
||||||
|
|
@ -2089,15 +2095,17 @@ template assert*(cond: expr, msg = "") =
|
||||||
## raises an ``EAssertionFailure`` exception. However, the compiler may
|
## raises an ``EAssertionFailure`` exception. However, the compiler may
|
||||||
## not generate any code at all for ``assert`` if it is advised to do so.
|
## not generate any code at all for ``assert`` if it is advised to do so.
|
||||||
## Use ``assert`` for debugging purposes only.
|
## Use ``assert`` for debugging purposes only.
|
||||||
bind raiseAssert
|
bind raiseAssert, InstantiationInfo
|
||||||
when compileOption("assertions"):
|
when compileOption("assertions"):
|
||||||
if not cond:
|
if not cond:
|
||||||
|
{.line.}:
|
||||||
raiseAssert(astToStr(cond) & ' ' & msg)
|
raiseAssert(astToStr(cond) & ' ' & msg)
|
||||||
|
|
||||||
template doAssert*(cond: expr, msg = "") =
|
template doAssert*(cond: expr, msg = "") =
|
||||||
## same as `assert' but is always turned on and not affected by the
|
## same as `assert` but is always turned on and not affected by the
|
||||||
## ``--assertions`` command line switch.
|
## ``--assertions`` command line switch.
|
||||||
bind raiseAssert
|
bind raiseAssert, InstantiationInfo
|
||||||
if not cond:
|
if not cond:
|
||||||
|
{.line: InstantiationInfo().}:
|
||||||
raiseAssert(astToStr(cond) & ' ' & msg)
|
raiseAssert(astToStr(cond) & ' ' & msg)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
# To test stack overflow message
|
# To test stack overflow message
|
||||||
|
|
||||||
proc over(a: int): int =
|
proc over(a: int): int =
|
||||||
if a >= 400:
|
if a >= 10:
|
||||||
assert false
|
assert false
|
||||||
return
|
return
|
||||||
result = over(a+1)+5
|
result = over(a+1)+5
|
||||||
|
|
|
||||||
1
todo.txt
1
todo.txt
|
|
@ -1,7 +1,6 @@
|
||||||
version 0.8.14
|
version 0.8.14
|
||||||
==============
|
==============
|
||||||
|
|
||||||
- fix line info in assertions
|
|
||||||
- bug: tsortdev does not run with native GC
|
- bug: tsortdev does not run with native GC
|
||||||
|
|
||||||
version 0.9.0
|
version 0.9.0
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue