diff options
36 files changed, 468 insertions, 366 deletions
diff --git a/changelog.md b/changelog.md index d519ecfcf..4d205faf8 100644 --- a/changelog.md +++ b/changelog.md @@ -127,8 +127,6 @@ This now needs to be written as: - The behavior of ``$`` has been changed for all standard library collections. The collection-to-string implementations now perform proper quoting and escaping of strings and chars. -- Removed ``securehash`` stdlib module as it is not secure anymore. The module - is still available via ``compiler/securehash``. - The ``random`` procs in ``random.nim`` have all been deprecated. Instead use the new ``rand`` procs. The module now exports the state of the random number generator as type ``Rand`` so multiple threads can easily use their diff --git a/compiler/ast.nim b/compiler/ast.nim index 5b923acb2..27a44c6c2 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -62,8 +62,8 @@ type nkTripleStrLit, # a triple string literal """ nkNilLit, # the nil literal # end of atoms - nkMetaNode_Obsolete, # difficult to explain; represents itself - # (used for macros) + nkComesFrom, # "comes from" template/macro information for + # better stack trace generation nkDotCall, # used to temporarily flag a nkCall node; # this is used # for transforming ``s.len`` to ``len(s)`` diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 1505052cc..5a25a9853 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -683,9 +683,10 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) = d.storage = OnHeap else: var a: TLoc - var typ = skipTypes(e.sons[0].typ, abstractInst) + var typ = e.sons[0].typ if typ.kind in {tyUserTypeClass, tyUserTypeClassInst} and typ.isResolvedUserTypeClass: typ = typ.lastSon + typ = typ.skipTypes(abstractInst) if typ.kind == tyVar and tfVarIsPtr notin typ.flags and p.module.compileToCpp and e.sons[0].kind == nkHiddenAddr: initLocExprSingleUse(p, e[0][0], d) return @@ -849,7 +850,7 @@ proc genArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) = var a, b: TLoc initLocExpr(p, x, a) initLocExpr(p, y, b) - var ty = skipTypes(skipTypes(a.t, abstractVarRange), abstractPtrs) + var ty = skipTypes(a.t, abstractVarRange + abstractPtrs + tyUserTypeClasses) var first = intLiteral(firstOrd(ty)) # emit range check: if optBoundsCheck in p.options and tfUncheckedArray notin ty.flags: @@ -1982,10 +1983,35 @@ proc genComplexConst(p: BProc, sym: PSym, d: var TLoc) = assert((sym.loc.r != nil) and (sym.loc.t != nil)) putLocIntoDest(p, d, sym.loc) +template genStmtListExprImpl(exprOrStmt) {.dirty.} = + #let hasNimFrame = magicsys.getCompilerProc("nimFrame") != nil + let hasNimFrame = p.prc != nil and + sfSystemModule notin p.module.module.flags and + optStackTrace in p.prc.options + var frameName: Rope = nil + for i in 0 .. n.len - 2: + let it = n[i] + if it.kind == nkComesFrom: + if hasNimFrame and frameName == nil: + inc p.labels + frameName = "FR" & rope(p.labels) & "_" + let theMacro = it[0].sym + add p.s(cpsStmts), initFrameNoDebug(p, frameName, + makeCString theMacro.name.s, + theMacro.info.quotedFilename, it.info.line) + else: + genStmts(p, it) + if n.len > 0: exprOrStmt + if frameName != nil: + add p.s(cpsStmts), deinitFrameNoDebug(p, frameName) + proc genStmtListExpr(p: BProc, n: PNode, d: var TLoc) = - var length = sonsLen(n) - for i in countup(0, length - 2): genStmts(p, n.sons[i]) - if length > 0: expr(p, n.sons[length - 1], d) + genStmtListExprImpl: + expr(p, n[n.len - 1], d) + +proc genStmtList(p: BProc, n: PNode) = + genStmtListExprImpl: + genStmts(p, n[n.len - 1]) proc upConv(p: BProc, n: PNode, d: var TLoc) = var a: TLoc @@ -2184,8 +2210,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = of nkCheckedFieldExpr: genCheckedRecordField(p, n, d) of nkBlockExpr, nkBlockStmt: genBlock(p, n, d) of nkStmtListExpr: genStmtListExpr(p, n, d) - of nkStmtList: - for i in countup(0, sonsLen(n) - 1): genStmts(p, n.sons[i]) + of nkStmtList: genStmtList(p, n) of nkIfExpr, nkIfStmt: genIf(p, n, d) of nkWhen: # This should be a "when nimvm" node. diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 24a376dec..36816cc2c 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -564,9 +564,6 @@ proc genBreakStmt(p: BProc, t: PNode) = genLineDir(p, t) lineF(p, cpsStmts, "goto $1;$n", [label]) -proc getRaiseFrmt(p: BProc): string = - result = "#raiseException((#Exception*)$1, $2);$n" - proc genRaiseStmt(p: BProc, t: PNode) = if p.inExceptBlock > 0: # if the current try stmt have a finally block, @@ -580,7 +577,8 @@ proc genRaiseStmt(p: BProc, t: PNode) = var e = rdLoc(a) var typ = skipTypes(t.sons[0].typ, abstractPtrs) genLineDir(p, t) - lineCg(p, cpsStmts, getRaiseFrmt(p), [e, makeCString(typ.sym.name.s)]) + lineCg(p, cpsStmts, "#raiseException((#Exception*)$1, $2);$n", + [e, makeCString(typ.sym.name.s)]) else: genLineDir(p, t) # reraise the last exception: diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 07c2824d0..217138dd0 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -493,7 +493,32 @@ proc initLocExprSingleUse(p: BProc, e: PNode, result: var TLoc) = proc lenField(p: BProc): Rope = result = rope(if p.module.compileToCpp: "len" else: "Sup.len") -include ccgcalls, "ccgstmts.nim", "ccgexprs.nim" +include ccgcalls, "ccgstmts.nim" + +proc initFrame(p: BProc, procname, filename: Rope): Rope = + discard cgsym(p.module, "nimFrame") + if p.maxFrameLen > 0: + discard cgsym(p.module, "VarSlot") + result = rfmt(nil, "\tnimfrs_($1, $2, $3, $4);$n", + procname, filename, p.maxFrameLen.rope, + p.blocks[0].frameLen.rope) + else: + result = rfmt(nil, "\tnimfr_($1, $2);$n", procname, filename) + +proc initFrameNoDebug(p: BProc; frame, procname, filename: Rope; line: int): Rope = + discard cgsym(p.module, "nimFrame") + addf(p.blocks[0].sections[cpsLocals], "TFrame $1;$n", [frame]) + result = rfmt(nil, "\t$1.procname = $2; $1.filename = $3; " & + " $1.line = $4; $1.len = -1; nimFrame(&$1);$n", + frame, procname, filename, rope(line)) + +proc deinitFrameNoDebug(p: BProc; frame: Rope): Rope = + result = rfmt(p.module, "\t#popFrameOfAddr(&$1);$n", frame) + +proc deinitFrame(p: BProc): Rope = + result = rfmt(p.module, "\t#popFrame();$n") + +include ccgexprs # ----------------------------- dynamic library handling ----------------- # We don't finalize dynamic libs as the OS does this for us. @@ -600,7 +625,7 @@ proc symInDynamicLibPartial(m: BModule, sym: PSym) = sym.typ.sym = nil # generate a new name proc cgsym(m: BModule, name: string): Rope = - var sym = magicsys.getCompilerProc(name) + let sym = magicsys.getCompilerProc(name) if sym != nil: case sym.kind of skProc, skFunc, skMethod, skConverter, skIterator: genProc(m, sym) @@ -637,19 +662,6 @@ proc generateHeaders(m: BModule) = add(m.s[cfsHeaders], "#undef powerpc" & tnl) add(m.s[cfsHeaders], "#undef unix" & tnl) -proc initFrame(p: BProc, procname, filename: Rope): Rope = - discard cgsym(p.module, "nimFrame") - if p.maxFrameLen > 0: - discard cgsym(p.module, "VarSlot") - result = rfmt(nil, "\tnimfrs_($1, $2, $3, $4);$n", - procname, filename, p.maxFrameLen.rope, - p.blocks[0].frameLen.rope) - else: - result = rfmt(nil, "\tnimfr_($1, $2);$n", procname, filename) - -proc deinitFrame(p: BProc): Rope = - result = rfmt(p.module, "\t#popFrame();$n") - proc closureSetup(p: BProc, prc: PSym) = if tfCapturesEnv notin prc.typ.flags: return # prc.ast[paramsPos].last contains the type we're after: diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim index 7fa6df3da..704ff819c 100644 --- a/compiler/evaltempl.nim +++ b/compiler/evaltempl.nim @@ -109,7 +109,7 @@ proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode = var evalTemplateCounter* = 0 # to prevent endless recursion in templates instantiation -proc wrapInComesFrom*(info: TLineInfo; res: PNode): PNode = +proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode = when true: result = res result.info = info @@ -124,8 +124,12 @@ proc wrapInComesFrom*(info: TLineInfo; res: PNode): PNode = if x[i].kind in nkCallKinds: x.sons[i].info = info else: - result = newNodeI(nkPar, info) + result = newNodeI(nkStmtListExpr, info) + var d = newNodeI(nkComesFrom, info) + d.add newSymNode(sym, info) + result.add d result.add res + result.typ = res.typ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; fromHlo=false): PNode = inc(evalTemplateCounter) @@ -156,6 +160,6 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; fromHlo=false): PNode = for i in countup(0, safeLen(body) - 1): evalTemplateAux(body.sons[i], args, ctx, result) result.flags.incl nfFromTemplate - result = wrapInComesFrom(n.info, result) + result = wrapInComesFrom(n.info, tmpl, result) dec(evalTemplateCounter) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 7a473ea43..5299b2dbf 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -794,42 +794,40 @@ proc writeJsonBuildInstructions*(projectfile: string) = else: f.write escapeJson(x) - proc cfiles(f: File; buf: var string; list: CfileList, isExternal: bool) = - var i = 0 - for it in list: + proc cfiles(f: File; buf: var string; clist: CfileList, isExternal: bool) = + var pastStart = false + for it in clist: if CfileFlag.Cached in it.flags: continue let compileCmd = getCompileCFileCmd(it) + if pastStart: lit "],\L" lit "[" str it.cname lit ", " str compileCmd - inc i - if i == list.len: - lit "]\L" - else: - lit "],\L" - - proc linkfiles(f: File; buf, objfiles: var string) = - for i, it in externalToLink: - let - objFile = if noAbsolutePaths(): it.extractFilename else: it - objStr = addFileExt(objFile, CC[cCompiler].objExt) + pastStart = true + lit "]\L" + + proc linkfiles(f: File; buf, objfiles: var string; clist: CfileList; + llist: seq[string]) = + var pastStart = false + for it in llist: + let objfile = if noAbsolutePaths(): it.extractFilename + else: it + let objstr = addFileExt(objfile, CC[cCompiler].objExt) add(objfiles, ' ') - add(objfiles, objStr) - str objStr - if toCompile.len == 0 and i == externalToLink.high: - lit "\L" - else: - lit ",\L" - for i, x in toCompile: - let objStr = quoteShell(x.obj) + add(objfiles, objstr) + if pastStart: lit ",\L" + str objstr + pastStart = true + + for it in clist: + let objstr = quoteShell(it.obj) add(objfiles, ' ') - add(objfiles, objStr) - str objStr - if i == toCompile.high: - lit "\L" - else: - lit ",\L" + add(objfiles, objstr) + if pastStart: lit ",\L" + str objstr + pastStart = true + lit "\L" var buf = newStringOfCap(50) @@ -843,7 +841,7 @@ proc writeJsonBuildInstructions*(projectfile: string) = lit "],\L\"link\":[\L" var objfiles = "" # XXX add every file here that is to link - linkfiles(f, buf, objfiles) + linkfiles(f, buf, objfiles, toCompile, externalToLink) lit "],\L\"linkcmd\": " str getLinkCmd(projectfile, objfiles) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 50dfa22f8..65a6a5dae 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -2369,6 +2369,8 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = of nkGotoState, nkState: internalError(n.info, "first class iterators not implemented") of nkPragmaBlock: gen(p, n.lastSon, r) + of nkComesFrom: + discard "XXX to implement for better stack traces" else: internalError(n.info, "gen: unknown node type: " & $n.kind) var globals: PGlobals diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 820439524..cf43ba15d 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -723,7 +723,7 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass; result = accessViaEnvParam(n, owner) else: result = accessViaEnvVar(n, owner, d, c) - of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, + of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkComesFrom, nkTemplateDef, nkTypeSection: discard of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef: diff --git a/compiler/nimblecmd.nim b/compiler/nimblecmd.nim index 39c3a17e7..0f9e03352 100644 --- a/compiler/nimblecmd.nim +++ b/compiler/nimblecmd.nim @@ -28,6 +28,10 @@ proc newVersion*(ver: string): Version = proc isSpecial(ver: Version): bool = return ($ver).len > 0 and ($ver)[0] == '#' +proc isValidVersion(v: string): bool = + if v.len > 0: + if v[0] in {'#'} + Digits: return true + proc `<`*(ver: Version, ver2: Version): bool = ## This is synced from Nimble's version module. @@ -72,15 +76,23 @@ proc getPathVersion*(p: string): tuple[name, version: string] = result.name = p return + for i in sepIdx..<p.len: + if p[i] in {DirSep, AltSep}: + result.name = p + return + result.name = p[0 .. sepIdx - 1] result.version = p.substr(sepIdx + 1) -proc addPackage(packages: StringTableRef, p: string) = +proc addPackage(packages: StringTableRef, p: string; info: TLineInfo) = let (name, ver) = getPathVersion(p) - let version = newVersion(ver) - if packages.getOrDefault(name).newVersion < version or - (not packages.hasKey(name)): - packages[name] = $version + if isValidVersion(ver): + let version = newVersion(ver) + if packages.getOrDefault(name).newVersion < version or + (not packages.hasKey(name)): + packages[name] = $version + else: + localError(info, "invalid package name: " & p) iterator chosen(packages: StringTableRef): string = for key, val in pairs(packages): @@ -109,7 +121,7 @@ proc addPathRec(dir: string, info: TLineInfo) = if dir[pos] in {DirSep, AltSep}: inc(pos) for k,p in os.walkDir(dir): if k == pcDir and p[pos] != '.': - addPackage(packages, p) + addPackage(packages, p, info) for p in packages.chosen: addNimblePath(p, info) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 267ce7de7..d4b401c02 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -1406,8 +1406,8 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = put(g, tkBracketRi, "]") of nkTupleClassTy: put(g, tkTuple, "tuple") - of nkMetaNode_Obsolete: - put(g, tkParLe, "(META|") + of nkComesFrom: + put(g, tkParLe, "(ComesFrom|") gsub(g, n, 0) put(g, tkParRi, ")") of nkGotoState, nkState: diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index dac267263..8eb76457c 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -73,7 +73,8 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string; cbos copyFile: os.copyFile(getString(a, 0), getString(a, 1)) cbos getLastModificationTime: - setResult(a, toSeconds(getLastModificationTime(getString(a, 0)))) + # depends on Time's implementation! + setResult(a, int64(getLastModificationTime(getString(a, 0)))) cbos rawExec: setResult(a, osproc.execCmd getString(a, 0)) diff --git a/compiler/sem.nim b/compiler/sem.nim index 495321de4..bc994201d 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -423,7 +423,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, result = evalMacroCall(c.module, c.cache, n, nOrig, sym) if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, sym, flags) - result = wrapInComesFrom(nOrig.info, result) + result = wrapInComesFrom(nOrig.info, sym, result) popInfoContext() proc forceBool(c: PContext, n: PNode): PNode = diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 7867c7e36..55c43ed09 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1365,13 +1365,16 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = if lhsIsResult: n.typ = enforceVoidContext if c.p.owner.kind != skMacro and resultTypeIsInferrable(lhs.sym.typ): - if cmpTypes(c, lhs.typ, rhs.typ) == isGeneric: + var rhsTyp = rhs.typ + if rhsTyp.kind in tyUserTypeClasses and rhsTyp.isResolvedUserTypeClass: + rhsTyp = rhsTyp.lastSon + if cmpTypes(c, lhs.typ, rhsTyp) in {isGeneric, isEqual}: internalAssert c.p.resultSym != nil - lhs.typ = rhs.typ - c.p.resultSym.typ = rhs.typ - c.p.owner.typ.sons[0] = rhs.typ + lhs.typ = rhsTyp + c.p.resultSym.typ = rhsTyp + c.p.owner.typ.sons[0] = rhsTyp else: - typeMismatch(n.info, lhs.typ, rhs.typ) + typeMismatch(n.info, lhs.typ, rhsTyp) n.sons[1] = fitNode(c, le, rhs, n.info) if not newDestructors: @@ -2380,6 +2383,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = if n.len != 1 and n.len != 2: illFormedAst(n) for i in 0 ..< n.len: n.sons[i] = semExpr(c, n.sons[i]) + of nkComesFrom: discard "ignore the comes from information for now" else: localError(n.info, errInvalidExpressionX, renderTree(n, {renderNoComments})) diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 1e7c0aa9e..d2d36140d 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -655,5 +655,8 @@ proc getConstExpr(m: PSym, n: PNode): PNode = result.typ = n.typ of nkBracketExpr: result = foldArrayAccess(m, n) of nkDotExpr: result = foldFieldAccess(m, n) + of nkStmtListExpr: + if n.len == 2 and n[0].kind == nkComesFrom: + result = getConstExpr(m, n[1]) else: discard diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index da2c6fe7f..16da06952 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -186,7 +186,7 @@ proc semGenericStmt(c: PContext, n: PNode, let a = n.sym let b = getGenSym(c, a) if b != a: n.sym = b - of nkEmpty, succ(nkSym)..nkNilLit: + of nkEmpty, succ(nkSym)..nkNilLit, nkComesFrom: # see tests/compile/tgensymgeneric.nim: # We need to open the gensym'ed symbol again so that the instantiation # creates a fresh copy; but this is wrong the very first reason for gensym diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index c85de35cd..8ed120c98 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -441,9 +441,10 @@ proc hasEmpty(typ: PType): bool = result = result or hasEmpty(s) proc makeDeref(n: PNode): PNode = - var t = skipTypes(n.typ, {tyGenericInst, tyAlias}) + var t = n.typ if t.kind in tyUserTypeClasses and t.isResolvedUserTypeClass: t = t.lastSon + t = skipTypes(t, {tyGenericInst, tyAlias}) result = n if t.kind == tyVar: result = newNodeIT(nkHiddenDeref, n.info, t.sons[0]) diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 1c9d8271a..f90dff8f1 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -331,7 +331,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = of nkMixinStmt: if c.scopeN > 0: result = semTemplBodySons(c, n) else: result = semMixinStmt(c.c, n, c.toMixin) - of nkEmpty, nkSym..nkNilLit: + of nkEmpty, nkSym..nkNilLit, nkComesFrom: discard of nkIfStmt: for i in countup(0, sonsLen(n)-1): @@ -528,7 +528,7 @@ proc semTemplBodyDirty(c: var TemplCtx, n: PNode): PNode = result = semTemplBodyDirty(c, n.sons[0]) of nkBindStmt: result = semBindStmt(c.c, n, c.toBind) - of nkEmpty, nkSym..nkNilLit: + of nkEmpty, nkSym..nkNilLit, nkComesFrom: discard else: # dotExpr is ambiguous: note that we explicitly allow 'x.TemplateParam', diff --git a/compiler/transf.nim b/compiler/transf.nim index 8e4bb935b..6bc809fd2 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -791,7 +791,7 @@ proc transform(c: PTransf, n: PNode): PTransNode = case n.kind of nkSym: result = transformSym(c, n) - of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: + of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkComesFrom: # nothing to be done for leaves: result = PTransNode(n) of nkBracketExpr: result = transformArrayAccess(c, n) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 252b7c788..3790a8392 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1847,6 +1847,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) = globalError(n.info, errGenerated, "VM is not allowed to 'cast'") of nkTypeOfExpr: genTypeLit(c, n.typ, dest) + of nkComesFrom: + discard "XXX to implement for better stack traces" else: globalError(n.info, errGenerated, "cannot generate VM code for " & $n) diff --git a/doc/lib.rst b/doc/lib.rst index 2719472fe..58dedc49c 100644 --- a/doc/lib.rst +++ b/doc/lib.rst @@ -380,6 +380,9 @@ Cryptography and Hashing * `base64 <base64.html>`_ This module implements a base64 encoder and decoder. +* `securehash <securehash.html>`_ + This module implements a sha1 encoder and decoder. + Multimedia support ------------------ diff --git a/lib/core/macros.nim b/lib/core/macros.nim index ee6c1a09f..b08a2198e 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -21,7 +21,7 @@ type nnkInt16Lit, nnkInt32Lit, nnkInt64Lit, nnkUIntLit, nnkUInt8Lit, nnkUInt16Lit, nnkUInt32Lit, nnkUInt64Lit, nnkFloatLit, nnkFloat32Lit, nnkFloat64Lit, nnkFloat128Lit, nnkStrLit, nnkRStrLit, - nnkTripleStrLit, nnkNilLit, nnkMetaNode, nnkDotCall, + nnkTripleStrLit, nnkNilLit, nnkComesFrom, nnkDotCall, nnkCommand, nnkCall, nnkCallStrLit, nnkInfix, nnkPrefix, nnkPostfix, nnkHiddenCallConv, nnkExprEqExpr, diff --git a/lib/pure/math.nim b/lib/pure/math.nim index 7fd8bbcef..a9dabfa48 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -291,6 +291,8 @@ when not defined(JS): ## echo fmod(-2.5, 0.3) ## -0.1 else: + proc trunc*(x: float32): float32 {.importc: "Math.trunc", nodecl.} + proc trunc*(x: float64): float64 {.importc: "Math.trunc", nodecl.} proc floor*(x: float32): float32 {.importc: "Math.floor", nodecl.} proc floor*(x: float64): float64 {.importc: "Math.floor", nodecl.} proc ceil*(x: float32): float32 {.importc: "Math.ceil", nodecl.} diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 87f6def29..c18d03289 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -816,32 +816,40 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path: k = getSymlinkFileKind(y) yield (k, y) -iterator walkDirRec*(dir: string, filter={pcFile, pcDir}): string {. - tags: [ReadDirEffect].} = - ## Recursively walks over the directory `dir` and yields for each file in `dir`. - ## The full path for each file is returned. Directories are not returned. +iterator walkDirRec*(dir: string, yieldFilter = {pcFile}, + followFilter = {pcDir}): string {.tags: [ReadDirEffect].} = + ## Recursively walks over the directory `dir` and yields for each file + ## or directory in `dir`. + ## The full path for each file or directory is returned. ## **Warning**: ## Modifying the directory structure while the iterator ## is traversing may result in undefined behavior! ## - ## Walking is recursive. `filter` controls the behaviour of the iterator: + ## Walking is recursive. `filters` controls the behaviour of the iterator: ## ## --------------------- --------------------------------------------- - ## filter meaning + ## yieldFilter meaning ## --------------------- --------------------------------------------- ## ``pcFile`` yield real files ## ``pcLinkToFile`` yield symbolic links to files + ## ``pcDir`` yield real directories + ## ``pcLinkToDir`` yield symbolic links to directories + ## --------------------- --------------------------------------------- + ## + ## --------------------- --------------------------------------------- + ## followFilter meaning + ## --------------------- --------------------------------------------- ## ``pcDir`` follow real directories ## ``pcLinkToDir`` follow symbolic links to directories ## --------------------- --------------------------------------------- ## var stack = @[dir] while stack.len > 0: - for k,p in walkDir(stack.pop()): - if k in filter: - case k - of pcFile, pcLinkToFile: yield p - of pcDir, pcLinkToDir: stack.add(p) + for k, p in walkDir(stack.pop()): + if k in {pcDir, pcLinkToDir} and k in followFilter: + stack.add(p) + if k in yieldFilter: + yield p proc rawRemoveDir(dir: string) = when defined(windows): diff --git a/compiler/securehash.nim b/lib/pure/securehash.nim index 57c1f3631..57c1f3631 100644 --- a/compiler/securehash.nim +++ b/lib/pure/securehash.nim diff --git a/lib/pure/strformat.nim b/lib/pure/strformat.nim index c4044867d..180cbcbec 100644 --- a/lib/pure/strformat.nim +++ b/lib/pure/strformat.nim @@ -42,7 +42,7 @@ An expression like ``fmt"{key} is {value:arg} {{z}}"`` is transformed into: format(key, temp) format(" is ", temp) format(value, arg, temp) - format("{z}", temp) + format(" {z}", temp) temp Parts of the string that are enclosed in the curly braces are interpreted @@ -94,7 +94,7 @@ The general form of a standard format specifier is:: [[fill]align][sign][#][0][minimumwidth][.precision][type] -The brackets ([]) indicate an optional element. +The square brackets ``[]`` indicate an optional element. The optional align flag can be one of the following: @@ -126,8 +126,9 @@ The 'sign' option is only valid for numeric types, and can be one of the followi positive as well as negative numbers. ``-`` Indicates that a sign should be used only for negative numbers (this is the default behavior). -`` `` (space) Indicates that a leading space should be used on +(space) Indicates that a leading space should be used on positive numbers. +================= ==================================================== If the '#' character is present, integers use the 'alternate form' for formatting. This means that binary, octal, and hexadecimal output will be prefixed diff --git a/lib/pure/times.nim b/lib/pure/times.nim index dcc817b7b..606acbc1c 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -26,7 +26,6 @@ ## echo "Using predefined formats: ", getClockStr(), " ", getDateStr() ## ## echo "epochTime() float value: ", epochTime() -## echo "getTime() float value: ", toSeconds(getTime()) ## echo "cpuTime() float value: ", cpuTime() ## echo "An hour from now : ", now() + 1.hours ## echo "An hour from (UTC) now: ", getTime().utc + initInterval(0,0,0,1) @@ -180,7 +179,7 @@ proc assertValidDate(monthday: MonthdayRange, month: Month, year: int) {.inline. proc toEpochDay*(monthday: MonthdayRange, month: Month, year: int): int64 = ## Get the epoch day from a year/month/day date. ## The epoch day is the number of days since 1970/01/01 (it might be negative). - assertValidDate monthday, month, year + assertValidDate monthday, month, year # Based on http://howardhinnant.github.io/date_algorithms.html var (y, m, d) = (year, ord(month), monthday.int) if m <= 2: @@ -194,7 +193,7 @@ proc toEpochDay*(monthday: MonthdayRange, month: Month, year: int): int64 = proc fromEpochDay*(epochday: int64): tuple[monthday: MonthdayRange, month: Month, year: int] = ## Get the year/month/day date from a epoch day. - ## The epoch day is the number of days since 1970/01/01 (it might be negative). + ## The epoch day is the number of days since 1970/01/01 (it might be negative). # Based on http://howardhinnant.github.io/date_algorithms.html var z = epochday z.inc 719468 @@ -494,11 +493,11 @@ proc local*(dt: DateTime): DateTime = dt.inZone(local()) proc utc*(t: Time): DateTime = - ## Shorthand for ``t.inZone(utc())``. + ## Shorthand for ``t.inZone(utc())``. t.inZone(utc()) proc local*(t: Time): DateTime = - ## Shorthand for ``t.inZone(local())``. + ## Shorthand for ``t.inZone(local())``. t.inZone(local()) proc getTime*(): Time {.tags: [TimeEffect], benign.} @@ -590,7 +589,7 @@ proc evaluateInterval(dt: DateTime, interval: TimeInterval): tuple[adjDiff, absD anew.year.dec() else: curMonth.dec() - result.adjDiff -= getDaysInMonth(curMonth, anew.year) * secondsInDay + result.adjDiff -= getDaysInMonth(curMonth, anew.year) * secondsInDay # Adding else: for mth in 1 .. newinterv.months: @@ -610,7 +609,7 @@ proc `+`*(dt: DateTime, interval: TimeInterval): DateTime = ## Adds ``interval`` to ``dt``. Components from ``interval`` are added ## in the order of their size, i.e first the ``years`` component, then the ``months`` ## component and so on. The returned ``DateTime`` will have the same timezone as the input. - ## + ## ## Note that when adding months, monthday overflow is allowed. This means that if the resulting ## month doesn't have enough days it, the month will be incremented and the monthday will be ## set to the number of days overflowed. So adding one month to `31 October` will result in `31 November`, @@ -1392,7 +1391,7 @@ proc timeInfoToTime*(dt: DateTime): Time {.tags: [], benign, deprecated.} = ## ## **Warning:** This procedure is deprecated since version 0.14.0. ## Use ``toTime`` instead. - dt.toTime + dt.toTime when defined(JS): var startMilsecs = getTime() diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 70c18ae21..8e42ea468 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -70,6 +70,18 @@ proc getFrame*(): PFrame {.compilerRtl, inl.} = framePtr proc popFrame {.compilerRtl, inl.} = framePtr = framePtr.prev +when false: + proc popFrameOfAddr(s: PFrame) {.compilerRtl.} = + var it = framePtr + if it == s: + framePtr = framePtr.prev + else: + while it != nil: + if it == s: + framePtr = it.prev + break + it = it.prev + proc setFrame*(s: PFrame) {.compilerRtl, inl.} = framePtr = s diff --git a/tests/concepts/t6462.nim b/tests/concepts/t6462.nim new file mode 100644 index 000000000..2fa2268f8 --- /dev/null +++ b/tests/concepts/t6462.nim @@ -0,0 +1,23 @@ +discard """ + output: "true" +""" + +import future + +type + FilterMixin*[T] = ref object + test*: (T) -> bool + trans*: (T) -> T + + SeqGen*[T] = ref object + fil*: FilterMixin[T] + + WithFilter[T] = concept a + a.fil is FilterMixin[T] + +proc test*[T](a: WithFilter[T]): (T) -> bool = + a.fil.test + +var s = SeqGen[int](fil: FilterMixin[int](test: nil, trans: nil)) +echo s.test() == nil + diff --git a/tests/concepts/tcomparable.nim b/tests/concepts/tcomparable.nim new file mode 100644 index 000000000..06612a47e --- /dev/null +++ b/tests/concepts/tcomparable.nim @@ -0,0 +1,13 @@ +type + Comparable = concept a + (a < a) is bool + +proc myMax(a, b: Comparable): Comparable = + if a < b: + return b + else: + return a + +doAssert myMax(5, 10) == 10 +doAssert myMax(31.3, 1.23124) == 31.3 + diff --git a/tests/concepts/titerable.nim b/tests/concepts/titerable.nim new file mode 100644 index 000000000..b18658b2a --- /dev/null +++ b/tests/concepts/titerable.nim @@ -0,0 +1,20 @@ +discard """ + nimout: "int\nint" + output: 15 +""" + +import typetraits + +type + Iterable[T] = concept x + for value in x: + type(value) is T + +proc sum*[T](iter: Iterable[T]): T = + static: echo T.name + for element in iter: + static: echo element.type.name + result += element + +echo sum([1, 2, 3, 4, 5]) + diff --git a/tests/testament/htmlgen.nim b/tests/testament/htmlgen.nim index 05c24b2b5..bf26a956d 100644 --- a/tests/testament/htmlgen.nim +++ b/tests/testament/htmlgen.nim @@ -9,54 +9,33 @@ ## HTML generator for the tester. -import cgi, backend, strutils, json, os +import cgi, backend, strutils, json, os, tables, times import "testamenthtml.templ" -proc generateTestRunTabListItemPartial(outfile: File, testRunRow: JsonNode, firstRow = false) = +proc generateTestResultPanelPartial(outfile: File, testResultRow: JsonNode) = let - # The first tab gets the bootstrap class for a selected tab - firstTabActiveClass = if firstRow: "active" - else: "" - commitId = htmlQuote testRunRow["commit"].str - hash = htmlQuote(testRunRow["commit"].str) - branch = htmlQuote(testRunRow["branch"].str) - machineId = htmlQuote testRunRow["machine"].str - machineName = htmlQuote(testRunRow["machine"].str) - - outfile.generateHtmlTabListItem( - firstTabActiveClass, - commitId, - machineId, - branch, - hash, - machineName - ) - -proc generateTestResultPanelPartial(outfile: File, testResultRow: JsonNode, onlyFailing = false) = - let - trId = htmlQuote(testResultRow["category"].str & "_" & testResultRow["name"].str) + trId = htmlQuote(testResultRow["category"].str & "_" & testResultRow["name"].str). + multiReplace({".": "_", " ": "_", ":": "_"}) name = testResultRow["name"].str.htmlQuote() category = testResultRow["category"].str.htmlQuote() target = testResultRow["target"].str.htmlQuote() action = testResultRow["action"].str.htmlQuote() result = htmlQuote testResultRow["result"].str - expected = htmlQuote testResultRow["expected"].str - gotten = htmlQuote testResultRow["given"].str + expected = testResultRow["expected"].str + gotten = testResultRow["given"].str timestamp = "unknown" - var panelCtxClass, textCtxClass, bgCtxClass, resultSign, resultDescription: string + var + panelCtxClass, textCtxClass, bgCtxClass: string + resultSign, resultDescription: string case result of "reSuccess": - if onlyFailing: - return panelCtxClass = "success" textCtxClass = "success" bgCtxClass = "success" resultSign = "ok" resultDescription = "PASS" of "reIgnored": - if onlyFailing: - return panelCtxClass = "info" textCtxClass = "info" bgCtxClass = "info" @@ -71,9 +50,7 @@ proc generateTestResultPanelPartial(outfile: File, testResultRow: JsonNode, only outfile.generateHtmlTestresultPanelBegin( trId, name, target, category, action, resultDescription, - timestamp, - result, resultSign, - panelCtxClass, textCtxClass, bgCtxClass + timestamp, result, resultSign, panelCtxClass, textCtxClass, bgCtxClass ) if expected.isNilOrWhitespace() and gotten.isNilOrWhitespace(): outfile.generateHtmlTestresultOutputNone() @@ -90,7 +67,7 @@ type totalCount, successCount, ignoredCount, failedCount: int successPercentage, ignoredPercentage, failedPercentage: BiggestFloat -proc allTestResults(): AllTests = +proc allTestResults(onlyFailing = false): AllTests = result.data = newJArray() for file in os.walkFiles("testresults/*.json"): let data = parseFile(file) @@ -98,69 +75,74 @@ proc allTestResults(): AllTests = echo "[ERROR] ignoring json file that is not an array: ", file else: for elem in data: - result.data.add elem let state = elem["result"].str + inc result.totalCount if state.contains("reSuccess"): inc result.successCount elif state.contains("reIgnored"): inc result.ignoredCount - - result.totalCount = result.data.len - result.successPercentage = 100 * (result.successCount.toBiggestFloat() / result.totalCount.toBiggestFloat()) - result.ignoredPercentage = 100 * (result.ignoredCount.toBiggestFloat() / result.totalCount.toBiggestFloat()) - result.failedCount = result.totalCount - result.successCount - result.ignoredCount - result.failedPercentage = 100 * (result.failedCount.toBiggestFloat() / result.totalCount.toBiggestFloat()) - - -proc generateTestResultsPanelGroupPartial(outfile: File, allResults: JsonNode, onlyFailing = false) = + if not onlyFailing or not(state.contains("reSuccess")): + result.data.add elem + result.successPercentage = 100 * + (result.successCount.toBiggestFloat / result.totalCount.toBiggestFloat) + result.ignoredPercentage = 100 * + (result.ignoredCount.toBiggestFloat / result.totalCount.toBiggestFloat) + result.failedCount = result.totalCount - + result.successCount - result.ignoredCount + result.failedPercentage = 100 * + (result.failedCount.toBiggestFloat / result.totalCount.toBiggestFloat) + +proc generateTestResultsPanelGroupPartial(outfile: File, allResults: JsonNode) = for testresultRow in allResults: - generateTestResultPanelPartial(outfile, testresultRow, onlyFailing) + generateTestResultPanelPartial(outfile, testresultRow) -proc generateTestRunTabContentPartial(outfile: File, allResults: AllTests, testRunRow: JsonNode, onlyFailing = false, firstRow = false) = +proc generateAllTestsContent(outfile: File, allResults: AllTests, + onlyFailing = false) = + if allResults.data.len < 1: return # Nothing to do if there is no data. + # Only results from one test run means that test run environment info is the + # same for all tests let - # The first tab gets the bootstrap classes for a selected and displaying tab content - firstTabActiveClass = if firstRow: " in active" - else: "" - commitId = htmlQuote testRunRow["commit"].str - hash = htmlQuote(testRunRow["commit"].str) - branch = htmlQuote(testRunRow["branch"].str) - machineId = htmlQuote testRunRow["machine"].str - machineName = htmlQuote(testRunRow["machine"].str) - os = htmlQuote("unknown_os") - cpu = htmlQuote("unknown_cpu") - - outfile.generateHtmlTabPageBegin( - firstTabActiveClass, commitId, - machineId, branch, hash, machineName, os, cpu, + firstRow = allResults.data[0] + commit = htmlQuote firstRow["commit"].str + branch = htmlQuote firstRow["branch"].str + machine = htmlQuote firstRow["machine"].str + + outfile.generateHtmlAllTestsBegin( + machine, commit, branch, allResults.totalCount, - allResults.successCount, formatBiggestFloat(allResults.successPercentage, ffDecimal, 2) & "%", - allResults.ignoredCount, formatBiggestFloat(allResults.ignoredPercentage, ffDecimal, 2) & "%", - allResults.failedCount, formatBiggestFloat(allResults.failedPercentage, ffDecimal, 2) & "%" + allResults.successCount, + formatBiggestFloat(allResults.successPercentage, ffDecimal, 2) & "%", + allResults.ignoredCount, + formatBiggestFloat(allResults.ignoredPercentage, ffDecimal, 2) & "%", + allResults.failedCount, + formatBiggestFloat(allResults.failedPercentage, ffDecimal, 2) & "%", + onlyFailing ) - generateTestResultsPanelGroupPartial(outfile, allResults.data, onlyFailing) - outfile.generateHtmlTabPageEnd() - -proc generateTestRunsHtmlPartial(outfile: File, allResults: AllTests, onlyFailing = false) = - # Iterating the results twice, get entire result set in one go - outfile.generateHtmlTabListBegin() - if allResults.data.len > 0: - generateTestRunTabListItemPartial(outfile, allResults.data[0], true) - outfile.generateHtmlTabListEnd() - - outfile.generateHtmlTabContentsBegin() - var firstRow = true - for testRunRow in allResults.data: - generateTestRunTabContentPartial(outfile, allResults, testRunRow, onlyFailing, firstRow) - if firstRow: - firstRow = false - outfile.generateHtmlTabContentsEnd() + generateTestResultsPanelGroupPartial(outfile, allResults.data) + outfile.generateHtmlAllTestsEnd() proc generateHtml*(filename: string, onlyFailing: bool) = + let + currentTime = getTime().getLocalTime() + timestring = htmlQuote format(currentTime, "yyyy-MM-dd HH:mm:ss 'UTC'zzz") var outfile = open(filename, fmWrite) outfile.generateHtmlBegin() - generateTestRunsHtmlPartial(outfile, allTestResults(), onlyFailing) + generateAllTestsContent(outfile, allTestResults(onlyFailing), onlyFailing) - outfile.generateHtmlEnd() + outfile.generateHtmlEnd(timestring) outfile.flushFile() close(outfile) + +proc dumpJsonTestResults*(prettyPrint, onlyFailing: bool) = + var + outfile = stdout + jsonString: string + + let results = allTestResults(onlyFailing) + if prettyPrint: + jsonString = results.data.pretty() + else: + jsonString = $ results.data + + outfile.writeLine(jsonString) diff --git a/tests/testament/specs.nim b/tests/testament/specs.nim index e8513ab24..ac79e3942 100644 --- a/tests/testament/specs.nim +++ b/tests/testament/specs.nim @@ -116,7 +116,7 @@ proc specDefaults*(result: var TSpec) = result.maxCodeSize = 0 proc parseTargets*(value: string): set[TTarget] = - for v in value.normalize.split: + for v in value.normalize.splitWhitespace: case v of "c": result.incl(targetC) of "cpp", "c++": result.incl(targetCpp) @@ -192,7 +192,7 @@ proc parseSpec*(filename: string): TSpec = of "ccodecheck": result.ccodeCheck = e.value of "maxcodesize": discard parseInt(e.value, result.maxCodeSize) of "target", "targets": - for v in e.value.normalize.split: + for v in e.value.normalize.splitWhitespace: case v of "c": result.targets.incl(targetC) of "cpp", "c++": result.targets.incl(targetCpp) diff --git a/tests/testament/testamenthtml.templ b/tests/testament/testamenthtml.templ index f7477f3aa..9190f370e 100644 --- a/tests/testament/testamenthtml.templ +++ b/tests/testament/testamenthtml.templ @@ -29,7 +29,7 @@ */ /** - * + * * @param {number} index * @param {Element[]} elemArray * @param {executeForElement} executeOnItem @@ -69,17 +69,16 @@ } /** - * @param {string} tabId The id of the tabpanel div to search. * @param {string} [category] Optional bootstrap panel context class (danger, warning, info, success) * @param {executeForElement} executeOnEachPanel */ - function wholePanelAll(tabId, category, executeOnEachPanel) { + function wholePanelAll(category, executeOnEachPanel) { var selector = "div.panel"; if (typeof category === "string" && category) { selector += "-" + category; } - var jqPanels = $(selector, $("#" + tabId)); + var jqPanels = $(selector); /** @type {Element[]} */ var elemArray = jqPanels.toArray(); @@ -87,17 +86,16 @@ } /** - * @param {string} tabId The id of the tabpanel div to search. * @param {string} [category] Optional bootstrap panel context class (danger, warning, info, success) * @param {executeForElement} executeOnEachPanel */ - function panelBodyAll(tabId, category, executeOnEachPanelBody) { + function panelBodyAll(category, executeOnEachPanelBody) { var selector = "div.panel"; if (typeof category === "string" && category) { selector += "-" + category; } - var jqPanels = $(selector, $("#" + tabId)); + var jqPanels = $(selector); var jqPanelBodies = $("div.panel-body", jqPanels); /** @type {Element[]} */ @@ -107,35 +105,31 @@ } /** - * @param {string} tabId The id of the tabpanel div to search. * @param {string} [category] Optional bootstrap panel context class (danger, warning, info, success) */ - function showAll(tabId, category) { - wholePanelAll(tabId, category, executeShowOnElement); + function showAll(category) { + wholePanelAll(category, executeShowOnElement); } /** - * @param {string} tabId The id of the tabpanel div to search. * @param {string} [category] Optional bootstrap panel context class (danger, warning, info, success) */ - function hideAll(tabId, category) { - wholePanelAll(tabId, category, executeHideOnElement); + function hideAll(category) { + wholePanelAll(category, executeHideOnElement); } /** - * @param {string} tabId The id of the tabpanel div to search. * @param {string} [category] Optional bootstrap panel context class (danger, warning, info, success) */ - function expandAll(tabId, category) { - panelBodyAll(tabId, category, executeExpandOnElement); + function expandAll(category) { + panelBodyAll(category, executeExpandOnElement); } /** - * @param {string} tabId The id of the tabpanel div to search. * @param {string} [category] Optional bootstrap panel context class (danger, warning, info, success) */ - function collapseAll(tabId, category) { - panelBodyAll(tabId, category, executeCollapseOnElement); + function collapseAll(category) { + panelBodyAll(category, executeCollapseOnElement); } </script> </head> @@ -143,176 +137,161 @@ <div class="container"> <h1>Testament Test Results <small>Nim Tester</small></h1> #end proc -#proc generateHtmlTabListBegin*(outfile: File) = - <ul class="nav nav-tabs" role="tablist"> -#end proc -#proc generateHtmlTabListItem*(outfile: File, firstTabActiveClass, commitId, -# machineId, branch, hash, machineName: string) = - <li role="presentation" class="%firstTabActiveClass"> - <a href="#tab-commit-%commitId-machine-%machineId" aria-controls="tab-commit-%commitId-machine-%machineId" role="tab" data-toggle="tab"> - %branch#%hash@%machineName - </a> - </li> -#end proc -#proc generateHtmlTabListEnd*(outfile: File) = - </ul> -#end proc -#proc generateHtmlTabContentsBegin*(outfile: File) = - <div class="tab-content"> -#end proc -#proc generateHtmlTabPageBegin*(outfile: File, firstTabActiveClass, commitId, -# machineId, branch, hash, machineName, os, cpu: string, totalCount: BiggestInt, +#proc generateHtmlAllTestsBegin*(outfile: File, machine, commit, branch: string, +# totalCount: BiggestInt, # successCount: BiggestInt, successPercentage: string, # ignoredCount: BiggestInt, ignoredPercentage: string, -# failedCount: BiggestInt, failedPercentage: string) = - <div id="tab-commit-%commitId-machine-%machineId" class="tab-pane fade%firstTabActiveClass" role="tabpanel"> - <h2>%branch#%hash@%machineName</h2> - <dl class="dl-horizontal"> - <dt>Branch</dt> - <dd>%branch</dd> - <dt>Commit Hash</dt> - <dd><code>%hash</code></dd> - <dt>Machine Name</dt> - <dd>%machineName</dd> - <dt>OS</dt> - <dd>%os</dd> - <dt title="CPU Architecture">CPU</dt> - <dd>%cpu</dd> - <dt>All Tests</dt> - <dd> - <span class="glyphicon glyphicon-th-list"></span> - %totalCount - </dd> - <dt>Successful Tests</dt> - <dd> - <span class="glyphicon glyphicon-ok-sign"></span> - %successCount (%successPercentage) - </dd> - <dt>Skipped Tests</dt> - <dd> - <span class="glyphicon glyphicon-question-sign"></span> - %ignoredCount (%ignoredPercentage) - </dd> - <dt>Failed Tests</dt> - <dd> - <span class="glyphicon glyphicon-exclamation-sign"></span> - %failedCount (%failedPercentage) - </dd> - </dl> - <div class="table-responsive"> - <table class="table table-condensed"> - <tr> - <th class="text-right" style="vertical-align:middle">All Tests</th> - <td> - <div class="btn-group"> - <button class="btn btn-default" type="button" onclick="showAll('tab-commit-%commitId-machine-%machineId');">Show All</button> - <button class="btn btn-default" type="button" onclick="hideAll('tab-commit-%commitId-machine-%machineId');">Hide All</button> - <button class="btn btn-default" type="button" onclick="expandAll('tab-commit-%commitId-machine-%machineId');">Expand All</button> - <button class="btn btn-default" type="button" onclick="collapseAll('tab-commit-%commitId-machine-%machineId');">Collapse All</button> - </div> - </td> - </tr> - <tr> - <th class="text-right" style="vertical-align:middle">Successful Tests</th> - <td> - <div class="btn-group"> - <button class="btn btn-default" type="button" onclick="showAll('tab-commit-%commitId-machine-%machineId', 'success');">Show All</button> - <button class="btn btn-default" type="button" onclick="hideAll('tab-commit-%commitId-machine-%machineId', 'success');">Hide All</button> - <button class="btn btn-default" type="button" onclick="expandAll('tab-commit-%commitId-machine-%machineId', 'success');">Expand All</button> - <button class="btn btn-default" type="button" onclick="collapseAll('tab-commit-%commitId-machine-%machineId', 'success');">Collapse All</button> - </div> - </td> - </tr> - <tr> - <th class="text-right" style="vertical-align:middle">Skipped Tests</th> - <td> - <div class="btn-group"> - <button class="btn btn-default" type="button" onclick="showAll('tab-commit-%commitId-machine-%machineId', 'info');">Show All</button> - <button class="btn btn-default" type="button" onclick="hideAll('tab-commit-%commitId-machine-%machineId', 'info');">Hide All</button> - <button class="btn btn-default" type="button" onclick="expandAll('tab-commit-%commitId-machine-%machineId', 'info');">Expand All</button> - <button class="btn btn-default" type="button" onclick="collapseAll('tab-commit-%commitId-machine-%machineId', 'info');">Collapse All</button> - </div> - </td> - </tr> - <tr> - <th class="text-right" style="vertical-align:middle">Failed Tests</th> - <td> - <div class="btn-group"> - <button class="btn btn-default" type="button" onclick="showAll('tab-commit-%commitId-machine-%machineId', 'danger');">Show All</button> - <button class="btn btn-default" type="button" onclick="hideAll('tab-commit-%commitId-machine-%machineId', 'danger');">Hide All</button> - <button class="btn btn-default" type="button" onclick="expandAll('tab-commit-%commitId-machine-%machineId', 'danger');">Expand All</button> - <button class="btn btn-default" type="button" onclick="collapseAll('tab-commit-%commitId-machine-%machineId', 'danger');">Collapse All</button> - </div> - </td> - </tr> - </table> - </div> - <div class="panel-group"> +# failedCount: BiggestInt, failedPercentage: string, onlyFailing = false) = + <dl class="dl-horizontal"> + <dt>Hostname</dt> + <dd>%machine</dd> + <dt>Git Commit</dt> + <dd><code>%commit</code></dd> + <dt title="Git Branch reference">Branch ref.</dt> + <dd>%branch</dd> + </dl> + <dl class="dl-horizontal"> + <dt>All Tests</dt> + <dd> + <span class="glyphicon glyphicon-th-list"></span> + %totalCount + </dd> + <dt>Successful Tests</dt> + <dd> + <span class="glyphicon glyphicon-ok-sign"></span> + %successCount (%successPercentage) + </dd> + <dt>Skipped Tests</dt> + <dd> + <span class="glyphicon glyphicon-question-sign"></span> + %ignoredCount (%ignoredPercentage) + </dd> + <dt>Failed Tests</dt> + <dd> + <span class="glyphicon glyphicon-exclamation-sign"></span> + %failedCount (%failedPercentage) + </dd> + </dl> + <div class="table-responsive"> + <table class="table table-condensed"> +# if not onlyFailing: + <tr> + <th class="text-right" style="vertical-align:middle">All Tests</th> + <td> + <div class="btn-group"> + <button class="btn btn-default" type="button" onclick="showAll();">Show All</button> + <button class="btn btn-default" type="button" onclick="hideAll();">Hide All</button> + <button class="btn btn-default" type="button" onclick="expandAll();">Expand All</button> + <button class="btn btn-default" type="button" onclick="collapseAll();">Collapse All</button> + </div> + </td> + </tr> + <tr> + <th class="text-right" style="vertical-align:middle">Successful Tests</th> + <td> + <div class="btn-group"> + <button class="btn btn-default" type="button" onclick="showAll('success');">Show All</button> + <button class="btn btn-default" type="button" onclick="hideAll('success');">Hide All</button> + <button class="btn btn-default" type="button" onclick="expandAll('success');">Expand All</button> + <button class="btn btn-default" type="button" onclick="collapseAll('success');">Collapse All</button> + </div> + </td> + </tr> +# end if + <tr> + <th class="text-right" style="vertical-align:middle">Skipped Tests</th> + <td> + <div class="btn-group"> + <button class="btn btn-default" type="button" onclick="showAll('info');">Show All</button> + <button class="btn btn-default" type="button" onclick="hideAll('info');">Hide All</button> + <button class="btn btn-default" type="button" onclick="expandAll('info');">Expand All</button> + <button class="btn btn-default" type="button" onclick="collapseAll('info');">Collapse All</button> + </div> + </td> + </tr> + <tr> + <th class="text-right" style="vertical-align:middle">Failed Tests</th> + <td> + <div class="btn-group"> + <button class="btn btn-default" type="button" onclick="showAll('danger');">Show All</button> + <button class="btn btn-default" type="button" onclick="hideAll('danger');">Hide All</button> + <button class="btn btn-default" type="button" onclick="expandAll('danger');">Expand All</button> + <button class="btn btn-default" type="button" onclick="collapseAll('danger');">Collapse All</button> + </div> + </td> + </tr> + </table> + </div> + <div class="panel-group"> #end proc #proc generateHtmlTestresultPanelBegin*(outfile: File, trId, name, target, category, -# action, resultDescription, timestamp, result, resultSign, +# action, resultDescription, timestamp, result, resultSign, # panelCtxClass, textCtxClass, bgCtxClass: string) = - <div id="panel-testResult-%trId" class="panel panel-%panelCtxClass"> - <div class="panel-heading" style="cursor:pointer" data-toggle="collapse" data-target="#panel-body-testResult-%trId" aria-controls="panel-body-testResult-%trId" aria-expanded="false"> - <div class="row"> - <h4 class="col-xs-3 col-sm-1 panel-title"> - <span class="glyphicon glyphicon-%resultSign-sign"></span> - <strong>%resultDescription</strong> - </h4> - <h4 class="col-xs-1 panel-title"><span class="badge">%target</span></h4> - <h4 class="col-xs-5 col-sm-7 panel-title" title="%name"><code class="text-%textCtxClass">%name</code></h4> - <h4 class="col-xs-3 col-sm-3 panel-title text-right"><span class="badge">%category</span></h4> - </div> - </div> - <div id="panel-body-testResult-%trId" class="panel-body collapse bg-%bgCtxClass"> - <dl class="dl-horizontal"> - <dt>Name</dt> - <dd><code class="text-%textCtxClass">%name</code></dd> - <dt>Category</dt> - <dd><span class="badge">%category</span></dd> - <dt>Timestamp</dt> - <dd>%timestamp</dd> - <dt>Nim Action</dt> - <dd><code class="text-%textCtxClass">%action</code></dd> - <dt>Nim Backend Target</dt> - <dd><span class="badge">%target</span></dd> - <dt>Code</dt> - <dd><code class="text-%textCtxClass">%result</code></dd> - </dl> + <div id="panel-testResult-%trId" class="panel panel-%panelCtxClass"> + <div class="panel-heading" style="cursor:pointer" data-toggle="collapse" data-target="#panel-body-testResult-%trId" aria-controls="panel-body-testResult-%trId" aria-expanded="false"> + <div class="row"> + <h4 class="col-xs-3 col-sm-1 panel-title"> + <span class="glyphicon glyphicon-%resultSign-sign"></span> + <strong>%resultDescription</strong> + </h4> + <h4 class="col-xs-1 panel-title"><span class="badge">%target</span></h4> + <h4 class="col-xs-5 col-sm-7 panel-title" title="%name"><code class="text-%textCtxClass">%name</code></h4> + <h4 class="col-xs-3 col-sm-3 panel-title text-right"><span class="badge">%category</span></h4> + </div> + </div> + <div id="panel-body-testResult-%trId" class="panel-body collapse bg-%bgCtxClass"> + <dl class="dl-horizontal"> + <dt>Name</dt> + <dd><code class="text-%textCtxClass">%name</code></dd> + <dt>Category</dt> + <dd><span class="badge">%category</span></dd> + <dt>Timestamp</dt> + <dd>%timestamp</dd> + <dt>Nim Action</dt> + <dd><code class="text-%textCtxClass">%action</code></dd> + <dt>Nim Backend Target</dt> + <dd><span class="badge">%target</span></dd> + <dt>Code</dt> + <dd><code class="text-%textCtxClass">%result</code></dd> + </dl> #end proc #proc generateHtmlTestresultOutputDetails*(outfile: File, expected, gotten: string) = - <div class="table-responsive"> - <table class="table table-condensed"> - <thead> - <tr> - <th>Expected</th> - <th>Actual</th> - </tr> - </thead> - <tbody> - <tr> - <td><pre>%expected</pre></td> - <td><pre>%gotten</pre></td> - </tr> - </tbody> - </table> - </div> + <div class="table-responsive"> + <table class="table table-condensed"> + <thead> + <tr> + <th>Expected</th> + <th>Actual</th> + </tr> + </thead> + <tbody> + <tr> + <td><pre>%expected</pre></td> + <td><pre>%gotten</pre></td> + </tr> + </tbody> + </table> + </div> #end proc #proc generateHtmlTestresultOutputNone*(outfile: File) = - <p class="sr-only">No output details</p> + <p class="sr-only">No output details</p> #end proc #proc generateHtmlTestresultPanelEnd*(outfile: File) = - </div> - </div> -#end proc -#proc generateHtmlTabPageEnd*(outfile: File) = </div> </div> #end proc -#proc generateHtmlTabContentsEnd*(outfile: File) = +#proc generateHtmlAllTestsEnd*(outfile: File) = </div> #end proc -#proc generateHtmlEnd*(outfile: File) = +#proc generateHtmlEnd*(outfile: File, timestamp: string) = + <hr /> + <footer> + <p> + Report generated by: <code>testament</code> – Nim Tester + <br /> + Made with Nim. Generated on: %timestamp + </p> + </footer> </div> </body> -</html> \ No newline at end of file +</html> diff --git a/tools/niminst/niminst.nim b/tools/niminst/niminst.nim index ab0ce6a5b..9c15326b0 100644 --- a/tools/niminst/niminst.nim +++ b/tools/niminst/niminst.nim @@ -15,7 +15,7 @@ when haveZipLib: import os, osproc, strutils, parseopt, parsecfg, strtabs, streams, debcreation, - "../../compiler/securehash" + securehash const maxOS = 20 # max number of OSes diff --git a/web/website.ini b/web/website.ini index d8deb2d70..32b1936d5 100644 --- a/web/website.ini +++ b/web/website.ini @@ -64,7 +64,7 @@ srcdoc2: "pure/asyncfile;pure/asyncftpclient;pure/lenientops" srcdoc2: "pure/md5;pure/rationals" srcdoc2: "posix/posix;pure/distros;pure/oswalkdir" srcdoc2: "pure/collections/heapqueue" -srcdoc2: "pure/fenv;impure/rdstdin;pure/strformat" +srcdoc2: "pure/fenv;pure/securehash;impure/rdstdin;pure/strformat" srcdoc2: "pure/segfaults" srcdoc2: "pure/basic2d;pure/basic3d;pure/mersenne;pure/coro;pure/httpcore" srcdoc2: "pure/bitops;pure/nimtracker;pure/punycode;pure/volatile;js/asyncjs" |