'assert' is now implemented without compiler magic

This commit is contained in:
Araq 2011-12-04 20:14:50 +01:00
commit 70cf34cbdc
16 changed files with 66 additions and 24 deletions

View file

@ -370,7 +370,8 @@ type
mConTArr, mConTT, mSlice, mConTArr, mConTT, mSlice,
mFields, mFieldPairs, mFields, mFieldPairs,
mAppendStrCh, mAppendStrStr, mAppendSeqElem, mAppendStrCh, mAppendStrStr, mAppendSeqElem,
mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq, mAssert, mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq,
mAssert, mAstToStr, mRand,
mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast, mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast,
mNewString, mNewStringOfCap, mNewString, mNewStringOfCap,
mReset, mReset,

View file

@ -607,7 +607,7 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
InternalError(e.info, "genCheckedRecordField") # generate the checks: InternalError(e.info, "genCheckedRecordField") # generate the checks:
for i in countup(1, sonsLen(e) - 1): for i in countup(1, sonsLen(e) - 1):
it = e.sons[i] it = e.sons[i]
assert(it.kind == nkCall) assert(it.kind in nkCallKinds)
assert(it.sons[0].kind == nkSym) assert(it.sons[0].kind == nkSym)
op = it.sons[0].sym op = it.sons[0].sym
if op.magic == mNot: it = it.sons[1] if op.magic == mNot: it = it.sons[1]
@ -1403,7 +1403,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mIncl, mExcl, mCard, mLtSet, mLeSet, mEqSet, mMulSet, mPlusSet, mMinusSet, of mIncl, mExcl, mCard, mLtSet, mLeSet, mEqSet, mMulSet, mPlusSet, mMinusSet,
mInSet: mInSet:
genSetOp(p, e, d, op) genSetOp(p, e, d, op)
of mNewString, mNewStringOfCap, mCopyStr, mCopyStrLast, mExit: of mNewString, mNewStringOfCap, mCopyStr, mCopyStrLast, mExit, mRand:
var opr = e.sons[0].sym var opr = e.sons[0].sym
if lfNoDecl notin opr.loc.flags: if lfNoDecl notin opr.loc.flags:
discard cgsym(p.module, opr.loc.r.ropeToStr) discard cgsym(p.module, opr.loc.r.ropeToStr)

View file

@ -1162,7 +1162,8 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
of nkEmpty: result = n of nkEmpty: result = n
of nkSym: result = evalSym(c, n, flags) of nkSym: result = evalSym(c, n, flags)
of nkType..nkNilLit: result = copyNode(n) # end of atoms of nkType..nkNilLit: result = copyNode(n) # end of atoms
of nkCall, nkHiddenCallConv, nkMacroStmt, nkCommand, nkCallStrLit: of nkCall, nkHiddenCallConv, nkMacroStmt, nkCommand, nkCallStrLit, nkInfix,
nkPrefix, nkPostfix:
result = evalMagicOrCall(c, n) result = evalMagicOrCall(c, n)
of nkCurly, nkBracket, nkRange: of nkCurly, nkBracket, nkRange:
# flags need to be passed here for mNAddMultiple :-( # flags need to be passed here for mNAddMultiple :-(

View file

@ -412,6 +412,7 @@ const
PosErrorFormat* = "$1($2, $3) Error: $4" PosErrorFormat* = "$1($2, $3) Error: $4"
PosWarningFormat* = "$1($2, $3) Warning: $4" PosWarningFormat* = "$1($2, $3) Warning: $4"
PosHintFormat* = "$1($2, $3) Hint: $4" PosHintFormat* = "$1($2, $3) Hint: $4"
PosContextFormat = "$1($2, $3) Info: $4"
RawErrorFormat* = "Error: $1" RawErrorFormat* = "Error: $1"
RawWarningFormat* = "Warning: $1" RawWarningFormat* = "Warning: $1"
RawHintFormat* = "Hint: $1" RawHintFormat* = "Hint: $1"
@ -536,7 +537,7 @@ proc writeContext(lastinfo: TLineInfo) =
var info = lastInfo var info = lastInfo
for i in countup(0, len(msgContext) - 1): for i in countup(0, len(msgContext) - 1):
if msgContext[i] != lastInfo and msgContext[i] != info: if msgContext[i] != lastInfo and msgContext[i] != info:
MsgWriteln(posErrorFormat % [toFilename(msgContext[i]), MsgWriteln(posContextFormat % [toFilename(msgContext[i]),
coordToStr(msgContext[i].line), coordToStr(msgContext[i].line),
coordToStr(msgContext[i].col), coordToStr(msgContext[i].col),
getMessageStr(errInstantiationFrom, "")]) getMessageStr(errInstantiationFrom, "")])

