diff options
66 files changed, 1024 insertions, 426 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 7ebcdddb1..3a4158204 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -525,6 +525,8 @@ const tfOldSchoolExprStmt* = tfVarargs # for now used to distinguish \ # 'varargs[expr]' from 'varargs[untyped]'. Eventually 'expr' will be # deprecated and this mess can be cleaned up. + tfVoid* = tfVarargs # for historical reasons we conflated 'void' with + # 'empty' ('@[]' has the type 'seq[empty]'). skError* = skUnknown # type flags that are essential for type equality: @@ -537,35 +539,48 @@ type mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mAddr, mTypeOf, mRoof, mPlugin, mEcho, mShallowCopy, mSlurp, mStaticExec, mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst, - mUnaryLt, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray, - mLengthStr, mLengthArray, mLengthSeq, mXLenStr, mXLenSeq, + mUnaryLt, mInc, mDec, mOrd, + mNew, mNewFinalize, mNewSeq, + mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq, + mXLenStr, mXLenSeq, mIncl, mExcl, mCard, mChr, mGCref, mGCunref, - mAddI, mSubI, mMulI, mDivI, mModI, mSucc, mPred, mAddF64, mSubF64, mMulF64, mDivF64, - - mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI, - mMinF64, mMaxF64, mAddU, mSubU, mMulU, - mDivU, mModU, mEqI, mLeI, - mLtI, + mShrI, mShlI, mBitandI, mBitorI, mBitxorI, + mMinI, mMaxI, + mMinF64, mMaxF64, + mAddU, mSubU, mMulU, mDivU, mModU, + mEqI, mLeI, mLtI, mEqF64, mLeF64, mLtF64, - mLeU, mLtU, mLeU64, mLtU64, - mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef, - mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mEqProc, mUnaryMinusI, - mUnaryMinusI64, mAbsI, mNot, + mLeU, mLtU, + mLeU64, mLtU64, + mEqEnum, mLeEnum, mLtEnum, + mEqCh, mLeCh, mLtCh, + mEqB, mLeB, mLtB, + mEqRef, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, + mXor, mEqProc, + mUnaryMinusI, mUnaryMinusI64, mAbsI, mNot, mUnaryPlusI, mBitnotI, - mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64, - mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32, - mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr, - mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr, - mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet, - mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mSlice, + mUnaryPlusF64, mUnaryMinusF64, mAbsF64, + mZe8ToI, mZe8ToI64, + mZe16ToI, mZe16ToI64, + mZe32ToI64, mZeIToI64, + mToU8, mToU16, mToU32, + mToFloat, mToBiggestFloat, + mToInt, mToBiggestInt, + mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, + mStrToStr, mEnumToStr, + mAnd, mOr, + mEqStr, mLeStr, mLtStr, + mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet, mSymDiffSet, + mConStrStr, mSlice, mDotDot, # this one is only necessary to give nice compile time warnings mFields, mFieldPairs, mOmpParFor, mAppendStrCh, mAppendStrStr, mAppendSeqElem, - mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq, + mInRange, mInSet, mRepr, mExit, + mSetLengthStr, mSetLengthSeq, mIsPartOf, mAstToStr, mParallel, mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast, mNewString, mNewStringOfCap, mParseBiggestFloat, @@ -599,23 +614,32 @@ const mIncl, mExcl, mCard, mChr, mAddI, mSubI, mMulI, mDivI, mModI, mAddF64, mSubF64, mMulF64, mDivF64, - mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI, - mMinF64, mMaxF64, mAddU, mSubU, mMulU, - mDivU, mModU, mEqI, mLeI, - mLtI, + mShrI, mShlI, mBitandI, mBitorI, mBitxorI, + mMinI, mMaxI, + mMinF64, mMaxF64, + mAddU, mSubU, mMulU, mDivU, mModU, + mEqI, mLeI, mLtI, mEqF64, mLeF64, mLtF64, - mLeU, mLtU, mLeU64, mLtU64, - mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef, - mEqProc, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mUnaryMinusI, - mUnaryMinusI64, mAbsI, mNot, - mUnaryPlusI, mBitnotI, - mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64, - mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32, - mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr, - mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr, - mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet, - mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, - mAppendStrCh, mAppendStrStr, mAppendSeqElem, + mLeU, mLtU, + mLeU64, mLtU64, + mEqEnum, mLeEnum, mLtEnum, + mEqCh, mLeCh, mLtCh, + mEqB, mLeB, mLtB, + mEqRef, mEqProc, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, + mUnaryMinusI, mUnaryMinusI64, mAbsI, mNot, mUnaryPlusI, mBitnotI, + mUnaryPlusF64, mUnaryMinusF64, mAbsF64, + mZe8ToI, mZe8ToI64, + mZe16ToI, mZe16ToI64, + mZe32ToI64, mZeIToI64, + mToU8, mToU16, mToU32, + mToFloat, mToBiggestFloat, + mToInt, mToBiggestInt, + mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, + mStrToStr, mEnumToStr, + mAnd, mOr, + mEqStr, mLeStr, mLtStr, + mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet, mSymDiffSet, + mConStrStr, mAppendStrCh, mAppendStrStr, mAppendSeqElem, mInRange, mInSet, mRepr, mCopyStr, mCopyStrLast} # magics that require special semantic checking and diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 2dacc25e9..86ecc9db8 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -159,6 +159,17 @@ proc genArgNoParam(p: BProc, n: PNode): Rope = initLocExprSingleUse(p, n, a) result = rdLoc(a) +template genParamLoop(params) {.dirty.} = + if i < sonsLen(typ): + assert(typ.n.sons[i].kind == nkSym) + let paramType = typ.n.sons[i] + if not paramType.typ.isCompileTimeOnly: + if params != nil: add(params, ~", ") + add(params, genArg(p, ri.sons[i], paramType.sym, ri)) + else: + if params != nil: add(params, ~", ") + add(params, genArgNoParam(p, ri.sons[i])) + proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) = var op: TLoc # this is a hotspot in the compiler @@ -170,13 +181,7 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) = assert(sonsLen(typ) == sonsLen(typ.n)) var length = sonsLen(ri) for i in countup(1, length - 1): - if ri.sons[i].typ.isCompileTimeOnly: continue - if params != nil: add(params, ~", ") - if i < sonsLen(typ): - assert(typ.n.sons[i].kind == nkSym) - add(params, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri)) - else: - add(params, genArgNoParam(p, ri.sons[i])) + genParamLoop(params) fixupCall(p, le, ri, d, op.r, params) proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = @@ -198,13 +203,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = var length = sonsLen(ri) for i in countup(1, length - 1): assert(sonsLen(typ) == sonsLen(typ.n)) - if ri.sons[i].typ.isCompileTimeOnly: continue - if i < sonsLen(typ): - assert(typ.n.sons[i].kind == nkSym) - add(pl, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri)) - else: - add(pl, genArgNoParam(p, ri.sons[i])) - if i < length - 1: add(pl, ~", ") + genParamLoop(pl) template genCallPattern {.dirty.} = lineF(p, cpsStmts, callPattern & ";$n", [op.r, pl, pl.addComma, rawProc]) @@ -241,13 +240,14 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = genCallPattern() proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope = - if ri.sons[i].typ.isCompileTimeOnly: - result = nil - elif i < sonsLen(typ): + if i < sonsLen(typ): # 'var T' is 'T&' in C++. This means we ignore the request of # any nkHiddenAddr when it's a 'var T'. - assert(typ.n.sons[i].kind == nkSym) - if typ.sons[i].kind == tyVar and ri.sons[i].kind == nkHiddenAddr: + let paramType = typ.n.sons[i] + assert(paramType.kind == nkSym) + if paramType.typ.isCompileTimeOnly: + result = nil + elif typ.sons[i].kind == tyVar and ri.sons[i].kind == nkHiddenAddr: result = genArgNoParam(p, ri.sons[i][0]) else: result = genArgNoParam(p, ri.sons[i]) #, typ.n.sons[i].sym) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 493749848..c237eeffa 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -347,8 +347,8 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = else: useStringh(p.module) linefmt(p, cpsStmts, - "memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1));$n", - rdLoc(dest), rdLoc(src)) + "memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n", + rdLoc(dest), rdLoc(src), getTypeDesc(p.module, ty)) of tyOpenArray, tyVarargs: # open arrays are always on the stack - really? What if a sequence is # passed to an open array? @@ -1052,9 +1052,9 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = # seq = (typeof seq) incrSeq(&seq->Sup, sizeof(x)); # seq->data[seq->len-1] = x; let seqAppendPattern = if not p.module.compileToCpp: - "$1 = ($2) #incrSeq(&($1)->Sup, sizeof($3));$n" + "$1 = ($2) #incrSeqV2(&($1)->Sup, sizeof($3));$n" else: - "$1 = ($2) #incrSeq($1, sizeof($3));$n" + "$1 = ($2) #incrSeqV2($1, sizeof($3));$n" var a, b, dest: TLoc initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[2], b) @@ -1064,8 +1064,9 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = getTypeDesc(p.module, skipTypes(e.sons[2].typ, abstractVar))]) keepAlive(p, a) initLoc(dest, locExpr, b.t, OnHeap) - dest.r = rfmt(nil, "$1->data[$1->$2-1]", rdLoc(a), lenField(p)) + dest.r = rfmt(nil, "$1->data[$1->$2]", rdLoc(a), lenField(p)) genAssignment(p, dest, b, {needToCopy, afDestIsNil}) + lineCg(p, cpsStmts, "++$1->$2;$n", rdLoc(a), lenField(p)) gcUsage(e) proc genReset(p: BProc, n: PNode) = @@ -1319,6 +1320,8 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) = putIntoDest(p, d, e.typ, ropecg(p.module, "#reprAny($1, $2)", [ rdLoc(a), genTypeInfo(p.module, t)])) + of tyEmpty: + localError(e.info, "'repr' doesn't support 'void' type") else: putIntoDest(p, d, e.typ, ropecg(p.module, "#reprAny($1, $2)", [addrLoc(a), genTypeInfo(p.module, t)])) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 5129c8023..f12a24fa2 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1101,7 +1101,10 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) = genGotoVar(p, e.sons[1]) elif not fieldDiscriminantCheckNeeded(p, e): var a: TLoc - initLocExpr(p, e.sons[0], a) + if e[0].kind in {nkDerefExpr, nkHiddenDeref}: + genDeref(p, e[0], a, enforceDeref=true) + else: + initLocExpr(p, e.sons[0], a) if fastAsgn: incl(a.flags, lfNoDeepCopy) assert(a.t != nil) loadInto(p, e.sons[0], e.sons[1], a) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 3742fd2fd..84d02d1da 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -323,7 +323,8 @@ proc paramStorageLoc(param: PSym): TStorageLoc = result = OnUnknown proc genProcParams(m: BModule, t: PType, rettype, params: var Rope, - check: var IntSet, declareEnvironment=true) = + check: var IntSet, declareEnvironment=true; + weakDep=false) = params = nil if (t.sons[0] == nil) or isInvalidReturnType(t.sons[0]): rettype = ~"void" @@ -341,6 +342,8 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope, add(params, ~"*") incl(param.loc.flags, lfIndirect) param.loc.s = OnUnknown + elif weakDep: + add(params, getTypeDescWeak(m, param.typ, check)) else: add(params, getTypeDescAux(m, param.typ, check)) add(params, ~" ") @@ -577,7 +580,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope = result = getTypeName(t) idTablePut(m.typeCache, t, result) var rettype, desc: Rope - genProcParams(m, t, rettype, desc, check) + genProcParams(m, t, rettype, desc, check, true, true) if not isImportedType(t): if t.callConv != ccClosure: # procedure vars may need a closure! addf(m.s[cfsTypes], "typedef $1_PTR($2, $3) $4;$n", diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 783949403..2e95918cc 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -853,14 +853,14 @@ proc genMainProc(m: BModule) = # functions, which might otherwise merge their stack frames. PreMainBody = "void PreMainInner() {$N" & - "\tsystemInit();$N" & + "\tsystemInit000();$N" & "$1" & "$2" & "$3" & "}$N$N" & "void PreMain() {$N" & "\tvoid (*volatile inner)();$N" & - "\tsystemDatInit();$N" & + "\tsystemDatInit000();$N" & "\tinner = PreMainInner;$N" & "$4$5" & "\t(*inner)();$N" & @@ -950,7 +950,7 @@ proc genMainProc(m: BModule) = gBreakpoints.add(m.genFilenames) let initStackBottomCall = - if platform.targetOS == osStandalone: "".rope + if platform.targetOS == osStandalone or gSelectedGC == gcNone: "".rope else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N") inc(m.labels) appcg(m, m.s[cfsProcs], PreMainBody, [ @@ -974,8 +974,8 @@ proc getSomeInitName(m: PSym, suffix: string): Rope = result.add m.name.s result.add suffix -proc getInitName(m: PSym): Rope = getSomeInitName(m, "Init") -proc getDatInitName(m: PSym): Rope = getSomeInitName(m, "DatInit") +proc getInitName(m: PSym): Rope = getSomeInitName(m, "Init000") +proc getDatInitName(m: PSym): Rope = getSomeInitName(m, "DatInit000") proc registerModuleToMain(m: PSym) = var diff --git a/compiler/installer.ini b/compiler/installer.ini index 70df9fd24..52a3d0886 100644 --- a/compiler/installer.ini +++ b/compiler/installer.ini @@ -103,6 +103,9 @@ Files: "lib/impure/nre/private/*.nim" Files: "lib/wrappers/*.nim" Files: "lib/wrappers/readline/*.nim" +Files: "lib/wrappers/linenoise/*.nim" +Files: "lib/wrappers/linenoise/*.c" +Files: "lib/wrappers/linenoise/*.h" Files: "lib/wrappers/sdl/*.nim" Files: "lib/wrappers/zip/*.nim" Files: "lib/wrappers/zip/libzip_all.c" diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 87408f395..6e317fb7e 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1046,9 +1046,18 @@ proc genArg(p: PProc, n: PNode, r: var TCompRes) = proc genArgs(p: PProc, n: PNode, r: var TCompRes) = add(r.res, "(") var hasArgs = false + + var typ = skipTypes(n.sons[0].typ, abstractInst) + assert(typ.kind == tyProc) + assert(sonsLen(typ) == sonsLen(typ.n)) + for i in countup(1, sonsLen(n) - 1): let it = n.sons[i] - if it.typ.isCompileTimeOnly: continue + if i < sonsLen(typ): + assert(typ.n.sons[i].kind == nkSym) + let paramType = typ.n.sons[i] + if paramType.typ.isCompileTimeOnly: continue + if hasArgs: add(r.res, ", ") genArg(p, it, r) hasArgs = true diff --git a/compiler/main.nim b/compiler/main.nim index ee4a34fbb..47fae7fa7 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -378,3 +378,4 @@ proc mainCommand* = when SimulateCaasMemReset: resetMemory() + resetAttributes() diff --git a/compiler/msgs.nim b/compiler/msgs.nim index f1d1029e4..bb247ea54 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -865,6 +865,11 @@ proc rawMessage*(msg: TMsgKind, args: openArray[string]) = proc rawMessage*(msg: TMsgKind, arg: string) = rawMessage(msg, [arg]) +proc resetAttributes* = + if {optUseColors, optStdout} * gGlobalOptions == {optUseColors}: + terminal.resetAttributes() + stdout.flushFile() + proc writeSurroundingSrc(info: TLineInfo) = const indent = " " msgWriteln(indent & $info.sourceLine) diff --git a/compiler/options.nim b/compiler/options.nim index f312c877c..af1e21e60 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -330,13 +330,16 @@ proc rawFindFile2(f: string): string = result = "" proc findFile*(f: string): string {.procvar.} = - result = f.rawFindFile - if result.len == 0: - result = f.toLower.rawFindFile + if f.isAbsolute: + result = if f.existsFile: f else: "" + else: + result = f.rawFindFile if result.len == 0: - result = f.rawFindFile2 + result = f.toLower.rawFindFile if result.len == 0: - result = f.toLower.rawFindFile2 + result = f.rawFindFile2 + if result.len == 0: + result = f.toLower.rawFindFile2 proc findModule*(modulename, currentModule: string): string = # returns path to module diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 6f37fe756..c771155af 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -276,7 +276,8 @@ proc processNote(c: PContext, n: PNode) = if (n.kind == nkExprColonExpr) and (sonsLen(n) == 2) and (n.sons[0].kind == nkBracketExpr) and (n.sons[0].sons[1].kind == nkIdent) and - (n.sons[0].sons[0].kind == nkIdent) and (n.sons[1].kind == nkIdent): + (n.sons[0].sons[0].kind == nkIdent): + #and (n.sons[1].kind == nkIdent): var nk: TNoteKind case whichKeyword(n.sons[0].sons[0].ident) of wHint: diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 376c0d6f7..7cd8e25ee 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -31,6 +31,7 @@ type buf*: string pendingNL*: int # negative if not active; else contains the # indentation value + pendingWhitespace: int comStack*: seq[PNode] # comment stack flags*: TRenderFlags checkAnon: bool # we're in a context that can contain sfAnon @@ -83,6 +84,7 @@ proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) = g.buf = "" g.flags = renderFlags g.pendingNL = -1 + g.pendingWhitespace = -1 g.checkAnon = false proc addTok(g: var TSrcGen, kind: TTokType, s: string) = @@ -97,12 +99,21 @@ proc addPendingNL(g: var TSrcGen) = addTok(g, tkSpaces, "\n" & spaces(g.pendingNL)) g.lineLen = g.pendingNL g.pendingNL = - 1 + g.pendingWhitespace = -1 + elif g.pendingWhitespace >= 0: + addTok(g, tkSpaces, spaces(g.pendingWhitespace)) + g.pendingWhitespace = -1 proc putNL(g: var TSrcGen, indent: int) = if g.pendingNL >= 0: addPendingNL(g) else: addTok(g, tkSpaces, "\n") g.pendingNL = indent g.lineLen = indent + g.pendingWhitespace = -1 + +proc previousNL(g: TSrcGen): bool = + result = g.pendingNL >= 0 or (g.tokens.len > 0 and + g.tokens[^1].kind == tkSpaces) proc putNL(g: var TSrcGen) = putNL(g, g.indent) @@ -127,10 +138,13 @@ proc dedent(g: var TSrcGen) = dec(g.lineLen, IndentWidth) proc put(g: var TSrcGen, kind: TTokType, s: string) = - addPendingNL(g) - if len(s) > 0: - addTok(g, kind, s) - inc(g.lineLen, len(s)) + if kind != tkSpaces: + addPendingNL(g) + if len(s) > 0: + addTok(g, kind, s) + inc(g.lineLen, len(s)) + else: + g.pendingWhitespace = s.len proc putLong(g: var TSrcGen, kind: TTokType, s: string, lineLen: int) = # use this for tokens over multiple lines. @@ -1196,6 +1210,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = if renderNoPragmas notin g.flags: if g.inPragma <= 0: inc g.inPragma + #if not previousNL(g): put(g, tkSpaces, Space) put(g, tkCurlyDotLe, "{.") gcomma(g, n, emptyContext) diff --git a/compiler/rodread.nim b/compiler/rodread.nim index 02e909aac..92ce00240 100644 --- a/compiler/rodread.nim +++ b/compiler/rodread.nim @@ -90,7 +90,7 @@ import os, options, strutils, nversion, ast, astalgo, msgs, platform, condsyms, - ropes, idents, securehash, idgen, types, rodutils, memfiles + ropes, idents, securehash, idgen, types, rodutils, memfiles, tables type TReasonForRecompile* = enum ## all the reasons that can trigger recompilation @@ -136,7 +136,7 @@ type readerIndex: int line: int # only used for debugging, but is always in the code moduleID: int - syms: TIdTable # already processed symbols + syms: Table[int, PSym] # already processed symbols memfile: MemFile # unfortunately there is no point in time where we # can close this! XXX methods*: TSymSeq @@ -372,11 +372,11 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym = else: internalError(info, "decodeSym: no ident") #echo "decoding: {", ident.s - result = PSym(idTableGet(r.syms, id)) + result = r.syms[id] if result == nil: new(result) result.id = id - idTablePut(r.syms, result, result) + r.syms[result.id] = result if debugIds: registerID(result) elif result.id != id: internalError(info, "decodeSym: wrong id") @@ -481,7 +481,7 @@ proc processInterf(r: PRodReader, module: PSym) = var s = newStub(r, w, key) s.owner = module strTableAdd(module.tab, s) - idTablePut(r.syms, s, s) + r.syms[s.id] = s proc processCompilerProcs(r: PRodReader, module: PSym) = if r.compilerProcsIdx == 0: internalError("processCompilerProcs") @@ -491,11 +491,11 @@ proc processCompilerProcs(r: PRodReader, module: PSym) = inc(r.pos) var key = decodeVInt(r.s, r.pos) inc(r.pos) # #10 - var s = PSym(idTableGet(r.syms, key)) + var s = r.syms[key] if s == nil: s = newStub(r, w, key) s.owner = module - idTablePut(r.syms, s, s) + r.syms[s.id] = s strTableAdd(rodCompilerprocs, s) proc processIndex(r: PRodReader; idx: var TIndex; outf: File = nil) = @@ -667,7 +667,7 @@ proc newRodReader(modfilename: string, hash: SecureHash, r.line = 1 r.readerIndex = readerIndex r.filename = modfilename - initIdTable(r.syms) + r.syms = initTable[int, PSym]() # we terminate the file explicitly with ``\0``, so the cast to `cstring` # is safe: r.s = cast[cstring](r.memfile.mem) @@ -737,7 +737,7 @@ proc getReader(moduleId: int): PRodReader = return nil proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym = - result = PSym(idTableGet(r.syms, id)) + result = r.syms[id] if result == nil: # load the symbol: var d = iiTableGet(r.index.tab, id) @@ -802,7 +802,7 @@ proc getHash*(fileIdx: int32): SecureHash = if gMods[fileIdx].hashDone: return gMods[fileIdx].hash - result = secureHashFile(fileIdx.toFilename) + result = secureHashFile(fileIdx.toFullPath) gMods[fileIdx].hash = result template growCache*(cache, pos) = @@ -859,7 +859,7 @@ proc handleSymbolFile(module: PSym): PRodReader = result = gMods[fileIdx].rd if result != nil: module.id = result.moduleID - idTablePut(result.syms, module, module) + result.syms[module.id] = module processInterf(result, module) processCompilerProcs(result, module) loadConverters(result) diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim index 6f7000efc..d48a9ba40 100644 --- a/compiler/rodwrite.nim +++ b/compiler/rodwrite.nim @@ -11,14 +11,14 @@ # rod files is a pass, reading of rod files is not! This is why reading and # writing of rod files is split into two different modules. -import +import intsets, os, options, strutils, nversion, ast, astalgo, msgs, platform, condsyms, ropes, idents, securehash, rodread, passes, importer, idgen, rodutils # implementation -type +type TRodWriter = object of TPassContext module: PSym hash: SecureHash @@ -46,15 +46,15 @@ proc addInterfaceSym(w: PRodWriter, s: PSym) proc addStmt(w: PRodWriter, n: PNode) proc writeRod(w: PRodWriter) -proc getDefines(): string = +proc getDefines(): string = result = "" for d in definedSymbolNames(): if result.len != 0: add(result, " ") add(result, d) -proc fileIdx(w: PRodWriter, filename: string): int = - for i in countup(0, high(w.files)): - if w.files[i] == filename: +proc fileIdx(w: PRodWriter, filename: string): int = + for i in countup(0, high(w.files)): + if w.files[i] == filename: return i result = len(w.files) setLen(w.files, result + 1) @@ -63,7 +63,7 @@ proc fileIdx(w: PRodWriter, filename: string): int = template filename*(w: PRodWriter): string = w.module.filename -proc newRodWriter(hash: SecureHash, module: PSym): PRodWriter = +proc newRodWriter(hash: SecureHash, module: PSym): PRodWriter = new(result) result.sstack = @[] result.tstack = @[] @@ -85,12 +85,12 @@ proc newRodWriter(hash: SecureHash, module: PSym): PRodWriter = result.init = "" result.origFile = module.info.toFilename result.data = newStringOfCap(12_000) - + proc addModDep(w: PRodWriter, dep: string) = if w.modDeps.len != 0: add(w.modDeps, ' ') encodeVInt(fileIdx(w, dep), w.modDeps) -const +const rodNL = "\x0A" proc addInclDep(w: PRodWriter, dep: string) = @@ -110,18 +110,18 @@ proc pushSym(w: PRodWriter, s: PSym) = if iiTableGet(w.index.tab, s.id) == InvalidKey: w.sstack.add(s) -proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode, - result: var string) = - if n == nil: +proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode, + result: var string) = + if n == nil: # nil nodes have to be stored too: result.add("()") return result.add('(') - encodeVInt(ord(n.kind), result) + encodeVInt(ord(n.kind), result) # we do not write comments for now # Line information takes easily 20% or more of the filesize! Therefore we # omit line information if it is the same as the father's line information: - if fInfo.fileIndex != n.info.fileIndex: + if fInfo.fileIndex != n.info.fileIndex: result.add('?') encodeVInt(n.info.col, result) result.add(',') @@ -139,7 +139,7 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode, # No need to output the file index, as this is the serialization of one # file. var f = n.flags * PersistentNodeFlags - if f != {}: + if f != {}: result.add('$') encodeVInt(cast[int32](f), result) if n.typ != nil: @@ -147,16 +147,16 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode, encodeVInt(n.typ.id, result) pushType(w, n.typ) case n.kind - of nkCharLit..nkInt64Lit: + of nkCharLit..nkInt64Lit: if n.intVal != 0: result.add('!') encodeVBiggestInt(n.intVal, result) - of nkFloatLit..nkFloat64Lit: - if n.floatVal != 0.0: + of nkFloatLit..nkFloat64Lit: + if n.floatVal != 0.0: result.add('!') encodeStr($n.floatVal, result) of nkStrLit..nkTripleStrLit: - if n.strVal != "": + if n.strVal != "": result.add('!') encodeStr(n.strVal, result) of nkIdent: @@ -167,25 +167,25 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode, encodeVInt(n.sym.id, result) pushSym(w, n.sym) else: - for i in countup(0, sonsLen(n) - 1): + for i in countup(0, sonsLen(n) - 1): encodeNode(w, n.info, n.sons[i], result) add(result, ')') -proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) = +proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) = var oldLen = result.len result.add('<') if loc.k != low(loc.k): encodeVInt(ord(loc.k), result) - if loc.s != low(loc.s): + if loc.s != low(loc.s): add(result, '*') encodeVInt(ord(loc.s), result) - if loc.flags != {}: + if loc.flags != {}: add(result, '$') encodeVInt(cast[int32](loc.flags), result) if loc.t != nil: add(result, '^') encodeVInt(cast[int32](loc.t.id), result) pushType(w, loc.t) - if loc.r != nil: + if loc.r != nil: add(result, '!') encodeStr($loc.r, result) if oldLen + 1 == result.len: @@ -193,9 +193,9 @@ proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) = setLen(result, oldLen) else: add(result, '>') - -proc encodeType(w: PRodWriter, t: PType, result: var string) = - if t == nil: + +proc encodeType(w: PRodWriter, t: PType, result: var string) = + if t == nil: # nil nodes have to be stored too: result.add("[]") return @@ -207,38 +207,38 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) = encodeVInt(ord(t.kind), result) add(result, '+') encodeVInt(t.id, result) - if t.n != nil: + if t.n != nil: encodeNode(w, unknownLineInfo(), t.n, result) - if t.flags != {}: + if t.flags != {}: add(result, '$') encodeVInt(cast[int32](t.flags), result) - if t.callConv != low(t.callConv): + if t.callConv != low(t.callConv): add(result, '?') encodeVInt(ord(t.callConv), result) - if t.owner != nil: + if t.owner != nil: add(result, '*') encodeVInt(t.owner.id, result) pushSym(w, t.owner) - if t.sym != nil: + if t.sym != nil: add(result, '&') encodeVInt(t.sym.id, result) pushSym(w, t.sym) - if t.size != - 1: + if t.size != - 1: add(result, '/') encodeVBiggestInt(t.size, result) - if t.align != 2: + if t.align != 2: add(result, '=') encodeVInt(t.align, result) encodeLoc(w, t.loc, result) - for i in countup(0, sonsLen(t) - 1): - if t.sons[i] == nil: + for i in countup(0, sonsLen(t) - 1): + if t.sons[i] == nil: add(result, "^()") - else: - add(result, '^') + else: + add(result, '^') encodeVInt(t.sons[i].id, result) pushType(w, t.sons[i]) -proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) = +proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) = add(result, '|') encodeVInt(ord(lib.kind), result) add(result, '|') @@ -277,10 +277,10 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) = if s.magic != mNone: result.add('@') encodeVInt(ord(s.magic), result) - if s.options != w.options: + if s.options != w.options: result.add('!') encodeVInt(cast[int32](s.options), result) - if s.position != 0: + if s.position != 0: result.add('%') encodeVInt(s.position, result) if s.offset != - 1: @@ -308,7 +308,7 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) = if codeAst != nil: # resore the AST: s.ast.sons[codePos] = codeAst - + proc addToIndex(w: var TIndex, key, val: int) = if key - w.lastIdxKey == 1: # we do not store a key-diff of 1 to safe space @@ -329,24 +329,25 @@ when debugWrittenIds: proc symStack(w: PRodWriter): int = var i = 0 - while i < len(w.sstack): + while i < len(w.sstack): var s = w.sstack[i] if sfForward in s.flags: w.sstack[result] = s inc result elif iiTableGet(w.index.tab, s.id) == InvalidKey: var m = getModule(s) - if m == nil: internalError("symStack: module nil: " & s.name.s) - if (m.id == w.module.id) or (sfFromGeneric in s.flags): + if m == nil and s.kind != skPackage: + internalError("symStack: module nil: " & s.name.s) + if s.kind == skPackage or m.id == w.module.id or sfFromGeneric in s.flags: # put definition in here var L = w.data.len - addToIndex(w.index, s.id, L) + addToIndex(w.index, s.id, L) when debugWrittenIds: incl(debugWritten, s.id) encodeSym(w, s, w.data) add(w.data, rodNL) # put into interface section if appropriate: - if {sfExported, sfFromGeneric} * s.flags == {sfExported} and - s.kind in ExportableSymKinds: + if {sfExported, sfFromGeneric} * s.flags == {sfExported} and + s.kind in ExportableSymKinds: encodeStr(s.name.s, w.interf) add(w.interf, ' ') encodeVInt(s.id, w.interf) @@ -362,26 +363,26 @@ proc symStack(w: PRodWriter): int = if s.kind == skMethod and sfDispatcher notin s.flags: if w.methods.len != 0: add(w.methods, ' ') encodeVInt(s.id, w.methods) - elif iiTableGet(w.imports.tab, s.id) == InvalidKey: + elif iiTableGet(w.imports.tab, s.id) == InvalidKey: addToIndex(w.imports, s.id, m.id) when debugWrittenIds: - if not Contains(debugWritten, s.id): + if not contains(debugWritten, s.id): echo(w.filename) debug(s) debug(s.owner) debug(m) - InternalError("Symbol referred to but never written") + internalError("Symbol referred to but never written") inc(i) setLen(w.sstack, result) -proc typeStack(w: PRodWriter): int = +proc typeStack(w: PRodWriter): int = var i = 0 - while i < len(w.tstack): + while i < len(w.tstack): var t = w.tstack[i] if t.kind == tyForward: w.tstack[result] = t inc result - elif iiTableGet(w.index.tab, t.id) == InvalidKey: + elif iiTableGet(w.index.tab, t.id) == InvalidKey: var L = w.data.len addToIndex(w.index, t.id, L) encodeType(w, t, w.data) @@ -401,24 +402,24 @@ proc processStacks(w: PRodWriter, finalPass: bool) = if finalPass and (oldS != 0 or oldT != 0): internalError("could not serialize some forwarded symbols/types") -proc rawAddInterfaceSym(w: PRodWriter, s: PSym) = +proc rawAddInterfaceSym(w: PRodWriter, s: PSym) = pushSym(w, s) processStacks(w, false) -proc addInterfaceSym(w: PRodWriter, s: PSym) = - if w == nil: return - if s.kind in ExportableSymKinds and - {sfExported, sfCompilerProc} * s.flags != {}: +proc addInterfaceSym(w: PRodWriter, s: PSym) = + if w == nil: return + if s.kind in ExportableSymKinds and + {sfExported, sfCompilerProc} * s.flags != {}: rawAddInterfaceSym(w, s) -proc addStmt(w: PRodWriter, n: PNode) = +proc addStmt(w: PRodWriter, n: PNode) = encodeVInt(w.data.len, w.init) add(w.init, rodNL) encodeNode(w, unknownLineInfo(), n, w.data) add(w.data, rodNL) processStacks(w, false) -proc writeRod(w: PRodWriter) = +proc writeRod(w: PRodWriter) = processStacks(w, true) var f: File if not open(f, completeGeneratedFilePath(changeFileExt( @@ -439,12 +440,12 @@ proc writeRod(w: PRodWriter) = encodeStr(w.origFile, orig) f.write(orig) f.write(rodNL) - + var hash = "HASH:" encodeStr($w.hash, hash) f.write(hash) f.write(rodNL) - + var options = "OPTIONS:" encodeVInt(cast[int32](w.options), options) f.write(options) @@ -458,31 +459,31 @@ proc writeRod(w: PRodWriter) = var cmd = "CMD:" encodeVInt(cast[int32](gCmd), cmd) f.write(cmd) - f.write(rodNL) - + f.write(rodNL) + f.write("DEFINES:") f.write(w.defines) f.write(rodNL) - + var files = "FILES(" & rodNL - for i in countup(0, high(w.files)): + for i in countup(0, high(w.files)): encodeStr(w.files[i], files) files.add(rodNL) f.write(files) f.write(')' & rodNL) - + f.write("INCLUDES(" & rodNL) f.write(w.inclDeps) f.write(')' & rodNL) - + f.write("DEPS:") f.write(w.modDeps) f.write(rodNL) - + f.write("INTERF(" & rodNL) f.write(w.interf) f.write(')' & rodNL) - + f.write("COMPILERPROCS(" & rodNL) f.write(w.compilerProcs) f.write(')' & rodNL) @@ -490,11 +491,11 @@ proc writeRod(w: PRodWriter) = f.write("INDEX(" & rodNL) f.write(w.index.r) f.write(')' & rodNL) - + f.write("IMPORTS(" & rodNL) f.write(w.imports.r) f.write(')' & rodNL) - + f.write("CONVERTERS:") f.write(w.converters) f.write(rodNL) @@ -502,11 +503,11 @@ proc writeRod(w: PRodWriter) = f.write("METHODS:") f.write(w.methods) f.write(rodNL) - + f.write("INIT(" & rodNL) f.write(w.init) f.write(')' & rodNL) - + f.write("DATA(" & rodNL) f.write(w.data) f.write(')' & rodNL) @@ -514,23 +515,23 @@ proc writeRod(w: PRodWriter) = # for reading: f.write("\0") f.close() - + #echo "interf: ", w.interf.len #echo "index: ", w.index.r.len #echo "init: ", w.init.len #echo "data: ", w.data.len -proc process(c: PPassContext, n: PNode): PNode = +proc process(c: PPassContext, n: PNode): PNode = result = n - if c == nil: return + if c == nil: return var w = PRodWriter(c) case n.kind of nkStmtList: for i in countup(0, sonsLen(n) - 1): discard process(c, n.sons[i]) #var s = n.sons[namePos].sym #addInterfaceSym(w, s) - of nkProcDef, nkMethodDef, nkIteratorDef, nkConverterDef, - nkTemplateDef, nkMacroDef: + of nkProcDef, nkMethodDef, nkIteratorDef, nkConverterDef, + nkTemplateDef, nkMacroDef: var s = n.sons[namePos].sym if s == nil: internalError(n.info, "rodwrite.process") if n.sons[bodyPos] == nil: @@ -539,17 +540,17 @@ proc process(c: PPassContext, n: PNode): PNode = sfForward notin s.flags: addInterfaceSym(w, s) of nkVarSection, nkLetSection, nkConstSection: - for i in countup(0, sonsLen(n) - 1): + for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] if a.kind == nkCommentStmt: continue addInterfaceSym(w, a.sons[0].sym) - of nkTypeSection: - for i in countup(0, sonsLen(n) - 1): + of nkTypeSection: + for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] - if a.kind == nkCommentStmt: continue + if a.kind == nkCommentStmt: continue if a.sons[0].kind != nkSym: internalError(a.info, "rodwrite.process") var s = a.sons[0].sym - addInterfaceSym(w, s) + addInterfaceSym(w, s) # this takes care of enum fields too # Note: The check for ``s.typ.kind = tyEnum`` is wrong for enum # type aliasing! Otherwise the same enum symbol would be included @@ -557,20 +558,20 @@ proc process(c: PPassContext, n: PNode): PNode = # # if (a.sons[2] <> nil) and (a.sons[2].kind = nkEnumTy) then begin # a := s.typ.n; - # for j := 0 to sonsLen(a)-1 do - # addInterfaceSym(w, a.sons[j].sym); - # end - of nkImportStmt: + # for j := 0 to sonsLen(a)-1 do + # addInterfaceSym(w, a.sons[j].sym); + # end + of nkImportStmt: for i in countup(0, sonsLen(n) - 1): addModDep(w, getModuleName(n.sons[i])) addStmt(w, n) - of nkFromStmt: + of nkFromStmt: addModDep(w, getModuleName(n.sons[0])) addStmt(w, n) - of nkIncludeStmt: + of nkIncludeStmt: for i in countup(0, sonsLen(n) - 1): addInclDep(w, getModuleName(n.sons[i])) - of nkPragma: + of nkPragma: addStmt(w, n) - else: + else: discard proc myOpen(module: PSym): PPassContext = @@ -579,7 +580,7 @@ proc myOpen(module: PSym): PPassContext = rawAddInterfaceSym(w, module) result = w -proc myClose(c: PPassContext, n: PNode): PNode = +proc myClose(c: PPassContext, n: PNode): PNode = result = process(c, n) var w = PRodWriter(c) writeRod(w) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 886f9458d..fba64776d 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -33,6 +33,7 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = if result.typ.kind == tyVar: result = newDeref(result) elif {efWantStmt, efAllowStmt} * flags != {}: result.typ = newTypeS(tyEmpty, c) + result.typ.flags.incl tfVoid else: localError(n.info, errExprXHasNoType, renderTree(result, {renderNoComments})) diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 23666656e..729222220 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -435,7 +435,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode = mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq, mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait, mDotDot, mNLen..mNError, mEqRef, mSlurp, mStaticExec, mNGenSym, mSpawn, - mParallel, mPlugin: + mParallel, mPlugin, mGetTypeInfo: discard of mEqProc: result = newIntNodeT(ord( diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 161d22fc1..a138981b7 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -260,6 +260,12 @@ proc semTemplSomeDecl(c: var TemplCtx, n: PNode, symKind: TSymKind; start=0) = addLocalDecl(c, a.sons[j], symKind) proc semPattern(c: PContext, n: PNode): PNode + +proc semTemplBodySons(c: var TemplCtx, n: PNode): PNode = + result = n + for i in 0.. < n.len: + result.sons[i] = semTemplBody(c, n.sons[i]) + proc semTemplBody(c: var TemplCtx, n: PNode): PNode = result = n semIdeForTemplateOrGenericCheck(n, c.cursorInBody) @@ -420,9 +426,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = return symChoice(c.c, n, s, scForceOpen) else: return symChoice(c.c, n, s, scOpen) - result = n - for i in countup(0, sonsLen(n) - 1): - result.sons[i] = semTemplBody(c, n.sons[i]) + result = semTemplBodySons(c, n) proc semTemplBodyDirty(c: var TemplCtx, n: PNode): PNode = result = n @@ -475,7 +479,7 @@ proc transformToExpr(n: PNode): PNode = proc semTemplateDef(c: PContext, n: PNode): PNode = var s: PSym - if c.p.owner.kind == skModule: + if isTopLevel(c): s = semIdentVis(c, skTemplate, n.sons[0], {sfExported}) incl(s.flags, sfGlobal) else: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 144a41ff0..b518f0fb9 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1051,6 +1051,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = return newOrPrevType(tyError, prev, c) else: var m = newCandidate(c, t) + m.isNoCall = true matches(c, n, copyTree(n), m) if m.state != csMatch and not m.typedescMatched: @@ -1338,7 +1339,11 @@ proc processMagicType(c: PContext, m: PSym) = of mTypeDesc: setMagicType(m, tyTypeDesc, 0) rawAddSon(m.typ, newTypeS(tyNone, c)) - of mVoidType: setMagicType(m, tyEmpty, 0) + of mVoidType: + setMagicType(m, tyEmpty, 0) + # for historical reasons we conflate 'void' with 'empty' so that '@[]' + # has the type 'seq[void]'. + m.typ.flags.incl tfVoid of mArray: setMagicType(m, tyArray, 0) of mOpenArray: diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index fc7807228..3ac145eb8 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -90,6 +90,7 @@ type allowMetaTypes*: bool # allow types such as seq[Number] # i.e. the result contains unresolved generics skipTypedesc*: bool # wether we should skip typeDescs + recursionLimit: int proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym @@ -365,6 +366,19 @@ proc propagateFieldFlags(t: PType, n: PNode) = else: discard proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = + template bailout = + if cl.recursionLimit > 100: + # bail out, see bug #2509. But note this caching is in general wrong, + # look at this example where TwoVectors should not share the generic + # instantiations (bug #3112): + + # type + # Vector[N: static[int]] = array[N, float64] + # TwoVectors[Na, Nb: static[int]] = (Vector[Na], Vector[Nb]) + result = PType(idTableGet(cl.localCache, t)) + if result != nil: return result + inc cl.recursionLimit + result = t if t == nil: return @@ -420,8 +434,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = result = t of tyGenericInst: - result = PType(idTableGet(cl.localCache, t)) - if result != nil: return result + bailout() result = instCopyType(cl, t) idTablePut(cl.localCache, t, result) for i in 1 .. <result.sonsLen: @@ -431,8 +444,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = else: if containsGenericType(t): #if not cl.allowMetaTypes: - result = PType(idTableGet(cl.localCache, t)) - if result != nil: return result + bailout() result = instCopyType(cl, t) result.size = -1 # needs to be recomputed #if not cl.allowMetaTypes: diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 540f0a04f..ef1c01b7a 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -47,6 +47,7 @@ type coerceDistincts*: bool # this is an explicit coercion that can strip away # a distrinct type typedescMatched*: bool + isNoCall*: bool # misused for generic type instantiations C[T] inheritancePenalty: int # to prefer closest father object type errors*: CandidateErrors # additional clarifications to be displayed to the # user if overload resolution fails @@ -268,6 +269,9 @@ proc concreteType(c: TCandidate, t: PType): PType = addSonSkipIntLit(result, t.sons[1]) # XXX: semantic checking for the type? of tyNil: result = nil # what should it be? + of tyTypeDesc: + if c.isNoCall: result = t + else: result = nil of tySequence, tySet: if t.sons[0].kind == tyEmpty: result = nil else: result = t diff --git a/compiler/vm.nim b/compiler/vm.nim index 6d496d6e1..40d273ceb 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1168,9 +1168,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = c.module) of opcGorge: decodeBC(rkNode) + inc pc + let rd = c.code[pc].regA + createStr regs[ra] regs[ra].node.strVal = opGorge(regs[rb].node.strVal, - regs[rc].node.strVal) + regs[rc].node.strVal, regs[rd].node.strVal) of opcNError: stackTrace(c, tos, pc, errUser, regs[ra].node.strVal) of opcNWarning: diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index 88bb7ae24..73016108d 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -import ast, types, msgs, osproc, streams, options, idents +import ast, types, msgs, osproc, streams, options, idents, securehash proc readOutput(p: Process): string = result = "" @@ -19,15 +19,35 @@ proc readOutput(p: Process): string = result.setLen(result.len - "\n".len) discard p.waitForExit -proc opGorge*(cmd, input: string): string = - try: - var p = startProcess(cmd, options={poEvalCommand}) - if input.len != 0: - p.inputStream.write(input) - p.inputStream.close() - result = p.readOutput - except IOError, OSError: - result = "" +proc opGorge*(cmd, input, cache: string): string = + if cache.len > 0:# and optForceFullMake notin gGlobalOptions: + let h = secureHash(cmd & "\t" & input & "\t" & cache) + let filename = options.toGeneratedFile("gorge_" & $h, "txt") + var f: File + if open(f, filename): + result = f.readAll + f.close + return + var readSuccessful = false + try: + var p = startProcess(cmd, options={poEvalCommand}) + if input.len != 0: + p.inputStream.write(input) + p.inputStream.close() + result = p.readOutput + readSuccessful = true + writeFile(filename, result) + except IOError, OSError: + if not readSuccessful: result = "" + else: + try: + var p = startProcess(cmd, options={poEvalCommand}) + if input.len != 0: + p.inputStream.write(input) + p.inputStream.close() + result = p.readOutput + except IOError, OSError: + result = "" proc opSlurp*(file: string, info: TLineInfo, module: PSym): string = try: diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 004adedb9..7abcbdb92 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -599,6 +599,18 @@ proc genBinaryABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) = c.freeTemp(tmp) c.freeTemp(tmp2) +proc genBinaryABCD(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) = + let + tmp = c.genx(n.sons[1]) + tmp2 = c.genx(n.sons[2]) + tmp3 = c.genx(n.sons[3]) + if dest < 0: dest = c.getTemp(n.typ) + c.gABC(n, opc, dest, tmp, tmp2) + c.gABC(n, opc, tmp3) + c.freeTemp(tmp) + c.freeTemp(tmp2) + c.freeTemp(tmp3) + proc genNarrow(c: PCtx; n: PNode; dest: TDest) = let t = skipTypes(n.typ, abstractVar-{tyTypeDesc}) # uint is uint64 in the VM, we we only need to mask the result for @@ -932,7 +944,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = c.gABC(n, opcTypeTrait, dest, tmp) c.freeTemp(tmp) of mSlurp: genUnaryABC(c, n, dest, opcSlurp) - of mStaticExec: genBinaryABC(c, n, dest, opcGorge) + of mStaticExec: genBinaryABCD(c, n, dest, opcGorge) of mNLen: genUnaryABI(c, n, dest, opcLenSeq) of mNChild: genBinaryABC(c, n, dest, opcNChild) of mNSetChild, mNDel: diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index e036c3b9a..4773258cf 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -86,6 +86,9 @@ $moduledesc $content """ +doc.listing_start = "<pre class = \"listing\">" +doc.listing_end = "</pre>" + # * $analytics: Google analytics location, includes <script> tags doc.file = """<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" @@ -578,7 +581,7 @@ pre { box-sizing: border-box; min-width: calc(100% - 19.5px); padding: 9.5px; - margin: 0 10px 0px 10px; + margin: 0.25em 10px 0.25em 10px; font-size: 14px; line-height: 20px; white-space: pre !important; @@ -981,6 +984,10 @@ div.align-right { /* div.align-center * { */ /* text-align: left } */ + +ul.simple > li { + margin-bottom: 0.5em } + ol.simple, ul.simple { margin-bottom: 1em; } diff --git a/doc/lib.txt b/doc/lib.txt index 14a13c0d2..6a8f32e07 100644 --- a/doc/lib.txt +++ b/doc/lib.txt @@ -35,11 +35,6 @@ Core implicitly by the compiler. Do not import it directly. It relies on compiler magic to work. -* `unsigned <unsigned.html>`_ - This module implements basic arithmetic operators for unsigned integers. - To discourage users from using unsigned integers, it's not part - of ``system``, but an extra import. - * `threads <threads.html>`_ Nim thread support. **Note**: This is part of the system module. Do not import it explicitly. diff --git a/doc/nep1.txt b/doc/nep1.txt new file mode 100644 index 000000000..e44ec8382 --- /dev/null +++ b/doc/nep1.txt @@ -0,0 +1,208 @@ +============================================== +Nim Enhancement Proposal #1 - Standard Library Style Guide +============================================== +:Author: Clay Sweetser +:Version: |nimversion| + +.. contents:: + + +Introduction +============ +Although Nim supports a variety of code and formatting styles, it is +nevertheless beneficial that certain community efforts, such as the standard +library, should follow a consistent set of style guidelines when suitable. +This enhancement proposal aims to list a series of guidelines that the standard +library should follow. + +Note that there can be exceptions to these rules. Nim being as flexible as it +is, there will be parts of this style guide that don't make sense in certain +contexts. Furthermore, just as +`Python's style guide<http://legacy.python.org/dev/peps/pep-0008/>`_ changes +over time, this style guide will too. + +These rules will only be enforced for contributions to the Nim +codebase and official projects, such as the Nim compiler, the standard library, +and the various official tools such as C2Nim. + +---------------- +Style Guidelines +---------------- + +Spacing and Whitespace Conventions +----------------------------------- + +- Lines should be no longer than 80 characters. Limiting the amount of + information present on each line makes for more readable code - the reader + has smaller chunks to process. + +- Two spaces should be used for indentation of blocks; tabstops are not allowed + (the compiler enforces this). Using spaces means that the appearance of code + is more consistent across editors. Unlike spaces, tabstop width varies across + editors, and not all editors provide means of changing this width. + +- Although use of whitespace for stylistic reasons other than the ones endorsed + by this guide are allowed, careful thought should be put into such practices. + Not all editors support automatic alignment of code sections, and re-aligning + long sections of code by hand can quickly become tedious. + + .. code-block:: nim + # This is bad, as the next time someone comes + # to edit this code block, they + # must re-align all the assignments again: + type + WordBool* = int16 + CalType* = int + ... # 5 lines later + CalId* = int + LongLong* = int64 + LongLongPtr* = ptr LongLong + + +Naming Conventions +------------------------- + +Note: While the rules outlined below are the *current* naming conventions, +these conventions have not always been in place. Previously, the naming +conventions for identifiers followed the Pascal tradition of prefixes which +indicated the base type of the identifier - PFoo for pointer and reference +types, TFoo for value types, EFoo for exceptions, etc. Though this has since +changed, there are many places in the standard library which still use this +convention. Such style remains in place purely for legacy reasons, and will be +changed in the future. + +- Type identifiers should be in PascalCase. All other identifiers should be in + camelCase with the exception of constants which **may** use PascalCase but + are not required to. + + .. code-block:: nim + const aConstant = 42 + const FooBar = 4.2 + + var aVariable = "Meep" + + type FooBar = object + + For constants coming from a C/C++ wrapper, ALL_UPPERCASE are allowed, but ugly. + (Why shout CONSTANT? Constants do no harm, variables do!) + +- When naming types that come in value, pointer, and reference varieties, use a + regular name for the variety that is to be used the most, and add a "Obj", + "Ref", or "Ptr" suffix for the other varieties. If there is no single variety + that will be used the most, add the suffixes to the pointer variants only. The + same applies to C/C++ wrappers. + + .. code-block:: nim + type + Handle = int64 # Will be used most often + HandleRef = ref Handle # Will be used less often +- Exception and Error types should have the "Error" suffix. + + .. code-block:: nim + type UnluckyError = object of Exception +- Unless marked with the `{.pure.}` pragma, members of enums should have an + identifying prefix, such as an abbreviation of the enum's name. + + .. code-block:: nim + type PathComponent = enum + pcDir + pcLinkToDir + pcFile + pcLinkToFile +- Non-pure enum values should use camelCase whereas pure enum values should use + PascalCase. + + .. code-block:: nim + type PathComponent {.pure.} = enum + Dir + LinkToDir + File + LinkToFile +- In the age of HTTP, HTML, FTP, TCP, IP, UTF, WWW it is foolish to pretend + these are somewhat special words requiring all uppercase. Instead tread them as what they are: Real words. So it's ``parseUrl`` rather than ``parseURL``, ``checkHttpHeader`` instead of ``checkHTTPHeader`` etc. + + +Coding Conventions +------------------ + +- The 'return' statement should only be used when it's control-flow properties + are required. Use a procedures implicit 'result' variable instead. This + improves readability. + +- Prefer to return `[]` and `""` instead of `nil`, or throw an exception if + that is appropriate. + +- Use a proc when possible, only using the more powerful facilities of macros, + templates, iterators, and converters when necessary. + +- Use the 'let' statement (not the var statement) when declaring variables that + do not change within their scope. Using the let statement ensures that + variables remain immutable, and gives those who read the code a better idea + of the code's purpose. + +- For new types, it is usually recommended to have both 'ref' and 'object' + versions of the type available for others to use. By making both variants + available for use, the type may be allocated both on the stack and the heap. + + +Conventions for multi-line statements and expressions +----------------------------------------------------- + +- Any tuple type declarations that are longer than one line should use the + regular object type layout instead. This enhances the readability of the + tuple declaration by splitting its members information across multiple lines. + + .. code-block:: nim + type + ShortTuple = tuple[a: int, b: string] + + ReallyLongTuple = tuple + wordyTupleMemberOne: string + wordyTupleMemberTwo: int + wordyTupleMemberThree: double +- Similarly, any procedure type declarations that are longer than one line + should be formatted in the style of a regular type. + + .. code-block:: nim + type + EventCallback = proc ( + timeRecieved: Time + errorCode: int + event: Event + ) +- Multi-line procedure declarations/argument lists should continue on the same + column as the opening brace. This style is different from that of procedure + type declarations in order to distinguish between the heading of a procedure + and its body. If the procedure name is too long to make this style + convenient, then one of the styles for multi-line procedure calls (or + consider renaming your procedure). + + .. code-block:: nim + proc lotsOfArguments(argOne: string, argTwo: int, argThree:float + argFour: proc(), argFive: bool): int + {.heyLookALongPragma.} = +- Multi-line procedure calls should either have one argument per line (like + multi-line type declarations) or continue on the same column as the opening + parenthesis (like multi-line procedure declarations). It is suggested that + the former style be used for procedure calls with complex argument + structures, and the latter style for procedure calls with simpler argument + structures. + + .. code-block:: nim + # Each argument on a new line, like type declarations + # Best suited for 'complex' procedure calls. + readDirectoryChangesW( + directoryHandle.THandle, + buffer.start, + bufferSize.int32, + watchSubdir.WinBool, + filterFlags, + cast[ptr dword](nil), + cast[Overlapped](ol), + cast[OverlappedCompletionRoutine](nil) + ) + + # Multiple arguments on new lines, aligned to the opening parenthesis + # Best suited for 'simple' procedure calls + startProcess(nimExecutable, currentDirectory, compilerArguments + environment, processOptions) diff --git a/doc/nimc.txt b/doc/nimc.txt index e90c38002..15c9f2955 100644 --- a/doc/nimc.txt +++ b/doc/nimc.txt @@ -388,7 +388,7 @@ Use two backticks to produce a single verbatim backtick. For a toplevel emit statement the section where in the generated C/C++ file the code should be emitted can be influenced via the -prefixes ``/*TYPESECTION*/`` or ``/*VARSECTION*/``: +prefixes ``/*TYPESECTION*/`` or ``/*VARSECTION*/`` or ``/*INCLUDESECTION*/``: .. code-block:: Nim {.emit: """/*TYPESECTION*/ diff --git a/doc/nimdoc.css b/doc/nimdoc.css index e3bab07de..a002b6be1 100644 --- a/doc/nimdoc.css +++ b/doc/nimdoc.css @@ -1,4 +1,9 @@ /* +NOTE - THIS IS PROBABLY NOT THE CSS FILE YOU WANT +The CSS text used by Nim's documentation tools (such as 'koch web', +'rst2html', etc) is contained in 'config\nimdoc.cfg' +*/ +/* :Author: David Goodger :Contact: goodger@python.org :Date: $Date: 2006-05-21 22:44:42 +0200 (Sun, 21 May 2006) $ diff --git a/doc/sets_fragment.txt b/doc/sets_fragment.txt index 84b13e672..15f0962ef 100644 --- a/doc/sets_fragment.txt +++ b/doc/sets_fragment.txt @@ -1,6 +1,16 @@ The set type models the mathematical notion of a set. The set's -basetype can only be an ordinal type. The reason is that sets are implemented -as high performance bit vectors. +basetype can only be an ordinal type of a certain size, namely: + * ``int8``-``int16`` + * ``uint8``/``byte``-``uint16`` + * ``char`` + * ``enum`` +or equivalent. The reason is that sets are implemented as high +performance bit vectors. Attempting to declare a set with a larger type will +result in an error: + +.. code-block:: nim + + var s: set[int64] # Error: set is too large Sets can be constructed via the set constructor: ``{}`` is the empty set. The empty set is type compatible with any concrete set type. The constructor diff --git a/doc/tools.txt b/doc/tools.txt index b0a45c575..bad603925 100644 --- a/doc/tools.txt +++ b/doc/tools.txt @@ -4,6 +4,10 @@ Tools available with Nim The standard distribution ships with the following tools: +- | `Documentation generator <docs/docgen.html>`_ + | The builtin document generator ``nim doc2`` generates HTML documentation + from ``.nim`` source files. + - | `Nimsuggest for IDE support <nimsuggest.html>`_ | Through the ``nimsuggest`` tool, any IDE can query a ``.nim`` source file and obtain useful information like definition of symbols or suggestions for diff --git a/doc/tut1.txt b/doc/tut1.txt index 34684a850..0d2de3c1e 100644 --- a/doc/tut1.txt +++ b/doc/tut1.txt @@ -20,7 +20,8 @@ This document is a tutorial for the programming language *Nim*. This tutorial assumes that you are familiar with basic programming concepts like variables, types or statements but is kept very basic. The `manual <manual.html>`_ contains many more examples of the advanced language features. - +All code examples in this tutorial, as well as the ones found in the rest of +Nim's documentation, follow the `Nim style guide <nep1.html>`. The first program @@ -1233,8 +1234,8 @@ Example: .. code-block:: nim var - x: seq[int] # a sequence of integers - x = @[1, 2, 3, 4, 5, 6] # the @ turns the array into a sequence + x: seq[int] # a reference to a sequence of integers + x = @[1, 2, 3, 4, 5, 6] # the @ turns the array into a sequence allocated on the heap Sequence variables are initialized with ``nil``. However, most sequence operations cannot deal with ``nil`` (leading to an exception being @@ -1278,6 +1279,23 @@ The `len <system.html#len,TOpenArray>`_, `low <system.html#low>`_ and `high with a compatible base type can be passed to an openarray parameter, the index type does not matter. +.. code-block:: nim + var + fruits: seq[string] # reference to a sequence of strings that is initialized with 'nil' + capitals: array[3, string] # array of strings with a fixed size + + fruits = @[] # creates an empty sequence on the heap that will be referenced by 'fruits' + + capitals = ["New York", "London", "Berlin"] # array 'capitals' allows only assignment of three elements + fruits.add("Banana") # sequence 'fruits' is dynamically expandable during runtime + fruits.add("Mango") + + proc openArraySize(oa: openArray[string]): int = + oa.len + + assert openArraySize(fruits) == 2 # procedure accepts a sequence as parameter + assert openArraySize(capitals) == 3 # but also an array type + The openarray type cannot be nested: multidimensional openarrays are not supported because this is seldom needed and cannot be done efficiently. diff --git a/examples/wingui.nim b/examples/wingui.nim deleted file mode 100644 index 2c2c387bb..000000000 --- a/examples/wingui.nim +++ /dev/null @@ -1,9 +0,0 @@ -# test a Windows GUI application - -import - windows, shellapi, nb30, mmsystem, shfolder - -#proc MessageBox(hWnd: int, lpText, lpCaption: CString, uType: uint): int -# {stdcall, import: "MessageBox", header: "<windows.h>"} - -discard MessageBox(0, "Hello World!", "Nimrod GUI Application", 0) diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim index dc97784c3..1f9fb1072 100644 --- a/lib/core/typeinfo.nim +++ b/lib/core/typeinfo.nim @@ -13,7 +13,7 @@ ## details from its clients, it remains inherently unsafe! ## ## See the `marshal <marshal.html>`_ module for what this module allows you -## to do. +## to do. {.push hints: off.} @@ -54,7 +54,7 @@ type akUInt16 = 42, ## any represents an unsigned in16 akUInt32 = 43, ## any represents an unsigned int32 akUInt64 = 44, ## any represents an unsigned int64 - + Any* = object ## can represent any nim value; NOTE: the wrapped ## value can be modified with its wrapper! This means ## that ``Any`` keeps a non-traced pointer to its @@ -114,7 +114,7 @@ proc newAny(value: pointer, rawType: PNimType): Any = when declared(system.VarSlot): proc toAny*(x: VarSlot): Any {.inline.} = - ## constructs a ``Any`` object from a variable slot ``x``. + ## constructs a ``Any`` object from a variable slot ``x``. ## This captures `x`'s address, so `x` can be modified with its ## ``Any`` wrapper! The client needs to ensure that the wrapper ## **does not** live longer than `x`! @@ -128,16 +128,16 @@ proc toAny*[T](x: var T): Any {.inline.} = ## that the wrapper **does not** live longer than `x`! result.value = addr(x) result.rawType = cast[PNimType](getTypeInfo(x)) - -proc kind*(x: Any): AnyKind {.inline.} = + +proc kind*(x: Any): AnyKind {.inline.} = ## get the type kind result = AnyKind(ord(x.rawType.kind)) proc size*(x: Any): int {.inline.} = ## returns the size of `x`'s type. result = x.rawType.size - -proc baseTypeKind*(x: Any): AnyKind {.inline.} = + +proc baseTypeKind*(x: Any): AnyKind {.inline.} = ## get the base type's kind; ``akNone`` is returned if `x` has no base type. if x.rawType.base != nil: result = AnyKind(ord(x.rawType.base.kind)) @@ -146,7 +146,7 @@ proc baseTypeSize*(x: Any): int {.inline.} = ## returns the size of `x`'s basetype. if x.rawType.base != nil: result = x.rawType.base.size - + proc invokeNew*(x: Any) = ## performs ``new(x)``. `x` needs to represent a ``ref``. assert x.rawType.kind == tyRef @@ -183,7 +183,7 @@ proc `[]`*(x: Any, i: int): Any = case x.rawType.kind of tyArray: var bs = x.rawType.base.size - if i >=% x.rawType.size div bs: + if i >=% x.rawType.size div bs: raise newException(IndexError, "index out of bounds") return newAny(x.value +!! i*bs, x.rawType.base) of tySequence: @@ -200,7 +200,7 @@ proc `[]=`*(x: Any, i: int, y: Any) = case x.rawType.kind of tyArray: var bs = x.rawType.base.size - if i >=% x.rawType.size div bs: + if i >=% x.rawType.size div bs: raise newException(IndexError, "index out of bounds") assert y.rawType == x.rawType.base genericAssign(x.value +!! i*bs, y.value, y.rawType) @@ -231,23 +231,23 @@ proc base*(x: Any): Any = proc isNil*(x: Any): bool = ## `isNil` for an any `x` that represents a sequence, string, cstring, ## proc or some pointer type. - assert x.rawType.kind in {tyString, tyCString, tyRef, tyPtr, tyPointer, + assert x.rawType.kind in {tyString, tyCString, tyRef, tyPtr, tyPointer, tySequence, tyProc} result = isNil(cast[ppointer](x.value)[]) proc getPointer*(x: Any): pointer = ## retrieve the pointer value out of `x`. ``x`` needs to be of kind - ## ``akString``, ``akCString``, ``akProc``, ``akRef``, ``akPtr``, + ## ``akString``, ``akCString``, ``akProc``, ``akRef``, ``akPtr``, ## ``akPointer``, ``akSequence``. - assert x.rawType.kind in {tyString, tyCString, tyRef, tyPtr, tyPointer, + assert x.rawType.kind in {tyString, tyCString, tyRef, tyPtr, tyPointer, tySequence, tyProc} result = cast[ppointer](x.value)[] proc setPointer*(x: Any, y: pointer) = ## sets the pointer value of `x`. ``x`` needs to be of kind - ## ``akString``, ``akCString``, ``akProc``, ``akRef``, ``akPtr``, + ## ``akString``, ``akCString``, ``akProc``, ``akRef``, ``akPtr``, ## ``akPointer``, ``akSequence``. - assert x.rawType.kind in {tyString, tyCString, tyRef, tyPtr, tyPointer, + assert x.rawType.kind in {tyString, tyCString, tyRef, tyPtr, tyPointer, tySequence, tyProc} cast[ppointer](x.value)[] = y @@ -309,7 +309,7 @@ proc getFieldNode(p: pointer, n: ptr TNimNode, if cmpIgnoreStyle(n.name, name) == 0: result = n of nkList: - for i in 0..n.len-1: + for i in 0..n.len-1: result = getFieldNode(p, n.sons[i], name) if result != nil: break of nkCase: @@ -345,7 +345,7 @@ proc `[]`*(x: Any, fieldName: string): Any = result.value = x.value +!! n.offset result.rawType = n.typ elif x.rawType.kind == tyObject and x.rawType.base != nil: - return `[]`(TAny(value: x.value, rawType: x.rawType.base), fieldName) + return `[]`(Any(value: x.value, rawType: x.rawType.base), fieldName) else: raise newException(ValueError, "invalid field name: " & fieldName) @@ -366,22 +366,22 @@ proc getInt*(x: Any): int = assert skipRange(x.rawType).kind == tyInt result = cast[ptr int](x.value)[] -proc getInt8*(x: Any): int8 = +proc getInt8*(x: Any): int8 = ## retrieve the int8 value out of `x`. `x` needs to represent an int8. assert skipRange(x.rawType).kind == tyInt8 result = cast[ptr int8](x.value)[] -proc getInt16*(x: Any): int16 = +proc getInt16*(x: Any): int16 = ## retrieve the int16 value out of `x`. `x` needs to represent an int16. assert skipRange(x.rawType).kind == tyInt16 result = cast[ptr int16](x.value)[] - -proc getInt32*(x: Any): int32 = + +proc getInt32*(x: Any): int32 = ## retrieve the int32 value out of `x`. `x` needs to represent an int32. assert skipRange(x.rawType).kind == tyInt32 result = cast[ptr int32](x.value)[] -proc getInt64*(x: Any): int64 = +proc getInt64*(x: Any): int64 = ## retrieve the int64 value out of `x`. `x` needs to represent an int64. assert skipRange(x.rawType).kind == tyInt64 result = cast[ptr int64](x.value)[] @@ -517,7 +517,7 @@ proc getEnumOrdinal*(x: Any, name: string): int = var n = typ.node var s = n.sons for i in 0 .. n.len-1: - if cmpIgnoreStyle($s[i].name, name) == 0: + if cmpIgnoreStyle($s[i].name, name) == 0: if ntfEnumHole notin typ.flags: return i else: @@ -527,7 +527,7 @@ proc getEnumOrdinal*(x: Any, name: string): int = proc getEnumField*(x: Any, ordinalValue: int): string = ## gets the enum field name as a string. `x` needs to represent an enum ## but is only used to access the type information. The field name of - ## `ordinalValue` is returned. + ## `ordinalValue` is returned. var typ = skipRange(x.rawType) assert typ.kind == tyEnum var e = ordinalValue @@ -546,17 +546,17 @@ proc getEnumField*(x: Any): string = ## gets the enum field name as a string. `x` needs to represent an enum. result = getEnumField(x, getBiggestInt(x).int) -proc getFloat*(x: Any): float = - ## retrieve the float value out of `x`. `x` needs to represent an float. +proc getFloat*(x: Any): float = + ## retrieve the float value out of `x`. `x` needs to represent an float. assert skipRange(x.rawType).kind == tyFloat result = cast[ptr float](x.value)[] -proc getFloat32*(x: Any): float32 = +proc getFloat32*(x: Any): float32 = ## retrieve the float32 value out of `x`. `x` needs to represent an float32. assert skipRange(x.rawType).kind == tyFloat32 result = cast[ptr float32](x.value)[] - -proc getFloat64*(x: Any): float64 = + +proc getFloat64*(x: Any): float64 = ## retrieve the float64 value out of `x`. `x` needs to represent an float64. assert skipRange(x.rawType).kind == tyFloat64 result = cast[ptr float64](x.value)[] @@ -579,23 +579,23 @@ proc setBiggestFloat*(x: Any, y: BiggestFloat) = of tyFloat64: cast[ptr float64](x.value)[] = y else: assert false -proc getString*(x: Any): string = +proc getString*(x: Any): string = ## retrieve the string value out of `x`. `x` needs to represent a string. assert x.rawType.kind == tyString if not isNil(cast[ptr pointer](x.value)[]): result = cast[ptr string](x.value)[] -proc setString*(x: Any, y: string) = +proc setString*(x: Any, y: string) = ## sets the string value of `x`. `x` needs to represent a string. assert x.rawType.kind == tyString cast[ptr string](x.value)[] = y -proc getCString*(x: Any): cstring = +proc getCString*(x: Any): cstring = ## retrieve the cstring value out of `x`. `x` needs to represent a cstring. assert x.rawType.kind == tyCString result = cast[ptr cstring](x.value)[] -proc assign*(x, y: Any) = +proc assign*(x, y: Any) = ## copies the value of `y` to `x`. The assignment operator for ``Any`` ## does NOT do this; it performs a shallow copy instead! assert y.rawType == x.rawType @@ -637,7 +637,7 @@ proc inclSetElement*(x: Any, elem: int) = of 2: var a = cast[ptr int16](p) a[] = a[] or (1'i16 shl int16(e)) - of 4: + of 4: var a = cast[ptr int32](p) a[] = a[] or (1'i32 shl int32(e)) of 8: @@ -651,7 +651,7 @@ when isMainModule: type TE = enum blah, blah2 - + TestObj = object test, asd: int case test2: TE @@ -665,7 +665,7 @@ when isMainModule: var y = 78 x[4] = toAny(y) assert cast[ptr int](x[2].value)[] == 2 - + var test2: tuple[name: string, s: int] = ("test", 56) var x2 = toAny(test2) var i = 0 @@ -675,7 +675,7 @@ when isMainModule: of 1: assert n == "s" and $a.kind == "akInt" else: assert false inc i - + var test3: TestObj test3.test = 42 test3.test2 = blah2 @@ -683,27 +683,27 @@ when isMainModule: i = 0 for n, a in fields(x3): case i - of 0: assert n == "test" and $a.kind == "akInt" + of 0: assert n == "test" and $a.kind == "akInt" of 1: assert n == "asd" and $a.kind == "akInt" of 2: assert n == "test2" and $a.kind == "akEnum" else: assert false inc i - + var test4: ref string new(test4) test4[] = "test" var x4 = toAny(test4) assert($x4[].kind() == "akString") - + block: # gimme a new scope dammit var myarr: array[0..4, array[0..4, string]] = [ - ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], - ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], + ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], + ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"]] var m = toAny(myArr) for i in 0 .. m.len-1: for j in 0 .. m[i].len-1: echo getString(m[i][j]) - + diff --git a/lib/core/unsigned.nim b/lib/core/unsigned.nim index 20fcd03aa..93a29e1c9 100644 --- a/lib/core/unsigned.nim +++ b/lib/core/unsigned.nim @@ -7,51 +7,12 @@ # distribution, for details about the copyright. # -## This module implements basic arithmetic operators for unsigned integers. -## To discourage users from using ``unsigned``, it's not part of ``system``, -## but an extra import. +## **Warning:** Since version 0.11.4 this module is deprecated. +## +## This module implemented basic arithmetic operators for unsigned integers. +## These operators are now available in the ``system`` module directly. -proc `not`*[T: SomeUnsignedInt](x: T): T {.magic: "BitnotI", noSideEffect.} - ## computes the `bitwise complement` of the integer `x`. - -proc `shr`*[T: SomeUnsignedInt](x, y: T): T {.magic: "ShrI", noSideEffect.} - ## computes the `shift right` operation of `x` and `y`. - -proc `shl`*[T: SomeUnsignedInt](x, y: T): T {.magic: "ShlI", noSideEffect.} - ## computes the `shift left` operation of `x` and `y`. - -proc `and`*[T: SomeUnsignedInt](x, y: T): T {.magic: "BitandI", noSideEffect.} - ## computes the `bitwise and` of numbers `x` and `y`. - -proc `or`*[T: SomeUnsignedInt](x, y: T): T {.magic: "BitorI", noSideEffect.} - ## computes the `bitwise or` of numbers `x` and `y`. - -proc `xor`*[T: SomeUnsignedInt](x, y: T): T {.magic: "BitxorI", noSideEffect.} - ## computes the `bitwise xor` of numbers `x` and `y`. - -proc `==`*[T: SomeUnsignedInt](x, y: T): bool {.magic: "EqI", noSideEffect.} - ## Compares two unsigned integers for equality. - -proc `+`*[T: SomeUnsignedInt](x, y: T): T {.magic: "AddU", noSideEffect.} - ## Binary `+` operator for unsigned integers. - -proc `-`*[T: SomeUnsignedInt](x, y: T): T {.magic: "SubU", noSideEffect.} - ## Binary `-` operator for unsigned integers. - -proc `*`*[T: SomeUnsignedInt](x, y: T): T {.magic: "MulU", noSideEffect.} - ## Binary `*` operator for unsigned integers. - -proc `div`*[T: SomeUnsignedInt](x, y: T): T {.magic: "DivU", noSideEffect.} - ## computes the integer division. This is roughly the same as - ## ``floor(x/y)``. - -proc `mod`*[T: SomeUnsignedInt](x, y: T): T {.magic: "ModU", noSideEffect.} - ## computes the integer modulo operation. This is the same as - ## ``x - (x div y) * y``. - -proc `<=`*[T: SomeUnsignedInt](x, y: T): bool {.magic: "LeU", noSideEffect.} - ## Returns true iff ``x <= y``. - -proc `<`*[T: SomeUnsignedInt](x, y: T): bool {.magic: "LtU", noSideEffect.} - ## Returns true iff ``unsigned(x) < unsigned(y)``. +{.deprecated.} +export `shr`, `shl`, `and`, `or`, `xor`, `==`, `+`, `-`, `*`, `div`, `mod`, + `<=`, `<` diff --git a/lib/nimbase.h b/lib/nimbase.h index eea618bac..e796ba735 100644 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -399,6 +399,10 @@ typedef int assert_numbits[sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof( # define NIM_EXTERNC #endif +/* we have to tinker with TNimType as it's both part of system.nim and + typeinfo.nim but system.nim doesn't export it cleanly... */ +typedef struct TNimType TNimType; + /* ---------------- platform specific includes ----------------------- */ /* VxWorks related includes */ diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index f9c8198f2..cc21b9382 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -46,6 +46,7 @@ type target*: OutputTarget config*: StringTableRef splitAfter*: int # split too long entries in the TOC + listingCounter: int tocPart*: seq[TocEntry] hasToc*: bool theIndex: string # Contents of the index file to be dumped at the end. @@ -832,7 +833,7 @@ proc parseCodeBlockParams(d: PDoc, n: PRstNode): CodeBlockParams = if result.langStr != "": result.lang = getSourceLanguage(result.langStr) -proc buildLinesHTMLTable(params: CodeBlockParams, code: string): +proc buildLinesHTMLTable(d: PDoc; params: CodeBlockParams, code: string): tuple[beginTable, endTable: string] = ## Returns the necessary tags to start/end a code block in HTML. ## @@ -840,20 +841,24 @@ proc buildLinesHTMLTable(params: CodeBlockParams, code: string): ## <pre> pair. Otherwise it will build a table and insert an initial column ## with all the line numbers, which requires you to pass the `code` to detect ## how many lines have to be generated (and starting at which point!). + inc d.listingCounter + let id = $d.listingCounter if not params.numberLines: - result = ("<pre>", "</pre>") + result = (d.config["doc.listing_start"] % id, + d.config["doc.listing_end"] % id) return var codeLines = 1 + code.strip.countLines assert codeLines > 0 - result.beginTable = """<table class="line-nums-table"><tbody><tr><td class="blob-line-nums"><pre>""" + result.beginTable = """<table class="line-nums-table"><tbody><tr><td class="blob-line-nums"><pre class="line-nums">""" var line = params.startLine while codeLines > 0: result.beginTable.add($line & "\n") line.inc codeLines.dec - result.beginTable.add("</pre></td><td><pre>") - result.endTable = "</pre></td></tr></tbody></table>" + result.beginTable.add("</pre></td><td>" & (d.config["doc.listing_start"] % id)) + result.endTable = (d.config["doc.listing_end"] % id) & + "</td></tr></tbody></table>" & (d.config["doc.listing_button"] % id) proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) = ## Renders a code block, appending it to `result`. @@ -871,7 +876,7 @@ proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) = var m = n.sons[2].sons[0] assert m.kind == rnLeaf - let (blockStart, blockEnd) = params.buildLinesHTMLTable(m.text) + let (blockStart, blockEnd) = buildLinesHTMLTable(d, params, m.text) dispA(d.target, result, blockStart, "\\begin{rstpre}\n", []) if params.lang == langNone: @@ -1209,6 +1214,9 @@ $moduledesc $content </div> """) + setConfigVar("doc.listing_start", "<pre class = \"listing\">") + setConfigVar("doc.listing_end", "</pre>") + setConfigVar("doc.listing_button", "</pre>") setConfigVar("doc.body_no_toc", "$moduledesc $content") setConfigVar("doc.file", "$content") setConfigVar("doc.smiley_format", "/images/smilies/$1.gif") diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 2ca2098b3..e6b8088c5 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -834,11 +834,12 @@ proc post*(client: AsyncHttpClient, url: string, body = "", multipart: Multipart else: x var xb = mpBody.withNewLine() & body - client.headers["Content-Type"] = mpHeader.split(": ")[1] + if multipart != nil: + client.headers["Content-Type"] = mpHeader.split(": ")[1] client.headers["Content-Length"] = $len(xb) result = await client.request(url, httpPOST, xb) - + when not defined(testing) and isMainModule: when true: # Async diff --git a/lib/pure/marshal.nim b/lib/pure/marshal.nim index 49f049e46..173cd1e81 100644 --- a/lib/pure/marshal.nim +++ b/lib/pure/marshal.nim @@ -17,7 +17,7 @@ ## .. code-block:: nim ## ## type -## A = object +## A = object of RootObj ## B = object of A ## f: int ## diff --git a/lib/pure/math.nim b/lib/pure/math.nim index d3f1f3814..821ab738b 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -56,7 +56,7 @@ type fcNegInf ## value is negative infinity proc classify*(x: float): FloatClass = - ## classifies a floating point value. Returns `x`'s class as specified by + ## Classifies a floating point value. Returns `x`'s class as specified by ## `FloatClass`. # JavaScript and most C compilers have no classify: @@ -74,7 +74,7 @@ proc classify*(x: float): FloatClass = proc binom*(n, k: int): int {.noSideEffect.} = - ## computes the binomial coefficient + ## Computes the binomial coefficient if k <= 0: return 1 if 2*k > n: return binom(n, n-k) result = n @@ -82,18 +82,18 @@ proc binom*(n, k: int): int {.noSideEffect.} = result = (result * (n + 1 - i)) div i proc fac*(n: int): int {.noSideEffect.} = - ## computes the faculty/factorial function. + ## Computes the faculty/factorial function. result = 1 for i in countup(2, n): result = result * i proc isPowerOfTwo*(x: int): bool {.noSideEffect.} = - ## returns true, if `x` is a power of two, false otherwise. + ## Returns true, if `x` is a power of two, false otherwise. ## Zero and negative numbers are not a power of two. return (x > 0) and ((x and (x - 1)) == 0) proc nextPowerOfTwo*(x: int): int {.noSideEffect.} = - ## returns `x` rounded up to the nearest power of two. + ## Returns `x` rounded up to the nearest power of two. ## Zero and negative numbers get rounded up to 1. result = x - 1 when defined(cpu64): @@ -108,28 +108,28 @@ proc nextPowerOfTwo*(x: int): int {.noSideEffect.} = result += 1 + ord(x<=0) proc countBits32*(n: int32): int {.noSideEffect.} = - ## counts the set bits in `n`. + ## Counts the set bits in `n`. var v = n v = v -% ((v shr 1'i32) and 0x55555555'i32) v = (v and 0x33333333'i32) +% ((v shr 2'i32) and 0x33333333'i32) result = ((v +% (v shr 4'i32) and 0xF0F0F0F'i32) *% 0x1010101'i32) shr 24'i32 proc sum*[T](x: openArray[T]): T {.noSideEffect.} = - ## computes the sum of the elements in `x`. + ## Computes the sum of the elements in `x`. ## If `x` is empty, 0 is returned. for i in items(x): result = result + i template toFloat(f: float): float = f proc mean*[T](x: openArray[T]): float {.noSideEffect.} = - ## computes the mean of the elements in `x`, which are first converted to floats. + ## Computes the mean of the elements in `x`, which are first converted to floats. ## If `x` is empty, NaN is returned. ## ``toFloat(x: T): float`` must be defined. for i in items(x): result = result + toFloat(i) result = result / toFloat(len(x)) proc variance*[T](x: openArray[T]): float {.noSideEffect.} = - ## computes the variance of the elements in `x`. + ## Computes the variance of the elements in `x`. ## If `x` is empty, NaN is returned. ## ``toFloat(x: T): float`` must be defined. result = 0.0 @@ -140,41 +140,43 @@ proc variance*[T](x: openArray[T]): float {.noSideEffect.} = result = result / toFloat(len(x)) proc random*(max: int): int {.benign.} - ## returns a random number in the range 0..max-1. The sequence of + ## Returns a random number in the range 0..max-1. The sequence of ## random number is always the same, unless `randomize` is called ## which initializes the random number generator with a "random" ## number, i.e. a tickcount. proc random*(max: float): float {.benign.} - ## returns a random number in the range 0..<max. The sequence of + ## Returns a random number in the range 0..<max. The sequence of ## random number is always the same, unless `randomize` is called ## which initializes the random number generator with a "random" ## number, i.e. a tickcount. This has a 16-bit resolution on windows ## and a 48-bit resolution on other platforms. proc randomize*() {.benign.} - ## initializes the random number generator with a "random" + ## Initializes the random number generator with a "random" ## number, i.e. a tickcount. Note: Does nothing for the JavaScript target, ## as JavaScript does not support this. proc randomize*(seed: int) {.benign.} - ## initializes the random number generator with a specific seed. + ## Initializes the random number generator with a specific seed. ## Note: Does nothing for the JavaScript target, ## as JavaScript does not support this. {.push noSideEffect.} when not defined(JS): proc sqrt*(x: float): float {.importc: "sqrt", header: "<math.h>".} - ## computes the square root of `x`. + ## Computes the square root of `x`. proc cbrt*(x: float): float {.importc: "cbrt", header: "<math.h>".} - ## computes the cubic root of `x` + ## Computes the cubic root of `x` proc ln*(x: float): float {.importc: "log", header: "<math.h>".} - ## computes ln(x). + ## Computes the natural log of `x` proc log10*(x: float): float {.importc: "log10", header: "<math.h>".} + ## Computes the common logarithm (base 10) of `x` proc log2*(x: float): float = return ln(x) / ln(2.0) + ## Computes the binary logarithm (base 2) of `x` proc exp*(x: float): float {.importc: "exp", header: "<math.h>".} - ## computes e**x. + ## Computes the exponential function of `x` (pow(E, x)) proc frexp*(x: float, exponent: var int): float {. importc: "frexp", header: "<math.h>".} @@ -185,11 +187,14 @@ when not defined(JS): ## m. proc round*(x: float): int {.importc: "lrint", header: "<math.h>".} - ## converts a float to an int by rounding. + ## Converts a float to an int by rounding. proc arccos*(x: float): float {.importc: "acos", header: "<math.h>".} + ## Computes the arc cosine of `x` proc arcsin*(x: float): float {.importc: "asin", header: "<math.h>".} + ## Computes the arc sine of `x` proc arctan*(x: float): float {.importc: "atan", header: "<math.h>".} + ## Calculate the arc tangent of `y` / `x` proc arctan2*(y, x: float): float {.importc: "atan2", header: "<math.h>".} ## Calculate the arc tangent of `y` / `x`. ## `atan2` returns the arc tangent of `y` / `x`; it produces correct @@ -197,16 +202,23 @@ when not defined(JS): ## (`x` near 0). proc cos*(x: float): float {.importc: "cos", header: "<math.h>".} + ## Computes the cosine of `x` proc cosh*(x: float): float {.importc: "cosh", header: "<math.h>".} + ## Computes the hyperbolic cosine of `x` proc hypot*(x, y: float): float {.importc: "hypot", header: "<math.h>".} - ## same as ``sqrt(x*x + y*y)``. + ## Computes the hypotenuse of a right-angle triangle with `x` and + ## `y` as its base and height. Equivalent to ``sqrt(x*x + y*y)``. proc sinh*(x: float): float {.importc: "sinh", header: "<math.h>".} + ## Computes the hyperbolic sine of `x` proc sin*(x: float): float {.importc: "sin", header: "<math.h>".} + ## Computes the sine of `x` proc tan*(x: float): float {.importc: "tan", header: "<math.h>".} + ## Computes the tangent of `x` proc tanh*(x: float): float {.importc: "tanh", header: "<math.h>".} + ## Computes the hyperbolic tangent of `x` proc pow*(x, y: float): float {.importc: "pow", header: "<math.h>".} - ## computes x to power raised of y. + ## Computes `x` to power of `y`. proc erf*(x: float): float {.importc: "erf", header: "<math.h>".} ## The error function @@ -269,10 +281,26 @@ when not defined(JS): result = int(rand()) mod max proc trunc*(x: float): float {.importc: "trunc", header: "<math.h>".} + ## Truncates `x` to the decimal point + ## + ## .. code-block:: nim + ## echo trunc(PI) # 3.0 proc floor*(x: float): float {.importc: "floor", header: "<math.h>".} + ## Computes the floor function (i.e., the largest integer not greater than `x`) + ## + ## .. code-block:: nim + ## echo floor(-3.5) ## -4.0 proc ceil*(x: float): float {.importc: "ceil", header: "<math.h>".} + ## Computes the ceiling function (i.e., the smallest integer not less than `x`) + ## + ## .. code-block:: nim + ## echo ceil(-2.1) ## -2.0 proc fmod*(x, y: float): float {.importc: "fmod", header: "<math.h>".} + ## Computes the remainder of `x` divided by `y` + ## + ## .. code-block:: nim + ## echo fmod(-2.5, 0.3) ## -0.1 else: proc mathrandom(): float {.importc: "Math.random", nodecl.} diff --git a/lib/pure/net.nim b/lib/pure/net.nim index d9f4845f3..141543c70 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -294,7 +294,7 @@ proc getSocketError*(socket: Socket): OSErrorCode = if result == 0.OSErrorCode: result = socket.lastError if result == 0.OSErrorCode: - raise newException(OSError, "No valid socket error code available") + raiseOSError(result, "No valid socket error code available") proc socketError*(socket: Socket, err: int = -1, async = false, lastError = (-1).OSErrorCode) = @@ -332,10 +332,8 @@ proc socketError*(socket: Socket, err: int = -1, async = false, else: let errStr = $ErrErrorString(sslErr, nil) raiseSSLError(errStr & ": " & errStr) - let osMsg = osErrorMsg osLastError() - if osMsg != "": - errStr.add ". The OS reports: " & osMsg - raise newException(OSError, errStr) + let osErr = osLastError() + raiseOSError(osErr, errStr) of SSL_ERROR_SSL: raiseSSLError() else: raiseSSLError("Unknown Error") @@ -921,7 +919,7 @@ proc send*(socket: Socket, data: string, socketError(socket, lastError = lastError) if sent != data.len: - raise newException(OSError, "Could not send all data.") + raiseOSError(osLastError(), "Could not send all data.") proc trySend*(socket: Socket, data: string): bool {.tags: [WriteIOEffect].} = ## Safe alternative to ``send``. Does not raise an EOS when an error occurs, diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 59a56a1ab..48d255dca 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -621,6 +621,20 @@ proc parentDir*(path: string): string {. else: result = "" +proc tailDir*(path: string): string {. + noSideEffect, rtl, extern: "nos$1".} = + ## Returns the tail part of `path`.. + ## + ## | Example: ``tailDir("/usr/local/bin") == "local/bin"``. + ## | Example: ``tailDir("usr/local/bin/") == "local/bin"``. + ## | Example: ``tailDir("bin") == ""``. + var q = 1 + if len(path) >= 1 and path[len(path)-1] in {DirSep, AltSep}: q = 2 + for i in 0..len(path)-q: + if path[i] in {DirSep, AltSep}: + return substr(path, i+1) + result = "" + proc isRootDir*(path: string): bool {. noSideEffect, rtl, extern: "nos$1".} = ## Checks whether a given `path` is a root directory @@ -1022,7 +1036,7 @@ proc moveFile*(source, dest: string) {.rtl, extern: "nos$1", if moveFileA(source, dest, 0'i32) == 0'i32: raiseOSError(osLastError()) else: if c_rename(source, dest) != 0'i32: - raise newException(OSError, $strerror(errno)) + raiseOSError(osLastError(), $strerror(errno)) when not declared(ENOENT) and not defined(Windows): when NoFakeVars: @@ -1057,7 +1071,7 @@ proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].} raiseOSError(osLastError()) else: if c_remove(file) != 0'i32 and errno != ENOENT: - raise newException(OSError, $strerror(errno)) + raiseOSError(osLastError(), $strerror(errno)) proc execShellCmd*(command: string): int {.rtl, extern: "nos$1", tags: [ExecIOEffect].} = diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim index e1abb0a4f..f8b2c3d8d 100644 --- a/lib/pure/parsexml.nim +++ b/lib/pure/parsexml.nim @@ -535,6 +535,10 @@ proc parseAttribute(my: var XmlParser) = pos = lexbase.handleLF(my, pos) buf = my.buf pendingSpace = true + of '/': + pos = lexbase.handleRefillChar(my, pos) + buf = my.buf + add(my.b, '/') else: if buf[pos] == quote: inc(pos) diff --git a/lib/pure/rawsockets.nim b/lib/pure/rawsockets.nim index 349b0d97a..7873e7226 100644 --- a/lib/pure/rawsockets.nim +++ b/lib/pure/rawsockets.nim @@ -207,7 +207,7 @@ proc getAddrInfo*(address: string, port: Port, domain: Domain = AF_INET, when useWinVersion: raiseOSError(osLastError()) else: - raise newException(OSError, $gai_strerror(gaiResult)) + raiseOSError(osLastError(), $gai_strerror(gaiResult)) proc dealloc*(ai: ptr AddrInfo) = freeaddrinfo(ai) @@ -251,7 +251,7 @@ proc getServByName*(name, proto: string): Servent {.tags: [ReadIOEffect].} = var s = winlean.getservbyname(name, proto) else: var s = posix.getservbyname(name, proto) - if s == nil: raise newException(OSError, "Service not found.") + if s == nil: raiseOSError(osLastError(), "Service not found.") result.name = $s.s_name result.aliases = cstringArrayToSeq(s.s_aliases) result.port = Port(s.s_port) @@ -267,7 +267,7 @@ proc getServByPort*(port: Port, proto: string): Servent {.tags: [ReadIOEffect].} var s = winlean.getservbyport(ze(int16(port)).cint, proto) else: var s = posix.getservbyport(ze(int16(port)).cint, proto) - if s == nil: raise newException(OSError, "Service not found.") + if s == nil: raiseOSError(osLastError(), "Service not found.") result.name = $s.s_name result.aliases = cstringArrayToSeq(s.s_aliases) result.port = Port(s.s_port) @@ -286,7 +286,7 @@ proc getHostByAddr*(ip: string): Hostent {.tags: [ReadIOEffect].} = var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).Socklen, cint(posix.AF_INET)) if s == nil: - raise newException(OSError, $hstrerror(h_errno)) + raiseOSError(osLastError(), $hstrerror(h_errno)) result.name = $s.h_name result.aliases = cstringArrayToSeq(s.h_aliases) @@ -298,7 +298,7 @@ proc getHostByAddr*(ip: string): Hostent {.tags: [ReadIOEffect].} = elif s.h_addrtype == posix.AF_INET6: result.addrtype = AF_INET6 else: - raise newException(OSError, "unknown h_addrtype") + raiseOSError(osLastError(), "unknown h_addrtype") result.addrList = cstringArrayToSeq(s.h_addr_list) result.length = int(s.h_length) @@ -319,7 +319,7 @@ proc getHostByName*(name: string): Hostent {.tags: [ReadIOEffect].} = elif s.h_addrtype == posix.AF_INET6: result.addrtype = AF_INET6 else: - raise newException(OSError, "unknown h_addrtype") + raiseOSError(osLastError(), "unknown h_addrtype") result.addrList = cstringArrayToSeq(s.h_addr_list) result.length = int(s.h_length) @@ -335,7 +335,7 @@ proc getSockDomain*(socket: SocketHandle): Domain = elif name.sa_family == rawAfInet6: result = AF_INET6 else: - raise newException(OSError, "unknown socket family in getSockFamily") + raiseOSError(osLastError(), "unknown socket family in getSockFamily") proc getAddrString*(sockAddr: ptr SockAddr): string = @@ -353,7 +353,7 @@ proc getAddrString*(sockAddr: ptr SockAddr): string = if posix.IN6_IS_ADDR_V4MAPPED(addr6) != 0: result = result.substr("::ffff:".len) else: - raise newException(OSError, "unknown socket family in getAddrString") + raiseOSError(osLastError(), "unknown socket family in getAddrString") proc getSockName*(socket: SocketHandle): Port = diff --git a/compiler/securehash.nim b/lib/pure/securehash.nim index 8ac6acb0e..8ac6acb0e 100644 --- a/compiler/securehash.nim +++ b/lib/pure/securehash.nim diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim index aa8ad39d1..bfc393a96 100644 --- a/lib/pure/selectors.nim +++ b/lib/pure/selectors.nim @@ -295,7 +295,8 @@ proc contains*(s: Selector, key: SelectorKey): bool = ## ensures that the keys are equal. File descriptors may not always be ## unique especially when an fd is closed and then a new one is opened, ## the new one may have the same value. - return key.fd in s and s.fds[key.fd] == key + when not defined(nimdoc): + return key.fd in s and s.fds[key.fd] == key {.deprecated: [TEvent: Event, PSelectorKey: SelectorKey, TReadyInfo: ReadyInfo, PSelector: Selector].} diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim index a10255e5b..18b2ab1e9 100644 --- a/lib/pure/sockets.nim +++ b/lib/pure/sockets.nim @@ -441,7 +441,7 @@ template gaiNim(a, p, h, list: expr): stmt = when defined(windows): raiseOSError(osLastError()) else: - raise newException(OSError, $gai_strerror(gaiResult)) + raiseOSError(osLastError(), $gai_strerror(gaiResult)) proc bindAddr*(socket: Socket, port = Port(0), address = "") {. tags: [ReadIOEffect].} = @@ -671,7 +671,7 @@ proc getServByName*(name, proto: string): Servent {.tags: [ReadIOEffect].} = var s = winlean.getservbyname(name, proto) else: var s = posix.getservbyname(name, proto) - if s == nil: raise newException(OSError, "Service not found.") + if s == nil: raiseOSError(osLastError(), "Service not found.") result.name = $s.s_name result.aliases = cstringArrayToSeq(s.s_aliases) result.port = Port(s.s_port) @@ -687,7 +687,7 @@ proc getServByPort*(port: Port, proto: string): Servent {.tags: [ReadIOEffect].} var s = winlean.getservbyport(ze(int16(port)).cint, proto) else: var s = posix.getservbyport(ze(int16(port)).cint, proto) - if s == nil: raise newException(OSError, "Service not found.") + if s == nil: raiseOSError(osLastError(), "Service not found.") result.name = $s.s_name result.aliases = cstringArrayToSeq(s.s_aliases) result.port = Port(s.s_port) @@ -706,7 +706,7 @@ proc getHostByAddr*(ip: string): Hostent {.tags: [ReadIOEffect].} = var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).Socklen, cint(posix.AF_INET)) if s == nil: - raise newException(OSError, $hstrerror(h_errno)) + raiseOSError(osLastError(), $hstrerror(h_errno)) result.name = $s.h_name result.aliases = cstringArrayToSeq(s.h_aliases) @@ -718,7 +718,7 @@ proc getHostByAddr*(ip: string): Hostent {.tags: [ReadIOEffect].} = elif s.h_addrtype == posix.AF_INET6: result.addrtype = AF_INET6 else: - raise newException(OSError, "unknown h_addrtype") + raiseOSError(osLastError(), "unknown h_addrtype") result.addrList = cstringArrayToSeq(s.h_addr_list) result.length = int(s.h_length) @@ -739,7 +739,7 @@ proc getHostByName*(name: string): Hostent {.tags: [ReadIOEffect].} = elif s.h_addrtype == posix.AF_INET6: result.addrtype = AF_INET6 else: - raise newException(OSError, "unknown h_addrtype") + raiseOSError(osLastError(), "unknown h_addrtype") result.addrList = cstringArrayToSeq(s.h_addr_list) result.length = int(s.h_length) @@ -1594,7 +1594,7 @@ proc send*(socket: Socket, data: string) {.tags: [WriteIOEffect].} = raiseOSError(osLastError()) if sent != data.len: - raise newException(OSError, "Could not send all data.") + raiseOSError(osLastError(), "Could not send all data.") proc sendAsync*(socket: Socket, data: string): int {.tags: [WriteIOEffect].} = ## sends data to a non-blocking socket. diff --git a/lib/pure/times.nim b/lib/pure/times.nim index e4d3f7494..f1315a9fd 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -789,7 +789,8 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) = of "sat": info.weekday = dSat else: - raise newException(ValueError, "invalid day of week ") + raise newException(ValueError, + "Couldn't parse day of week (ddd), got: " & value[j..j+2]) j += 3 of "dddd": if value.len >= j+6 and value[j..j+5].cmpIgnoreCase("sunday") == 0: @@ -814,7 +815,8 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) = info.weekday = dSat j += 8 else: - raise newException(ValueError, "invalid day of week ") + raise newException(ValueError, + "Couldn't parse day of week (dddd), got: " & value) of "h", "H": var pd = parseInt(value[j..j+1], sv) info.hour = sv @@ -865,7 +867,8 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) = of "dec": info.month = mDec else: - raise newException(ValueError, "invalid month") + raise newException(ValueError, + "Couldn't parse month (MMM), got: " & value) j += 3 of "MMMM": if value.len >= j+7 and value[j..j+6].cmpIgnoreCase("january") == 0: @@ -905,7 +908,8 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) = info.month = mDec j += 8 else: - raise newException(ValueError, "invalid month") + raise newException(ValueError, + "Couldn't parse month (MMMM), got: " & value) of "s": var pd = parseInt(value[j..j+1], sv) info.second = sv @@ -936,7 +940,8 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) = elif value[j] == '-': info.timezone = 0-parseInt($value[j+1]) else: - raise newException(ValueError, "Sign for timezone " & value[j]) + raise newException(ValueError, + "Couldn't parse timezone offset (z), got: " & value[j]) j += 2 of "zz": if value[j] == '+': @@ -944,7 +949,8 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) = elif value[j] == '-': info.timezone = 0-value[j+1..j+2].parseInt() else: - raise newException(ValueError, "Sign for timezone " & value[j]) + raise newException(ValueError, + "Couldn't parse timezone offset (zz), got: " & value[j]) j += 3 of "zzz": if value[j] == '+': @@ -952,7 +958,8 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) = elif value[j] == '-': info.timezone = 0-value[j+1..j+2].parseInt() else: - raise newException(ValueError, "Sign for timezone " & value[j]) + raise newException(ValueError, + "Couldn't parse timezone offset (zzz), got: " & value[j]) j += 6 of "ZZZ": info.tzname = value[j..j+2].toUpper() @@ -1020,10 +1027,10 @@ proc parse*(value, layout: string): TimeInfo = # These are literals in both the layout and the value string if layout[i] == '\'': inc(i) - inc(j) while layout[i] != '\'' and layout.len-1 > i: inc(i) inc(j) + inc(i) else: inc(i) inc(j) @@ -1112,6 +1119,8 @@ when isMainModule: s = "2006-01-12T15:04:05Z-07:00" f = "yyyy-MM-ddTHH:mm:ssZzzz" assert($s.parse(f) == "Thu Jan 12 15:04:05 2006") + f = "yyyy-MM-dd'T'HH:mm:ss'Z'zzz" + assert($s.parse(f) == "Thu Jan 12 15:04:05 2006") # RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00" s = "2006-01-12T15:04:05.999999999Z-07:00" f = "yyyy-MM-ddTHH:mm:ss.999999999Zzzz" diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim index 4446eaa0c..5e20db32b 100644 --- a/lib/pure/unicode.nim +++ b/lib/pure/unicode.nim @@ -27,7 +27,7 @@ proc `==`*(a, b: Rune): bool = return int(a) == int(b) template ones(n: expr): expr = ((1 shl n)-1) proc runeLen*(s: string): int {.rtl, extern: "nuc$1".} = - ## returns the number of Unicode characters of the string `s`. + ## Returns the number of Unicode characters of the string ``s`` var i = 0 while i < len(s): if ord(s[i]) <=% 127: inc(i) @@ -40,7 +40,7 @@ proc runeLen*(s: string): int {.rtl, extern: "nuc$1".} = inc(result) proc runeLenAt*(s: string, i: Natural): int = - ## returns the number of bytes the rune starting at ``s[i]`` takes. + ## Returns the number of bytes the rune starting at ``s[i]`` takes if ord(s[i]) <=% 127: result = 1 elif ord(s[i]) shr 5 == 0b110: result = 2 elif ord(s[i]) shr 4 == 0b1110: result = 3 @@ -50,8 +50,8 @@ proc runeLenAt*(s: string, i: Natural): int = else: result = 1 template fastRuneAt*(s: string, i: int, result: expr, doInc = true) = - ## Returns the unicode character ``s[i]`` in `result`. If ``doInc == true`` - ## `i` is incremented by the number of bytes that have been processed. + ## Returns the Unicode character ``s[i]`` in ``result``. If ``doInc == true`` + ## ``i`` is incremented by the number of bytes that have been processed. bind ones if ord(s[i]) <=% 127: result = Rune(ord(s[i])) @@ -106,8 +106,8 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) = when doInc: inc(i) proc validateUtf8*(s: string): int = - ## returns the position of the invalid byte in ``s`` if the string ``s`` does - ## not hold valid UTF-8 data. Otherwise -1 is returned. + ## Returns the position of the invalid byte in ``s`` if the string ``s`` does + ## not hold valid UTF-8 data. Otherwise ``-1`` is returned. var i = 0 let L = s.len while i < L: @@ -131,11 +131,11 @@ proc validateUtf8*(s: string): int = return -1 proc runeAt*(s: string, i: Natural): Rune = - ## returns the unicode character in `s` at byte index `i` + ## Returns the unicode character in ``s`` at byte index ``i`` fastRuneAt(s, i, result, false) proc toUTF8*(c: Rune): string {.rtl, extern: "nuc$1".} = - ## converts a rune into its UTF8 representation + ## Converts a rune into its UTF-8 representation var i = RuneImpl(c) if i <=% 127: result = newString(1) @@ -174,11 +174,11 @@ proc toUTF8*(c: Rune): string {.rtl, extern: "nuc$1".} = discard # error, exception? proc `$`*(rune: Rune): string = - ## converts a rune to a string + ## Converts a Rune to a string rune.toUTF8 proc `$`*(runes: seq[Rune]): string = - ## converts a sequence of runes to a string + ## Converts a sequence of Runes to a string result = "" for rune in runes: result.add(rune.toUTF8) @@ -1163,8 +1163,8 @@ proc binarySearch(c: RuneImpl, tab: openArray[RuneImpl], len, stride: int): int return -1 proc toLower*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} = - ## Converts `c` into lower case. This works for any Unicode character. - ## If possible, prefer `toLower` over `toUpper`. + ## Converts ``c`` into lower case. This works for any Unicode character. + ## If possible, prefer ``toLower`` over ``toUpper``. var c = RuneImpl(c) var p = binarySearch(c, tolowerRanges, len(tolowerRanges) div 3, 3) if p >= 0 and c >= tolowerRanges[p] and c <= tolowerRanges[p+1]: @@ -1175,8 +1175,8 @@ proc toLower*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} = return Rune(c) proc toUpper*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} = - ## Converts `c` into upper case. This works for any Unicode character. - ## If possible, prefer `toLower` over `toUpper`. + ## Converts ``c`` into upper case. This works for any Unicode character. + ## If possible, prefer ``toLower`` over ``toUpper``. var c = RuneImpl(c) var p = binarySearch(c, toupperRanges, len(toupperRanges) div 3, 3) if p >= 0 and c >= toupperRanges[p] and c <= toupperRanges[p+1]: @@ -1187,6 +1187,7 @@ proc toUpper*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} = return Rune(c) proc toTitle*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} = + ## Converts ``c`` to title case var c = RuneImpl(c) var p = binarySearch(c, toTitleSinglets, len(toTitleSinglets) div 2, 2) if p >= 0 and c == toTitleSinglets[p]: @@ -1194,8 +1195,8 @@ proc toTitle*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} = return Rune(c) proc isLower*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = - ## returns true iff `c` is a lower case Unicode character - ## If possible, prefer `isLower` over `isUpper`. + ## Returns true iff ``c`` is a lower case Unicode character. + ## If possible, prefer ``isLower`` over ``isUpper``. var c = RuneImpl(c) # Note: toUpperRanges is correct here! var p = binarySearch(c, toupperRanges, len(toupperRanges) div 3, 3) @@ -1206,8 +1207,8 @@ proc isLower*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = return true proc isUpper*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = - ## returns true iff `c` is a upper case Unicode character - ## If possible, prefer `isLower` over `isUpper`. + ## Returns true iff ``c`` is a upper case Unicode character. + ## If possible, prefer ``isLower`` over ``isUpper``. var c = RuneImpl(c) # Note: toLowerRanges is correct here! var p = binarySearch(c, tolowerRanges, len(tolowerRanges) div 3, 3) @@ -1218,7 +1219,7 @@ proc isUpper*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = return true proc isAlpha*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = - ## returns true iff `c` is an *alpha* Unicode character (i.e. a letter) + ## Returns true iff ``c`` is an *alpha* Unicode character (i.e., a letter) if isUpper(c) or isLower(c): return true var c = RuneImpl(c) @@ -1230,17 +1231,18 @@ proc isAlpha*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = return true proc isTitle*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = + ## Returns true iff ``c`` is a Unicode titlecase character return isUpper(c) and isLower(c) proc isWhiteSpace*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = - ## returns true iff `c` is a Unicode whitespace character + ## Returns true iff ``c`` is a Unicode whitespace character var c = RuneImpl(c) var p = binarySearch(c, spaceRanges, len(spaceRanges) div 2, 2) if p >= 0 and c >= spaceRanges[p] and c <= spaceRanges[p+1]: return true proc isCombining*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = - ## returns true iff `c` is a Unicode combining character + ## Returns true iff ``c`` is a Unicode combining character var c = RuneImpl(c) # Optimized to return false immediately for ASCII @@ -1251,7 +1253,7 @@ proc isCombining*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = (c >= 0xfe20 and c <= 0xfe2f)) iterator runes*(s: string): Rune = - ## iterates over any unicode character of the string `s`. + ## Iterates over any unicode character of the string ``s`` var i = 0 result: Rune @@ -1259,8 +1261,14 @@ iterator runes*(s: string): Rune = fastRuneAt(s, i, result, true) yield result +proc toRunes*(s: string): seq[Rune] = + ## Obtains a sequence containing the Runes in ``s`` + result = newSeq[Rune]() + for r in s.runes: + result.add(r) + proc cmpRunesIgnoreCase*(a, b: string): int {.rtl, extern: "nuc$1", procvar.} = - ## compares two UTF8 strings and ignores the case. Returns: + ## Compares two UTF-8 strings and ignores the case. Returns: ## ## | 0 iff a == b ## | < 0 iff a < b @@ -1277,8 +1285,8 @@ proc cmpRunesIgnoreCase*(a, b: string): int {.rtl, extern: "nuc$1", procvar.} = result = a.len - b.len proc reversed*(s: string): string = - ## returns the reverse of `s`, interpreting it as unicode characters. Unicode - ## combining characters are correctly interpreted as well: + ## Returns the reverse of ``s``, interpreting it as Unicode characters. + ## Unicode combining characters are correctly interpreted as well: ## ## .. code-block:: nim ## @@ -1322,3 +1330,4 @@ when isMainModule: assert reversed("先秦兩漢") == "漢兩秦先" assert reversed("as⃝df̅") == "f̅ds⃝a" assert reversed("a⃞b⃞c⃞") == "c⃞b⃞a⃞" + assert len(toRunes("as⃝df̅")) == runeLen("as⃝df̅") diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index 70b314e63..c459023a9 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -105,10 +105,10 @@ template suite*(name: expr, body: stmt): stmt {.immediate, dirty.} = ## [OK] 2 + 2 = 4 ## [OK] (2 + -2) != 4 block: - template setup*(setupBody: stmt): stmt {.immediate, dirty.} = + template setup(setupBody: stmt): stmt {.immediate, dirty.} = template testSetupIMPL: stmt {.immediate, dirty.} = setupBody - template teardown*(teardownBody: stmt): stmt {.immediate, dirty.} = + template teardown(teardownBody: stmt): stmt {.immediate, dirty.} = template testTeardownIMPL: stmt {.immediate, dirty.} = teardownBody body diff --git a/lib/system.nim b/lib/system.nim index 1977c2203..91495f31a 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -389,9 +389,9 @@ type ## Each exception has to inherit from `Exception`. See the full `exception ## hierarchy`_. parent*: ref Exception ## parent exception (can be used as a stack) - name: cstring ## The exception's name is its Nim identifier. - ## This field is filled automatically in the - ## ``raise`` statement. + name*: cstring ## The exception's name is its Nim identifier. + ## This field is filled automatically in the + ## ``raise`` statement. msg* {.exportc: "message".}: string ## the exception's message. Not ## providing an exception message ## is bad style. @@ -888,9 +888,52 @@ proc `<%` *(x, y: int64): bool {.magic: "LtU64", noSideEffect.} ## treats `x` and `y` as unsigned and compares them. ## Returns true iff ``unsigned(x) < unsigned(y)``. +# unsigned integer operations: +proc `not`*[T: SomeUnsignedInt](x: T): T {.magic: "BitnotI", noSideEffect.} + ## computes the `bitwise complement` of the integer `x`. -# floating point operations: +proc `shr`*[T: SomeUnsignedInt](x, y: T): T {.magic: "ShrI", noSideEffect.} + ## computes the `shift right` operation of `x` and `y`. + +proc `shl`*[T: SomeUnsignedInt](x, y: T): T {.magic: "ShlI", noSideEffect.} + ## computes the `shift left` operation of `x` and `y`. + +proc `and`*[T: SomeUnsignedInt](x, y: T): T {.magic: "BitandI", noSideEffect.} + ## computes the `bitwise and` of numbers `x` and `y`. + +proc `or`*[T: SomeUnsignedInt](x, y: T): T {.magic: "BitorI", noSideEffect.} + ## computes the `bitwise or` of numbers `x` and `y`. + +proc `xor`*[T: SomeUnsignedInt](x, y: T): T {.magic: "BitxorI", noSideEffect.} + ## computes the `bitwise xor` of numbers `x` and `y`. + +proc `==`*[T: SomeUnsignedInt](x, y: T): bool {.magic: "EqI", noSideEffect.} + ## Compares two unsigned integers for equality. +proc `+`*[T: SomeUnsignedInt](x, y: T): T {.magic: "AddU", noSideEffect.} + ## Binary `+` operator for unsigned integers. + +proc `-`*[T: SomeUnsignedInt](x, y: T): T {.magic: "SubU", noSideEffect.} + ## Binary `-` operator for unsigned integers. + +proc `*`*[T: SomeUnsignedInt](x, y: T): T {.magic: "MulU", noSideEffect.} + ## Binary `*` operator for unsigned integers. + +proc `div`*[T: SomeUnsignedInt](x, y: T): T {.magic: "DivU", noSideEffect.} + ## computes the integer division. This is roughly the same as + ## ``floor(x/y)``. + +proc `mod`*[T: SomeUnsignedInt](x, y: T): T {.magic: "ModU", noSideEffect.} + ## computes the integer modulo operation. This is the same as + ## ``x - (x div y) * y``. + +proc `<=`*[T: SomeUnsignedInt](x, y: T): bool {.magic: "LeU", noSideEffect.} + ## Returns true iff ``x <= y``. + +proc `<`*[T: SomeUnsignedInt](x, y: T): bool {.magic: "LtU", noSideEffect.} + ## Returns true iff ``unsigned(x) < unsigned(y)``. + +# floating point operations: proc `+` *(x: float32): float32 {.magic: "UnaryPlusF64", noSideEffect.} proc `-` *(x: float32): float32 {.magic: "UnaryMinusF64", noSideEffect.} proc `+` *(x, y: float32): float32 {.magic: "AddF64", noSideEffect.} @@ -1466,8 +1509,7 @@ when not defined(nimrodVM): ## or other memory may be corrupted. ## The freed memory must belong to its allocating thread! ## Use `deallocShared` to deallocate from a shared heap. - proc free*[T](p: ptr T) {.inline, benign.} = - dealloc(p) + proc allocShared*(size: Natural): pointer {.noconv, rtl, benign.} ## allocates a new memory block on the shared heap with at ## least ``size`` bytes. The block has to be freed with @@ -2131,7 +2173,11 @@ proc `$`*[T: tuple|object](x: T): string = if not firstElement: result.add(", ") result.add(name) result.add(": ") - result.add($value) + when compiles(value.isNil): + if value.isNil: result.add "nil" + else: result.add($value) + else: + result.add($value) firstElement = false result.add(")") @@ -3048,11 +3094,11 @@ proc staticRead*(filename: string): string {.magic: "Slurp".} ## ## `slurp <#slurp>`_ is an alias for ``staticRead``. -proc gorge*(command: string, input = ""): string {. +proc gorge*(command: string, input = "", cache = ""): string {. magic: "StaticExec".} = discard ## This is an alias for `staticExec <#staticExec>`_. -proc staticExec*(command: string, input = ""): string {. +proc staticExec*(command: string, input = "", cache = ""): string {. magic: "StaticExec".} = discard ## Executes an external process at compile-time. ## if `input` is not an empty string, it will be passed as a standard input @@ -3065,6 +3111,15 @@ proc staticExec*(command: string, input = ""): string {. ## `gorge <#gorge>`_ is an alias for ``staticExec``. Note that you can use ## this proc inside a pragma like `passC <nimc.html#passc-pragma>`_ or `passL ## <nimc.html#passl-pragma>`_. + ## + ## If ``cache`` is not empty, the results of ``staticExec`` are cached within + ## the ``nimcache`` directory. Use ``--forceBuild`` to get rid of this caching + ## behaviour then. ``command & input & cache`` (the concatenated string) is + ## used to determine wether the entry in the cache is still valid. You can + ## use versioning information for ``cache``: + ## + ## .. code-block:: nim + ## const stateMachine = staticExec("dfaoptimizer", "input", "0.8.0") proc `+=`*[T: SomeOrdinal|uint|uint64](x: var T, y: T) {.magic: "Inc", noSideEffect.} ## Increments an ordinal @@ -3286,14 +3341,19 @@ when declared(initDebugger): when hasAlloc: # XXX: make these the default (or implement the NilObject optimization) proc safeAdd*[T](x: var seq[T], y: T) {.noSideEffect.} = + ## Adds ``y`` to ``x`` unless ``x`` is not yet initialized; in that case, + ## ``x`` becomes ``@[y]`` if x == nil: x = @[y] else: x.add(y) proc safeAdd*(x: var string, y: char) = + ## Adds ``y`` to ``x``. If ``x`` is ``nil`` it is initialized to ``""`` if x == nil: x = "" x.add(y) proc safeAdd*(x: var string, y: string) = + ## Adds ``y`` to ``x`` unless ``x`` is not yet initalized; in that case, ``x`` + ## becomes ``y`` if x == nil: x = y else: x.add(y) diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index 33629016f..326c601bd 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -210,6 +210,14 @@ proc incrSeq(seq: PGenericSeq, elemSize: int): PGenericSeq {.compilerProc.} = GenericSeqSize)) inc(result.len) +proc incrSeqV2(seq: PGenericSeq, elemSize: int): PGenericSeq {.compilerProc.} = + # incrSeq version 2 + result = seq + if result.len >= result.space: + result.reserved = resize(result.space) + result = cast[PGenericSeq](growObj(result, elemSize * result.reserved + + GenericSeqSize)) + proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {. compilerRtl.} = result = seq diff --git a/tests/ccgbugs/taddhigh.nim b/tests/ccgbugs/taddhigh.nim new file mode 100644 index 000000000..d6ac8f650 --- /dev/null +++ b/tests/ccgbugs/taddhigh.nim @@ -0,0 +1,16 @@ +discard """ + output: '''@[5, 5, 5]''' +""" + +# bug #1832 + +var s = @[5] + +# Works fine: +let x = s[s.high] +s.add x + +# Causes the 0 to appear: +s.add s[s.high] + +echo s # @[5, 5, 0] diff --git a/tests/ccgbugs/tmissingderef.nim b/tests/ccgbugs/tmissingderef.nim index edff1dd4e..26418800a 100644 --- a/tests/ccgbugs/tmissingderef.nim +++ b/tests/ccgbugs/tmissingderef.nim @@ -1,5 +1,7 @@ discard """ - output: '''255 + output: '''[10, 0, 0, 0, 0, 0, 0, 0] + +255 1 1 0.5''' """ @@ -27,4 +29,13 @@ proc mainowar = var b = p[] echo b[0] + +# bug 2963 +var + a = [8, 7, 3, 10, 0, 0, 0, 1] + b = [10, 0, 0, 0, 0, 0, 0, 0] + ap = addr a +ap[] = b +echo repr(a) + mainowar() diff --git a/tests/ccgbugs/trecursive_closure.nim b/tests/ccgbugs/trecursive_closure.nim index 50c363a4a..f64382a8c 100644 --- a/tests/ccgbugs/trecursive_closure.nim +++ b/tests/ccgbugs/trecursive_closure.nim @@ -6,3 +6,9 @@ proc f(x: proc: MalType) = discard x() f(nil) + +# bug #2823 + +type A = object #of RootObj <-- Uncomment this to get no errors + test: proc(i: A): bool +var a: proc(i: A): bool # Or comment this line to get no errors diff --git a/tests/cpp/ttypeinfo2.nim b/tests/cpp/ttypeinfo2.nim new file mode 100644 index 000000000..64bd43e96 --- /dev/null +++ b/tests/cpp/ttypeinfo2.nim @@ -0,0 +1,6 @@ +discard """ + cmd: "nim cpp $file" +""" +# bug #2841 +import typeinfo +var tt: Any diff --git a/tests/iter/tscheduler.nim b/tests/iter/tscheduler.nim index a267f15c4..f4b04f311 100644 --- a/tests/iter/tscheduler.nim +++ b/tests/iter/tscheduler.nim @@ -7,6 +7,7 @@ a2 8 a2 6 a2 4 a2 2''' + disabled: "true" """ import os, strutils, times, algorithm diff --git a/tests/metatype/tstatic_ones.nim b/tests/metatype/tstatic_ones.nim new file mode 100644 index 000000000..73a88447d --- /dev/null +++ b/tests/metatype/tstatic_ones.nim @@ -0,0 +1,28 @@ +discard """ + output: "@[2, 2, 2, 2, 2]" +""" + +# bug #3144 + +type IntArray[N: static[int]] = array[N, int] + +proc `$`(a: IntArray): string = $(@(a)) + +proc `+=`[N: static[int]](a: var IntArray[N], b: IntArray[N]) = + for i in 0 .. < N: + a[i] += b[i] + +proc zeros(N: static[int]): IntArray[N] = + for i in 0 .. < N: + result[i] = 0 + +proc ones(N: static[int]): IntArray[N] = + for i in 0 .. < N: + result[i] = 1 + +proc sum[N: static[int]](vs: seq[IntArray[N]]): IntArray[N] = + result = zeros(N) + for v in vs: + result += v + +echo sum(@[ones(5), ones(5)]) diff --git a/tests/metatype/tstaticvector.nim b/tests/metatype/tstaticvector.nim index c9923f469..69ee0e935 100644 --- a/tests/metatype/tstaticvector.nim +++ b/tests/metatype/tstaticvector.nim @@ -1,17 +1,39 @@ +discard """ + output: '''0 +0 +2 +100''' +""" type RectArray*[R, C: static[int], T] = distinct array[R * C, T] - + StaticMatrix*[R, C: static[int], T] = object elements*: RectArray[R, C, T] - + StaticVector*[N: static[int], T] = StaticMatrix[N, 1, T] - + proc foo*[N, T](a: StaticVector[N, T]): T = 0.T proc foobar*[N, T](a, b: StaticVector[N, T]): T = 0.T - - + + var a: StaticVector[3, int] - + echo foo(a) # OK -echo foobar(a, a) # <--- hangs compiler +echo foobar(a, a) # <--- hangs compiler + +# bug #3112 + +type + Vector[N: static[int]] = array[N, float64] + TwoVectors[Na, Nb: static[int]] = tuple + a: Vector[Na] + b: Vector[Nb] + +when isMainModule: + var v: TwoVectors[2, 100] + echo v[0].len + echo v[1].len + #let xx = 50 + v[1][50] = 0.0 + diff --git a/tests/typerel/ttypedesc_as_genericparam1.nim b/tests/typerel/ttypedesc_as_genericparam1.nim new file mode 100644 index 000000000..677bf6fc8 --- /dev/null +++ b/tests/typerel/ttypedesc_as_genericparam1.nim @@ -0,0 +1,6 @@ +discard """ + line: 6 + errormsg: "type mismatch: got (typedesc[int])" +""" +# bug #3079, #1146 +echo repr(int) diff --git a/tests/typerel/ttypedesc_as_genericparam2.nim b/tests/typerel/ttypedesc_as_genericparam2.nim new file mode 100644 index 000000000..0b4281269 --- /dev/null +++ b/tests/typerel/ttypedesc_as_genericparam2.nim @@ -0,0 +1,9 @@ +discard """ + line: 9 + errormsg: "'repr' doesn't support 'void' type" +""" + +# bug #2879 + +var s: seq[int] +echo repr(s.new_seq(3)) diff --git a/tests/vm/tslurp.nim b/tests/vm/tslurp.nim index f9456ce6b..fc3dc6f0a 100644 --- a/tests/vm/tslurp.nim +++ b/tests/vm/tslurp.nim @@ -1,6 +1,12 @@ +import os + +template getScriptDir(): string = + parentDir(instantiationInfo(-1, true).filename) const - myRes = slurp"../../readme.txt" + relRes = slurp"../../readme.txt" + absRes = slurp(parentDir(parentDir(getScriptDir())) / "readme.txt") -echo myRes +echo relRes +echo absRes diff --git a/todo.txt b/todo.txt index 839d568c8..8734b8f19 100644 --- a/todo.txt +++ b/todo.txt @@ -1,6 +1,7 @@ version 0.11.4 ============== +- ``unsafeAddr`` - document special cased varargs[untyped] and varargs[typed] - The remaining bugs of the lambda lifting pass that is responsible to enable @@ -10,7 +11,8 @@ version 0.11.4 - make '--implicitStatic:on' the default; then we can also clean up the 'static[T]' mess in the compiler! -- Finish the implementation of the 'parallel' statement. +- Mark the 'parallel' statement as experimental. +- add "all threads are blocked" detection to 'spawn' - Deprecate ``immediate`` for templates and macros - make 'nil' work for 'add': - resizeString @@ -21,9 +23,9 @@ version 0.11.4 version 1.0 =========== +- map ``string`` and ``seq`` to ``std::string`` and ``std::vector`` - macro support for '='; bind '=' to a memory region - remove echo $foo gotcha -- add "all threads are blocked" detection to 'spawn' - figure out why C++ bootstrapping is so much slower - nimsuggest: auto-completion needs to work in 'class' macros - The bitwise 'not' operator will be renamed to 'bnot' to diff --git a/web/documentation.txt b/web/documentation.txt index 67f8b4070..14d88245d 100644 --- a/web/documentation.txt +++ b/web/documentation.txt @@ -14,10 +14,17 @@ Nim's Documentation - | `Language Manual <docs/manual.html>`_ | The Nim manual is a draft that will evolve into a proper specification. + - | `Nim Style Guide <docs/nep1.html>`_ + | The stylistic conventions that Nim's official projects adhere to. + - | `Compiler User Guide <docs/nimc.html>`_ | The user guide lists command line arguments, special features of the compiler, etc. + - | `Nim Backend Integration <docs/backends.html>`_ + | The Backend Integeration guide gives further information of how Nim can + interact with C, C++, Objective C and JavaScript. + .. container:: standout diff --git a/web/news.txt b/web/news.txt index cffffffee..a5bc600b9 100644 --- a/web/news.txt +++ b/web/news.txt @@ -40,6 +40,8 @@ News ``varargs[expr]`` instead. The same applies to ``varargs[typed]`` vs ``varargs[stmt]``. - ``sequtils.delete`` doesn't take confusing default arguments anymore. + - ``system.free`` was an error-prone alias to ``system.dealloc`` and has + been removed. Library additions @@ -47,7 +49,8 @@ News - The nre module has been added, providing a better interface to PCRE than re. - - The ``expandSymlink`` procedure has been added to the ``os`` module. + - The ``expandSymlink`` proc has been added to the ``os`` module. + - The ``tailDir`` proc has been added to the ``os`` module. Language Additions ------------------ diff --git a/web/website.ini b/web/website.ini index fb98d639a..95f0f5b57 100644 --- a/web/website.ini +++ b/web/website.ini @@ -31,7 +31,7 @@ file: ticker.txt [Documentation] doc: "endb;intern;apis;lib;manual.txt;tut1;tut2;nimc;overview;filters" doc: "tools;niminst;nimgrep;gc;estp;idetools;docgen;koch;backends.txt" -doc: "nimfix.txt;nimsuggest.txt" +doc: "nimfix.txt;nimsuggest.txt;nep1.txt" pdf: "manual.txt;lib;tut1;tut2;nimc;niminst;gc" srcdoc2: "system.nim" srcdoc2: "core/macros;pure/marshal;core/typeinfo;core/unsigned" |