mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-04 12:07:51 +00:00
'assert' is now implemented without compiler magic
This commit is contained in:
@@ -370,7 +370,8 @@ type
|
||||
mConTArr, mConTT, mSlice,
|
||||
mFields, mFieldPairs,
|
||||
mAppendStrCh, mAppendStrStr, mAppendSeqElem,
|
||||
mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq, mAssert,
|
||||
mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq,
|
||||
mAssert, mAstToStr, mRand,
|
||||
mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast,
|
||||
mNewString, mNewStringOfCap,
|
||||
mReset,
|
||||
|
||||
@@ -607,7 +607,7 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
|
||||
InternalError(e.info, "genCheckedRecordField") # generate the checks:
|
||||
for i in countup(1, sonsLen(e) - 1):
|
||||
it = e.sons[i]
|
||||
assert(it.kind == nkCall)
|
||||
assert(it.kind in nkCallKinds)
|
||||
assert(it.sons[0].kind == nkSym)
|
||||
op = it.sons[0].sym
|
||||
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,
|
||||
mInSet:
|
||||
genSetOp(p, e, d, op)
|
||||
of mNewString, mNewStringOfCap, mCopyStr, mCopyStrLast, mExit:
|
||||
of mNewString, mNewStringOfCap, mCopyStr, mCopyStrLast, mExit, mRand:
|
||||
var opr = e.sons[0].sym
|
||||
if lfNoDecl notin opr.loc.flags:
|
||||
discard cgsym(p.module, opr.loc.r.ropeToStr)
|
||||
|
||||
@@ -1162,7 +1162,8 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
|
||||
of nkEmpty: result = n
|
||||
of nkSym: result = evalSym(c, n, flags)
|
||||
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)
|
||||
of nkCurly, nkBracket, nkRange:
|
||||
# flags need to be passed here for mNAddMultiple :-(
|
||||
|
||||
@@ -412,6 +412,7 @@ const
|
||||
PosErrorFormat* = "$1($2, $3) Error: $4"
|
||||
PosWarningFormat* = "$1($2, $3) Warning: $4"
|
||||
PosHintFormat* = "$1($2, $3) Hint: $4"
|
||||
PosContextFormat = "$1($2, $3) Info: $4"
|
||||
RawErrorFormat* = "Error: $1"
|
||||
RawWarningFormat* = "Warning: $1"
|
||||
RawHintFormat* = "Hint: $1"
|
||||
@@ -536,10 +537,10 @@ proc writeContext(lastinfo: TLineInfo) =
|
||||
var info = lastInfo
|
||||
for i in countup(0, len(msgContext) - 1):
|
||||
if msgContext[i] != lastInfo and msgContext[i] != info:
|
||||
MsgWriteln(posErrorFormat % [toFilename(msgContext[i]),
|
||||
coordToStr(msgContext[i].line),
|
||||
coordToStr(msgContext[i].col),
|
||||
getMessageStr(errInstantiationFrom, "")])
|
||||
MsgWriteln(posContextFormat % [toFilename(msgContext[i]),
|
||||
coordToStr(msgContext[i].line),
|
||||
coordToStr(msgContext[i].col),
|
||||
getMessageStr(errInstantiationFrom, "")])
|
||||
info = msgContext[i]
|
||||
|
||||
proc rawMessage*(msg: TMsgKind, args: openarray[string]) =
|
||||
|
||||
@@ -993,6 +993,12 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||
result = semDirectOp(c, n, flags)
|
||||
of mSlurp: result = semSlurp(c, n, 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)
|
||||
|
||||
proc semIfExpr(c: PContext, n: PNode): PNode =
|
||||
|
||||
@@ -209,6 +209,8 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
||||
mParseExprToAst, mParseStmtToAst, mExpandToAst,
|
||||
mNLen..mNError, mEqRef:
|
||||
nil
|
||||
of mRand:
|
||||
result = newIntNodeT(math.random(a.getInt.int), n)
|
||||
else: InternalError(a.info, "evalOp(" & $m & ')')
|
||||
|
||||
proc getConstIfExpr(c: PSym, n: PNode): PNode =
|
||||
@@ -440,6 +442,8 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
|
||||
result = magicCall(m, n)
|
||||
of mIs:
|
||||
result = newIntNodeT(ord(sameType(n[1].typ, n[2].typ)), n)
|
||||
of mAstToStr:
|
||||
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
|
||||
else:
|
||||
result = magicCall(m, n)
|
||||
except EOverflow:
|
||||
|
||||
@@ -404,7 +404,7 @@ proc semFor(c: PContext, n: PNode): PNode =
|
||||
openScope(c.tab)
|
||||
n.sons[length-2] = semExprNoDeref(c, n.sons[length-2], {efWantIterator})
|
||||
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:
|
||||
GlobalError(n.sons[length - 2].info, errIteratorExpected)
|
||||
elif call.sons[0].sym.magic != mNone:
|
||||
|
||||
@@ -597,7 +597,7 @@ proc matchesAux*(c: PContext, n: PNode, m: var TCandidate,
|
||||
var f = 1 # iterates over formal parameters
|
||||
var a = 1 # iterates over the actual given arguments
|
||||
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
|
||||
var formalLen = sonsLen(m.callee.n)
|
||||
addSon(m.call, copyTree(n.sons[0]))
|
||||
|
||||
@@ -117,7 +117,7 @@ proc getParser(ident: PIdent): TParserKind =
|
||||
rawMessage(errInvalidDirectiveX, ident.s)
|
||||
|
||||
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
|
||||
elif n.kind == nkIdent:
|
||||
result = n.ident
|
||||
|
||||
@@ -468,7 +468,7 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||
addVar(v, copyTree(n.sons[i])) # declare new vars
|
||||
add(result, v.ptransNode)
|
||||
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")
|
||||
|
||||
var newC = newTransCon(call.sons[0].sym)
|
||||
|
||||
@@ -1050,13 +1050,6 @@ proc deallocShared*(p: Pointer) {.noconv, rtl.}
|
||||
## memory (or just freeing it twice!) a core dump may happen
|
||||
## 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.}
|
||||
## swaps the values `a` and `b`. This is often more efficient than
|
||||
## ``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 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)
|
||||
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ proc initRawChannel(p: pointer) =
|
||||
|
||||
proc deinitRawChannel(p: pointer) =
|
||||
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)
|
||||
c.mask = ChannelDeadMask
|
||||
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`.
|
||||
var cap = q.mask+1
|
||||
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
|
||||
var n = cast[pbytes](Alloc0(q.region, cap*2*typ.size))
|
||||
var z = 0
|
||||
@@ -175,7 +175,7 @@ proc rawSend(q: PRawChannel, data: pointer, typ: PNimType) =
|
||||
q.wr = (q.wr + 1) and q.mask
|
||||
|
||||
proc rawRecv(q: PRawChannel, data: pointer, typ: PNimType) =
|
||||
assert q.count > 0
|
||||
sysAssert q.count > 0, "rawRecv"
|
||||
dec q.count
|
||||
storeAux(data, addr(q.data[q.rd * typ.size]), typ, q, mLoad)
|
||||
q.rd = (q.rd + 1) and q.mask
|
||||
|
||||
@@ -410,7 +410,7 @@ proc NimCopy(x: pointer, ti: PNimType): pointer {.compilerproc.}
|
||||
|
||||
proc NimCopyAux(dest, src: Pointer, n: ptr TNimNode) {.exportc.} =
|
||||
case n.kind
|
||||
of nkNone: sysAssert(false)
|
||||
of nkNone: sysAssert(false, "NimCopyAux")
|
||||
of nkSlot:
|
||||
asm "`dest`[`n`.offset] = NimCopy(`src`[`n`.offset], `n`.typ);"
|
||||
of nkList:
|
||||
|
||||
14
tests/run/tuserassert.nim
Normal file
14
tests/run/tuserassert.nim
Normal 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)
|
||||
|
||||
3
todo.txt
3
todo.txt
@@ -1,6 +1,7 @@
|
||||
version 0.8.14
|
||||
==============
|
||||
|
||||
- find a proper bugfix for C compilers optimizing away stack roots
|
||||
- warning for implicit openArray -> varargs convention
|
||||
- implement explicit varargs; **but** ``len(varargs)`` problem remains!
|
||||
--> 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
|
||||
that has inlining semantics?
|
||||
- codegen should use "NIM_CAST" macro and respect aliasing rules for GCC
|
||||
|
||||
- remove unused mAssert magic
|
||||
|
||||
Version 2
|
||||
=========
|
||||
|
||||
@@ -53,6 +53,8 @@ Changes affecting backwards compatibility
|
||||
because they should not be used directly anymore.
|
||||
Wrapper procs have been created that should be used instead.
|
||||
- ``export`` is now a keyword.
|
||||
- ``assert`` is now implemented in pure Nimrod; it's easy to implement your
|
||||
own assertion schemes now.
|
||||
|
||||
|
||||
Language Additions
|
||||
@@ -140,6 +142,7 @@ Library Additions
|
||||
and ``exec`` on Posix systems. Define the symbol ``useFork`` to revert to
|
||||
the old implementation.
|
||||
- Added ``intsets.assign``.
|
||||
- Added ``system.astToStr`` and ``system.rand``.
|
||||
|
||||
|
||||
2011-07-10 Version 0.8.12 released
|
||||
|
||||
Reference in New Issue
Block a user