View file

@ -993,6 +993,12 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
result = semDirectOp(c, n, flags) result = semDirectOp(c, n, flags)
of mSlurp: result = semSlurp(c, n, flags) of mSlurp: result = semSlurp(c, n, flags)
of mExpandToAst: result = semExpandToAst(c, n, s, flags) of mExpandToAst: result = semExpandToAst(c, n, s, flags)
of mAstToStr:
if sonsLen(n) == 2:
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
result.typ = getSysType(tyString)
else:
result = semDirectOp(c, n, flags)
else: result = semDirectOp(c, n, flags) else: result = semDirectOp(c, n, flags)
proc semIfExpr(c: PContext, n: PNode): PNode = proc semIfExpr(c: PContext, n: PNode): PNode =

View file

@ -209,6 +209,8 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
mParseExprToAst, mParseStmtToAst, mExpandToAst, mParseExprToAst, mParseStmtToAst, mExpandToAst,
mNLen..mNError, mEqRef: mNLen..mNError, mEqRef:
nil nil
of mRand:
result = newIntNodeT(math.random(a.getInt.int), n)
else: InternalError(a.info, "evalOp(" & $m & ')') else: InternalError(a.info, "evalOp(" & $m & ')')
proc getConstIfExpr(c: PSym, n: PNode): PNode = proc getConstIfExpr(c: PSym, n: PNode): PNode =
@ -440,6 +442,8 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
result = magicCall(m, n) result = magicCall(m, n)
of mIs: of mIs:
result = newIntNodeT(ord(sameType(n[1].typ, n[2].typ)), n) result = newIntNodeT(ord(sameType(n[1].typ, n[2].typ)), n)
of mAstToStr:
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
else: else:
result = magicCall(m, n) result = magicCall(m, n)
except EOverflow: except EOverflow:

View file

@ -404,7 +404,7 @@ proc semFor(c: PContext, n: PNode): PNode =
openScope(c.tab) openScope(c.tab)
n.sons[length-2] = semExprNoDeref(c, n.sons[length-2], {efWantIterator}) n.sons[length-2] = semExprNoDeref(c, n.sons[length-2], {efWantIterator})
var call = n.sons[length-2] var call = n.sons[length-2]
if call.kind != nkCall or call.sons[0].kind != nkSym or if call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
call.sons[0].sym.kind != skIterator: call.sons[0].sym.kind != skIterator:
GlobalError(n.sons[length - 2].info, errIteratorExpected) GlobalError(n.sons[length - 2].info, errIteratorExpected)
elif call.sons[0].sym.magic != mNone: elif call.sons[0].sym.magic != mNone:

View file

