mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-31 10:53:40 +00:00
Compare commits
29 Commits
v0.19.4
...
version-0-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c6f601d48e | ||
|
|
d353c20c03 | ||
|
|
b85cc17998 | ||
|
|
8c4c3464e1 | ||
|
|
f575cdc1ae | ||
|
|
15c526c298 | ||
|
|
a62685372f | ||
|
|
8b7cd2e19f | ||
|
|
80e9270580 | ||
|
|
d92f322faa | ||
|
|
dbca89730b | ||
|
|
f1c297e439 | ||
|
|
3cf038027b | ||
|
|
0e34258749 | ||
|
|
897b63e5cd | ||
|
|
c9c5abcdc1 | ||
|
|
541b8df315 | ||
|
|
2d1dea9484 | ||
|
|
aa2dfd1cef | ||
|
|
32780acc61 | ||
|
|
3aeaa90bd8 | ||
|
|
99fc4029e0 | ||
|
|
37ff8753a1 | ||
|
|
f1a78b8b4c | ||
|
|
12bc7c9882 | ||
|
|
c9441c6f79 | ||
|
|
eb42853ff4 | ||
|
|
c366a8e386 | ||
|
|
56d213ca9b |
@@ -181,9 +181,16 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
|
||||
else: discard
|
||||
of nkObjConstr:
|
||||
result = arNo
|
||||
for i in 1..<b.len:
|
||||
for i in 1 ..< b.len:
|
||||
let res = isPartOf(a, b[i][1])
|
||||
if res != arNo:
|
||||
result = res
|
||||
if res == arYes: break
|
||||
of nkCall:
|
||||
result = arNo
|
||||
for i in 1 ..< b.len:
|
||||
let res = isPartOf(a, b[i])
|
||||
if res != arNo:
|
||||
result = res
|
||||
if res == arYes: break
|
||||
else: discard
|
||||
|
||||
@@ -990,7 +990,7 @@ const
|
||||
miscPos* = 5 # used for undocumented and hacky stuff
|
||||
bodyPos* = 6 # position of body; use rodread.getBody() instead!
|
||||
resultPos* = 7
|
||||
dispatcherPos* = 8 # caution: if method has no 'result' it can be position 7!
|
||||
dispatcherPos* = 8
|
||||
|
||||
nkCallKinds* = {nkCall, nkInfix, nkPrefix, nkPostfix,
|
||||
nkCommand, nkCallStrLit, nkHiddenCallConv}
|
||||
@@ -1711,8 +1711,7 @@ proc toVar*(typ: PType): PType =
|
||||
proc toRef*(typ: PType): PType =
|
||||
## If ``typ`` is a tyObject then it is converted into a `ref <typ>` and
|
||||
## returned. Otherwise ``typ`` is simply returned as-is.
|
||||
result = typ
|
||||
if typ.kind == tyObject:
|
||||
if typ.skipTypes({tyAlias, tyGenericInst}).kind == tyObject:
|
||||
result = newType(tyRef, typ.owner)
|
||||
rawAddSon(result, typ)
|
||||
|
||||
@@ -1720,19 +1719,19 @@ proc toObject*(typ: PType): PType =
|
||||
## If ``typ`` is a tyRef then its immediate son is returned (which in many
|
||||
## cases should be a ``tyObject``).
|
||||
## Otherwise ``typ`` is simply returned as-is.
|
||||
result = typ
|
||||
if result.kind == tyRef:
|
||||
result = result.lastSon
|
||||
let t = typ.skipTypes({tyAlias, tyGenericInst})
|
||||
if t.kind == tyRef: t.lastSon
|
||||
else: typ
|
||||
|
||||
proc isException*(t: PType): bool =
|
||||
# check if `y` is object type and it inherits from Exception
|
||||
assert(t != nil)
|
||||
|
||||
if t.kind != tyObject:
|
||||
if t.kind notin {tyObject, tyGenericInst}:
|
||||
return false
|
||||
|
||||
var base = t
|
||||
while base != nil:
|
||||
while base != nil and base.kind in {tyRef, tyObject, tyGenericInst}:
|
||||
if base.sym != nil and base.sym.magic == mException:
|
||||
return true
|
||||
base = base.lastSon
|
||||
|
||||
@@ -165,7 +165,6 @@ proc mapType(conf: ConfigRef; typ: PType): TCTypeKind =
|
||||
of tySet:
|
||||
if mapSetType(conf, base) == ctArray: result = ctPtrToArray
|
||||
else: result = ctPtr
|
||||
# XXX for some reason this breaks the pegs module
|
||||
else: result = ctPtr
|
||||
of tyPointer: result = ctPtr
|
||||
of tySequence: result = ctNimSeq
|
||||
|
||||
@@ -37,10 +37,9 @@ proc genConv(n: PNode, d: PType, downcast: bool; conf: ConfigRef): PNode =
|
||||
|
||||
proc getDispatcher*(s: PSym): PSym =
|
||||
## can return nil if is has no dispatcher.
|
||||
let dispn = lastSon(s.ast)
|
||||
if dispn.kind == nkSym:
|
||||
let disp = dispn.sym
|
||||
if sfDispatcher in disp.flags: result = disp
|
||||
if dispatcherPos < s.ast.len:
|
||||
result = s.ast[dispatcherPos].sym
|
||||
doAssert sfDispatcher in result.flags
|
||||
|
||||
proc methodCall*(n: PNode; conf: ConfigRef): PNode =
|
||||
result = n
|
||||
@@ -99,13 +98,14 @@ proc sameMethodBucket(a, b: PSym): MethodResult =
|
||||
return No
|
||||
|
||||
proc attachDispatcher(s: PSym, dispatcher: PNode) =
|
||||
var L = s.ast.len-1
|
||||
var x = s.ast.sons[L]
|
||||
if x.kind == nkSym and sfDispatcher in x.sym.flags:
|
||||
if dispatcherPos < s.ast.len:
|
||||
# we've added a dispatcher already, so overwrite it
|
||||
s.ast.sons[L] = dispatcher
|
||||
s.ast.sons[dispatcherPos] = dispatcher
|
||||
else:
|
||||
s.ast.add(dispatcher)
|
||||
setLen(s.ast.sons, dispatcherPos+1)
|
||||
if s.ast[resultPos] == nil:
|
||||
s.ast[resultPos] = newNodeI(nkEmpty, s.info)
|
||||
s.ast.sons[dispatcherPos] = dispatcher
|
||||
|
||||
proc createDispatcher(s: PSym): PSym =
|
||||
var disp = copySym(s)
|
||||
@@ -165,7 +165,7 @@ proc methodDef*(g: ModuleGraph; s: PSym, fromCache: bool) =
|
||||
case sameMethodBucket(disp, s)
|
||||
of Yes:
|
||||
add(g.methods[i].methods, s)
|
||||
attachDispatcher(s, lastSon(disp.ast))
|
||||
attachDispatcher(s, disp.ast[dispatcherPos])
|
||||
fixupDispatcher(s, disp, g.config)
|
||||
#echo "fixup ", disp.name.s, " ", disp.id
|
||||
when useEffectSystem: checkMethodEffects(g, disp, s)
|
||||
|
||||
@@ -48,14 +48,14 @@ const
|
||||
"Copyright (c) 2006-" & copyrightYear & " by Andreas Rumpf\n"
|
||||
|
||||
const
|
||||
Usage = slurp"../doc/basicopt.txt".replace("//", "")
|
||||
Usage = slurp"../doc/basicopt.txt".replace(" //", " ")
|
||||
FeatureDesc = block:
|
||||
var x = ""
|
||||
for f in low(Feature)..high(Feature):
|
||||
if x.len > 0: x.add "|"
|
||||
x.add $f
|
||||
x
|
||||
AdvancedUsage = slurp"../doc/advopt.txt".replace("//", "") % FeatureDesc
|
||||
AdvancedUsage = slurp"../doc/advopt.txt".replace(" //", " ") % FeatureDesc
|
||||
|
||||
proc getCommandLineDesc(conf: ConfigRef): string =
|
||||
result = (HelpMessage % [VersionAsString, platform.OS[conf.target.hostOS].name,
|
||||
|
||||
@@ -92,6 +92,7 @@ proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
|
||||
rawImportSymbol(c, e)
|
||||
e = nextIdentIter(it, fromMod.tab)
|
||||
else: rawImportSymbol(c, s)
|
||||
suggestSym(c.config, n.info, s, c.graph.usageSym, false)
|
||||
|
||||
proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) =
|
||||
var i: TTabIter
|
||||
|
||||
@@ -476,6 +476,7 @@ proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string,
|
||||
r.res = "$1 = (($1 $2 $3) $4)" % [x.rdLoc, rope op, y.rdLoc, trimmer]
|
||||
else:
|
||||
r.res = "(($1 $2 $3) $4)" % [x.rdLoc, rope op, y.rdLoc, trimmer]
|
||||
r.kind = resExpr
|
||||
|
||||
proc ternaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
|
||||
var x, y, z: TCompRes
|
||||
@@ -1706,13 +1707,13 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||
of mHigh:
|
||||
unaryExpr(p, n, r, "", "($1 != null ? ($1.length-1) : -1)")
|
||||
of mInc:
|
||||
if n[1].typ.skipTypes(abstractRange).kind in tyUInt .. tyUInt64:
|
||||
if n[1].typ.skipTypes(abstractRange).kind in {tyUInt..tyUInt64}:
|
||||
binaryUintExpr(p, n, r, "+", true)
|
||||
else:
|
||||
if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 += $2")
|
||||
else: binaryExpr(p, n, r, "addInt", "$1 = addInt($1, $2)")
|
||||
of ast.mDec:
|
||||
if n[1].typ.skipTypes(abstractRange).kind in tyUInt .. tyUInt64:
|
||||
if n[1].typ.skipTypes(abstractRange).kind in {tyUInt..tyUInt64}:
|
||||
binaryUintExpr(p, n, r, "-", true)
|
||||
else:
|
||||
if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 -= $2")
|
||||
|
||||
@@ -823,11 +823,12 @@ proc semRaise(c: PContext, n: PNode): PNode =
|
||||
checkSonsLen(n, 1, c.config)
|
||||
if n[0].kind != nkEmpty:
|
||||
n[0] = semExprWithType(c, n[0])
|
||||
let typ = n[0].typ
|
||||
var typ = n[0].typ
|
||||
if not isImportedException(typ, c.config):
|
||||
if typ.kind != tyRef or typ.lastSon.kind != tyObject:
|
||||
typ = typ.skipTypes({tyAlias, tyGenericInst})
|
||||
if typ.kind != tyRef:
|
||||
localError(c.config, n.info, errExprCannotBeRaised)
|
||||
if typ.len > 0 and not isException(typ.lastSon):
|
||||
if not isException(typ.lastSon):
|
||||
localError(c.config, n.info, "raised object of type $1 does not inherit from Exception",
|
||||
[typeToString(typ)])
|
||||
|
||||
|
||||
@@ -725,8 +725,8 @@ proc addInheritedFieldsAux(c: PContext, check: var IntSet, pos: var int,
|
||||
of nkOfBranch, nkElse:
|
||||
addInheritedFieldsAux(c, check, pos, lastSon(n.sons[i]))
|
||||
else: internalError(c.config, n.info, "addInheritedFieldsAux(record case branch)")
|
||||
of nkRecList:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
of nkRecList, nkRecWhen, nkElifBranch, nkElse:
|
||||
for i in 0 ..< sonsLen(n):
|
||||
addInheritedFieldsAux(c, check, pos, n.sons[i])
|
||||
of nkSym:
|
||||
incl(check, n.sym.name.id)
|
||||
@@ -972,7 +972,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||
if lifted != nil: paramType.sons[i] = lifted
|
||||
|
||||
let body = paramType.base
|
||||
if body.kind == tyForward:
|
||||
if body.kind in {tyForward, tyError}:
|
||||
# this may happen for proc type appearing in a type section
|
||||
# before one of its param types
|
||||
return
|
||||
|
||||
@@ -67,11 +67,10 @@ proc cacheTypeInst*(inst: PType) =
|
||||
# update the refcount
|
||||
let gt = inst.sons[0]
|
||||
let t = if gt.kind == tyGenericBody: gt.lastSon else: gt
|
||||
if t.kind in {tyStatic, tyGenericParam} + tyTypeClasses:
|
||||
if t.kind in {tyStatic, tyError, tyGenericParam} + tyTypeClasses:
|
||||
return
|
||||
gt.sym.typeInstCache.safeAdd(inst)
|
||||
|
||||
|
||||
type
|
||||
LayeredIdTable* = object
|
||||
topLayer*: TIdTable
|
||||
@@ -336,6 +335,9 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
||||
# but we already raised an error!
|
||||
rawAddSon(result, header.sons[i])
|
||||
|
||||
if body.kind == tyError:
|
||||
return
|
||||
|
||||
let bbody = lastSon body
|
||||
var newbody = replaceTypeVarsT(cl, bbody)
|
||||
let bodyIsNew = newbody != bbody
|
||||
|
||||
@@ -196,18 +196,23 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
|
||||
else:
|
||||
c.hashSym(t.sym)
|
||||
if {sfAnon, sfGenSym} * t.sym.flags != {}:
|
||||
# generated object names can be identical, so we need to
|
||||
# disambiguate furthermore by hashing the field types and names:
|
||||
# mild hack to prevent endless recursions (makes nimforum compile again):
|
||||
let oldFlags = t.sym.flags
|
||||
t.sym.flags = t.sym.flags - {sfAnon, sfGenSym}
|
||||
let n = t.n
|
||||
for i in 0 ..< n.len:
|
||||
assert n[i].kind == nkSym
|
||||
let s = n[i].sym
|
||||
c.hashSym s
|
||||
c.hashType s.typ, flags
|
||||
t.sym.flags = oldFlags
|
||||
# Generated object names can be identical, so we need to
|
||||
# disambiguate furthermore by hashing the field types and names.
|
||||
if t.n.len > 0:
|
||||
let oldFlags = t.sym.flags
|
||||
# Mild hack to prevent endless recursion.
|
||||
t.sym.flags = t.sym.flags - {sfAnon, sfGenSym}
|
||||
for n in t.n:
|
||||
assert(n.kind == nkSym)
|
||||
let s = n.sym
|
||||
c.hashSym s
|
||||
c.hashType s.typ, flags
|
||||
t.sym.flags = oldFlags
|
||||
else:
|
||||
# The object has no fields: we _must_ add something here in order to
|
||||
# make the hash different from the one we produce by hashing only the
|
||||
# type name.
|
||||
c &= ".empty"
|
||||
else:
|
||||
c &= t.id
|
||||
if t.len > 0 and t.sons[0] != nil:
|
||||
|
||||
@@ -130,6 +130,7 @@ proc elemType*(t: PType): PType =
|
||||
case t.kind
|
||||
of tyGenericInst, tyDistinct, tyAlias, tySink: result = elemType(lastSon(t))
|
||||
of tyArray: result = t.sons[1]
|
||||
of tyError: result = t
|
||||
else: result = t.lastSon
|
||||
assert(result != nil)
|
||||
|
||||
|
||||
@@ -1211,6 +1211,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
of opcNarrowU:
|
||||
decodeB(rkInt)
|
||||
regs[ra].intVal = regs[ra].intVal and ((1'i64 shl rb)-1)
|
||||
of opcSignExtend:
|
||||
# like opcNarrowS, but no out of range possible
|
||||
decodeB(rkInt)
|
||||
let imm = 64 - rb
|
||||
regs[ra].intVal = ashr(regs[ra].intVal shl imm, imm)
|
||||
of opcIsNil:
|
||||
decodeB(rkInt)
|
||||
let node = regs[rb].node
|
||||
|
||||
@@ -71,6 +71,7 @@ type
|
||||
opcSubStr, opcParseFloat, opcConv, opcCast,
|
||||
opcQuit,
|
||||
opcNarrowS, opcNarrowU,
|
||||
opcSignExtend,
|
||||
|
||||
opcAddStrCh,
|
||||
opcAddStrStr,
|
||||
|
||||
@@ -361,16 +361,28 @@ proc genIf(c: PCtx, n: PNode; dest: var TDest) =
|
||||
for endPos in endings: c.patch(endPos)
|
||||
c.clearDest(n, dest)
|
||||
|
||||
proc isTemp(c: PCtx; dest: TDest): bool =
|
||||
result = dest >= 0 and c.prc.slots[dest].kind >= slotTempUnknown
|
||||
|
||||
proc genAndOr(c: PCtx; n: PNode; opc: TOpcode; dest: var TDest) =
|
||||
# asgn dest, a
|
||||
# tjmp|fjmp L1
|
||||
# asgn dest, b
|
||||
# L1:
|
||||
if dest < 0: dest = getTemp(c, n.typ)
|
||||
c.gen(n.sons[1], dest)
|
||||
let L1 = c.xjmp(n, opc, dest)
|
||||
c.gen(n.sons[2], dest)
|
||||
let copyBack = dest < 0 or not isTemp(c, dest)
|
||||
let tmp = if copyBack:
|
||||
getTemp(c, n.typ)
|
||||
else:
|
||||
TRegister dest
|
||||
c.gen(n.sons[1], tmp)
|
||||
let L1 = c.xjmp(n, opc, tmp)
|
||||
c.gen(n.sons[2], tmp)
|
||||
c.patch(L1)
|
||||
if dest < 0:
|
||||
dest = tmp
|
||||
elif copyBack:
|
||||
c.gABC(n, opcAsgnInt, dest, tmp)
|
||||
freeTemp(c, tmp)
|
||||
|
||||
proc canonValue*(n: PNode): PNode =
|
||||
result = n
|
||||
@@ -938,11 +950,18 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||
c.freeTemp(tmp)
|
||||
c.freeTemp(tmp2)
|
||||
|
||||
of mShlI: genBinaryABCnarrowU(c, n, dest, opcShlInt)
|
||||
of mAshrI: genBinaryABCnarrow(c, n, dest, opcAshrInt)
|
||||
of mBitandI: genBinaryABCnarrowU(c, n, dest, opcBitandInt)
|
||||
of mBitorI: genBinaryABCnarrowU(c, n, dest, opcBitorInt)
|
||||
of mBitxorI: genBinaryABCnarrowU(c, n, dest, opcBitxorInt)
|
||||
of mShlI:
|
||||
genBinaryABC(c, n, dest, opcShlInt)
|
||||
# genNarrowU modified
|
||||
let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
|
||||
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and t.size < 8):
|
||||
c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
|
||||
elif t.kind in {tyInt8..tyInt32} or (t.kind == tyInt and t.size < 8):
|
||||
c.gABC(n, opcSignExtend, dest, TRegister(t.size*8))
|
||||
of mAshrI: genBinaryABC(c, n, dest, opcAshrInt)
|
||||
of mBitandI: genBinaryABC(c, n, dest, opcBitandInt)
|
||||
of mBitorI: genBinaryABC(c, n, dest, opcBitorInt)
|
||||
of mBitxorI: genBinaryABC(c, n, dest, opcBitxorInt)
|
||||
of mAddU: genBinaryABCnarrowU(c, n, dest, opcAddu)
|
||||
of mSubU: genBinaryABCnarrowU(c, n, dest, opcSubu)
|
||||
of mMulU: genBinaryABCnarrowU(c, n, dest, opcMulu)
|
||||
@@ -961,7 +980,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||
of mLtPtr, mLtU, mLtU64: genBinaryABC(c, n, dest, opcLtu)
|
||||
of mEqProc, mEqRef, mEqUntracedRef:
|
||||
genBinaryABC(c, n, dest, opcEqRef)
|
||||
of mXor: genBinaryABCnarrowU(c, n, dest, opcXor)
|
||||
of mXor: genBinaryABC(c, n, dest, opcXor)
|
||||
of mNot: genUnaryABC(c, n, dest, opcNot)
|
||||
of mUnaryMinusI, mUnaryMinusI64:
|
||||
genUnaryABC(c, n, dest, opcUnaryMinusInt)
|
||||
@@ -970,7 +989,10 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||
of mUnaryPlusI, mUnaryPlusF64: gen(c, n.sons[1], dest)
|
||||
of mBitnotI:
|
||||
genUnaryABC(c, n, dest, opcBitnotInt)
|
||||
genNarrowU(c, n, dest)
|
||||
#genNarrowU modified, do not narrow signed types
|
||||
let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
|
||||
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and t.size < 8):
|
||||
c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
|
||||
of mToFloat, mToBiggestFloat, mToInt,
|
||||
mToBiggestInt, mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr,
|
||||
mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr:
|
||||
@@ -1386,9 +1408,6 @@ proc checkCanEval(c: PCtx; n: PNode) =
|
||||
skIterator} and sfForward in s.flags:
|
||||
cannotEval(c, n)
|
||||
|
||||
proc isTemp(c: PCtx; dest: TDest): bool =
|
||||
result = dest >= 0 and c.prc.slots[dest].kind >= slotTempUnknown
|
||||
|
||||
template needsAdditionalCopy(n): untyped =
|
||||
not c.isTemp(dest) and not fitsRegister(n.typ)
|
||||
|
||||
|
||||
9
koch.nim
9
koch.nim
@@ -74,7 +74,7 @@ template withDir(dir, body) =
|
||||
setCurrentDir(dir)
|
||||
body
|
||||
finally:
|
||||
setCurrentdir(old)
|
||||
setCurrentDir(old)
|
||||
|
||||
proc tryExec(cmd: string): bool =
|
||||
echo(cmd)
|
||||
@@ -110,6 +110,11 @@ proc bundleNimbleSrc(latest: bool) =
|
||||
exec("git checkout -f stable")
|
||||
exec("git pull")
|
||||
|
||||
proc bundleC2nim() =
|
||||
if not dirExists("dist/c2nim/.git"):
|
||||
exec("git clone https://github.com/nim-lang/c2nim.git dist/c2nim")
|
||||
nimCompile("dist/c2nim/c2nim", options = "--noNimblePath --path:.")
|
||||
|
||||
proc bundleNimbleExe(latest: bool) =
|
||||
bundleNimbleSrc(latest)
|
||||
# now compile Nimble and copy it to $nim/bin for the installer.ini
|
||||
@@ -160,6 +165,7 @@ proc bundleWinTools() =
|
||||
buildVccTool()
|
||||
nimexec("c -o:bin/nimgrab.exe -d:ssl tools/nimgrab.nim")
|
||||
nimexec("c -o:bin/nimgrep.exe tools/nimgrep.nim")
|
||||
bundleC2nim()
|
||||
when false:
|
||||
# not yet a tool worth including
|
||||
nimexec(r"c --cc:vcc --app:gui -o:bin\downloader.exe -d:ssl --noNimblePath " &
|
||||
@@ -548,6 +554,7 @@ when isMainModule:
|
||||
else: buildTools(existsDir(".git") or latest)
|
||||
of "pushcsource", "pushcsources": pushCsources()
|
||||
of "valgrind": valgrind(op.cmdLineRest)
|
||||
of "c2nim": bundleC2nim()
|
||||
else: showHelp()
|
||||
break
|
||||
of cmdEnd: break
|
||||
|
||||
@@ -649,7 +649,7 @@ proc newLit*(f: float64): NimNode {.compileTime.} =
|
||||
result = newNimNode(nnkFloat64Lit)
|
||||
result.floatVal = f
|
||||
|
||||
when compiles(float128):
|
||||
when declared(float128):
|
||||
proc newLit*(f: float128): NimNode {.compileTime.} =
|
||||
## produces a new float literal node.
|
||||
result = newNimNode(nnkFloat128Lit)
|
||||
@@ -976,6 +976,8 @@ proc newIfStmt*(branches: varargs[tuple[cond, body: NimNode]]):
|
||||
## )
|
||||
##
|
||||
result = newNimNode(nnkIfStmt)
|
||||
if len(branches) < 1:
|
||||
error("If statement must have at least one branch")
|
||||
for i in branches:
|
||||
result.add(newTree(nnkElifBranch, i.cond, i.body))
|
||||
|
||||
|
||||
@@ -389,8 +389,6 @@ static N_INLINE(NI32, float32ToInt32)(float x) {
|
||||
NIM_CHAR data[(length) + 1]; \
|
||||
} name = {{length, (NI) ((NU)length | NIM_STRLIT_FLAG)}, str}
|
||||
|
||||
typedef struct TStringDesc* string;
|
||||
|
||||
/* declared size of a sequence/variable length array: */
|
||||
#if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER)
|
||||
# define SEQ_DECL_SIZE /* empty is correct! */
|
||||
|
||||
@@ -32,6 +32,18 @@ const useICC_builtins = defined(icc) and useBuiltins
|
||||
const useVCC_builtins = defined(vcc) and useBuiltins
|
||||
const arch64 = sizeof(int) == 8
|
||||
|
||||
template forwardImpl(impl, arg) {.dirty.} =
|
||||
when sizeof(x) <= 4:
|
||||
when x is SomeSignedInt:
|
||||
impl(cast[uint32](x.int32))
|
||||
else:
|
||||
impl(x.uint32)
|
||||
else:
|
||||
when x is SomeSignedInt:
|
||||
impl(cast[uint64](x.int64))
|
||||
else:
|
||||
impl(x.uint64)
|
||||
|
||||
# #### Pure Nim version ####
|
||||
|
||||
proc firstSetBit_nim(x: uint32): int {.inline, nosideeffect.} =
|
||||
@@ -185,8 +197,7 @@ proc countSetBits*(x: SomeInteger): int {.inline, nosideeffect.} =
|
||||
# TODO: figure out if ICC support _popcnt32/_popcnt64 on platform without POPCNT.
|
||||
# like GCC and MSVC
|
||||
when nimvm:
|
||||
when sizeof(x) <= 4: result = countSetBits_nim(x.uint32)
|
||||
else: result = countSetBits_nim(x.uint64)
|
||||
result = forwardImpl(countSetBits_nim, x)
|
||||
else:
|
||||
when useGCC_builtins:
|
||||
when sizeof(x) <= 4: result = builtin_popcount(x.cuint).int
|
||||
@@ -216,8 +227,7 @@ proc parityBits*(x: SomeInteger): int {.inline, nosideeffect.} =
|
||||
# Can be used a base if creating ASM version.
|
||||
# https://stackoverflow.com/questions/21617970/how-to-check-if-value-has-even-parity-of-bits-or-odd
|
||||
when nimvm:
|
||||
when sizeof(x) <= 4: result = parity_impl(x.uint32)
|
||||
else: result = parity_impl(x.uint64)
|
||||
result = forwardImpl(parity_impl, x)
|
||||
else:
|
||||
when useGCC_builtins:
|
||||
when sizeof(x) <= 4: result = builtin_parity(x.uint32).int
|
||||
@@ -235,8 +245,7 @@ proc firstSetBit*(x: SomeInteger): int {.inline, nosideeffect.} =
|
||||
when noUndefined:
|
||||
if x == 0:
|
||||
return 0
|
||||
when sizeof(x) <= 4: result = firstSetBit_nim(x.uint32)
|
||||
else: result = firstSetBit_nim(x.uint64)
|
||||
result = forwardImpl(firstSetBit_nim, x)
|
||||
else:
|
||||
when noUndefined and not useGCC_builtins:
|
||||
if x == 0:
|
||||
@@ -270,8 +279,7 @@ proc fastLog2*(x: SomeInteger): int {.inline, nosideeffect.} =
|
||||
if x == 0:
|
||||
return -1
|
||||
when nimvm:
|
||||
when sizeof(x) <= 4: result = fastlog2_nim(x.uint32)
|
||||
else: result = fastlog2_nim(x.uint64)
|
||||
result = forwardImpl(fastlog2_nim, x)
|
||||
else:
|
||||
when useGCC_builtins:
|
||||
when sizeof(x) <= 4: result = 31 - builtin_clz(x.uint32).int
|
||||
@@ -302,8 +310,7 @@ proc countLeadingZeroBits*(x: SomeInteger): int {.inline, nosideeffect.} =
|
||||
if x == 0:
|
||||
return 0
|
||||
when nimvm:
|
||||
when sizeof(x) <= 4: result = sizeof(x)*8 - 1 - fastlog2_nim(x.uint32)
|
||||
else: result = sizeof(x)*8 - 1 - fastlog2_nim(x.uint64)
|
||||
result = sizeof(x)*8 - 1 - forwardImpl(fastlog2_nim, x)
|
||||
else:
|
||||
when useGCC_builtins:
|
||||
when sizeof(x) <= 4: result = builtin_clz(x.uint32).int - (32 - sizeof(x)*8)
|
||||
|
||||
@@ -320,6 +320,10 @@ gSomeReady.initSemaphore()
|
||||
proc slave(w: ptr Worker) {.thread.} =
|
||||
isSlave = true
|
||||
while true:
|
||||
if w.shutdown:
|
||||
w.shutdown = false
|
||||
atomicDec currentPoolSize
|
||||
break
|
||||
when declared(atomicStoreN):
|
||||
atomicStoreN(addr(w.ready), true, ATOMIC_SEQ_CST)
|
||||
else:
|
||||
@@ -340,9 +344,6 @@ proc slave(w: ptr Worker) {.thread.} =
|
||||
dec numSlavesRunning
|
||||
|
||||
if w.q.len != 0: w.cleanFlowVars
|
||||
if w.shutdown:
|
||||
w.shutdown = false
|
||||
atomicDec currentPoolSize
|
||||
|
||||
proc distinguishedSlave(w: ptr Worker) {.thread.} =
|
||||
while true:
|
||||
|
||||
@@ -600,6 +600,7 @@ proc escapeJsonUnquoted*(s: string; result: var string) =
|
||||
of '\b': result.add("\\b")
|
||||
of '\f': result.add("\\f")
|
||||
of '\t': result.add("\\t")
|
||||
of '\v': result.add("\\v")
|
||||
of '\r': result.add("\\r")
|
||||
of '"': result.add("\\\"")
|
||||
of '\0'..'\7': result.add("\\u000" & $ord(c))
|
||||
|
||||
@@ -218,6 +218,9 @@ proc parseString(my: var JsonParser): TokKind =
|
||||
of 't':
|
||||
add(my.a, '\t')
|
||||
inc(pos, 2)
|
||||
of 'v':
|
||||
add(my.a, '\v')
|
||||
inc(pos, 2)
|
||||
of 'u':
|
||||
if my.rawStringLiterals:
|
||||
add(my.a, 'u')
|
||||
|
||||
@@ -175,7 +175,7 @@ proc `+`*(a, b: RunningStat): RunningStat =
|
||||
(n*n) +
|
||||
4.0*delta*(a.n.float*b.mom3 - b.n.float*a.mom3) / n
|
||||
result.max = max(a.max, b.max)
|
||||
result.min = max(a.min, b.min)
|
||||
result.min = min(a.min, b.min)
|
||||
|
||||
proc `+=`*(a: var RunningStat, b: RunningStat) {.inline.} =
|
||||
## add a second RunningStats `b` to `a`
|
||||
|
||||
@@ -435,7 +435,7 @@ proc isNilOrWhitespace*(s: string): bool {.noSideEffect, procvar, rtl, extern: "
|
||||
proc substrEq(s: string, pos: int, substr: string): bool =
|
||||
var i = 0
|
||||
var length = substr.len
|
||||
while i < length and s[pos+i] == substr[i]:
|
||||
while i < length and pos+i < s.len and s[pos+i] == substr[i]:
|
||||
inc i
|
||||
return i == length
|
||||
|
||||
|
||||
@@ -2023,7 +2023,7 @@ const
|
||||
NimMinor* {.intdefine.}: int = 19
|
||||
## is the minor number of Nim's version.
|
||||
|
||||
NimPatch* {.intdefine.}: int = 4
|
||||
NimPatch* {.intdefine.}: int = 6
|
||||
## is the patch number of Nim's version.
|
||||
|
||||
NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch
|
||||
@@ -4321,25 +4321,6 @@ template doAssertRaises*(exception, code: untyped): typed =
|
||||
if wrong:
|
||||
raiseAssert(astToStr(exception) & " wasn't raised by:\n" & astToStr(code))
|
||||
|
||||
when defined(cpp) and appType != "lib" and
|
||||
not defined(js) and not defined(nimscript) and
|
||||
hostOS != "standalone" and not defined(noCppExceptions):
|
||||
proc setTerminate(handler: proc() {.noconv.})
|
||||
{.importc: "std::set_terminate", header: "<exception>".}
|
||||
setTerminate proc() {.noconv.} =
|
||||
# Remove ourself as a handler, reinstalling the default handler.
|
||||
setTerminate(nil)
|
||||
|
||||
let ex = getCurrentException()
|
||||
let trace = ex.getStackTrace()
|
||||
when defined(genode):
|
||||
# stderr not available by default, use the LOG session
|
||||
echo trace & "Error: unhandled exception: " & ex.msg &
|
||||
" [" & $ex.name & "]\n"
|
||||
else:
|
||||
stderr.write trace & "Error: unhandled exception: " & ex.msg &
|
||||
" [" & $ex.name & "]\n"
|
||||
quit 1
|
||||
|
||||
when not defined(js):
|
||||
proc toOpenArray*[T](x: seq[T]; first, last: int): openarray[T] {.
|
||||
|
||||
@@ -466,6 +466,41 @@ when defined(endb):
|
||||
var
|
||||
dbgAborting: bool # whether the debugger wants to abort
|
||||
|
||||
when defined(cpp) and appType != "lib" and
|
||||
not defined(js) and not defined(nimscript) and
|
||||
hostOS != "standalone" and not defined(noCppExceptions):
|
||||
|
||||
type
|
||||
StdException {.importcpp: "std::exception", header: "<exception>".} = object
|
||||
|
||||
proc what(ex: StdException): cstring {.importcpp: "((char *)#.what())".}
|
||||
|
||||
proc setTerminate(handler: proc() {.noconv.})
|
||||
{.importc: "std::set_terminate", header: "<exception>".}
|
||||
|
||||
setTerminate proc() {.noconv.} =
|
||||
# Remove ourself as a handler, reinstalling the default handler.
|
||||
setTerminate(nil)
|
||||
|
||||
var msg = "Unknown error in unexpected exception handler"
|
||||
try:
|
||||
raise
|
||||
except Exception:
|
||||
msg = currException.getStackTrace() & "Error: unhandled exception: " &
|
||||
currException.msg & " [" & $currException.name & "]"
|
||||
except StdException as e:
|
||||
msg = "Error: unhandled cpp exception: " & $e.what()
|
||||
except:
|
||||
msg = "Error: unhandled unknown cpp exception"
|
||||
|
||||
when defined(genode):
|
||||
# stderr not available by default, use the LOG session
|
||||
echo msg
|
||||
else:
|
||||
writeToStdErr msg & "\n"
|
||||
|
||||
quit 1
|
||||
|
||||
when not defined(noSignalHandler) and not defined(useNimRtl):
|
||||
proc signalHandler(sign: cint) {.exportc: "signalHandler", noconv.} =
|
||||
template processSignal(s, action: untyped) {.dirty.} =
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
discard """
|
||||
output: '''(10, (20, ))'''
|
||||
output: '''(10, (20, ))
|
||||
42'''
|
||||
"""
|
||||
|
||||
import strutils, sequtils
|
||||
@@ -22,5 +23,17 @@ proc dosomething(): seq[TThing] =
|
||||
|
||||
result = @[TThing(data: 10, children: result)]
|
||||
|
||||
when isMainModule:
|
||||
echo($dosomething()[0])
|
||||
echo($dosomething()[0])
|
||||
|
||||
|
||||
# bug #9844
|
||||
|
||||
proc f(v: int): int = v
|
||||
|
||||
type X = object
|
||||
v: int
|
||||
|
||||
var x = X(v: 42)
|
||||
|
||||
x = X(v: f(x.v))
|
||||
echo x.v
|
||||
|
||||
@@ -8,3 +8,18 @@ proc foo[T](t: T) =
|
||||
|
||||
foo(123)
|
||||
foo("baz")
|
||||
|
||||
# Empty type in template is correctly disambiguated
|
||||
block:
|
||||
template foo() =
|
||||
type M = object
|
||||
discard
|
||||
var y = M()
|
||||
|
||||
foo()
|
||||
|
||||
type M = object
|
||||
x: int
|
||||
|
||||
var x = M(x: 1)
|
||||
doAssert(x.x == 1)
|
||||
|
||||
9
tests/cpp/tterminate_handler.nim
Normal file
9
tests/cpp/tterminate_handler.nim
Normal file
@@ -0,0 +1,9 @@
|
||||
discard """
|
||||
targets: "cpp"
|
||||
outputsub: "Error: unhandled unknown cpp exception"
|
||||
exitcode: 1
|
||||
"""
|
||||
type Crap {.importcpp: "int".} = object
|
||||
|
||||
var c: Crap
|
||||
raise c
|
||||
@@ -4,6 +4,8 @@ discard """
|
||||
type
|
||||
ESomething = object of Exception
|
||||
ESomeOtherErr = object of Exception
|
||||
ESomethingGen[T] = object of Exception
|
||||
ESomethingGenRef[T] = ref object of Exception
|
||||
|
||||
proc genErrors(s: string) =
|
||||
if s == "error!":
|
||||
@@ -27,4 +29,17 @@ proc blah(): int =
|
||||
|
||||
echo blah()
|
||||
|
||||
# Issue #7845, raise generic exception
|
||||
var x: ref ESomethingGen[int]
|
||||
new(x)
|
||||
try:
|
||||
raise x
|
||||
except ESomethingGen[int] as e:
|
||||
discard
|
||||
|
||||
try:
|
||||
raise new(ESomethingGenRef[int])
|
||||
except ESomethingGenRef[int] as e:
|
||||
discard
|
||||
except:
|
||||
discard
|
||||
|
||||
13
tests/js/tbasics.nim
Normal file
13
tests/js/tbasics.nim
Normal file
@@ -0,0 +1,13 @@
|
||||
discard """
|
||||
output: '''1'''
|
||||
"""
|
||||
|
||||
# bug #10697
|
||||
proc test2 =
|
||||
var val = uint16(0)
|
||||
var i = 0
|
||||
if i < 2:
|
||||
val += uint16(1)
|
||||
echo int(val)
|
||||
|
||||
test2()
|
||||
@@ -1,10 +1,5 @@
|
||||
discard """
|
||||
file: "tbitops.nim"
|
||||
output: "OK"
|
||||
"""
|
||||
import bitops
|
||||
|
||||
|
||||
proc main() =
|
||||
const U8 = 0b0011_0010'u8
|
||||
const I8 = 0b0011_0010'i8
|
||||
@@ -80,25 +75,6 @@ proc main() =
|
||||
doAssert( U8.rotateLeftBits(3) == 0b10010001'u8)
|
||||
doAssert( U8.rotateRightBits(3) == 0b0100_0110'u8)
|
||||
|
||||
static :
|
||||
# test bitopts at compile time with vm
|
||||
doAssert( U8.fastLog2 == 5)
|
||||
doAssert( I8.fastLog2 == 5)
|
||||
doAssert( U8.countLeadingZeroBits == 2)
|
||||
doAssert( I8.countLeadingZeroBits == 2)
|
||||
doAssert( U8.countTrailingZeroBits == 1)
|
||||
doAssert( I8.countTrailingZeroBits == 1)
|
||||
doAssert( U8.firstSetBit == 2)
|
||||
doAssert( I8.firstSetBit == 2)
|
||||
doAssert( U8.parityBits == 1)
|
||||
doAssert( I8.parityBits == 1)
|
||||
doAssert( U8.countSetBits == 3)
|
||||
doAssert( I8.countSetBits == 3)
|
||||
doAssert( U8.rotateLeftBits(3) == 0b10010001'u8)
|
||||
doAssert( U8.rotateRightBits(3) == 0b0100_0110'u8)
|
||||
|
||||
|
||||
|
||||
template test_undefined_impl(ffunc: untyped; expected: int; is_static: bool) =
|
||||
doAssert( ffunc(0'u8) == expected)
|
||||
doAssert( ffunc(0'i8) == expected)
|
||||
@@ -143,26 +119,8 @@ proc main() =
|
||||
doAssert( U64A.rotateLeftBits(64) == U64A)
|
||||
doAssert( U64A.rotateRightBits(64) == U64A)
|
||||
|
||||
static: # check for undefined behavior with rotate by zero.
|
||||
doAssert( U8.rotateLeftBits(0) == U8)
|
||||
doAssert( U8.rotateRightBits(0) == U8)
|
||||
doAssert( U16.rotateLeftBits(0) == U16)
|
||||
doAssert( U16.rotateRightBits(0) == U16)
|
||||
doAssert( U32.rotateLeftBits(0) == U32)
|
||||
doAssert( U32.rotateRightBits(0) == U32)
|
||||
doAssert( U64A.rotateLeftBits(0) == U64A)
|
||||
doAssert( U64A.rotateRightBits(0) == U64A)
|
||||
|
||||
# check for undefined behavior with rotate by integer width.
|
||||
doAssert( U8.rotateLeftBits(8) == U8)
|
||||
doAssert( U8.rotateRightBits(8) == U8)
|
||||
doAssert( U16.rotateLeftBits(16) == U16)
|
||||
doAssert( U16.rotateRightBits(16) == U16)
|
||||
doAssert( U32.rotateLeftBits(32) == U32)
|
||||
doAssert( U32.rotateRightBits(32) == U32)
|
||||
doAssert( U64A.rotateLeftBits(64) == U64A)
|
||||
doAssert( U64A.rotateRightBits(64) == U64A)
|
||||
|
||||
echo "OK"
|
||||
|
||||
main()
|
||||
static:
|
||||
# test everything on vm as well
|
||||
main()
|
||||
|
||||
45
tests/vm/tbitops.nim
Normal file
45
tests/vm/tbitops.nim
Normal file
@@ -0,0 +1,45 @@
|
||||
discard """
|
||||
output: ""
|
||||
"""
|
||||
|
||||
import strutils
|
||||
|
||||
const x = [1'i32, -1, -10, 10, -10, 10, -20, 30, -40, 50, 7 shl 28, -(7 shl 28), 7 shl 28, -(7 shl 28)]
|
||||
const y = [-1'i32, 1, -10, -10, 10, 10, -20, -30, 40, 50, 1 shl 30, 1 shl 30, -(1 shl 30), -(1 shl 30)]
|
||||
|
||||
const res_xor = block:
|
||||
var tmp: seq[int64]
|
||||
for i in 0 ..< x.len:
|
||||
tmp.add(int64(x[i] xor y[i]))
|
||||
tmp
|
||||
|
||||
const res_and = block:
|
||||
var tmp: seq[int64]
|
||||
for i in 0 ..< x.len:
|
||||
tmp.add(int64(x[i] and y[i]))
|
||||
tmp
|
||||
|
||||
const res_or = block:
|
||||
var tmp: seq[int64]
|
||||
for i in 0 ..< x.len:
|
||||
tmp.add(int64(x[i] or y[i]))
|
||||
tmp
|
||||
|
||||
const res_not = block:
|
||||
var tmp: seq[int64]
|
||||
for i in 0 ..< x.len:
|
||||
tmp.add(not x[i])
|
||||
tmp
|
||||
|
||||
let xx = x
|
||||
let yy = y
|
||||
|
||||
for i in 0..<xx.len:
|
||||
let z_xor = int64(xx[i] xor yy[i])
|
||||
let z_and = int64(xx[i] and yy[i])
|
||||
let z_or = int64(xx[i] or yy[i])
|
||||
let z_not = int64(not xx[i])
|
||||
doAssert(z_xor == res_xor[i], $i & ": " & $res_xor[i] & " " & $z_xor)
|
||||
doAssert(z_and == res_and[i], $i & ": " & $res_and[i] & " " & $z_and)
|
||||
doAssert(z_or == res_or[i], $i & ": " & $res_or[i] & " " & $z_or)
|
||||
doAssert(z_not == res_not[i], $i & ": " & $res_not[i] & " " & $z_not)
|
||||
@@ -31,7 +31,7 @@ static:
|
||||
assert str == "abc"
|
||||
|
||||
# #6086
|
||||
import math, sequtils, future
|
||||
import math, sequtils, sugar
|
||||
|
||||
block:
|
||||
proc f: int =
|
||||
@@ -148,3 +148,22 @@ static:
|
||||
|
||||
static:
|
||||
doAssert foo().i == 1
|
||||
|
||||
|
||||
# #10886
|
||||
|
||||
proc tor(): bool =
|
||||
result = true
|
||||
result = false or result
|
||||
|
||||
proc tand(): bool =
|
||||
result = false
|
||||
result = true and result
|
||||
|
||||
const
|
||||
ctor = tor()
|
||||
ctand = not tand()
|
||||
|
||||
static:
|
||||
doAssert ctor
|
||||
doAssert ctand
|
||||
|
||||
@@ -8,6 +8,9 @@ const
|
||||
mingw = "mingw$1-6.3.0.7z" % arch
|
||||
url = r"https://nim-lang.org/download/" & mingw
|
||||
|
||||
var
|
||||
interactive = true
|
||||
|
||||
type
|
||||
DownloadResult = enum
|
||||
Failure,
|
||||
@@ -38,19 +41,28 @@ proc downloadMingw(): DownloadResult =
|
||||
if cmd.len > 0:
|
||||
if execShellCmd(cmd) != 0:
|
||||
echo "download failed! ", cmd
|
||||
openDefaultBrowser(url)
|
||||
result = Manual
|
||||
if interactive:
|
||||
openDefaultBrowser(url)
|
||||
result = Manual
|
||||
else:
|
||||
result = Failure
|
||||
else:
|
||||
if unzip(): result = Success
|
||||
else:
|
||||
openDefaultBrowser(url)
|
||||
result = Manual
|
||||
if interactive:
|
||||
openDefaultBrowser(url)
|
||||
result = Manual
|
||||
else:
|
||||
result = Failure
|
||||
|
||||
when defined(windows):
|
||||
import registry
|
||||
|
||||
proc askBool(m: string): bool =
|
||||
stdout.write m
|
||||
if not interactive:
|
||||
stdout.writeLine "y (non-interactive mode)"
|
||||
return true
|
||||
while true:
|
||||
try:
|
||||
let answer = stdin.readLine().normalize
|
||||
@@ -67,6 +79,9 @@ when defined(windows):
|
||||
proc askNumber(m: string; a, b: int): int =
|
||||
stdout.write m
|
||||
stdout.write " [" & $a & ".." & $b & "] "
|
||||
if not interactive:
|
||||
stdout.writeLine $a & " (non-interactive mode)"
|
||||
return a
|
||||
while true:
|
||||
let answer = stdin.readLine()
|
||||
try:
|
||||
@@ -291,4 +306,6 @@ when isMainModule:
|
||||
when defined(testdownload):
|
||||
discard downloadMingw()
|
||||
else:
|
||||
if "-y" in commandLineParams():
|
||||
interactive = false
|
||||
main()
|
||||
|
||||
@@ -54,6 +54,11 @@ proc execCleanPath*(cmd: string,
|
||||
proc nimexec*(cmd: string) =
|
||||
exec findNim() & " " & cmd
|
||||
|
||||
proc nimCompile*(input: string, outputDir = "bin", mode = "c", options = "") =
|
||||
let output = outputDir / input.splitFile.name.exe
|
||||
let cmd = findNim() & " " & mode & " -o:" & output & " " & options & " " & input
|
||||
exec cmd
|
||||
|
||||
const
|
||||
pdf = """
|
||||
doc/manual.rst
|
||||
|
||||
Reference in New Issue
Block a user