@ -597,7 +597,7 @@ proc matchesAux*(c: PContext, n: PNode, m: var TCandidate,
var f = 1 # iterates over formal parameters var f = 1 # iterates over formal parameters
var a = 1 # iterates over the actual given arguments var a = 1 # iterates over the actual given arguments
m.state = csMatch # until proven otherwise m.state = csMatch # until proven otherwise
m.call = newNodeI(nkCall, n.info) m.call = newNodeI(n.kind, n.info)
m.call.typ = base(m.callee) # may be nil m.call.typ = base(m.callee) # may be nil
var formalLen = sonsLen(m.callee.n) var formalLen = sonsLen(m.callee.n)
addSon(m.call, copyTree(n.sons[0])) addSon(m.call, copyTree(n.sons[0]))

View file

@ -117,7 +117,7 @@ proc getParser(ident: PIdent): TParserKind =
rawMessage(errInvalidDirectiveX, ident.s) rawMessage(errInvalidDirectiveX, ident.s)
proc getCallee(n: PNode): PIdent = proc getCallee(n: PNode): PIdent =
if (n.kind == nkCall) and (n.sons[0].kind == nkIdent): if n.kind in nkCallKinds and n.sons[0].kind == nkIdent:
result = n.sons[0].ident result = n.sons[0].ident
elif n.kind == nkIdent: elif n.kind == nkIdent:
result = n.ident result = n.ident

View file

@ -468,7 +468,7 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
addVar(v, copyTree(n.sons[i])) # declare new vars addVar(v, copyTree(n.sons[i])) # declare new vars
add(result, v.ptransNode) add(result, v.ptransNode)
var call = n.sons[length - 2] var call = n.sons[length - 2]
if call.kind != nkCall or call.sons[0].kind != nkSym: if call.kind notin nkCallKinds or call.sons[0].kind != nkSym:
InternalError(call.info, "transformFor") InternalError(call.info, "transformFor")
var newC = newTransCon(call.sons[0].sym) var newC = newTransCon(call.sons[0].sym)

View file

@ -1050,13 +1050,6 @@ proc deallocShared*(p: Pointer) {.noconv, rtl.}
## memory (or just freeing it twice!) a core dump may happen ## memory (or just freeing it twice!) a core dump may happen
## or other memory may be corrupted. ## or other memory may be corrupted.
proc assert*(cond: bool) {.magic: "Assert", noSideEffect.}
## provides a means to implement `programming by contracts`:idx: in Nimrod.
## ``assert`` evaluates expression ``cond`` and if ``cond`` is false, it
## raises an ``EAssertionFailure`` exception. However, the compiler may
## not generate any code at all for ``assert`` if it is advised to do so.
## Use ``assert`` for debugging purposes only.
proc swap*[T](a, b: var T) {.magic: "Swap", noSideEffect.} proc swap*[T](a, b: var T) {.magic: "Swap", noSideEffect.}
## swaps the values `a` and `b`. This is often more efficient than ## swaps the values `a` and `b`. This is often more efficient than
## ``tmp = a; a = b; b = tmp``. Particularly useful for sorting algorithms. ## ``tmp = a; a = b; b = tmp``. Particularly useful for sorting algorithms.
@ -2071,3 +2064,21 @@ proc `/=` *(x: var float, y:float) {.inline, noSideEffect.} =
proc `&=`* (x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.} proc `&=`* (x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.}
proc rand*(max: int): int {.magic: "Rand", sideEffect.}
## compile-time `random` function. Useful for debugging.
proc astToStr*[T](x: T): string {.magic: "AstToStr", noSideEffect.}
## converts the AST of `x` into a string representation. This is very useful
## for debugging.
template assert*(cond: expr, msg = "") =
## provides a means to implement `programming by contracts`:idx: in Nimrod.
## ``assert`` evaluates expression ``cond`` and if ``cond`` is false, it
## raises an ``EAssertionFailure`` exception. However, the compiler may
## not generate any code at all for ``assert`` if it is advised to do so.
## Use ``assert`` for debugging purposes only.
when compileOption("assertions"):
if not cond:
raise newException(EAssertionFailed, astToStr(cond) & ' ' & msg)

View file

@ -38,7 +38,7 @@ proc initRawChannel(p: pointer) =
proc deinitRawChannel(p: pointer) = proc deinitRawChannel(p: pointer) =
var c = cast[PRawChannel](p) var c = cast[PRawChannel](p)
# we need to grab the lock to be save against sending threads! # we need to grab the lock to be safe against sending threads!
acquireSys(c.lock) acquireSys(c.lock)
c.mask = ChannelDeadMask c.mask = ChannelDeadMask
deallocOsPages(c.region) deallocOsPages(c.region)
@ -154,7 +154,7 @@ proc rawSend(q: PRawChannel, data: pointer, typ: PNimType) =
## adds an `item` to the end of the queue `q`. ## adds an `item` to the end of the queue `q`.
var cap = q.mask+1 var cap = q.mask+1
if q.count >= cap: if q.count >= cap:
# start with capicity for 2 entries in the queue: # start with capacity for 2 entries in the queue:
if cap == 0: cap = 1 if cap == 0: cap = 1
var n = cast[pbytes](Alloc0(q.region, cap*2*typ.size)) var n = cast[pbytes](Alloc0(q.region, cap*2*typ.size))
var z = 0 var z = 0
@ -175,7 +175,7 @@ proc rawSend(q: PRawChannel, data: pointer, typ: PNimType) =
q.wr = (q.wr + 1) and q.mask q.wr = (q.wr + 1) and q.mask
proc rawRecv(q: PRawChannel, data: pointer, typ: PNimType) = proc rawRecv(q: PRawChannel, data: pointer, typ: PNimType) =
assert q.count > 0 sysAssert q.count > 0, "rawRecv"
dec q.count dec q.count
storeAux(data, addr(q.data[q.rd * typ.size]), typ, q, mLoad) storeAux(data, addr(q.data[q.rd * typ.size]), typ, q, mLoad)
q.rd = (q.rd + 1) and q.mask q.rd = (q.rd + 1) and q.mask

View file

@ -410,7 +410,7 @@ proc NimCopy(x: pointer, ti: PNimType): pointer {.compilerproc.}
proc NimCopyAux(dest, src: Pointer, n: ptr TNimNode) {.exportc.} = proc NimCopyAux(dest, src: Pointer, n: ptr TNimNode) {.exportc.} =
case n.kind case n.kind
of nkNone: sysAssert(false) of nkNone: sysAssert(false, "NimCopyAux")
of nkSlot: of nkSlot:
asm "`dest`[`n`.offset] = NimCopy(`src`[`n`.offset], `n`.typ);" asm "`dest`[`n`.offset] = NimCopy(`src`[`n`.offset], `n`.typ);"
of nkList: of nkList:

14
tests/run/tuserassert.nim Normal file
View file

@ -0,0 +1,14 @@
discard """
output: "454 == 45ugh"
"""
template myAssert(cond: expr) =
when rand(3) < 2:
let c = cond.astToStr
{.warning: "code activated: " & c.}
if not cond:
echo c, "ugh"
myAssert(454 == 45)

View file

@ -1,6 +1,7 @@
version 0.8.14 version 0.8.14
============== ==============
- find a proper bugfix for C compilers optimizing away stack roots
- warning for implicit openArray -> varargs convention - warning for implicit openArray -> varargs convention
- implement explicit varargs; **but** ``len(varargs)`` problem remains! - implement explicit varargs; **but** ``len(varargs)`` problem remains!
--> solve by implicit conversion from varargs to openarray --> solve by implicit conversion from varargs to openarray
@ -123,7 +124,7 @@ Low priority
need to recompile clients; er ... what about templates, macros or anything need to recompile clients; er ... what about templates, macros or anything
that has inlining semantics? that has inlining semantics?
- codegen should use "NIM_CAST" macro and respect aliasing rules for GCC - codegen should use "NIM_CAST" macro and respect aliasing rules for GCC
- remove unused mAssert magic
Version 2 Version 2
========= =========

View file

@ -53,6 +53,8 @@ Changes affecting backwards compatibility
because they should not be used directly anymore. because they should not be used directly anymore.
Wrapper procs have been created that should be used instead. Wrapper procs have been created that should be used instead.
- ``export`` is now a keyword. - ``export`` is now a keyword.
- ``assert`` is now implemented in pure Nimrod; it's easy to implement your
own assertion schemes now.
Language Additions Language Additions
@ -140,6 +142,7 @@ Library Additions
and ``exec`` on Posix systems. Define the symbol ``useFork`` to revert to and ``exec`` on Posix systems. Define the symbol ``useFork`` to revert to
the old implementation. the old implementation.
- Added ``intsets.assign``. - Added ``intsets.assign``.
- Added ``system.astToStr`` and ``system.rand``.
2011-07-10 Version 0.8.12 released 2011-07-10 Version 0.8.12 released