mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-04 04:02:41 +00:00
make at least bootstrapping work
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -58,6 +58,7 @@ dist/
|
||||
.*/
|
||||
~*
|
||||
|
||||
# testament cruft
|
||||
# testament cruft; TODO: generate these in a gitignore'd dir in the first place.
|
||||
testresults/
|
||||
test.txt
|
||||
/test.ini
|
||||
|
||||
10
changelog.md
10
changelog.md
@@ -22,7 +22,8 @@
|
||||
become an error in the future.
|
||||
- The ``'c`` and ``'C'`` prefix for octal literals is now deprecated to
|
||||
bring the language in line with the standard library (e.g. ``parseOct``).
|
||||
|
||||
- The dot style for import paths (e.g ``import path.to.module`` instead of
|
||||
``import path/to/module``) has been deprecated.
|
||||
|
||||
#### Breaking changes in the standard library
|
||||
|
||||
@@ -59,6 +60,8 @@
|
||||
1-based coordinates on POSIX for correct behaviour; the Windows behaviour
|
||||
was always correct).
|
||||
|
||||
- ``lineInfoObj`` now returns absolute path instead of project path.
|
||||
It's used by ``lineInfo``, ``check``, ``expect``, ``require``, etc.
|
||||
|
||||
#### Breaking changes in the compiler
|
||||
|
||||
@@ -193,4 +196,9 @@
|
||||
- Nintendo Switch was added as a new platform target. See [the compiler user guide](https://nim-lang.org/docs/nimc.html)
|
||||
for more info.
|
||||
|
||||
- macros.bindSym now capable to accepts not only literal string or string constant expression.
|
||||
bindSym enhancement make it also can accepts computed string or ident node inside macros /
|
||||
compile time functions / static blocks. Only in templates / regular code it retains it's old behavior.
|
||||
This new feature can be accessed via {.experimental: "dynamicBindSym".} pragma/switch
|
||||
|
||||
### Bugfixes
|
||||
|
||||
@@ -1085,7 +1085,7 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
|
||||
# appendChar(s, 'z');
|
||||
# }
|
||||
var
|
||||
a, dest: TLoc
|
||||
a, dest, call: TLoc
|
||||
appends, lens: Rope
|
||||
assert(d.k == locNone)
|
||||
var L = 0
|
||||
@@ -1109,8 +1109,9 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
|
||||
linefmt(p, cpsStmts, "#prepareAdd($1, $2$3);$n",
|
||||
addrLoc(p.config, dest), lens, rope(L))
|
||||
else:
|
||||
linefmt(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n",
|
||||
rdLoc(dest), lens, rope(L))
|
||||
initLoc(call, locCall, e, OnHeap)
|
||||
call.r = ropecg(p.module, "#resizeString($1, $2$3)", [rdLoc(dest), lens, rope(L)])
|
||||
genAssignment(p, dest, call, {})
|
||||
add(p.s(cpsStmts), appends)
|
||||
gcUsage(p.config, e)
|
||||
|
||||
@@ -1119,17 +1120,20 @@ 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) #incrSeqV3(&($1)->Sup, $3);$n"
|
||||
"($2) #incrSeqV3(&($1)->Sup, $3)"
|
||||
else:
|
||||
"$1 = ($2) #incrSeqV3($1, $3);$n"
|
||||
var a, b, dest, tmpL: TLoc
|
||||
"($2) #incrSeqV3($1, $3)"
|
||||
var a, b, dest, tmpL, call: TLoc
|
||||
initLocExpr(p, e.sons[1], a)
|
||||
initLocExpr(p, e.sons[2], b)
|
||||
let seqType = skipTypes(e.sons[1].typ, {tyVar})
|
||||
lineCg(p, cpsStmts, seqAppendPattern, [
|
||||
rdLoc(a),
|
||||
getTypeDesc(p.module, e.sons[1].typ),
|
||||
genTypeInfo(p.module, seqType, e.info)])
|
||||
initLoc(call, locCall, e, OnHeap)
|
||||
call.r = ropecg(p.module, seqAppendPattern, [rdLoc(a),
|
||||
getTypeDesc(p.module, e.sons[1].typ),
|
||||
genTypeInfo(p.module, seqType, e.info)])
|
||||
# emit the write barrier if required, but we can always move here, so
|
||||
# use 'genRefAssign' for the seq.
|
||||
genRefAssign(p, a, call, {})
|
||||
#if bt != b.t:
|
||||
# echo "YES ", e.info, " new: ", typeToString(bt), " old: ", typeToString(b.t)
|
||||
initLoc(dest, locExpr, e.sons[2], OnHeap)
|
||||
@@ -1536,7 +1540,7 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
|
||||
if p.config.selectedGc == gcDestructors:
|
||||
genCall(p, e, d)
|
||||
return
|
||||
var a, b: TLoc
|
||||
var a, b, call: TLoc
|
||||
assert(d.k == locNone)
|
||||
var x = e.sons[1]
|
||||
if x.kind in {nkAddr, nkHiddenAddr}: x = x[0]
|
||||
@@ -1544,20 +1548,30 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
|
||||
initLocExpr(p, e.sons[2], b)
|
||||
let t = skipTypes(e.sons[1].typ, {tyVar})
|
||||
let setLenPattern = if not p.module.compileToCpp:
|
||||
"$1 = ($3) #setLengthSeqV2(&($1)->Sup, $4, $2);$n"
|
||||
"($3) #setLengthSeqV2(&($1)->Sup, $4, $2)"
|
||||
else:
|
||||
"$1 = ($3) #setLengthSeqV2($1, $4, $2);$n"
|
||||
"($3) #setLengthSeqV2($1, $4, $2)"
|
||||
|
||||
lineCg(p, cpsStmts, setLenPattern, [
|
||||
initLoc(call, locCall, e, OnHeap)
|
||||
call.r = ropecg(p.module, setLenPattern, [
|
||||
rdLoc(a), rdLoc(b), getTypeDesc(p.module, t),
|
||||
genTypeInfo(p.module, t.skipTypes(abstractInst), e.info)])
|
||||
genAssignment(p, a, call, {})
|
||||
gcUsage(p.config, e)
|
||||
|
||||
proc genSetLengthStr(p: BProc, e: PNode, d: var TLoc) =
|
||||
if p.config.selectedGc == gcDestructors:
|
||||
binaryStmtAddr(p, e, d, "#setLengthStrV2($1, $2);$n")
|
||||
else:
|
||||
binaryStmt(p, e, d, "$1 = #setLengthStr($1, $2);$n")
|
||||
var a, b, call: TLoc
|
||||
if d.k != locNone: internalError(p.config, e.info, "genSetLengthStr")
|
||||
initLocExpr(p, e.sons[1], a)
|
||||
initLocExpr(p, e.sons[2], b)
|
||||
|
||||
initLoc(call, locCall, e, OnHeap)
|
||||
call.r = ropecg(p.module, "#setLengthStr($1, $2)", [
|
||||
rdLoc(a), rdLoc(b)])
|
||||
genAssignment(p, a, call, {})
|
||||
gcUsage(p.config, e)
|
||||
|
||||
proc genSwap(p: BProc, e: PNode, d: var TLoc) =
|
||||
@@ -1878,7 +1892,12 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
if p.config.selectedGC == gcDestructors:
|
||||
binaryStmtAddr(p, e, d, "#nimAddCharV1($1, $2);$n")
|
||||
else:
|
||||
binaryStmt(p, e, d, "$1 = #addChar($1, $2);$n")
|
||||
var dest, b, call: TLoc
|
||||
initLoc(call, locCall, e, OnHeap)
|
||||
initLocExpr(p, e.sons[1], dest)
|
||||
initLocExpr(p, e.sons[2], b)
|
||||
call.r = ropecg(p.module, "#addChar($1, $2)", [rdLoc(dest), rdLoc(b)])
|
||||
genAssignment(p, dest, call, {})
|
||||
of mAppendStrStr: genStrAppend(p, e, d)
|
||||
of mAppendSeqElem:
|
||||
if p.config.selectedGc == gcDestructors:
|
||||
|
||||
@@ -588,7 +588,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
|
||||
let branch = n[i]
|
||||
case branch.kind
|
||||
of nkOfBranch:
|
||||
branch[1] = ctx.convertExprBodyToAsgn(branch[1], tmp)
|
||||
branch[^1] = ctx.convertExprBodyToAsgn(branch[^1], tmp)
|
||||
of nkElse:
|
||||
branch[0] = ctx.convertExprBodyToAsgn(branch[0], tmp)
|
||||
else:
|
||||
|
||||
@@ -73,3 +73,4 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
defineSymbol("nimNotNil")
|
||||
defineSymbol("nimVmExportFixed")
|
||||
defineSymbol("nimNewRuntime")
|
||||
defineSymbol("nimIncrSeqV3")
|
||||
|
||||
@@ -259,7 +259,7 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe
|
||||
of tkSpaces, tkInvalid:
|
||||
add(result, literal)
|
||||
of tkCurlyDotLe:
|
||||
dispA(d.conf, result, "<span>" & # This span is required for the JS to work properly
|
||||
dispA(d.conf, result, "<span>" & # This span is required for the JS to work properly
|
||||
"""<span class="Other">{</span><span class="Other pragmadots">...</span><span class="Other">}</span>
|
||||
</span>
|
||||
<span class="pragmawrap">
|
||||
@@ -517,12 +517,11 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
|
||||
path = path[cwd.len+1 .. ^1].replace('\\', '/')
|
||||
let gitUrl = getConfigVar(d.conf, "git.url")
|
||||
if gitUrl.len > 0:
|
||||
var commit = getConfigVar(d.conf, "git.commit")
|
||||
if commit.len == 0: commit = "master"
|
||||
let commit = getConfigVar(d.conf, "git.commit", "master")
|
||||
let develBranch = getConfigVar(d.conf, "git.devel", "devel")
|
||||
dispA(d.conf, seeSrcRope, "$1", "", [ropeFormatNamedVars(d.conf, docItemSeeSrc,
|
||||
["path", "line", "url", "commit"], [rope path,
|
||||
rope($n.info.line), rope gitUrl,
|
||||
rope commit])])
|
||||
["path", "line", "url", "commit", "devel"], [rope path,
|
||||
rope($n.info.line), rope gitUrl, rope commit, rope develBranch])])
|
||||
|
||||
add(d.section[k], ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.item"),
|
||||
["name", "header", "desc", "itemID", "header_plain", "itemSym",
|
||||
|
||||
@@ -92,7 +92,7 @@ compiler nintendoSwitchGCC:
|
||||
optSize: " -Os -ffast-math ",
|
||||
compilerExe: "aarch64-none-elf-gcc",
|
||||
cppCompiler: "aarch64-none-elf-g++",
|
||||
compileTmpl: "-MMD -MP -MF $dfile -c $options $include -o $objfile $file",
|
||||
compileTmpl: "-w -MMD -MP -MF $dfile -c $options $include -o $objfile $file",
|
||||
buildGui: " -mwindows",
|
||||
buildDll: " -shared",
|
||||
buildLib: "aarch64-none-elf-gcc-ar rcs $libfile $objfiles",
|
||||
@@ -645,7 +645,7 @@ proc compileCFile(conf: ConfigRef; list: CFileList, script: var Rope, cmds: var
|
||||
if optCompileOnly notin conf.globalOptions:
|
||||
add(cmds, compileCmd)
|
||||
let (_, name, _) = splitFile(it.cname)
|
||||
add(prettyCmds, "CC: " & name)
|
||||
add(prettyCmds, if hintCC in conf.notes: "CC: " & name else: "")
|
||||
if optGenScript in conf.globalOptions:
|
||||
add(script, compileCmd)
|
||||
add(script, "\n")
|
||||
@@ -659,7 +659,7 @@ proc getLinkCmd(conf: ConfigRef; projectfile, objfiles: string): string =
|
||||
libname = getCurrentDir() / libname
|
||||
else:
|
||||
libname = (libNameTmpl(conf) % splitFile(conf.projectName).name)
|
||||
result = CC[conf.cCompiler].buildLib % ["libfile", libname,
|
||||
result = CC[conf.cCompiler].buildLib % ["libfile", quoteShell(libname),
|
||||
"objfiles", objfiles]
|
||||
else:
|
||||
var linkerExe = getConfigVar(conf, conf.cCompiler, ".linkerexe")
|
||||
@@ -668,8 +668,10 @@ proc getLinkCmd(conf: ConfigRef; projectfile, objfiles: string): string =
|
||||
if needsExeExt(conf): linkerExe = addFileExt(linkerExe, "exe")
|
||||
if noAbsolutePaths(conf): result = linkerExe
|
||||
else: result = joinPath(conf.cCompilerpath, linkerExe)
|
||||
let buildgui = if optGenGuiApp in conf.globalOptions: CC[conf.cCompiler].buildGui
|
||||
else: ""
|
||||
let buildgui = if optGenGuiApp in conf.globalOptions and conf.target.targetOS == osWindows:
|
||||
CC[conf.cCompiler].buildGui
|
||||
else:
|
||||
""
|
||||
var exefile, builddll: string
|
||||
if optGenDynLib in conf.globalOptions:
|
||||
exefile = platform.OS[conf.target.targetOS].dllFrmt % splitFile(projectfile).name
|
||||
@@ -771,7 +773,8 @@ proc callCCompiler*(conf: ConfigRef; projectfile: string) =
|
||||
var prettyCmds: TStringSeq = @[]
|
||||
let prettyCb = proc (idx: int) =
|
||||
when declared(echo):
|
||||
echo prettyCmds[idx]
|
||||
let cmd = prettyCmds[idx]
|
||||
if cmd != "": echo cmd
|
||||
compileCFile(conf, conf.toCompile, script, cmds, prettyCmds)
|
||||
if optCompileOnly notin conf.globalOptions:
|
||||
execCmdsInParallel(conf, cmds, prettyCb)
|
||||
|
||||
@@ -222,7 +222,7 @@ proc interestingIterVar(s: PSym): bool {.inline.} =
|
||||
# XXX optimization: Only lift the variable if it lives across
|
||||
# yield/return boundaries! This can potentially speed up
|
||||
# closure iterators quite a bit.
|
||||
result = s.kind in {skVar, skLet, skTemp, skForVar} and sfGlobal notin s.flags
|
||||
result = s.kind in {skResult, skVar, skLet, skTemp, skForVar} and sfGlobal notin s.flags
|
||||
|
||||
template isIterator*(owner: PSym): bool =
|
||||
owner.kind == skIterator and owner.typ.callConv == ccClosure
|
||||
@@ -458,6 +458,10 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||
of nkLambdaKinds, nkIteratorDef, nkFuncDef:
|
||||
if n.typ != nil:
|
||||
detectCapturedVars(n[namePos], owner, c)
|
||||
of nkReturnStmt:
|
||||
if n[0].kind in {nkAsgn, nkFastAsgn}:
|
||||
detectCapturedVars(n[0].sons[1], owner, c)
|
||||
else: assert n[0].kind == nkEmpty
|
||||
else:
|
||||
for i in 0..<n.len:
|
||||
detectCapturedVars(n[i], owner, c)
|
||||
@@ -687,6 +691,13 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
|
||||
if n.len == 2:
|
||||
n.sons[1] = liftCapturedVars(n[1], owner, d, c)
|
||||
if n[1].kind == nkClosure: result = n[1]
|
||||
of nkReturnStmt:
|
||||
if n[0].kind in {nkAsgn, nkFastAsgn}:
|
||||
# we have a `result = result` expression produced by the closure
|
||||
# transform, let's not touch the LHS in order to make the lifting pass
|
||||
# correct when `result` is lifted
|
||||
n[0].sons[1] = liftCapturedVars(n[0].sons[1], owner, d, c)
|
||||
else: assert n[0].kind == nkEmpty
|
||||
else:
|
||||
if owner.isIterator:
|
||||
if nfLL in n.flags:
|
||||
@@ -757,6 +768,7 @@ proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool): PN
|
||||
if d.somethingToDo:
|
||||
var c = initLiftingPass(fn)
|
||||
result = liftCapturedVars(body, fn, d, c)
|
||||
# echo renderTree(result, {renderIds})
|
||||
if c.envvars.getOrDefault(fn.id) != nil:
|
||||
result = newTree(nkStmtList, rawClosureCreation(fn, d, c), result)
|
||||
else:
|
||||
|
||||
@@ -37,7 +37,7 @@ type
|
||||
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
|
||||
warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
|
||||
warnInconsistentSpacing, warnUser,
|
||||
hintSuccess, hintSuccessX,
|
||||
hintSuccess, hintSuccessX, hintCC,
|
||||
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
|
||||
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
|
||||
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
|
||||
@@ -94,6 +94,7 @@ const
|
||||
warnUser: "$1",
|
||||
hintSuccess: "operation successful",
|
||||
hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#)",
|
||||
hintCC: "CC: \'$1\'", # unused
|
||||
hintLineTooLong: "line too long",
|
||||
hintXDeclaredButNotUsed: "'$1' is declared but not used",
|
||||
hintConvToBaseNotNeeded: "conversion to base object is not needed",
|
||||
@@ -136,7 +137,7 @@ const
|
||||
"Spacing", "User"]
|
||||
|
||||
HintsToStr* = [
|
||||
"Success", "SuccessX", "LineTooLong",
|
||||
"Success", "SuccessX", "CC", "LineTooLong",
|
||||
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
|
||||
"ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
|
||||
"Path", "CondTrue", "Name", "Pattern", "Exec", "Link", "Dependency",
|
||||
|
||||
@@ -45,13 +45,6 @@ when false:
|
||||
if best.len > 0 and fileExists(res):
|
||||
result = res
|
||||
|
||||
const stdlibDirs = [
|
||||
"pure", "core", "arch",
|
||||
"pure/collections",
|
||||
"pure/concurrency", "impure",
|
||||
"wrappers", "wrappers/linenoise",
|
||||
"windows", "posix", "js"]
|
||||
|
||||
when false:
|
||||
proc resolveDollar(project, source, pkg, subdir: string; info: TLineInfo): string =
|
||||
template attempt(a) =
|
||||
@@ -120,7 +113,9 @@ proc getModuleName*(conf: ConfigRef; n: PNode): string =
|
||||
case n.kind
|
||||
of nkStrLit, nkRStrLit, nkTripleStrLit:
|
||||
try:
|
||||
result = pathSubs(conf, n.strVal, toFullPath(conf, n.info).splitFile().dir)
|
||||
result =
|
||||
pathSubs(conf, n.strVal, toFullPath(conf, n.info).splitFile().dir)
|
||||
.replace(" ")
|
||||
except ValueError:
|
||||
localError(conf, n.info, "invalid path: " & n.strVal)
|
||||
result = n.strVal
|
||||
@@ -147,16 +142,9 @@ proc getModuleName*(conf: ConfigRef; n: PNode): string =
|
||||
result = ""
|
||||
else:
|
||||
let modname = getModuleName(conf, n[2])
|
||||
if $n1 == "std":
|
||||
template attempt(a) =
|
||||
let x = addFileExt(a, "nim")
|
||||
if fileExists(x): return x
|
||||
for candidate in stdlibDirs:
|
||||
attempt(conf.libpath / candidate / modname)
|
||||
|
||||
# hacky way to implement 'x / y /../ z':
|
||||
result = getModuleName(conf, n1)
|
||||
result.add renderTree(n0, {renderNoComments})
|
||||
result.add renderTree(n0, {renderNoComments}).replace(" ")
|
||||
result.add modname
|
||||
of nkPrefix:
|
||||
when false:
|
||||
@@ -167,6 +155,7 @@ proc getModuleName*(conf: ConfigRef; n: PNode): string =
|
||||
# hacky way to implement 'x / y /../ z':
|
||||
result = renderTree(n, {renderNoComments}).replace(" ")
|
||||
of nkDotExpr:
|
||||
localError(conf, n.info, warnDeprecated, "using '.' instead of '/' in import paths")
|
||||
result = renderTree(n, {renderNoComments}).replace(".", "/")
|
||||
of nkImportAs:
|
||||
result = getModuleName(conf, n.sons[0])
|
||||
|
||||
@@ -116,7 +116,8 @@ type
|
||||
callOperator,
|
||||
parallel,
|
||||
destructor,
|
||||
notnil
|
||||
notnil,
|
||||
dynamicBindSym
|
||||
|
||||
SymbolFilesOption* = enum
|
||||
disabledSf, writeOnlySf, readOnlySf, v2Sf
|
||||
@@ -406,8 +407,8 @@ proc mainCommandArg*(conf: ConfigRef): string =
|
||||
proc existsConfigVar*(conf: ConfigRef; key: string): bool =
|
||||
result = hasKey(conf.configVars, key)
|
||||
|
||||
proc getConfigVar*(conf: ConfigRef; key: string): string =
|
||||
result = conf.configVars.getOrDefault key
|
||||
proc getConfigVar*(conf: ConfigRef; key: string, default = ""): string =
|
||||
result = conf.configVars.getOrDefault(key, default)
|
||||
|
||||
proc setConfigVar*(conf: ConfigRef; key, val: string) =
|
||||
conf.configVars[key] = val
|
||||
@@ -556,13 +557,28 @@ proc findFile*(conf: ConfigRef; f: string; suppressStdlib = false): string {.pro
|
||||
result = rawFindFile2(conf, f.toLowerAscii)
|
||||
patchModule(conf)
|
||||
|
||||
const stdlibDirs = [
|
||||
"pure", "core", "arch",
|
||||
"pure/collections",
|
||||
"pure/concurrency", "impure",
|
||||
"wrappers", "wrappers/linenoise",
|
||||
"windows", "posix", "js"]
|
||||
|
||||
proc findModule*(conf: ConfigRef; modulename, currentModule: string): string =
|
||||
# returns path to module
|
||||
const pkgPrefix = "pkg/"
|
||||
let m = addFileExt(modulename, NimExt)
|
||||
const stdPrefix = "std/"
|
||||
var m = addFileExt(modulename, NimExt)
|
||||
if m.startsWith(pkgPrefix):
|
||||
result = findFile(conf, m.substr(pkgPrefix.len), suppressStdlib = true)
|
||||
else:
|
||||
if m.startsWith(stdPrefix):
|
||||
let stripped = m.substr(stdPrefix.len)
|
||||
for candidate in stdlibDirs:
|
||||
let path = (conf.libpath / candidate / stripped)
|
||||
if fileExists(path):
|
||||
m = path
|
||||
break
|
||||
let currentPath = currentModule.splitFile.dir
|
||||
result = currentPath / m
|
||||
if not existsFile(result):
|
||||
|
||||
@@ -568,6 +568,7 @@ proc parsePar(p: var TParser): PNode =
|
||||
result = newNodeP(nkPar, p)
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
flexComment(p, result)
|
||||
if p.tok.tokType in {tkDiscard, tkInclude, tkIf, tkWhile, tkCase,
|
||||
tkTry, tkDefer, tkFinally, tkExcept, tkFor, tkBlock,
|
||||
tkConst, tkLet, tkWhen, tkVar,
|
||||
|
||||
@@ -627,15 +627,23 @@ proc gstmts(g: var TSrcGen, n: PNode, c: TContext, doIndent=true) =
|
||||
gcoms(g)
|
||||
if doIndent: dedent(g)
|
||||
else:
|
||||
if rfLongMode in c.flags: indentNL(g)
|
||||
indentNL(g)
|
||||
gsub(g, n)
|
||||
gcoms(g)
|
||||
dedent(g)
|
||||
optNL(g)
|
||||
if rfLongMode in c.flags: dedent(g)
|
||||
|
||||
|
||||
proc gcond(g: var TSrcGen, n: PNode) =
|
||||
if n.kind == nkStmtListExpr:
|
||||
put(g, tkParLe, "(")
|
||||
gsub(g, n)
|
||||
if n.kind == nkStmtListExpr:
|
||||
put(g, tkParRi, ")")
|
||||
|
||||
proc gif(g: var TSrcGen, n: PNode) =
|
||||
var c: TContext
|
||||
gsub(g, n.sons[0].sons[0])
|
||||
gcond(g, n.sons[0].sons[0])
|
||||
initContext(c)
|
||||
putWithSpace(g, tkColon, ":")
|
||||
if longMode(g, n) or (lsub(g, n.sons[0].sons[1]) + g.lineLen > MaxLineLen):
|
||||
@@ -650,7 +658,7 @@ proc gif(g: var TSrcGen, n: PNode) =
|
||||
proc gwhile(g: var TSrcGen, n: PNode) =
|
||||
var c: TContext
|
||||
putWithSpace(g, tkWhile, "while")
|
||||
gsub(g, n.sons[0])
|
||||
gcond(g, n.sons[0])
|
||||
putWithSpace(g, tkColon, ":")
|
||||
initContext(c)
|
||||
if longMode(g, n) or (lsub(g, n.sons[1]) + g.lineLen > MaxLineLen):
|
||||
@@ -714,7 +722,7 @@ proc gcase(g: var TSrcGen, n: PNode) =
|
||||
var last = if n.sons[length-1].kind == nkElse: -2 else: -1
|
||||
if longMode(g, n, 0, last): incl(c.flags, rfLongMode)
|
||||
putWithSpace(g, tkCase, "case")
|
||||
gsub(g, n.sons[0])
|
||||
gcond(g, n.sons[0])
|
||||
gcoms(g)
|
||||
optNL(g)
|
||||
gsons(g, n, c, 1, last)
|
||||
@@ -785,10 +793,7 @@ proc gblock(g: var TSrcGen, n: PNode) =
|
||||
if longMode(g, n) or (lsub(g, n.sons[1]) + g.lineLen > MaxLineLen):
|
||||
incl(c.flags, rfLongMode)
|
||||
gcoms(g)
|
||||
# XXX I don't get why this is needed here! gstmts should already handle this!
|
||||
indentNL(g)
|
||||
gstmts(g, n.sons[1], c)
|
||||
dedent(g)
|
||||
|
||||
proc gstaticStmt(g: var TSrcGen, n: PNode) =
|
||||
var c: TContext
|
||||
@@ -1104,13 +1109,13 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
put(g, tkAccent, "`")
|
||||
of nkIfExpr:
|
||||
putWithSpace(g, tkIf, "if")
|
||||
if n.len > 0: gsub(g, n.sons[0], 0)
|
||||
if n.len > 0: gcond(g, n.sons[0].sons[0])
|
||||
putWithSpace(g, tkColon, ":")
|
||||
if n.len > 0: gsub(g, n.sons[0], 1)
|
||||
gsons(g, n, emptyContext, 1)
|
||||
of nkElifExpr:
|
||||
putWithSpace(g, tkElif, " elif")
|
||||
gsub(g, n, 0)
|
||||
gcond(g, n[0])
|
||||
putWithSpace(g, tkColon, ":")
|
||||
gsub(g, n, 1)
|
||||
of nkElseExpr:
|
||||
|
||||
@@ -608,16 +608,18 @@ proc myProcess(context: PPassContext, n: PNode): PNode =
|
||||
rod.storeNode(c.graph, c.module, result)
|
||||
|
||||
proc testExamples(c: PContext) =
|
||||
let outputDir = c.config.getNimcacheDir / "runnableExamples"
|
||||
createDir(outputDir)
|
||||
let inp = toFullPath(c.config, c.module.info)
|
||||
let outp = inp.changeFileExt"" & "_examples.nim"
|
||||
let outp = outputDir / extractFilename(inp.changeFileExt"" & "_examples.nim")
|
||||
let nimcache = outp.changeFileExt"" & "_nimcache"
|
||||
renderModule(c.runnableExamples, inp, outp)
|
||||
renderModule(c.runnableExamples, inp, outp, conf = c.config)
|
||||
let backend = if isDefined(c.config, "js"): "js"
|
||||
elif isDefined(c.config, "cpp"): "cpp"
|
||||
elif isDefined(c.config, "objc"): "objc"
|
||||
else: "c"
|
||||
if os.execShellCmd(os.getAppFilename() & " " & backend & " --nimcache:" & nimcache & " -r " & outp) != 0:
|
||||
quit "[Examples] failed"
|
||||
quit "[Examples] failed: see " & outp
|
||||
else:
|
||||
removeFile(outp)
|
||||
removeFile(outp.changeFileExt(ExeExt))
|
||||
|
||||
@@ -505,7 +505,15 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
|
||||
|
||||
for i in 1..sonsLen(n)-1:
|
||||
let formal = s.ast.sons[genericParamsPos].sons[i-1].typ
|
||||
let arg = n[i].typ
|
||||
var arg = n[i].typ
|
||||
# try transforming the argument into a static one before feeding it into
|
||||
# typeRel
|
||||
if formal.kind == tyStatic and arg.kind != tyStatic:
|
||||
let evaluated = c.semTryConstExpr(c, n[i])
|
||||
if evaluated != nil:
|
||||
arg = newTypeS(tyStatic, c)
|
||||
arg.sons = @[evaluated.typ]
|
||||
arg.n = evaluated
|
||||
let tm = typeRel(m, formal, arg)
|
||||
if tm in {isNone, isConvertible}: return nil
|
||||
var newInst = generateInstance(c, s, m.bindings, n.info)
|
||||
|
||||
@@ -2031,9 +2031,10 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||
c.runnableExamples = newTree(nkStmtList,
|
||||
newTree(nkImportStmt, newStrNode(nkStrLit, expandFilename(inp))))
|
||||
let imports = newTree(nkStmtList)
|
||||
extractImports(n.lastSon, imports)
|
||||
var saved_lastSon = copyTree n.lastSon
|
||||
extractImports(saved_lastSon, imports)
|
||||
for imp in imports: c.runnableExamples.add imp
|
||||
c.runnableExamples.add newTree(nkBlockStmt, c.graph.emptyNode, copyTree n.lastSon)
|
||||
c.runnableExamples.add newTree(nkBlockStmt, c.graph.emptyNode, copyTree saved_lastSon)
|
||||
result = setMs(n, s)
|
||||
else:
|
||||
result = c.graph.emptyNode
|
||||
@@ -2126,7 +2127,7 @@ proc semSetConstr(c: PContext, n: PNode): PNode =
|
||||
n.sons[i] = semExprWithType(c, n.sons[i])
|
||||
if typ == nil:
|
||||
typ = skipTypes(n.sons[i].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
|
||||
if not isOrdinalType(typ):
|
||||
if not isOrdinalType(typ, allowEnumWithHoles=true):
|
||||
localError(c.config, n.info, errOrdinalTypeExpected)
|
||||
typ = makeRangeType(c, 0, MaxSetElements-1, n.info)
|
||||
elif lengthOrd(c.config, typ) > MaxSetElements:
|
||||
|
||||
@@ -609,7 +609,7 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
|
||||
if computeSize(g.config, a.typ) < 0:
|
||||
localError(g.config, a.info, "cannot evaluate 'sizeof' because its type is not defined completely")
|
||||
result = nil
|
||||
elif skipTypes(a.typ, typedescInst+{tyRange}).kind in
|
||||
elif skipTypes(a.typ, typedescInst+{tyRange, tyArray}).kind in
|
||||
IntegralTypes+NilableTypes+{tySet}:
|
||||
#{tyArray,tyObject,tyTuple}:
|
||||
result = newIntNodeT(getSize(g.config, a.typ), n, g)
|
||||
|
||||
@@ -207,6 +207,67 @@ proc semBindSym(c: PContext, n: PNode): PNode =
|
||||
else:
|
||||
errorUndeclaredIdentifier(c, n.sons[1].info, sl.strVal)
|
||||
|
||||
proc opBindSym(c: PContext, scope: PScope, n: PNode, isMixin: int, info: PNode): PNode =
|
||||
if n.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit, nkIdent}:
|
||||
localError(c.config, info.info, errStringOrIdentNodeExpected)
|
||||
return errorNode(c, n)
|
||||
|
||||
if isMixin < 0 or isMixin > high(TSymChoiceRule).int:
|
||||
localError(c.config, info.info, errConstExprExpected)
|
||||
return errorNode(c, n)
|
||||
|
||||
let id = if n.kind == nkIdent: n
|
||||
else: newIdentNode(getIdent(c.cache, n.strVal), info.info)
|
||||
|
||||
let tmpScope = c.currentScope
|
||||
c.currentScope = scope
|
||||
let s = qualifiedLookUp(c, id, {checkUndeclared})
|
||||
if s != nil:
|
||||
# we need to mark all symbols:
|
||||
result = symChoice(c, id, s, TSymChoiceRule(isMixin))
|
||||
else:
|
||||
errorUndeclaredIdentifier(c, info.info, if n.kind == nkIdent: n.ident.s
|
||||
else: n.strVal)
|
||||
c.currentScope = tmpScope
|
||||
|
||||
proc semDynamicBindSym(c: PContext, n: PNode): PNode =
|
||||
# inside regular code, bindSym resolves to the sym-choice
|
||||
# nodes (see tinspectsymbol)
|
||||
if not (c.inStaticContext > 0 or getCurrOwner(c).isCompileTimeProc):
|
||||
return semBindSym(c, n)
|
||||
|
||||
if c.graph.vm.isNil:
|
||||
setupGlobalCtx(c.module, c.graph)
|
||||
|
||||
let
|
||||
vm = PCtx c.graph.vm
|
||||
# cache the current scope to
|
||||
# prevent it lost into oblivion
|
||||
scope = c.currentScope
|
||||
|
||||
# cannot use this
|
||||
# vm.config.features.incl dynamicBindSym
|
||||
|
||||
proc bindSymWrapper(a: VmArgs) =
|
||||
# capture PContext and currentScope
|
||||
# param description:
|
||||
# 0. ident, a string literal / computed string / or ident node
|
||||
# 1. bindSym rule
|
||||
# 2. info node
|
||||
a.setResult opBindSym(c, scope, a.getNode(0), a.getInt(1).int, a.getNode(2))
|
||||
|
||||
let
|
||||
# altough we use VM callback here, it is not
|
||||
# executed like 'normal' VM callback
|
||||
idx = vm.registerCallback("bindSymImpl", bindSymWrapper)
|
||||
# dummy node to carry idx information to VM
|
||||
idxNode = newIntTypeNode(nkIntLit, idx, c.graph.getSysType(TLineInfo(), tyInt))
|
||||
|
||||
result = copyNode(n)
|
||||
for x in n: result.add x
|
||||
result.add n # info node
|
||||
result.add idxNode
|
||||
|
||||
proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode
|
||||
|
||||
proc semOf(c: PContext, n: PNode): PNode =
|
||||
@@ -270,7 +331,11 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||
of mOf: result = semOf(c, n)
|
||||
of mHigh, mLow: result = semLowHigh(c, n, n[0].sym.magic)
|
||||
of mShallowCopy: result = semShallowCopy(c, n, flags)
|
||||
of mNBindSym: result = semBindSym(c, n)
|
||||
of mNBindSym:
|
||||
if dynamicBindSym notin c.features:
|
||||
result = semBindSym(c, n)
|
||||
else:
|
||||
result = semDynamicBindSym(c, n)
|
||||
of mProcCall:
|
||||
result = n
|
||||
result.typ = n[1].typ
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
# included from sem.nim
|
||||
|
||||
const
|
||||
errStringOrIdentNodeExpected = "string or ident node expected"
|
||||
errStringLiteralExpected = "string literal expected"
|
||||
errIntLiteralExpected = "integer literal expected"
|
||||
errWrongNumberOfVariables = "wrong number of variables"
|
||||
@@ -136,7 +137,7 @@ proc semSet(c: PContext, n: PNode, prev: PType): PType =
|
||||
addSonSkipIntLit(result, base)
|
||||
if base.kind in {tyGenericInst, tyAlias, tySink}: base = lastSon(base)
|
||||
if base.kind != tyGenericParam:
|
||||
if not isOrdinalType(base):
|
||||
if not isOrdinalType(base, allowEnumWithHoles = true):
|
||||
localError(c.config, n.info, errOrdinalTypeExpected)
|
||||
elif lengthOrd(c.config, base) > MaxSetElements:
|
||||
localError(c.config, n.info, errSetTooBig)
|
||||
@@ -1508,26 +1509,20 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
of mSet: result = semSet(c, n, prev)
|
||||
of mOrdinal: result = semOrdinal(c, n, prev)
|
||||
of mSeq:
|
||||
let s = c.graph.sysTypes[tySequence]
|
||||
assert s != nil
|
||||
assert prev == nil
|
||||
result = copyType(s, s.owner, keepId=false)
|
||||
# XXX figure out why this has children already...
|
||||
result.sons.setLen 0
|
||||
result.n = nil
|
||||
if c.config.selectedGc == gcDestructors:
|
||||
result.flags = {tfHasAsgn}
|
||||
let s = c.graph.sysTypes[tySequence]
|
||||
assert s != nil
|
||||
assert prev == nil
|
||||
result = copyType(s, s.owner, keepId=false)
|
||||
# XXX figure out why this has children already...
|
||||
result.sons.setLen 0
|
||||
result.n = nil
|
||||
if c.config.selectedGc == gcDestructors:
|
||||
result.flags = {tfHasAsgn}
|
||||
else:
|
||||
result.flags = {}
|
||||
semContainerArg(c, n, "seq", result)
|
||||
else:
|
||||
result.flags = {}
|
||||
semContainerArg(c, n, "seq", result)
|
||||
when false:
|
||||
debugT = true
|
||||
echo "Start!"
|
||||
#debug result
|
||||
assert(not containsGenericType(result))
|
||||
debugT = false
|
||||
echo "End!"
|
||||
when false:
|
||||
result = semContainer(c, n, tySequence, "seq", prev)
|
||||
if c.config.selectedGc == gcDestructors:
|
||||
incl result.flags, tfHasAsgn
|
||||
@@ -1603,8 +1598,14 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
result = prev
|
||||
of nkSym:
|
||||
let s = getGenSym(c, n.sym)
|
||||
if s.kind == skType and s.typ != nil:
|
||||
var t = s.typ
|
||||
if s.kind == skType and s.typ != nil or
|
||||
s.kind == skParam and s.typ.kind == tyTypeDesc:
|
||||
var t =
|
||||
if s.kind == skType:
|
||||
s.typ
|
||||
else:
|
||||
internalAssert c.config, s.typ.base.kind != tyNone and prev == nil
|
||||
s.typ.base
|
||||
let alias = maybeAliasType(c, t, prev)
|
||||
if alias != nil:
|
||||
result = alias
|
||||
|
||||
@@ -498,9 +498,15 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||
add(result, typeToString(t.sons[i]))
|
||||
result.add "]"
|
||||
of tyAnd:
|
||||
result = typeToString(t.sons[0]) & " and " & typeToString(t.sons[1])
|
||||
for i, son in t.sons:
|
||||
result.add(typeToString(son))
|
||||
if i < t.sons.high:
|
||||
result.add(" and ")
|
||||
of tyOr:
|
||||
result = typeToString(t.sons[0]) & " or " & typeToString(t.sons[1])
|
||||
for i, son in t.sons:
|
||||
result.add(typeToString(son))
|
||||
if i < t.sons.high:
|
||||
result.add(" or ")
|
||||
of tyNot:
|
||||
result = "not " & typeToString(t.sons[0])
|
||||
of tyExpr:
|
||||
|
||||
@@ -616,19 +616,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
let rc = instr.regC
|
||||
case regs[ra].kind
|
||||
of rkNodeAddr:
|
||||
# XXX: Workaround for vmgen bug:
|
||||
let n = regs[rc].regToNode
|
||||
if (nfIsRef in regs[ra].nodeAddr[].flags or
|
||||
regs[ra].nodeAddr[].kind == nkNilLit) and nfIsRef notin n.flags:
|
||||
if regs[ra].nodeAddr[].kind == nkNilLit:
|
||||
stackTrace(c, tos, pc, errNilAccess)
|
||||
regs[ra].nodeAddr[][] = n[]
|
||||
regs[ra].nodeAddr[].flags.incl nfIsRef
|
||||
# `var object` parameters are sent as rkNodeAddr. When they are mutated
|
||||
# vmgen generates opcWrDeref, which means that we must dereference
|
||||
# twice.
|
||||
# TODO: This should likely be handled differently in vmgen.
|
||||
elif (nfIsRef notin regs[ra].nodeAddr[].flags and
|
||||
if (nfIsRef notin regs[ra].nodeAddr[].flags and
|
||||
nfIsRef notin n.flags):
|
||||
regs[ra].nodeAddr[][] = n[]
|
||||
else:
|
||||
@@ -1229,9 +1222,25 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
node.typ.callConv == ccClosure and node.sons[0].kind == nkNilLit and
|
||||
node.sons[1].kind == nkNilLit))
|
||||
of opcNBindSym:
|
||||
# cannot use this simple check
|
||||
# if dynamicBindSym notin c.config.features:
|
||||
|
||||
# bindSym with static input
|
||||
decodeBx(rkNode)
|
||||
regs[ra].node = copyTree(c.constants.sons[rbx])
|
||||
regs[ra].node.flags.incl nfIsRef
|
||||
of opcNDynBindSym:
|
||||
# experimental bindSym
|
||||
let
|
||||
rb = instr.regB
|
||||
rc = instr.regC
|
||||
idx = int(regs[rb+rc-1].intVal)
|
||||
callback = c.callbacks[idx].value
|
||||
args = VmArgs(ra: ra, rb: rb, rc: rc, slots: cast[pointer](regs),
|
||||
currentException: c.currentExceptionB,
|
||||
currentLineInfo: c.debug[pc])
|
||||
callback(args)
|
||||
regs[ra].node.flags.incl nfIsRef
|
||||
of opcNChild:
|
||||
decodeBC(rkNode)
|
||||
let idx = regs[rc].intVal.int
|
||||
@@ -1416,7 +1425,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
of opcNGetFile:
|
||||
decodeB(rkNode)
|
||||
let n = regs[rb].node
|
||||
regs[ra].node = newStrNode(nkStrLit, toFilename(c.config, n.info))
|
||||
regs[ra].node = newStrNode(nkStrLit, toFullPath(c.config, n.info))
|
||||
regs[ra].node.info = n.info
|
||||
regs[ra].node.typ = n.typ
|
||||
of opcNGetLine:
|
||||
@@ -1780,7 +1789,7 @@ proc getGlobalValue*(c: PCtx; s: PSym): PNode =
|
||||
|
||||
include vmops
|
||||
|
||||
proc setupGlobalCtx(module: PSym; graph: ModuleGraph) =
|
||||
proc setupGlobalCtx*(module: PSym; graph: ModuleGraph) =
|
||||
if graph.vm.isNil:
|
||||
graph.vm = newCtx(module, graph.cache, graph)
|
||||
registerAdditionalOps(PCtx graph.vm)
|
||||
|
||||
@@ -136,7 +136,7 @@ type
|
||||
opcLdGlobalAddr, # dest = addr(globals[Bx])
|
||||
|
||||
opcLdImmInt, # dest = immediate value
|
||||
opcNBindSym,
|
||||
opcNBindSym, opcNDynBindSym,
|
||||
opcSetType, # dest.typ = types[Bx]
|
||||
opcTypeTrait,
|
||||
opcMarshalLoad, opcMarshalStore,
|
||||
@@ -229,7 +229,8 @@ proc refresh*(c: PCtx, module: PSym) =
|
||||
c.prc = PProc(blocks: @[])
|
||||
c.loopIterations = MaxLoopIterations
|
||||
|
||||
proc registerCallback*(c: PCtx; name: string; callback: VmCallback) =
|
||||
proc registerCallback*(c: PCtx; name: string; callback: VmCallback): int {.discardable.} =
|
||||
result = c.callbacks.len
|
||||
c.callbacks.add((name, callback))
|
||||
|
||||
const
|
||||
|
||||
@@ -37,7 +37,9 @@ when hasFFI:
|
||||
import evalffi
|
||||
|
||||
type
|
||||
TGenFlag = enum gfAddrOf, gfFieldAccess
|
||||
TGenFlag = enum
|
||||
gfNode # Affects how variables are loaded - always loads as rkNode
|
||||
gfNodeAddr # Affects how variables are loaded - always loads as rkNodeAddr
|
||||
TGenFlags = set[TGenFlag]
|
||||
|
||||
proc debugInfo(c: PCtx; info: TLineInfo): string =
|
||||
@@ -563,7 +565,7 @@ proc genIndex(c: PCtx; n: PNode; arr: PType): TRegister =
|
||||
proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
|
||||
case le.kind
|
||||
of nkBracketExpr:
|
||||
let dest = c.genx(le.sons[0], {gfAddrOf, gfFieldAccess})
|
||||
let dest = c.genx(le.sons[0], {gfNode})
|
||||
let idx = c.genIndex(le.sons[1], le.sons[0].typ)
|
||||
c.gABC(le, opcWrArr, dest, idx, value)
|
||||
c.freeTemp(dest)
|
||||
@@ -571,17 +573,17 @@ proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
|
||||
of nkDotExpr, nkCheckedFieldExpr:
|
||||
# XXX field checks here
|
||||
let left = if le.kind == nkDotExpr: le else: le.sons[0]
|
||||
let dest = c.genx(left.sons[0], {gfAddrOf, gfFieldAccess})
|
||||
let dest = c.genx(left.sons[0], {gfNode})
|
||||
let idx = genField(c, left.sons[1])
|
||||
c.gABC(left, opcWrObj, dest, idx, value)
|
||||
c.freeTemp(dest)
|
||||
of nkDerefExpr, nkHiddenDeref:
|
||||
let dest = c.genx(le.sons[0], {gfAddrOf})
|
||||
let dest = c.genx(le.sons[0], {gfNode})
|
||||
c.gABC(le, opcWrDeref, dest, 0, value)
|
||||
c.freeTemp(dest)
|
||||
of nkSym:
|
||||
if le.sym.isGlobal:
|
||||
let dest = c.genx(le, {gfAddrOf})
|
||||
let dest = c.genx(le, {gfNodeAddr})
|
||||
c.gABC(le, opcWrDeref, dest, 0, value)
|
||||
c.freeTemp(dest)
|
||||
else:
|
||||
@@ -815,6 +817,43 @@ proc genVoidABC(c: PCtx, n: PNode, dest: TDest, opcode: TOpcode) =
|
||||
c.freeTemp(tmp2)
|
||||
c.freeTemp(tmp3)
|
||||
|
||||
proc genBindSym(c: PCtx; n: PNode; dest: var TDest) =
|
||||
# nah, cannot use c.config.features because sempass context
|
||||
# can have local experimental switch
|
||||
# if dynamicBindSym notin c.config.features:
|
||||
if n.len == 2: # hmm, reliable?
|
||||
# bindSym with static input
|
||||
if n[1].kind in {nkClosedSymChoice, nkOpenSymChoice, nkSym}:
|
||||
let idx = c.genLiteral(n[1])
|
||||
if dest < 0: dest = c.getTemp(n.typ)
|
||||
c.gABx(n, opcNBindSym, dest, idx)
|
||||
else:
|
||||
localError(c.config, n.info, "invalid bindSym usage")
|
||||
else:
|
||||
# experimental bindSym
|
||||
if dest < 0: dest = c.getTemp(n.typ)
|
||||
let x = c.getTempRange(n.len, slotTempUnknown)
|
||||
|
||||
# callee symbol
|
||||
var tmp0 = TDest(x)
|
||||
c.genLit(n.sons[0], tmp0)
|
||||
|
||||
# original parameters
|
||||
for i in 1..<n.len-2:
|
||||
var r = TRegister(x+i)
|
||||
c.gen(n.sons[i], r)
|
||||
|
||||
# info node
|
||||
var tmp1 = TDest(x+n.len-2)
|
||||
c.genLit(n.sons[^2], tmp1)
|
||||
|
||||
# payload idx
|
||||
var tmp2 = TDest(x+n.len-1)
|
||||
c.genLit(n.sons[^1], tmp2)
|
||||
|
||||
c.gABC(n, opcNDynBindSym, dest, x, n.len)
|
||||
c.freeTempRange(x, n.len)
|
||||
|
||||
proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||
case m
|
||||
of mAnd: c.genAndOr(n, opcFJmp, dest)
|
||||
@@ -1135,13 +1174,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||
of mNNewNimNode: genBinaryABC(c, n, dest, opcNNewNimNode)
|
||||
of mNCopyNimNode: genUnaryABC(c, n, dest, opcNCopyNimNode)
|
||||
of mNCopyNimTree: genUnaryABC(c, n, dest, opcNCopyNimTree)
|
||||
of mNBindSym:
|
||||
if n[1].kind in {nkClosedSymChoice, nkOpenSymChoice, nkSym}:
|
||||
let idx = c.genLiteral(n[1])
|
||||
if dest < 0: dest = c.getTemp(n.typ)
|
||||
c.gABx(n, opcNBindSym, dest, idx)
|
||||
else:
|
||||
localError(c.config, n.info, "invalid bindSym usage")
|
||||
of mNBindSym: genBindSym(c, n, dest)
|
||||
of mStrToIdent: genUnaryABC(c, n, dest, opcStrToIdent)
|
||||
of mEqIdent: genBinaryABC(c, n, dest, opcEqIdent)
|
||||
of mEqNimrodNode: genBinaryABC(c, n, dest, opcEqNimrodNode)
|
||||
@@ -1252,41 +1285,21 @@ proc canElimAddr(n: PNode): PNode =
|
||||
# addr ( deref ( x )) --> x
|
||||
result = n.sons[0].sons[0]
|
||||
|
||||
proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
|
||||
flags: TGenFlags) =
|
||||
# a nop for certain types
|
||||
let isAddr = opc in {opcAddrNode, opcAddrReg}
|
||||
if isAddr and (let m = canElimAddr(n); m != nil):
|
||||
proc genAddr(c: PCtx, n: PNode, dest: var TDest, flags: TGenFlags) =
|
||||
if (let m = canElimAddr(n); m != nil):
|
||||
gen(c, m, dest, flags)
|
||||
return
|
||||
|
||||
let af = if n[0].kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr}: {gfAddrOf, gfFieldAccess}
|
||||
else: {gfAddrOf}
|
||||
let newflags = if isAddr: flags+af else: flags
|
||||
# consider:
|
||||
# proc foo(f: var ref int) =
|
||||
# f = new(int)
|
||||
# proc blah() =
|
||||
# var x: ref int
|
||||
# foo x
|
||||
#
|
||||
# The type of 'f' is 'var ref int' and of 'x' is 'ref int'. Hence for
|
||||
# nkAddr we must not use 'unneededIndirection', but for deref we use it.
|
||||
if not isAddr and unneededIndirection(n.sons[0]):
|
||||
gen(c, n.sons[0], dest, newflags)
|
||||
if gfAddrOf notin flags and fitsRegister(n.typ):
|
||||
c.gABC(n, opcNodeToReg, dest, dest)
|
||||
elif isAddr and isGlobal(n.sons[0]):
|
||||
let af = if n[0].kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr}: {gfNode}
|
||||
else: {gfNodeAddr}
|
||||
let newflags = flags-{gfNode, gfNodeAddr}+af
|
||||
|
||||
if isGlobal(n.sons[0]):
|
||||
gen(c, n.sons[0], dest, flags+af)
|
||||
else:
|
||||
let tmp = c.genx(n.sons[0], newflags)
|
||||
if dest < 0: dest = c.getTemp(n.typ)
|
||||
if not isAddr:
|
||||
gABC(c, n, opc, dest, tmp)
|
||||
assert n.typ != nil
|
||||
if gfAddrOf notin flags and fitsRegister(n.typ):
|
||||
c.gABC(n, opcNodeToReg, dest, dest)
|
||||
elif c.prc.slots[tmp].kind >= slotTempUnknown:
|
||||
if c.prc.slots[tmp].kind >= slotTempUnknown:
|
||||
gABC(c, n, opcAddrNode, dest, tmp)
|
||||
# hack ahead; in order to fix bug #1781 we mark the temporary as
|
||||
# permanent, so that it's not used for anything else:
|
||||
@@ -1297,6 +1310,19 @@ proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
|
||||
gABC(c, n, opcAddrReg, dest, tmp)
|
||||
c.freeTemp(tmp)
|
||||
|
||||
proc genDeref(c: PCtx, n: PNode, dest: var TDest, flags: TGenFlags) =
|
||||
if unneededIndirection(n.sons[0]):
|
||||
gen(c, n.sons[0], dest, flags)
|
||||
if {gfNodeAddr, gfNode} * flags == {} and fitsRegister(n.typ):
|
||||
c.gABC(n, opcNodeToReg, dest, dest)
|
||||
else:
|
||||
let tmp = c.genx(n.sons[0], flags)
|
||||
if dest < 0: dest = c.getTemp(n.typ)
|
||||
gABC(c, n, opcLdDeref, dest, tmp)
|
||||
assert n.typ != nil
|
||||
if {gfNodeAddr, gfNode} * flags == {} and fitsRegister(n.typ):
|
||||
c.gABC(n, opcNodeToReg, dest, dest)
|
||||
|
||||
proc whichAsgnOpc(n: PNode): TOpcode =
|
||||
case n.typ.skipTypes(abstractRange-{tyTypeDesc}).kind
|
||||
of tyBool, tyChar, tyEnum, tyOrdinal, tyInt..tyInt64, tyUInt..tyUInt64:
|
||||
@@ -1382,7 +1408,7 @@ proc preventFalseAlias(c: PCtx; n: PNode; opc: TOpcode;
|
||||
proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
|
||||
case le.kind
|
||||
of nkBracketExpr:
|
||||
let dest = c.genx(le.sons[0], {gfAddrOf, gfFieldAccess})
|
||||
let dest = c.genx(le.sons[0], {gfNode})
|
||||
let idx = c.genIndex(le.sons[1], le.sons[0].typ)
|
||||
let tmp = c.genx(ri)
|
||||
if le.sons[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind in {
|
||||
@@ -1394,13 +1420,13 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
|
||||
of nkDotExpr, nkCheckedFieldExpr:
|
||||
# XXX field checks here
|
||||
let left = if le.kind == nkDotExpr: le else: le.sons[0]
|
||||
let dest = c.genx(left.sons[0], {gfAddrOf, gfFieldAccess})
|
||||
let dest = c.genx(left.sons[0], {gfNode})
|
||||
let idx = genField(c, left.sons[1])
|
||||
let tmp = c.genx(ri)
|
||||
c.preventFalseAlias(left, opcWrObj, dest, idx, tmp)
|
||||
c.freeTemp(tmp)
|
||||
of nkDerefExpr, nkHiddenDeref:
|
||||
let dest = c.genx(le.sons[0], {gfAddrOf})
|
||||
let dest = c.genx(le.sons[0], {gfNode})
|
||||
let tmp = c.genx(ri)
|
||||
c.preventFalseAlias(le, opcWrDeref, dest, 0, tmp)
|
||||
c.freeTemp(tmp)
|
||||
@@ -1409,7 +1435,7 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
|
||||
checkCanEval(c, le)
|
||||
if s.isGlobal:
|
||||
withTemp(tmp, le.typ):
|
||||
c.gen(le, tmp, {gfAddrOf})
|
||||
c.gen(le, tmp, {gfNodeAddr})
|
||||
let val = c.genx(ri)
|
||||
c.preventFalseAlias(le, opcWrDeref, tmp, 0, val)
|
||||
c.freeTemp(val)
|
||||
@@ -1427,7 +1453,7 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
|
||||
else:
|
||||
gen(c, ri, dest)
|
||||
else:
|
||||
let dest = c.genx(le, {gfAddrOf})
|
||||
let dest = c.genx(le, {gfNodeAddr})
|
||||
genAsgn(c, dest, ri, requiresCopy)
|
||||
|
||||
proc genTypeLit(c: PCtx; t: PType; dest: var TDest) =
|
||||
@@ -1463,6 +1489,8 @@ proc genGlobalInit(c: PCtx; n: PNode; s: PSym) =
|
||||
c.freeTemp(tmp)
|
||||
|
||||
proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
||||
# gfNodeAddr and gfNode are mutually exclusive
|
||||
assert card(flags * {gfNodeAddr, gfNode}) < 2
|
||||
let s = n.sym
|
||||
if s.isGlobal:
|
||||
if sfCompileTime in s.flags or c.mode == emRepl:
|
||||
@@ -1474,13 +1502,13 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
||||
else: genGlobalInit(c, n, s)
|
||||
if dest < 0: dest = c.getTemp(n.typ)
|
||||
assert s.typ != nil
|
||||
if gfAddrOf notin flags and fitsRegister(s.typ):
|
||||
if gfNodeAddr in flags:
|
||||
c.gABx(n, opcLdGlobalAddr, dest, s.position)
|
||||
elif fitsRegister(s.typ) and gfNode notin flags:
|
||||
var cc = c.getTemp(n.typ)
|
||||
c.gABx(n, opcLdGlobal, cc, s.position)
|
||||
c.gABC(n, opcNodeToReg, dest, cc)
|
||||
c.freeTemp(cc)
|
||||
elif {gfAddrOf, gfFieldAccess} * flags == {gfAddrOf}:
|
||||
c.gABx(n, opcLdGlobalAddr, dest, s.position)
|
||||
else:
|
||||
c.gABx(n, opcLdGlobal, dest, s.position)
|
||||
else:
|
||||
@@ -1498,7 +1526,8 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
||||
cannotEval(c, n)
|
||||
|
||||
template needsRegLoad(): untyped =
|
||||
gfAddrOf notin flags and fitsRegister(n.typ.skipTypes({tyVar, tyLent}))
|
||||
{gfNode, gfNodeAddr} * flags == {} and
|
||||
fitsRegister(n.typ.skipTypes({tyVar, tyLent}))
|
||||
|
||||
proc genArrAccess2(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
|
||||
flags: TGenFlags) =
|
||||
@@ -1634,7 +1663,7 @@ proc genVarSection(c: PCtx; n: PNode) =
|
||||
c.globals.add(sa)
|
||||
s.position = c.globals.len
|
||||
if a.sons[2].kind != nkEmpty:
|
||||
let tmp = c.genx(a.sons[0], {gfAddrOf})
|
||||
let tmp = c.genx(a.sons[0], {gfNodeAddr})
|
||||
let val = c.genx(a.sons[2])
|
||||
c.genAdditionalCopy(a.sons[2], opcWrDeref, tmp, 0, val)
|
||||
c.freeTemp(val)
|
||||
@@ -1839,8 +1868,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
|
||||
of nkDotExpr: genObjAccess(c, n, dest, flags)
|
||||
of nkCheckedFieldExpr: genCheckedObjAccess(c, n, dest, flags)
|
||||
of nkBracketExpr: genArrAccess(c, n, dest, flags)
|
||||
of nkDerefExpr, nkHiddenDeref: genAddrDeref(c, n, dest, opcLdDeref, flags)
|
||||
of nkAddr, nkHiddenAddr: genAddrDeref(c, n, dest, opcAddrNode, flags)
|
||||
of nkDerefExpr, nkHiddenDeref: genDeref(c, n, dest, flags)
|
||||
of nkAddr, nkHiddenAddr: genAddr(c, n, dest, flags)
|
||||
of nkIfStmt, nkIfExpr: genIf(c, n, dest)
|
||||
of nkWhenStmt:
|
||||
# This is "when nimvm" node. Chose the first branch.
|
||||
|
||||
@@ -55,6 +55,8 @@ doc.item.toc = """
|
||||
# HTML rendered for doc.item's seeSrc variable. Note that this will render to
|
||||
# the empty string if you don't pass anything through --docSeeSrcURL. Available
|
||||
# substitutaion variables here are:
|
||||
# * $commit: branch/commit to use in source link.
|
||||
# * $devel: branch to use in edit link.
|
||||
# * $path: relative path to the file being processed.
|
||||
# * $line: line of the item in the original source file.
|
||||
# * $url: whatever you did pass through the --docSeeSrcUrl switch (which also
|
||||
@@ -62,7 +64,7 @@ doc.item.toc = """
|
||||
doc.item.seesrc = """ <a
|
||||
href="${url}/tree/${commit}/${path}#L${line}"
|
||||
class="link-seesrc" target="_blank">Source</a>
|
||||
<a href="${url}/edit/devel/${path}#L${line}" class="link-seesrc" target="_blank" >Edit</a>
|
||||
<a href="${url}/edit/${devel}/${path}#L${line}" class="link-seesrc" target="_blank" >Edit</a>
|
||||
"""
|
||||
|
||||
doc.toc = """
|
||||
|
||||
@@ -6229,10 +6229,10 @@ imported:
|
||||
:test: "nim c $1"
|
||||
:status: 1
|
||||
|
||||
import strutils except `%`, toUpper
|
||||
import strutils except `%`, toUpperAscii
|
||||
|
||||
# doesn't work then:
|
||||
echo "$1" % "abc".toUpper
|
||||
echo "$1" % "abc".toUpperAscii
|
||||
|
||||
|
||||
It is not checked that the ``except`` list is really exported from the module.
|
||||
@@ -6261,24 +6261,24 @@ A module alias can be introduced via the ``as`` keyword:
|
||||
|
||||
echo su.format("$1", "lalelu")
|
||||
|
||||
The original module name is then not accessible. The
|
||||
notations ``path/to/module`` or ``path.to.module`` or ``"path/to/module"``
|
||||
can be used to refer to a module in subdirectories:
|
||||
The original module name is then not accessible. The notations
|
||||
``path/to/module`` or ``"path/to/module"`` can be used to refer to a module
|
||||
in subdirectories:
|
||||
|
||||
.. code-block:: nim
|
||||
import lib.pure.strutils, lib/pure/os, "lib/pure/times"
|
||||
import lib/pure/os, "lib/pure/times"
|
||||
|
||||
Note that the module name is still ``strutils`` and not ``lib.pure.strutils``
|
||||
Note that the module name is still ``strutils`` and not ``lib/pure/strutils``
|
||||
and so one **cannot** do:
|
||||
|
||||
.. code-block:: nim
|
||||
import lib.pure.strutils
|
||||
echo lib.pure.strutils
|
||||
import lib/pure/strutils
|
||||
echo lib/pure/strutils.toUpperAscii("abc")
|
||||
|
||||
Likewise the following does not make sense as the name is ``strutils`` already:
|
||||
|
||||
.. code-block:: nim
|
||||
import lib.pure.strutils as strutils
|
||||
import lib/pure/strutils as strutils
|
||||
|
||||
|
||||
Collective imports from a directory
|
||||
@@ -6297,7 +6297,8 @@ name is not a valid Nim identifier it needs to be a string literal:
|
||||
Pseudo import/include paths
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A directory can also be a so called "pseudo directory".
|
||||
A directory can also be a so called "pseudo directory". They can be used to
|
||||
avoid ambiguity when there are multiple modules with the same path.
|
||||
|
||||
There are two pseudo directories:
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
[Common]
|
||||
cc=gcc # '=' and ':' are the same
|
||||
--foo="bar" # '--cc' and 'cc' are the same, 'bar' and '"bar"' are the same
|
||||
--verbose
|
||||
|
||||
[Windows]
|
||||
|
||||
9
koch.nim
9
koch.nim
@@ -50,6 +50,7 @@ Boot options:
|
||||
|
||||
Commands for core developers:
|
||||
web [options] generates the website and the full documentation
|
||||
(see `nimweb.nim` for cmd line options)
|
||||
website [options] generates only the website
|
||||
csource -d:release builds the C sources for installation
|
||||
pdf builds the PDF documentation
|
||||
@@ -241,7 +242,15 @@ proc zip(args: string) =
|
||||
exec("$# --var:version=$# --var:mingw=none --main:compiler/nim.nim zip compiler/installer.ini" %
|
||||
["tools/niminst/niminst".exe, VersionAsString])
|
||||
|
||||
proc ensureCleanGit() =
|
||||
let (outp, status) = osproc.execCmdEx("git diff")
|
||||
if outp.len != 0:
|
||||
quit "Not a clean git repository; 'git diff' not empty!"
|
||||
if status != 0:
|
||||
quit "Not a clean git repository; 'git diff' returned non-zero!"
|
||||
|
||||
proc xz(args: string) =
|
||||
ensureCleanGit()
|
||||
bundleNimbleSrc()
|
||||
bundleNimsuggest(false)
|
||||
nimexec("cc -r $2 --var:version=$1 --var:mingw=none --main:compiler/nim.nim scripts compiler/installer.ini" %
|
||||
|
||||
@@ -382,16 +382,24 @@ type
|
||||
|
||||
{.deprecated: [TBindSymRule: BindSymRule].}
|
||||
|
||||
proc bindSym*(ident: static[string], rule: BindSymRule = brClosed): NimNode {.
|
||||
proc bindSym*(ident: string | NimNode, rule: BindSymRule = brClosed): NimNode {.
|
||||
magic: "NBindSym", noSideEffect.}
|
||||
## creates a node that binds `ident` to a symbol node. The bound symbol
|
||||
## may be an overloaded symbol.
|
||||
## if `ident` is a NimNode, it must have nkIdent kind.
|
||||
## If ``rule == brClosed`` either an ``nkClosedSymChoice`` tree is
|
||||
## returned or ``nkSym`` if the symbol is not ambiguous.
|
||||
## If ``rule == brOpen`` either an ``nkOpenSymChoice`` tree is
|
||||
## returned or ``nkSym`` if the symbol is not ambiguous.
|
||||
## If ``rule == brForceOpen`` always an ``nkOpenSymChoice`` tree is
|
||||
## returned even if the symbol is not ambiguous.
|
||||
##
|
||||
## experimental feature:
|
||||
## use {.experimental: "dynamicBindSym".} to activate it
|
||||
## if called from template / regular code, `ident` and `rule` must be
|
||||
## constant expression / literal value.
|
||||
## if called from macros / compile time procs / static blocks,
|
||||
## `ident` and `rule` can be VM computed value.
|
||||
|
||||
proc genSym*(kind: NimSymKind = nskLet; ident = ""): NimNode {.
|
||||
magic: "NGenSym", noSideEffect.}
|
||||
@@ -425,6 +433,7 @@ proc getColumn(arg: NimNode): int {.magic: "NLineInfo", noSideEffect.}
|
||||
proc getFile(arg: NimNode): string {.magic: "NLineInfo", noSideEffect.}
|
||||
|
||||
proc lineInfoObj*(n: NimNode): LineInfo {.compileTime.} =
|
||||
## returns ``LineInfo`` of ``n``, using absolute path for ``filename``
|
||||
result.filename = n.getFile
|
||||
result.line = n.getLine
|
||||
result.column = n.getColumn
|
||||
@@ -1284,7 +1293,7 @@ proc customPragmaNode(n: NimNode): NimNode =
|
||||
let
|
||||
typ = n.getTypeInst()
|
||||
|
||||
if typ.kind == nnkBracketExpr and typ.len > 1 and typ[1].kind == nnkProcTy:
|
||||
if typ.kind == nnkBracketExpr and typ.len > 1 and typ[1].kind == nnkProcTy:
|
||||
return typ[1][1]
|
||||
elif typ.typeKind == ntyTypeDesc:
|
||||
let impl = typ[1].getImpl()
|
||||
@@ -1319,6 +1328,8 @@ proc customPragmaNode(n: NimNode): NimNode =
|
||||
if identDefs.kind == nnkRecCase:
|
||||
identDefsStack.add(identDefs[0])
|
||||
for i in 1..<identDefs.len:
|
||||
# if it is and empty branch, skip
|
||||
if identDefs[i][0].kind == nnkNilLit: continue
|
||||
if identDefs[i][1].kind == nnkIdentDefs:
|
||||
identDefsStack.add(identDefs[i][1])
|
||||
else: # nnkRecList
|
||||
|
||||
@@ -449,10 +449,11 @@ proc generateSymbolIndex(symbols: seq[IndexEntry]): string =
|
||||
desc = if not symbols[j].linkDesc.isNil: symbols[j].linkDesc else: ""
|
||||
if desc.len > 0:
|
||||
result.addf("""<li><a class="reference external"
|
||||
title="$3" href="$1">$2</a></li>
|
||||
title="$3" data-doc-search-tag="$2" href="$1">$2</a></li>
|
||||
""", [url, text, desc])
|
||||
else:
|
||||
result.addf("""<li><a class="reference external" href="$1">$2</a></li>
|
||||
result.addf("""<li><a class="reference external"
|
||||
data-doc-search-tag="$2" href="$1">$2</a></li>
|
||||
""", [url, text])
|
||||
inc j
|
||||
result.add("</ul></dd>\n")
|
||||
@@ -493,6 +494,7 @@ proc generateDocumentationTOC(entries: seq[IndexEntry]): string =
|
||||
# Build a list of levels and extracted titles to make processing easier.
|
||||
var
|
||||
titleRef: string
|
||||
titleTag: string
|
||||
levels: seq[tuple[level: int, text: string]]
|
||||
L = 0
|
||||
level = 1
|
||||
@@ -519,10 +521,12 @@ proc generateDocumentationTOC(entries: seq[IndexEntry]): string =
|
||||
let link = entries[L].link
|
||||
if link.isDocumentationTitle:
|
||||
titleRef = link
|
||||
titleTag = levels[L].text
|
||||
else:
|
||||
result.add(level.indentToLevel(levels[L].level))
|
||||
result.add("<li><a href=\"" & link & "\">" &
|
||||
levels[L].text & "</a></li>\n")
|
||||
result.addf("""<li><a class="reference" data-doc-search-tag="$1" href="$2">
|
||||
$3</a></li>
|
||||
""", [titleTag & " : " & levels[L].text, link, levels[L].text])
|
||||
inc L
|
||||
result.add(level.indentToLevel(1) & "</ul>\n")
|
||||
assert(not titleRef.isNil,
|
||||
|
||||
@@ -854,20 +854,20 @@ when isMainModule:
|
||||
doAssert numbers.distribute(6)[0] == @[1, 2]
|
||||
doAssert numbers.distribute(6)[5] == @[7]
|
||||
let a = @[1, 2, 3, 4, 5, 6, 7]
|
||||
doAssert a.distribute(1, true) == @[@[1, 2, 3, 4, 5, 6, 7]]
|
||||
doAssert a.distribute(1, false) == @[@[1, 2, 3, 4, 5, 6, 7]]
|
||||
doAssert a.distribute(2, true) == @[@[1, 2, 3, 4], @[5, 6, 7]]
|
||||
doAssert a.distribute(2, false) == @[@[1, 2, 3, 4], @[5, 6, 7]]
|
||||
doAssert a.distribute(3, true) == @[@[1, 2, 3], @[4, 5], @[6, 7]]
|
||||
doAssert a.distribute(3, false) == @[@[1, 2, 3], @[4, 5, 6], @[7]]
|
||||
doAssert a.distribute(4, true) == @[@[1, 2], @[3, 4], @[5, 6], @[7]]
|
||||
doAssert a.distribute(4, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7]]
|
||||
doAssert a.distribute(5, true) == @[@[1, 2], @[3, 4], @[5], @[6], @[7]]
|
||||
doAssert a.distribute(5, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7], @[]]
|
||||
doAssert a.distribute(6, true) == @[@[1, 2], @[3], @[4], @[5], @[6], @[7]]
|
||||
doAssert a.distribute(6, false) == @[
|
||||
doAssert a.distribute(1, true) == @[@[1, 2, 3, 4, 5, 6, 7]]
|
||||
doAssert a.distribute(1, false) == @[@[1, 2, 3, 4, 5, 6, 7]]
|
||||
doAssert a.distribute(2, true) == @[@[1, 2, 3, 4], @[5, 6, 7]]
|
||||
doAssert a.distribute(2, false) == @[@[1, 2, 3, 4], @[5, 6, 7]]
|
||||
doAssert a.distribute(3, true) == @[@[1, 2, 3], @[4, 5], @[6, 7]]
|
||||
doAssert a.distribute(3, false) == @[@[1, 2, 3], @[4, 5, 6], @[7]]
|
||||
doAssert a.distribute(4, true) == @[@[1, 2], @[3, 4], @[5, 6], @[7]]
|
||||
doAssert a.distribute(4, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7]]
|
||||
doAssert a.distribute(5, true) == @[@[1, 2], @[3, 4], @[5], @[6], @[7]]
|
||||
doAssert a.distribute(5, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7], @[]]
|
||||
doAssert a.distribute(6, true) == @[@[1, 2], @[3], @[4], @[5], @[6], @[7]]
|
||||
doAssert a.distribute(6, false) == @[
|
||||
@[1, 2], @[3, 4], @[5, 6], @[7], @[], @[]]
|
||||
doAssert a.distribute(8, false) == a.distribute(8, true)
|
||||
doAssert a.distribute(8, false) == a.distribute(8, true)
|
||||
doAssert a.distribute(90, false) == a.distribute(90, true)
|
||||
var b = @[0]
|
||||
for f in 1 .. 25: b.add(f)
|
||||
|
||||
@@ -347,6 +347,18 @@ proc excl*[A](s: var HashSet[A], other: HashSet[A]) =
|
||||
assert other.isValid, "The set `other` needs to be initialized."
|
||||
for item in other: discard exclImpl(s, item)
|
||||
|
||||
proc pop*[A](s: var HashSet[A]): A =
|
||||
## Remove and return an arbitrary element from the set `s`.
|
||||
##
|
||||
## Raises KeyError if the set `s` is empty.
|
||||
##
|
||||
for h in 0..high(s.data):
|
||||
if isFilled(s.data[h].hcode):
|
||||
result = s.data[h].key
|
||||
excl(s, result)
|
||||
return result
|
||||
raise newException(KeyError, "set is empty")
|
||||
|
||||
proc containsOrIncl*[A](s: var HashSet[A], key: A): bool =
|
||||
## Includes `key` in the set `s` and tells if `key` was added to `s`.
|
||||
##
|
||||
|
||||
@@ -332,7 +332,7 @@ when defined(windows):
|
||||
if s.len == 0: return ""
|
||||
# educated guess of capacity:
|
||||
var cap = s.len + s.len shr 2
|
||||
result = newStringOfCap(cap*2)
|
||||
result = newString(cap*2)
|
||||
# convert to utf-16 LE
|
||||
var m = multiByteToWideChar(codePage = c.src, dwFlags = 0'i32,
|
||||
lpMultiByteStr = cstring(s),
|
||||
@@ -347,7 +347,7 @@ when defined(windows):
|
||||
lpWideCharStr = nil,
|
||||
cchWideChar = cint(0))
|
||||
# and do the conversion properly:
|
||||
result = newStringOfCap(cap*2)
|
||||
result = newString(cap*2)
|
||||
m = multiByteToWideChar(codePage = c.src, dwFlags = 0'i32,
|
||||
lpMultiByteStr = cstring(s),
|
||||
cbMultiByte = cint(s.len),
|
||||
@@ -364,7 +364,7 @@ when defined(windows):
|
||||
if int(c.dest) == 1200: return
|
||||
# otherwise the fun starts again:
|
||||
cap = s.len + s.len shr 2
|
||||
var res = newStringOfCap(cap)
|
||||
var res = newString(cap)
|
||||
m = wideCharToMultiByte(
|
||||
codePage = c.dest,
|
||||
dwFlags = 0'i32,
|
||||
@@ -382,7 +382,7 @@ when defined(windows):
|
||||
lpMultiByteStr = nil,
|
||||
cbMultiByte = cint(0))
|
||||
# and do the conversion properly:
|
||||
res = newStringOfCap(cap)
|
||||
res = newString(cap)
|
||||
m = wideCharToMultiByte(
|
||||
codePage = c.dest,
|
||||
dwFlags = 0'i32,
|
||||
|
||||
@@ -60,7 +60,7 @@ proc raiseOSError*(errorCode: OSErrorCode; additionalInfo = "") {.noinline.} =
|
||||
if additionalInfo.len == 0:
|
||||
e.msg = osErrorMsg(errorCode)
|
||||
else:
|
||||
e.msg = osErrorMsg(errorCode) & "\nAdditional info: " & additionalInfo
|
||||
e.msg = osErrorMsg(errorCode) & "\nAdditional info: '" & additionalInfo & "'"
|
||||
if e.msg == "":
|
||||
e.msg = "unknown OS error"
|
||||
raise e
|
||||
|
||||
@@ -92,6 +92,9 @@ proc newSelector*[T](): Selector[T] =
|
||||
result.maxFD = maxFD
|
||||
result.fds = newSeq[SelectorKey[T]](maxFD)
|
||||
|
||||
for i in 0 ..< maxFD:
|
||||
result.fds[i].ident = InvalidIdent
|
||||
|
||||
proc close*[T](s: Selector[T]) =
|
||||
let res = posix.close(s.epollFD)
|
||||
when hasThreadSupport:
|
||||
@@ -100,12 +103,6 @@ proc close*[T](s: Selector[T]) =
|
||||
if res != 0:
|
||||
raiseIOSelectorsError(osLastError())
|
||||
|
||||
template clearKey[T](key: ptr SelectorKey[T]) =
|
||||
var empty: T
|
||||
key.ident = 0
|
||||
key.events = {}
|
||||
key.data = empty
|
||||
|
||||
proc newSelectEvent*(): SelectEvent =
|
||||
let fdci = eventfd(0, 0)
|
||||
if fdci == -1:
|
||||
@@ -135,7 +132,7 @@ proc registerHandle*[T](s: Selector[T], fd: int | SocketHandle,
|
||||
events: set[Event], data: T) =
|
||||
let fdi = int(fd)
|
||||
s.checkFd(fdi)
|
||||
doAssert(s.fds[fdi].ident == 0, "Descriptor $# already registered" % $fdi)
|
||||
doAssert(s.fds[fdi].ident == InvalidIdent, "Descriptor $# already registered" % $fdi)
|
||||
s.setKey(fdi, events, 0, data)
|
||||
if events != {}:
|
||||
var epv = EpollEvent(events: EPOLLRDHUP)
|
||||
@@ -152,7 +149,7 @@ proc updateHandle*[T](s: Selector[T], fd: int | SocketHandle, events: set[Event]
|
||||
let fdi = int(fd)
|
||||
s.checkFd(fdi)
|
||||
var pkey = addr(s.fds[fdi])
|
||||
doAssert(pkey.ident != 0,
|
||||
doAssert(pkey.ident != InvalidIdent,
|
||||
"Descriptor $# is not registered in the selector!" % $fdi)
|
||||
doAssert(pkey.events * maskEvents == {})
|
||||
if pkey.events != events:
|
||||
@@ -180,7 +177,7 @@ proc unregister*[T](s: Selector[T], fd: int|SocketHandle) =
|
||||
let fdi = int(fd)
|
||||
s.checkFd(fdi)
|
||||
var pkey = addr(s.fds[fdi])
|
||||
doAssert(pkey.ident != 0,
|
||||
doAssert(pkey.ident != InvalidIdent,
|
||||
"Descriptor $# is not registered in the selector!" % $fdi)
|
||||
if pkey.events != {}:
|
||||
when not defined(android):
|
||||
@@ -243,7 +240,7 @@ proc unregister*[T](s: Selector[T], ev: SelectEvent) =
|
||||
let fdi = int(ev.efd)
|
||||
s.checkFd(fdi)
|
||||
var pkey = addr(s.fds[fdi])
|
||||
doAssert(pkey.ident != 0, "Event is not registered in the queue!")
|
||||
doAssert(pkey.ident != InvalidIdent, "Event is not registered in the queue!")
|
||||
doAssert(Event.User in pkey.events)
|
||||
var epv = EpollEvent()
|
||||
if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fdi.cint, addr epv) != 0:
|
||||
@@ -262,7 +259,7 @@ proc registerTimer*[T](s: Selector[T], timeout: int, oneshot: bool,
|
||||
setNonBlocking(fdi.cint)
|
||||
|
||||
s.checkFd(fdi)
|
||||
doAssert(s.fds[fdi].ident == 0)
|
||||
doAssert(s.fds[fdi].ident == InvalidIdent)
|
||||
|
||||
var events = {Event.Timer}
|
||||
var epv = EpollEvent(events: EPOLLIN or EPOLLRDHUP)
|
||||
@@ -307,7 +304,7 @@ when not defined(android):
|
||||
setNonBlocking(fdi.cint)
|
||||
|
||||
s.checkFd(fdi)
|
||||
doAssert(s.fds[fdi].ident == 0)
|
||||
doAssert(s.fds[fdi].ident == InvalidIdent)
|
||||
|
||||
var epv = EpollEvent(events: EPOLLIN or EPOLLRDHUP)
|
||||
epv.data.u64 = fdi.uint
|
||||
@@ -334,7 +331,7 @@ when not defined(android):
|
||||
setNonBlocking(fdi.cint)
|
||||
|
||||
s.checkFd(fdi)
|
||||
doAssert(s.fds[fdi].ident == 0)
|
||||
doAssert(s.fds[fdi].ident == InvalidIdent)
|
||||
|
||||
var epv = EpollEvent(events: EPOLLIN or EPOLLRDHUP)
|
||||
epv.data.u64 = fdi.uint
|
||||
@@ -347,7 +344,7 @@ when not defined(android):
|
||||
|
||||
proc registerEvent*[T](s: Selector[T], ev: SelectEvent, data: T) =
|
||||
let fdi = int(ev.efd)
|
||||
doAssert(s.fds[fdi].ident == 0, "Event is already registered in the queue!")
|
||||
doAssert(s.fds[fdi].ident == InvalidIdent, "Event is already registered in the queue!")
|
||||
s.setKey(fdi, {Event.User}, 0, data)
|
||||
var epv = EpollEvent(events: EPOLLIN or EPOLLRDHUP)
|
||||
epv.data.u64 = ev.efd.uint
|
||||
@@ -381,7 +378,7 @@ proc selectInto*[T](s: Selector[T], timeout: int,
|
||||
let fdi = int(resTable[i].data.u64)
|
||||
let pevents = resTable[i].events
|
||||
var pkey = addr(s.fds[fdi])
|
||||
doAssert(pkey.ident != 0)
|
||||
doAssert(pkey.ident != InvalidIdent)
|
||||
var rkey = ReadyKey(fd: fdi, events: {})
|
||||
|
||||
if (pevents and EPOLLERR) != 0 or (pevents and EPOLLHUP) != 0:
|
||||
@@ -482,7 +479,7 @@ template isEmpty*[T](s: Selector[T]): bool =
|
||||
(s.count == 0)
|
||||
|
||||
proc contains*[T](s: Selector[T], fd: SocketHandle|int): bool {.inline.} =
|
||||
return s.fds[fd.int].ident != 0
|
||||
return s.fds[fd.int].ident != InvalidIdent
|
||||
|
||||
proc getData*[T](s: Selector[T], fd: SocketHandle|int): var T =
|
||||
let fdi = int(fd)
|
||||
|
||||
@@ -114,6 +114,9 @@ proc newSelector*[T](): Selector[T] =
|
||||
result.fds = newSeq[SelectorKey[T]](maxFD)
|
||||
result.changes = newSeqOfCap[KEvent](MAX_KQUEUE_EVENTS)
|
||||
|
||||
for i in 0 ..< maxFD:
|
||||
result.fds[i].ident = InvalidIdent
|
||||
|
||||
result.sock = usock
|
||||
result.kqFD = kqFD
|
||||
result.maxFD = maxFD.int
|
||||
@@ -128,12 +131,6 @@ proc close*[T](s: Selector[T]) =
|
||||
if res1 != 0 or res2 != 0:
|
||||
raiseIOSelectorsError(osLastError())
|
||||
|
||||
template clearKey[T](key: ptr SelectorKey[T]) =
|
||||
var empty: T
|
||||
key.ident = 0
|
||||
key.events = {}
|
||||
key.data = empty
|
||||
|
||||
proc newSelectEvent*(): SelectEvent =
|
||||
var fds: array[2, cint]
|
||||
if posix.pipe(fds) != 0:
|
||||
@@ -221,7 +218,7 @@ proc registerHandle*[T](s: Selector[T], fd: int | SocketHandle,
|
||||
events: set[Event], data: T) =
|
||||
let fdi = int(fd)
|
||||
s.checkFd(fdi)
|
||||
doAssert(s.fds[fdi].ident == 0)
|
||||
doAssert(s.fds[fdi].ident == InvalidIdent)
|
||||
s.setKey(fdi, events, 0, data)
|
||||
|
||||
if events != {}:
|
||||
@@ -242,7 +239,7 @@ proc updateHandle*[T](s: Selector[T], fd: int | SocketHandle,
|
||||
let fdi = int(fd)
|
||||
s.checkFd(fdi)
|
||||
var pkey = addr(s.fds[fdi])
|
||||
doAssert(pkey.ident != 0,
|
||||
doAssert(pkey.ident != InvalidIdent,
|
||||
"Descriptor $# is not registered in the queue!" % $fdi)
|
||||
doAssert(pkey.events * maskEvents == {})
|
||||
|
||||
@@ -269,7 +266,7 @@ proc registerTimer*[T](s: Selector[T], timeout: int, oneshot: bool,
|
||||
data: T): int {.discardable.} =
|
||||
let fdi = getUnique(s)
|
||||
s.checkFd(fdi)
|
||||
doAssert(s.fds[fdi].ident == 0)
|
||||
doAssert(s.fds[fdi].ident == InvalidIdent)
|
||||
|
||||
let events = if oneshot: {Event.Timer, Event.Oneshot} else: {Event.Timer}
|
||||
let flags: cushort = if oneshot: EV_ONESHOT or EV_ADD else: EV_ADD
|
||||
@@ -291,7 +288,7 @@ proc registerSignal*[T](s: Selector[T], signal: int,
|
||||
data: T): int {.discardable.} =
|
||||
let fdi = getUnique(s)
|
||||
s.checkFd(fdi)
|
||||
doAssert(s.fds[fdi].ident == 0)
|
||||
doAssert(s.fds[fdi].ident == InvalidIdent)
|
||||
|
||||
s.setKey(fdi, {Event.Signal}, signal, data)
|
||||
var nmask, omask: Sigset
|
||||
@@ -315,7 +312,7 @@ proc registerProcess*[T](s: Selector[T], pid: int,
|
||||
data: T): int {.discardable.} =
|
||||
let fdi = getUnique(s)
|
||||
s.checkFd(fdi)
|
||||
doAssert(s.fds[fdi].ident == 0)
|
||||
doAssert(s.fds[fdi].ident == InvalidIdent)
|
||||
|
||||
var kflags: cushort = EV_ONESHOT or EV_ADD
|
||||
setKey(s, fdi, {Event.Process, Event.Oneshot}, pid, data)
|
||||
@@ -331,7 +328,7 @@ proc registerProcess*[T](s: Selector[T], pid: int,
|
||||
|
||||
proc registerEvent*[T](s: Selector[T], ev: SelectEvent, data: T) =
|
||||
let fdi = ev.rfd.int
|
||||
doAssert(s.fds[fdi].ident == 0, "Event is already registered in the queue!")
|
||||
doAssert(s.fds[fdi].ident == InvalidIdent, "Event is already registered in the queue!")
|
||||
setKey(s, fdi, {Event.User}, 0, data)
|
||||
|
||||
modifyKQueue(s, fdi.uint, EVFILT_READ, EV_ADD, 0, 0, nil)
|
||||
@@ -374,7 +371,7 @@ proc unregister*[T](s: Selector[T], fd: int|SocketHandle) =
|
||||
let fdi = int(fd)
|
||||
s.checkFd(fdi)
|
||||
var pkey = addr(s.fds[fdi])
|
||||
doAssert(pkey.ident != 0,
|
||||
doAssert(pkey.ident != InvalidIdent,
|
||||
"Descriptor [" & $fdi & "] is not registered in the queue!")
|
||||
|
||||
if pkey.events != {}:
|
||||
@@ -434,7 +431,7 @@ proc unregister*[T](s: Selector[T], ev: SelectEvent) =
|
||||
let fdi = int(ev.rfd)
|
||||
s.checkFd(fdi)
|
||||
var pkey = addr(s.fds[fdi])
|
||||
doAssert(pkey.ident != 0, "Event is not registered in the queue!")
|
||||
doAssert(pkey.ident != InvalidIdent, "Event is not registered in the queue!")
|
||||
doAssert(Event.User in pkey.events)
|
||||
modifyKQueue(s, uint(fdi), EVFILT_READ, EV_DELETE, 0, 0, nil)
|
||||
when not declared(CACHE_EVENTS):
|
||||
@@ -593,7 +590,7 @@ template isEmpty*[T](s: Selector[T]): bool =
|
||||
(s.count == 0)
|
||||
|
||||
proc contains*[T](s: Selector[T], fd: SocketHandle|int): bool {.inline.} =
|
||||
return s.fds[fd.int].ident != 0
|
||||
return s.fds[fd.int].ident != InvalidIdent
|
||||
|
||||
proc getData*[T](s: Selector[T], fd: SocketHandle|int): var T =
|
||||
let fdi = int(fd)
|
||||
|
||||
@@ -70,6 +70,9 @@ proc newSelector*[T](): Selector[T] =
|
||||
result.fds = newSeq[SelectorKey[T]](maxFD)
|
||||
result.pollfds = newSeq[TPollFd](maxFD)
|
||||
|
||||
for i in 0 ..< maxFD:
|
||||
result.fds[i].ident = InvalidIdent
|
||||
|
||||
proc close*[T](s: Selector[T]) =
|
||||
when hasThreadSupport:
|
||||
deinitLock(s.lock)
|
||||
@@ -77,12 +80,6 @@ proc close*[T](s: Selector[T]) =
|
||||
deallocSharedArray(s.pollfds)
|
||||
deallocShared(cast[pointer](s))
|
||||
|
||||
template clearKey[T](key: ptr SelectorKey[T]) =
|
||||
var empty: T
|
||||
key.ident = 0
|
||||
key.events = {}
|
||||
key.data = empty
|
||||
|
||||
template pollAdd[T](s: Selector[T], sock: cint, events: set[Event]) =
|
||||
withPollLock(s):
|
||||
var pollev: cshort = 0
|
||||
@@ -135,7 +132,7 @@ proc registerHandle*[T](s: Selector[T], fd: int | SocketHandle,
|
||||
events: set[Event], data: T) =
|
||||
var fdi = int(fd)
|
||||
s.checkFd(fdi)
|
||||
doAssert(s.fds[fdi].ident == 0)
|
||||
doAssert(s.fds[fdi].ident == InvalidIdent)
|
||||
setKey(s, fdi, events, 0, data)
|
||||
if events != {}: s.pollAdd(fdi.cint, events)
|
||||
|
||||
@@ -146,7 +143,7 @@ proc updateHandle*[T](s: Selector[T], fd: int | SocketHandle,
|
||||
let fdi = int(fd)
|
||||
s.checkFd(fdi)
|
||||
var pkey = addr(s.fds[fdi])
|
||||
doAssert(pkey.ident != 0,
|
||||
doAssert(pkey.ident != InvalidIdent,
|
||||
"Descriptor [" & $fdi & "] is not registered in the queue!")
|
||||
doAssert(pkey.events * maskEvents == {})
|
||||
|
||||
@@ -162,7 +159,7 @@ proc updateHandle*[T](s: Selector[T], fd: int | SocketHandle,
|
||||
|
||||
proc registerEvent*[T](s: Selector[T], ev: SelectEvent, data: T) =
|
||||
var fdi = int(ev.rfd)
|
||||
doAssert(s.fds[fdi].ident == 0, "Event is already registered in the queue!")
|
||||
doAssert(s.fds[fdi].ident == InvalidIdent, "Event is already registered in the queue!")
|
||||
var events = {Event.User}
|
||||
setKey(s, fdi, events, 0, data)
|
||||
events.incl(Event.Read)
|
||||
@@ -172,9 +169,9 @@ proc unregister*[T](s: Selector[T], fd: int|SocketHandle) =
|
||||
let fdi = int(fd)
|
||||
s.checkFd(fdi)
|
||||
var pkey = addr(s.fds[fdi])
|
||||
doAssert(pkey.ident != 0,
|
||||
doAssert(pkey.ident != InvalidIdent,
|
||||
"Descriptor [" & $fdi & "] is not registered in the queue!")
|
||||
pkey.ident = 0
|
||||
pkey.ident = InvalidIdent
|
||||
pkey.events = {}
|
||||
s.pollRemove(fdi.cint)
|
||||
|
||||
@@ -182,9 +179,9 @@ proc unregister*[T](s: Selector[T], ev: SelectEvent) =
|
||||
let fdi = int(ev.rfd)
|
||||
s.checkFd(fdi)
|
||||
var pkey = addr(s.fds[fdi])
|
||||
doAssert(pkey.ident != 0, "Event is not registered in the queue!")
|
||||
doAssert(pkey.ident != InvalidIdent, "Event is not registered in the queue!")
|
||||
doAssert(Event.User in pkey.events)
|
||||
pkey.ident = 0
|
||||
pkey.ident = InvalidIdent
|
||||
pkey.events = {}
|
||||
s.pollRemove(fdi.cint)
|
||||
|
||||
@@ -270,7 +267,7 @@ template isEmpty*[T](s: Selector[T]): bool =
|
||||
(s.count == 0)
|
||||
|
||||
proc contains*[T](s: Selector[T], fd: SocketHandle|int): bool {.inline.} =
|
||||
return s.fds[fd.int].ident != 0
|
||||
return s.fds[fd.int].ident != InvalidIdent
|
||||
|
||||
proc getData*[T](s: Selector[T], fd: SocketHandle|int): var T =
|
||||
let fdi = int(fd)
|
||||
|
||||
@@ -99,6 +99,9 @@ proc newSelector*[T](): Selector[T] =
|
||||
result = Selector[T]()
|
||||
result.fds = newSeq[SelectorKey[T]](FD_SETSIZE)
|
||||
|
||||
for i in 0 ..< FD_SETSIZE:
|
||||
result.fds[i].ident = InvalidIdent
|
||||
|
||||
IOFD_ZERO(addr result.rSet)
|
||||
IOFD_ZERO(addr result.wSet)
|
||||
IOFD_ZERO(addr result.eSet)
|
||||
@@ -195,7 +198,7 @@ proc setSelectKey[T](s: Selector[T], fd: SocketHandle, events: set[Event],
|
||||
var i = 0
|
||||
let fdi = int(fd)
|
||||
while i < FD_SETSIZE:
|
||||
if s.fds[i].ident == 0:
|
||||
if s.fds[i].ident == InvalidIdent:
|
||||
var pkey = addr(s.fds[i])
|
||||
pkey.ident = fdi
|
||||
pkey.events = events
|
||||
@@ -221,7 +224,7 @@ proc delKey[T](s: Selector[T], fd: SocketHandle) =
|
||||
var i = 0
|
||||
while i < FD_SETSIZE:
|
||||
if s.fds[i].ident == fd.int:
|
||||
s.fds[i].ident = 0
|
||||
s.fds[i].ident = InvalidIdent
|
||||
s.fds[i].events = {}
|
||||
s.fds[i].data = empty
|
||||
break
|
||||
@@ -335,7 +338,7 @@ proc selectInto*[T](s: Selector[T], timeout: int,
|
||||
var k = 0
|
||||
|
||||
while (i < FD_SETSIZE) and (k < count):
|
||||
if s.fds[i].ident != 0:
|
||||
if s.fds[i].ident != InvalidIdent:
|
||||
var flag = false
|
||||
var pkey = addr(s.fds[i])
|
||||
var rkey = ReadyKey(fd: int(pkey.ident), events: {})
|
||||
|
||||
@@ -1004,6 +1004,13 @@ proc processElseBranch(recCaseNode, elseBranch, jsonNode, kindType,
|
||||
exprColonExpr.add(ifStmt)
|
||||
|
||||
proc createConstructor(typeSym, jsonNode: NimNode): NimNode {.compileTime.}
|
||||
|
||||
proc detectDistinctType(typeSym: NimNode): NimNode =
|
||||
let
|
||||
typeImpl = getTypeImpl(typeSym)
|
||||
typeInst = getTypeInst(typeSym)
|
||||
result = if typeImpl.typeKind == ntyDistinct: typeImpl else: typeInst
|
||||
|
||||
proc processObjField(field, jsonNode: NimNode): seq[NimNode] =
|
||||
## Process a field from a ``RecList``.
|
||||
##
|
||||
@@ -1022,8 +1029,8 @@ proc processObjField(field, jsonNode: NimNode): seq[NimNode] =
|
||||
# Add the field value.
|
||||
# -> jsonNode["`field`"]
|
||||
let indexedJsonNode = createJsonIndexer(jsonNode, $field)
|
||||
exprColonExpr.add(createConstructor(getTypeInst(field), indexedJsonNode))
|
||||
|
||||
let typeNode = detectDistinctType(field)
|
||||
exprColonExpr.add(createConstructor(typeNode, indexedJsonNode))
|
||||
of nnkRecCase:
|
||||
# A "case" field that introduces a variant.
|
||||
let exprColonExpr = newNimNode(nnkExprColonExpr)
|
||||
@@ -1248,7 +1255,7 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode =
|
||||
let seqT = typeSym[1]
|
||||
let forLoopI = genSym(nskForVar, "i")
|
||||
let indexerNode = createJsonIndexer(jsonNode, forLoopI)
|
||||
let constructorNode = createConstructor(seqT, indexerNode)
|
||||
let constructorNode = createConstructor(detectDistinctType(seqT), indexerNode)
|
||||
|
||||
# Create a statement expression containing a for loop.
|
||||
result = quote do:
|
||||
@@ -1284,7 +1291,10 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode =
|
||||
|
||||
# Handle all other types.
|
||||
let obj = getType(typeSym)
|
||||
if obj.kind == nnkBracketExpr:
|
||||
let typeNode = getTypeImpl(typeSym)
|
||||
if typeNode.typeKind == ntyDistinct:
|
||||
result = createConstructor(typeNode, jsonNode)
|
||||
elif obj.kind == nnkBracketExpr:
|
||||
# When `Sym "Foo"` turns out to be a `ref object`.
|
||||
result = createConstructor(obj, jsonNode)
|
||||
else:
|
||||
@@ -1295,6 +1305,21 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode =
|
||||
# TODO: The fact that `jsonNode` here works to give a good line number
|
||||
# is weird. Specifying typeSym should work but doesn't.
|
||||
error("Use a named tuple instead of: " & $toStrLit(typeSym), jsonNode)
|
||||
of nnkDistinctTy:
|
||||
var baseType = typeSym
|
||||
# solve nested distinct types
|
||||
while baseType.typeKind == ntyDistinct:
|
||||
let impl = getTypeImpl(baseType[0])
|
||||
if impl.typeKind != ntyDistinct:
|
||||
baseType = baseType[0]
|
||||
break
|
||||
baseType = impl
|
||||
let ret = createConstructor(baseType, jsonNode)
|
||||
let typeInst = getTypeInst(typeSym)
|
||||
result = quote do:
|
||||
(
|
||||
`typeInst`(`ret`)
|
||||
)
|
||||
else:
|
||||
doAssert false, "Unable to create constructor for: " & $typeSym.kind
|
||||
|
||||
@@ -1418,7 +1443,7 @@ macro to*(node: JsonNode, T: typedesc): untyped =
|
||||
## doAssert data.person.age == 21
|
||||
## doAssert data.list == @[1, 2, 3, 4]
|
||||
|
||||
let typeNode = getTypeInst(T)
|
||||
let typeNode = getTypeImpl(T)
|
||||
expectKind(typeNode, nnkBracketExpr)
|
||||
doAssert(($typeNode[0]).normalize == "typedesc")
|
||||
|
||||
|
||||
@@ -231,6 +231,7 @@ const mimes* = {
|
||||
"xcf": "application/x-xcf",
|
||||
"fig": "application/x-xfig",
|
||||
"xpi": "application/x-xpinstall",
|
||||
"wasm": "application/wasm",
|
||||
"amr": "audio/amr",
|
||||
"awb": "audio/amr-wb",
|
||||
"amr": "audio/amr",
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
## immediately.
|
||||
##
|
||||
## .. code-block:: Nim
|
||||
## var socket = newSocket()
|
||||
## var socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
|
||||
## socket.sendTo("192.168.0.1", Port(27960), "status\n")
|
||||
##
|
||||
## Creating a server
|
||||
|
||||
@@ -971,7 +971,7 @@ proc rawCreateDir(dir: string): bool =
|
||||
elif errno in {EEXIST, ENOSYS}:
|
||||
result = false
|
||||
else:
|
||||
raiseOSError(osLastError())
|
||||
raiseOSError(osLastError(), dir)
|
||||
elif defined(posix):
|
||||
let res = mkdir(dir, 0o777)
|
||||
if res == 0'i32:
|
||||
@@ -980,7 +980,7 @@ proc rawCreateDir(dir: string): bool =
|
||||
result = false
|
||||
else:
|
||||
#echo res
|
||||
raiseOSError(osLastError())
|
||||
raiseOSError(osLastError(), dir)
|
||||
else:
|
||||
when useWinUnicode:
|
||||
wrapUnary(res, createDirectoryW, dir)
|
||||
@@ -992,7 +992,7 @@ proc rawCreateDir(dir: string): bool =
|
||||
elif getLastError() == 183'i32:
|
||||
result = false
|
||||
else:
|
||||
raiseOSError(osLastError())
|
||||
raiseOSError(osLastError(), dir)
|
||||
|
||||
proc existsOrCreateDir*(dir: string): bool {.rtl, extern: "nos$1",
|
||||
tags: [WriteDirEffect, ReadDirEffect].} =
|
||||
@@ -1005,7 +1005,7 @@ proc existsOrCreateDir*(dir: string): bool {.rtl, extern: "nos$1",
|
||||
if result:
|
||||
# path already exists - need to check that it is indeed a directory
|
||||
if not existsDir(dir):
|
||||
raise newException(IOError, "Failed to create the directory")
|
||||
raise newException(IOError, "Failed to create '" & dir & "'")
|
||||
|
||||
proc createDir*(dir: string) {.rtl, extern: "nos$1",
|
||||
tags: [WriteDirEffect, ReadDirEffect].} =
|
||||
|
||||
@@ -147,7 +147,7 @@ else: # UNIX-like operating system
|
||||
DirSep* = '/'
|
||||
AltSep* = DirSep
|
||||
PathSep* = ':'
|
||||
FileSystemCaseSensitive* = true
|
||||
FileSystemCaseSensitive* = when defined(macosx): false else: true
|
||||
ExeExt* = ""
|
||||
ScriptExt* = ""
|
||||
DynlibFormat* = when defined(macosx): "lib$1.dylib" else: "lib$1.so"
|
||||
@@ -410,6 +410,11 @@ proc cmpPaths*(pathA, pathB: string): int {.
|
||||
## | 0 iff pathA == pathB
|
||||
## | < 0 iff pathA < pathB
|
||||
## | > 0 iff pathA > pathB
|
||||
runnableExamples:
|
||||
when defined(macosx):
|
||||
doAssert cmpPaths("foo", "Foo") == 0
|
||||
elif defined(posix):
|
||||
doAssert cmpPaths("foo", "Foo") > 0
|
||||
if FileSystemCaseSensitive:
|
||||
result = cmp(pathA, pathB)
|
||||
else:
|
||||
|
||||
@@ -110,7 +110,7 @@ proc random*[T](a: openArray[T]): T {.deprecated.} =
|
||||
## Use ``rand`` instead.
|
||||
result = a[random(a.low..a.len)]
|
||||
|
||||
proc rand*(r: var Rand; max: int): int {.benign.} =
|
||||
proc rand*(r: var Rand; max: Natural): int {.benign.} =
|
||||
## 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"
|
||||
@@ -128,7 +128,7 @@ proc rand*(max: int): int {.benign.} =
|
||||
## number, i.e. a tickcount.
|
||||
rand(state, max)
|
||||
|
||||
proc rand*(r: var Rand; max: float): float {.benign.} =
|
||||
proc rand*(r: var Rand; max: range[0.0 .. high(float)]): float {.benign.} =
|
||||
## 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"
|
||||
@@ -218,4 +218,17 @@ when isMainModule:
|
||||
doAssert rand(0) == 0
|
||||
doAssert rand("a") == 'a'
|
||||
|
||||
when compileOption("rangeChecks"):
|
||||
try:
|
||||
discard rand(-1)
|
||||
doAssert false
|
||||
except RangeError:
|
||||
discard
|
||||
|
||||
try:
|
||||
discard rand(-1.0)
|
||||
doAssert false
|
||||
except RangeError:
|
||||
discard
|
||||
|
||||
main()
|
||||
|
||||
@@ -261,6 +261,9 @@ else:
|
||||
param: int
|
||||
data: T
|
||||
|
||||
const
|
||||
InvalidIdent = -1
|
||||
|
||||
proc raiseIOSelectorsError[T](message: T) =
|
||||
var msg = ""
|
||||
when T is string:
|
||||
@@ -302,6 +305,12 @@ else:
|
||||
if posix.sigprocmask(SIG_UNBLOCK, newmask, oldmask) == -1:
|
||||
raiseIOSelectorsError(osLastError())
|
||||
|
||||
template clearKey[T](key: ptr SelectorKey[T]) =
|
||||
var empty: T
|
||||
key.ident = InvalidIdent
|
||||
key.events = {}
|
||||
key.data = empty
|
||||
|
||||
when defined(linux):
|
||||
include ioselects/ioselectors_epoll
|
||||
elif bsdPlatform:
|
||||
|
||||
@@ -181,10 +181,27 @@ elif defined(windows):
|
||||
type
|
||||
Month* = enum ## Represents a month. Note that the enum starts at ``1``, so ``ord(month)`` will give
|
||||
## the month number in the range ``[1..12]``.
|
||||
mJan = 1, mFeb, mMar, mApr, mMay, mJun, mJul, mAug, mSep, mOct, mNov, mDec
|
||||
mJan = (1, "January")
|
||||
mFeb = "February"
|
||||
mMar = "March"
|
||||
mApr = "April"
|
||||
mMay = "May"
|
||||
mJun = "June"
|
||||
mJul = "July"
|
||||
mAug = "August"
|
||||
mSep = "September"
|
||||
mOct = "October"
|
||||
mNov = "November"
|
||||
mDec = "December"
|
||||
|
||||
WeekDay* = enum ## Represents a weekday.
|
||||
dMon, dTue, dWed, dThu, dFri, dSat, dSun
|
||||
dMon = "Monday"
|
||||
dTue = "Tuesday"
|
||||
dWed = "Wednesday"
|
||||
dThu = "Thursday"
|
||||
dFri = "Friday"
|
||||
dSat = "Saturday"
|
||||
dSun = "Sunday"
|
||||
|
||||
MonthdayRange* = range[1..31]
|
||||
HourRange* = range[0..23]
|
||||
@@ -1074,20 +1091,6 @@ proc getClockStr*(): string {.rtl, extern: "nt$1", tags: [TimeEffect].} =
|
||||
result = intToStr(ti.hour, 2) & ':' & intToStr(ti.minute, 2) &
|
||||
':' & intToStr(ti.second, 2)
|
||||
|
||||
proc `$`*(day: WeekDay): string =
|
||||
## Stringify operator for ``WeekDay``.
|
||||
const lookup: array[WeekDay, string] = ["Monday", "Tuesday", "Wednesday",
|
||||
"Thursday", "Friday", "Saturday", "Sunday"]
|
||||
return lookup[day]
|
||||
|
||||
proc `$`*(m: Month): string =
|
||||
## Stringify operator for ``Month``.
|
||||
const lookup: array[Month, string] = ["January", "February", "March",
|
||||
"April", "May", "June", "July", "August", "September", "October",
|
||||
"November", "December"]
|
||||
return lookup[m]
|
||||
|
||||
|
||||
proc toParts* (ti: TimeInterval): TimeIntervalParts =
|
||||
## Converts a `TimeInterval` into an array consisting of its time units,
|
||||
## starting with nanoseconds and ending with years
|
||||
|
||||
@@ -1479,8 +1479,8 @@ when defined(nimdoc):
|
||||
##
|
||||
## Note that this is a *runtime* call and using ``quit`` inside a macro won't
|
||||
## have any compile time effect. If you need to stop the compiler inside a
|
||||
## macro, use the `error <manual.html#error-pragma>`_ or `fatal
|
||||
## <manual.html#fatal-pragma>`_ pragmas.
|
||||
## macro, use the `error <manual.html#pragmas-error-pragma>`_ or `fatal
|
||||
## <manual.html#pragmas-fatal-pragma>`_ pragmas.
|
||||
|
||||
elif defined(genode):
|
||||
include genode/env
|
||||
@@ -2438,7 +2438,7 @@ iterator fieldPairs*[T: tuple|object](x: T): RootObj {.
|
||||
## When you iterate over objects with different field types you have to use
|
||||
## the compile time ``when`` instead of a runtime ``if`` to select the code
|
||||
## you want to run for each type. To perform the comparison use the `is
|
||||
## operator <manual.html#is-operator>`_. Example:
|
||||
## operator <manual.html#generics-is-operator>`_. Example:
|
||||
##
|
||||
## .. code-block:: Nim
|
||||
##
|
||||
@@ -3788,7 +3788,9 @@ template doAssert*(cond: bool, msg = "") =
|
||||
## same as `assert` but is always turned on and not affected by the
|
||||
## ``--assertions`` command line switch.
|
||||
bind instantiationInfo
|
||||
{.line: instantiationInfo().}:
|
||||
# NOTE: `true` is correct here; --excessiveStackTrace:on will control whether
|
||||
# or not to output full paths.
|
||||
{.line: instantiationInfo(-1, true).}:
|
||||
if not cond:
|
||||
raiseAssert(astToStr(cond) & ' ' &
|
||||
instantiationInfo(-1, false).fileName & '(' &
|
||||
|
||||
@@ -116,6 +116,8 @@ type
|
||||
nextChunkSize: int
|
||||
bottomData: AvlNode
|
||||
heapLinks: HeapLinks
|
||||
when defined(nimTypeNames):
|
||||
allocCounter, deallocCounter: int
|
||||
|
||||
const
|
||||
fsLookupTable: array[byte, int8] = [
|
||||
@@ -434,8 +436,9 @@ proc requestOsChunks(a: var MemRegion, size: int): PBigChunk =
|
||||
a.nextChunkSize = PageSize*4
|
||||
else:
|
||||
a.nextChunkSize = min(roundup(usedMem shr 2, PageSize), a.nextChunkSize * 2)
|
||||
var size = size
|
||||
a.nextChunkSize = min(a.nextChunkSize, MaxBigChunkSize)
|
||||
|
||||
var size = size
|
||||
if size > a.nextChunkSize:
|
||||
result = cast[PBigChunk](osAllocPages(size))
|
||||
else:
|
||||
@@ -737,6 +740,8 @@ when false:
|
||||
result = nil
|
||||
|
||||
proc rawAlloc(a: var MemRegion, requestedSize: int): pointer =
|
||||
when defined(nimTypeNames):
|
||||
inc(a.allocCounter)
|
||||
sysAssert(allocInv(a), "rawAlloc: begin")
|
||||
sysAssert(roundup(65, 8) == 72, "rawAlloc: roundup broken")
|
||||
sysAssert(requestedSize >= sizeof(FreeCell), "rawAlloc: requested size too small")
|
||||
@@ -810,6 +815,8 @@ proc rawAlloc0(a: var MemRegion, requestedSize: int): pointer =
|
||||
zeroMem(result, requestedSize)
|
||||
|
||||
proc rawDealloc(a: var MemRegion, p: pointer) =
|
||||
when defined(nimTypeNames):
|
||||
inc(a.deallocCounter)
|
||||
#sysAssert(isAllocatedPtr(a, p), "rawDealloc: no allocated pointer")
|
||||
sysAssert(allocInv(a), "rawDealloc: begin")
|
||||
var c = pageAddr(p)
|
||||
@@ -975,6 +982,10 @@ proc getOccupiedMem(a: MemRegion): int {.inline.} =
|
||||
result = a.occ
|
||||
# a.currMem - a.freeMem
|
||||
|
||||
when defined(nimTypeNames):
|
||||
proc getMemCounters(a: MemRegion): (int, int) {.inline.} =
|
||||
(a.allocCounter, a.deallocCounter)
|
||||
|
||||
# ---------------------- thread memory region -------------------------------
|
||||
|
||||
template instantiateForRegion(allocator: untyped) =
|
||||
@@ -1018,6 +1029,9 @@ template instantiateForRegion(allocator: untyped) =
|
||||
proc getOccupiedMem(): int = return allocator.occ #getTotalMem() - getFreeMem()
|
||||
proc getMaxMem*(): int = return getMaxMem(allocator)
|
||||
|
||||
when defined(nimTypeNames):
|
||||
proc getMemCounters*(): (int, int) = getMemCounters(allocator)
|
||||
|
||||
# -------------------- shared heap region ----------------------------------
|
||||
when hasThreadSupport:
|
||||
var sharedHeap: MemRegion
|
||||
|
||||
@@ -27,6 +27,9 @@ proc c_strcmp(a, b: cstring): cint {.
|
||||
importc: "strcmp", header: "<string.h>", noSideEffect.}
|
||||
proc c_strlen(a: cstring): csize {.
|
||||
importc: "strlen", header: "<string.h>", noSideEffect.}
|
||||
proc c_abort() {.
|
||||
importc: "abort", header: "<stdlib.h>", noSideEffect.}
|
||||
|
||||
|
||||
when defined(linux) and defined(amd64):
|
||||
type
|
||||
|
||||
@@ -548,7 +548,10 @@ proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
|
||||
gcTrace(res, csAllocated)
|
||||
track("growObj old", ol, 0)
|
||||
track("growObj new", res, newsize)
|
||||
when reallyDealloc:
|
||||
when defined(nimIncrSeqV3):
|
||||
# since we steal the old seq's contents, we set the old length to 0.
|
||||
cast[PGenericSeq](old).len = 0
|
||||
elif reallyDealloc:
|
||||
sysAssert(allocInv(gch.region), "growObj before dealloc")
|
||||
if ol.refcount shr rcShift <=% 1:
|
||||
# free immediately to save space:
|
||||
|
||||
@@ -57,6 +57,9 @@ when defined(nimTypeNames):
|
||||
for i in 0 .. n-1:
|
||||
c_fprintf(stdout, "[Heap] %s: #%ld; bytes: %ld\n", a[i][0], a[i][1], a[i][2])
|
||||
c_fprintf(stdout, "[Heap] total number of bytes: %ld\n", totalAllocated)
|
||||
when defined(nimTypeNames):
|
||||
let (allocs, deallocs) = getMemCounters()
|
||||
c_fprintf(stdout, "[Heap] allocs/deallocs: %ld/%ld\n", allocs, deallocs)
|
||||
|
||||
when defined(nimGcRefLeak):
|
||||
proc oomhandler() =
|
||||
|
||||
@@ -417,12 +417,18 @@ proc setStdIoUnbuffered() =
|
||||
discard c_setvbuf(stdin, nil, IONBF, 0)
|
||||
|
||||
when declared(stdout):
|
||||
when defined(windows) and compileOption("threads"):
|
||||
var echoLock: SysLock
|
||||
initSysLock echoLock
|
||||
|
||||
proc echoBinSafe(args: openArray[string]) {.compilerProc.} =
|
||||
# flockfile deadlocks some versions of Android 5.x.x
|
||||
when not defined(windows) and not defined(android) and not defined(nintendoswitch):
|
||||
proc flockfile(f: File) {.importc, noDecl.}
|
||||
proc funlockfile(f: File) {.importc, noDecl.}
|
||||
flockfile(stdout)
|
||||
when defined(windows) and compileOption("threads"):
|
||||
acquireSys echoLock
|
||||
for s in args:
|
||||
discard c_fwrite(s.cstring, s.len, 1, stdout)
|
||||
const linefeed = "\n" # can be 1 or more chars
|
||||
@@ -430,5 +436,7 @@ when declared(stdout):
|
||||
discard c_fflush(stdout)
|
||||
when not defined(windows) and not defined(android) and not defined(nintendoswitch):
|
||||
funlockfile(stdout)
|
||||
when defined(windows) and compileOption("threads"):
|
||||
releaseSys echoLock
|
||||
|
||||
{.pop.}
|
||||
|
||||
@@ -144,8 +144,13 @@ proc addChar(s: NimString, c: char): NimString =
|
||||
result = s
|
||||
if result.len >= result.space:
|
||||
let r = resize(result.space)
|
||||
result = cast[NimString](growObj(result,
|
||||
sizeof(TGenericSeq) + r + 1))
|
||||
when defined(nimIncrSeqV3):
|
||||
result = rawNewStringNoInit(r)
|
||||
result.len = s.len
|
||||
copyMem(addr result.data[0], unsafeAddr(s.data[0]), s.len+1)
|
||||
else:
|
||||
result = cast[NimString](growObj(result,
|
||||
sizeof(TGenericSeq) + r + 1))
|
||||
result.reserved = r
|
||||
result.data[result.len] = c
|
||||
result.data[result.len+1] = '\0'
|
||||
@@ -188,8 +193,13 @@ proc resizeString(dest: NimString, addlen: int): NimString {.compilerRtl.} =
|
||||
elif dest.len + addlen <= dest.space:
|
||||
result = dest
|
||||
else: # slow path:
|
||||
var sp = max(resize(dest.space), dest.len + addlen)
|
||||
result = cast[NimString](growObj(dest, sizeof(TGenericSeq) + sp + 1))
|
||||
let sp = max(resize(dest.space), dest.len + addlen)
|
||||
when defined(nimIncrSeqV3):
|
||||
result = rawNewStringNoInit(sp)
|
||||
result.len = dest.len
|
||||
copyMem(addr result.data[0], unsafeAddr(dest.data[0]), dest.len+1)
|
||||
else:
|
||||
result = cast[NimString](growObj(dest, sizeof(TGenericSeq) + sp + 1))
|
||||
result.reserved = sp
|
||||
#result = rawNewString(sp)
|
||||
#copyMem(result, dest, dest.len + sizeof(TGenericSeq))
|
||||
@@ -212,7 +222,15 @@ proc setLengthStr(s: NimString, newLen: int): NimString {.compilerRtl.} =
|
||||
elif n <= s.space:
|
||||
result = s
|
||||
else:
|
||||
result = resizeString(s, n)
|
||||
let sp = max(resize(s.space), newLen)
|
||||
when defined(nimIncrSeqV3):
|
||||
result = rawNewStringNoInit(sp)
|
||||
result.len = s.len
|
||||
copyMem(addr result.data[0], unsafeAddr(s.data[0]), s.len+1)
|
||||
zeroMem(addr result.data[s.len], newLen - s.len)
|
||||
result.reserved = sp
|
||||
else:
|
||||
result = resizeString(s, n)
|
||||
result.len = n
|
||||
result.data[n] = '\0'
|
||||
|
||||
@@ -242,6 +260,9 @@ proc incrSeqV2(seq: PGenericSeq, elemSize: int): PGenericSeq {.compilerProc.} =
|
||||
GenericSeqSize))
|
||||
result.reserved = r
|
||||
|
||||
template `+!`(p: pointer, s: int): pointer =
|
||||
cast[pointer](cast[int](p) +% s)
|
||||
|
||||
proc incrSeqV3(s: PGenericSeq, typ: PNimType): PGenericSeq {.compilerProc.} =
|
||||
if s == nil:
|
||||
result = cast[PGenericSeq](newSeq(typ, 1))
|
||||
@@ -250,9 +271,16 @@ proc incrSeqV3(s: PGenericSeq, typ: PNimType): PGenericSeq {.compilerProc.} =
|
||||
result = s
|
||||
if result.len >= result.space:
|
||||
let r = resize(result.space)
|
||||
result = cast[PGenericSeq](growObj(result, typ.base.size * r +
|
||||
when defined(nimIncrSeqV3):
|
||||
result = cast[PGenericSeq](newSeq(typ, r))
|
||||
result.len = s.len
|
||||
copyMem(result +! GenericSeqSize, s +! GenericSeqSize, s.len * typ.base.size)
|
||||
# since we steal the content from 's', it's crucial to set s's len to 0.
|
||||
s.len = 0
|
||||
else:
|
||||
result = cast[PGenericSeq](growObj(result, typ.base.size * r +
|
||||
GenericSeqSize))
|
||||
result.reserved = r
|
||||
result.reserved = r
|
||||
|
||||
proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {.
|
||||
compilerRtl, inl.} =
|
||||
@@ -296,7 +324,40 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {.
|
||||
|
||||
proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {.
|
||||
compilerRtl.} =
|
||||
sysAssert typ.kind == tySequence, "setLengthSeqV2: type is not a seq"
|
||||
if s == nil:
|
||||
result = cast[PGenericSeq](newSeq(typ, newLen))
|
||||
else:
|
||||
result = setLengthSeq(s, typ.base.size, newLen)
|
||||
when defined(nimIncrSeqV3):
|
||||
let elemSize = typ.base.size
|
||||
if s.space < newLen:
|
||||
let r = max(resize(s.space), newLen)
|
||||
result = cast[PGenericSeq](newSeq(typ, r))
|
||||
copyMem(result +! GenericSeqSize, s +! GenericSeqSize, s.len * elemSize)
|
||||
# since we steal the content from 's', it's crucial to set s's len to 0.
|
||||
s.len = 0
|
||||
elif newLen < s.len:
|
||||
result = s
|
||||
# we need to decref here, otherwise the GC leaks!
|
||||
when not defined(boehmGC) and not defined(nogc) and
|
||||
not defined(gcMarkAndSweep) and not defined(gogc) and
|
||||
not defined(gcRegions):
|
||||
if ntfNoRefs notin typ.base.flags:
|
||||
for i in newLen..result.len-1:
|
||||
forAllChildrenAux(cast[pointer](cast[ByteAddress](result) +%
|
||||
GenericSeqSize +% (i*%elemSize)),
|
||||
extGetCellType(result).base, waZctDecRef)
|
||||
|
||||
# XXX: zeroing out the memory can still result in crashes if a wiped-out
|
||||
# cell is aliased by another pointer (ie proc parameter or a let variable).
|
||||
# This is a tough problem, because even if we don't zeroMem here, in the
|
||||
# presence of user defined destructors, the user will expect the cell to be
|
||||
# "destroyed" thus creating the same problem. We can destoy the cell in the
|
||||
# finalizer of the sequence, but this makes destruction non-deterministic.
|
||||
zeroMem(cast[pointer](cast[ByteAddress](result) +% GenericSeqSize +%
|
||||
(newLen*%elemSize)), (result.len-%newLen) *% elemSize)
|
||||
else:
|
||||
result = s
|
||||
result.len = newLen
|
||||
else:
|
||||
result = setLengthSeq(s, typ.base.size, newLen)
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
discard """
|
||||
file: "t6100.nim"
|
||||
exitcode: 0
|
||||
output: "10000000"
|
||||
"""
|
||||
import asyncdispatch
|
||||
|
||||
let done = newFuture[int]()
|
||||
done.complete(1)
|
||||
|
||||
proc asyncSum: Future[int] {.async.} =
|
||||
for _ in 1..10_000_000:
|
||||
result += await done
|
||||
|
||||
echo waitFor asyncSum()
|
||||
@@ -1,19 +0,0 @@
|
||||
discard """
|
||||
file: "t7985.nim"
|
||||
exitcode: 0
|
||||
output: "(value: 1)"
|
||||
"""
|
||||
import json, asyncdispatch
|
||||
|
||||
proc getData(): Future[JsonNode] {.async.} =
|
||||
result = %*{"value": 1}
|
||||
|
||||
type
|
||||
MyData = object
|
||||
value: BiggestInt
|
||||
|
||||
proc main() {.async.} =
|
||||
let data = to(await(getData()), MyData)
|
||||
echo data
|
||||
|
||||
waitFor(main())
|
||||
47
tests/async/tasync_misc.nim
Normal file
47
tests/async/tasync_misc.nim
Normal file
@@ -0,0 +1,47 @@
|
||||
discard """
|
||||
exitcode: 0
|
||||
output: "ok"
|
||||
"""
|
||||
|
||||
import json, asyncdispatch
|
||||
block: #6100
|
||||
let done = newFuture[int]()
|
||||
done.complete(1)
|
||||
|
||||
proc asyncSum: Future[int] {.async.} =
|
||||
for _ in 1..10_000_000:
|
||||
result += await done
|
||||
|
||||
let res = waitFor asyncSum()
|
||||
doAssert(res == 10000000)
|
||||
|
||||
block: #7985
|
||||
proc getData(): Future[JsonNode] {.async.} =
|
||||
result = %*{"value": 1}
|
||||
|
||||
type
|
||||
MyData = object
|
||||
value: BiggestInt
|
||||
|
||||
proc main() {.async.} =
|
||||
let data = to(await(getData()), MyData)
|
||||
doAssert($data == "(value: 1)")
|
||||
|
||||
waitFor(main())
|
||||
|
||||
block: #8399
|
||||
proc bar(): Future[string] {.async.} = discard
|
||||
|
||||
proc foo(line: string) {.async.} =
|
||||
var res =
|
||||
case line[0]
|
||||
of '+', '-': @[]
|
||||
of '$': (let x = await bar(); @[""])
|
||||
else:
|
||||
nil
|
||||
|
||||
doAssert(res == @[""])
|
||||
|
||||
waitFor foo("$asd")
|
||||
|
||||
echo "ok"
|
||||
@@ -15,7 +15,7 @@ proc main =
|
||||
let val = s[i]()
|
||||
if val != $(i*i): echo "bug ", val
|
||||
|
||||
if getOccupiedMem() > 3000_000: quit("still a leak!")
|
||||
if getOccupiedMem() > 5000_000: quit("still a leak!")
|
||||
echo "success"
|
||||
|
||||
main()
|
||||
|
||||
16
tests/errmsgs/t8434.nim
Normal file
16
tests/errmsgs/t8434.nim
Normal file
@@ -0,0 +1,16 @@
|
||||
discard """
|
||||
errormsg: "type mismatch: got <byte, int literal(0)>"
|
||||
nimout: '''but expected one of:
|
||||
proc fun0[T1: int | float |
|
||||
object | array | seq](a1: T1; a2: int)
|
||||
first type mismatch at position: 1
|
||||
required type: T1: int or float or object or array or seq
|
||||
but expression 'byte(1)' is of type: byte
|
||||
|
||||
expression: fun0(byte(1), 0)
|
||||
'''
|
||||
"""
|
||||
|
||||
proc fun0[T1:int|float|object|array|seq](a1:T1, a2:int)=discard
|
||||
|
||||
fun0(byte(1), 0)
|
||||
@@ -16,9 +16,12 @@ proc main =
|
||||
dealloc p
|
||||
# c_fprintf(stdout, "iteration: %ld size: %ld\n", i, size)
|
||||
when defined(cpu64):
|
||||
# bug #7120
|
||||
var x = alloc(((1 shl 29) - 4) * 8)
|
||||
dealloc x
|
||||
# see https://github.com/nim-lang/Nim/issues/8509
|
||||
# this often made appveyor (on windows) fail with out of memory
|
||||
when defined(posix):
|
||||
# bug #7120
|
||||
var x = alloc(((1 shl 29) - 4) * 8)
|
||||
dealloc x
|
||||
|
||||
main()
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ proc handleRequest(query: string): StringTableRef =
|
||||
let x = foo
|
||||
result = x()
|
||||
|
||||
const Limit = when compileOption("gc", "markAndSweep"): 5*1024*1024 else: 700_000
|
||||
const Limit = 5*1024*1024
|
||||
|
||||
proc main =
|
||||
var counter = 0
|
||||
|
||||
11
tests/generics/t8403.nim
Normal file
11
tests/generics/t8403.nim
Normal file
@@ -0,0 +1,11 @@
|
||||
discard """
|
||||
output: "6.0"
|
||||
"""
|
||||
|
||||
proc sum*[T](s: seq[T], R: typedesc): R =
|
||||
var sum: R = 0
|
||||
for x in s:
|
||||
sum += R(x)
|
||||
return sum
|
||||
|
||||
echo @[1, 2, 3].sum(float)
|
||||
10
tests/generics/t8439.nim
Normal file
10
tests/generics/t8439.nim
Normal file
@@ -0,0 +1,10 @@
|
||||
discard """
|
||||
output: "1"
|
||||
"""
|
||||
|
||||
type
|
||||
Cardinal = enum
|
||||
north, east, south, west
|
||||
|
||||
proc foo[cardinal: static[Cardinal]](): int = 1
|
||||
echo(foo[north]())
|
||||
20
tests/iter/t338.nim
Normal file
20
tests/iter/t338.nim
Normal file
@@ -0,0 +1,20 @@
|
||||
discard """
|
||||
output: '''0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
'''
|
||||
"""
|
||||
|
||||
proc moo(): iterator (): int =
|
||||
iterator fooGen: int {.closure.} =
|
||||
while true:
|
||||
yield result
|
||||
result.inc
|
||||
return fooGen
|
||||
|
||||
var foo = moo()
|
||||
|
||||
for i in 0 .. 4:
|
||||
echo foo()
|
||||
@@ -1,4 +1,9 @@
|
||||
discard """
|
||||
msg: '''initApple
|
||||
deinitApple
|
||||
Coral
|
||||
enum
|
||||
redCoral, blackCoral'''
|
||||
output: '''TFoo
|
||||
TBar'''
|
||||
"""
|
||||
@@ -23,3 +28,40 @@ macro test: untyped =
|
||||
bindSym("TBar"))
|
||||
|
||||
test()
|
||||
|
||||
# issue 7827, bindSym power up
|
||||
{.experimental: "dynamicBindSym".}
|
||||
type
|
||||
Apple = ref object
|
||||
name: string
|
||||
color: int
|
||||
weight: int
|
||||
|
||||
proc initApple(name: string): Apple =
|
||||
discard
|
||||
|
||||
proc deinitApple(x: Apple) =
|
||||
discard
|
||||
|
||||
macro wrapObject(obj: typed, n: varargs[untyped]): untyped =
|
||||
let m = n[0]
|
||||
for x in m:
|
||||
var z = bindSym x
|
||||
echo z.repr
|
||||
|
||||
wrapObject(Apple):
|
||||
initApple
|
||||
deinitApple
|
||||
|
||||
type
|
||||
Coral = enum
|
||||
redCoral
|
||||
blackCoral
|
||||
|
||||
macro mixer(): untyped =
|
||||
let m = "Co" & "ral"
|
||||
let x = bindSym(m)
|
||||
echo x.repr
|
||||
echo getType(x).repr
|
||||
|
||||
mixer()
|
||||
|
||||
@@ -43,4 +43,35 @@ macro repr_and_parse(fn: typed): typed =
|
||||
echo fn_impl.repr
|
||||
result = parseStmt(fn_impl.repr)
|
||||
|
||||
repr_and_parse(f)
|
||||
repr_and_parse(f)
|
||||
|
||||
|
||||
#------------------------------------
|
||||
# bugs #8343 and #8344
|
||||
proc one_if_proc(x, y : int): int =
|
||||
if x < y: result = x
|
||||
else: result = y
|
||||
|
||||
proc test_block(x, y : int): int =
|
||||
block label:
|
||||
result = x
|
||||
result = y
|
||||
|
||||
#------------------------------------
|
||||
# bugs #8348
|
||||
|
||||
template `>`(x, y: untyped): untyped =
|
||||
## "is greater" operator. This is the same as ``y < x``.
|
||||
y < x
|
||||
|
||||
proc test_cond_stmtlist(x, y: int): int =
|
||||
result = x
|
||||
if x > y:
|
||||
result = x
|
||||
|
||||
|
||||
repr_and_parse(one_if_proc)
|
||||
repr_and_parse(test_block)
|
||||
repr_and_parse(test_cond_stmtlist)
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Test the sizeof proc
|
||||
|
||||
discard """
|
||||
file: "tsize.nim"
|
||||
output: "40 3 12 32"
|
||||
"""
|
||||
type
|
||||
TMyRecord {.final.} = object
|
||||
x, y: int
|
||||
@@ -7,4 +9,20 @@ type
|
||||
r: float
|
||||
s: string
|
||||
|
||||
TMyEnum = enum
|
||||
tmOne, tmTwo, tmThree, tmFour
|
||||
|
||||
TMyArray1 = array[3, uint8]
|
||||
TMyArray2 = array[1..3, int32]
|
||||
TMyArray3 = array[TMyEnum, float64]
|
||||
|
||||
const
|
||||
mysize1 = sizeof(TMyArray1)
|
||||
mysize2 = sizeof(TMyArray2)
|
||||
mysize3 = sizeof(TMyArray3)
|
||||
|
||||
write(stdout, sizeof(TMyRecord))
|
||||
echo ' ', mysize1, ' ', mysize2, ' ',mysize3
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -154,3 +154,23 @@ block:
|
||||
let a: proc(x: int) {.defaultValue(5).} = nil
|
||||
static:
|
||||
doAssert hasCustomPragma(a.type, defaultValue)
|
||||
|
||||
# bug #8371
|
||||
template thingy {.pragma.}
|
||||
|
||||
type
|
||||
Cardinal = enum
|
||||
north, east, south, west
|
||||
Something = object
|
||||
a: float32
|
||||
case cardinal: Cardinal
|
||||
of north:
|
||||
b {.thingy.}: int
|
||||
of east:
|
||||
c: int
|
||||
of south: discard
|
||||
else: discard
|
||||
|
||||
var foo: Something
|
||||
foo.cardinal = north
|
||||
doAssert foo.b.hasCustomPragma(thingy) == true
|
||||
|
||||
22
tests/sets/tsetpop.nim
Normal file
22
tests/sets/tsetpop.nim
Normal file
@@ -0,0 +1,22 @@
|
||||
discard """
|
||||
targets: "c c++ js"
|
||||
output: '''1000
|
||||
0
|
||||
set is empty
|
||||
'''
|
||||
"""
|
||||
|
||||
import sets
|
||||
|
||||
var a = initSet[int]()
|
||||
for i in 1..1000:
|
||||
a.incl(i)
|
||||
echo len(a)
|
||||
for i in 1..1000:
|
||||
discard a.pop()
|
||||
echo len(a)
|
||||
|
||||
try:
|
||||
echo a.pop()
|
||||
except KeyError as e:
|
||||
echo e.msg
|
||||
@@ -205,4 +205,12 @@ echo warnUninit in gNotes
|
||||
|
||||
# 7555
|
||||
doAssert {-1.int8, -2, -2}.card == 2
|
||||
doAssert {1, 2, 2, 3..5, 4..6}.card == 6
|
||||
doAssert {1, 2, 2, 3..5, 4..6}.card == 6
|
||||
|
||||
type Foo = enum
|
||||
Foo1 = 0
|
||||
Foo2 = 1
|
||||
Foo3 = 3
|
||||
|
||||
let x = { Foo1, Foo2 }
|
||||
# bug #8425
|
||||
|
||||
21
tests/stdlib/tencoding.nim
Normal file
21
tests/stdlib/tencoding.nim
Normal file
@@ -0,0 +1,21 @@
|
||||
discard """
|
||||
output: '''OK'''
|
||||
"""
|
||||
|
||||
#bug #8468
|
||||
|
||||
import encodings, strutils
|
||||
|
||||
when defined(windows):
|
||||
var utf16to8 = open(destEncoding = "utf-16", srcEncoding = "utf-8")
|
||||
var s = "some string"
|
||||
var c = utf16to8.convert(s)
|
||||
|
||||
var z = newStringOfCap(s.len * 2)
|
||||
for x in s:
|
||||
z.add x
|
||||
z.add chr(0)
|
||||
|
||||
doAssert z == c
|
||||
|
||||
echo "OK"
|
||||
@@ -337,7 +337,7 @@ when isMainModule:
|
||||
n2: Option[int]
|
||||
n3: Option[string]
|
||||
n4: Option[bool]
|
||||
|
||||
|
||||
var j0 = parseJson("""{"n1": 1, "n2": null, "n3": null, "n4": null}""")
|
||||
let j0Deser = j0.to(Obj)
|
||||
doAssert j0Deser.n1 == 1
|
||||
@@ -411,10 +411,109 @@ when isMainModule:
|
||||
doAssert dataDeser.a == 1
|
||||
doAssert dataDeser.f == 6
|
||||
doAssert dataDeser.i == 9.9'f32
|
||||
|
||||
|
||||
# deserialize directly into a table
|
||||
block:
|
||||
let s = """{"a": 1, "b": 2}"""
|
||||
let t = parseJson(s).to(Table[string, int])
|
||||
doAssert t["a"] == 1
|
||||
doAssert t["b"] == 2
|
||||
doAssert t["b"] == 2
|
||||
|
||||
block:
|
||||
# bug #8037
|
||||
type
|
||||
Apple = distinct string
|
||||
String = distinct Apple
|
||||
Email = distinct string
|
||||
MyList = distinct seq[int]
|
||||
MyYear = distinct Option[int]
|
||||
MyTable = distinct Table[string, int]
|
||||
MyArr = distinct array[3, float]
|
||||
MyRef = ref object
|
||||
name: string
|
||||
MyObj = object
|
||||
color: int
|
||||
MyDistRef = distinct MyRef
|
||||
MyDistObj = distinct MyObj
|
||||
Toot = object
|
||||
name*: String
|
||||
email*: Email
|
||||
list: MyList
|
||||
year: MyYear
|
||||
dict: MyTable
|
||||
arr: MyArr
|
||||
person: MyDistRef
|
||||
distfruit: MyDistObj
|
||||
dog: MyRef
|
||||
fruit: MyObj
|
||||
emails: seq[String]
|
||||
|
||||
var tJson = parseJson("""
|
||||
{
|
||||
"name":"Bongo",
|
||||
"email":"bongo@bingo.com",
|
||||
"list": [11,7,15],
|
||||
"year": 1975,
|
||||
"dict": {"a": 1, "b": 2},
|
||||
"arr": [1.0, 2.0, 7.0],
|
||||
"person": {"name": "boney"},
|
||||
"dog": {"name": "honey"},
|
||||
"fruit": {"color": 10},
|
||||
"distfruit": {"color": 11},
|
||||
"emails": ["abc", "123"]
|
||||
}
|
||||
""")
|
||||
|
||||
var t = to(tJson, Toot)
|
||||
doAssert string(t.name) == "Bongo"
|
||||
doAssert string(t.email) == "bongo@bingo.com"
|
||||
doAssert seq[int](t.list) == @[11,7,15]
|
||||
doAssert Option[int](t.year).get() == 1975
|
||||
doAssert Table[string,int](t.dict)["a"] == 1
|
||||
doAssert Table[string,int](t.dict)["b"] == 2
|
||||
doAssert array[3, float](t.arr) == [1.0,2.0,7.0]
|
||||
doAssert MyRef(t.person).name == "boney"
|
||||
doAssert MyObj(t.distFruit).color == 11
|
||||
doAssert t.dog.name == "honey"
|
||||
doAssert t.fruit.color == 10
|
||||
doAssert seq[string](t.emails) == @["abc", "123"]
|
||||
|
||||
block test_table:
|
||||
var y = parseJson("""{"a": 1, "b": 2, "c": 3}""")
|
||||
var u = y.to(MyTable)
|
||||
var v = y.to(Table[string, int])
|
||||
doAssert Table[string, int](u)["a"] == 1
|
||||
doAssert Table[string, int](u)["b"] == 2
|
||||
doAssert Table[string, int](u)["c"] == 3
|
||||
doAssert v["a"] == 1
|
||||
|
||||
block primitive_string:
|
||||
const kApple = "apple"
|
||||
var u = newJString(kApple)
|
||||
var v = u.to(Email)
|
||||
var w = u.to(Apple)
|
||||
var x = u.to(String)
|
||||
doAssert string(v) == kApple
|
||||
doAssert string(w) == kApple
|
||||
doAssert string(x) == kApple
|
||||
|
||||
block test_option:
|
||||
var u = newJInt(1137)
|
||||
var v = u.to(MyYear)
|
||||
var w = u.to(Option[int])
|
||||
doAssert Option[int](v).get() == 1137
|
||||
doAssert w.get() == 1137
|
||||
|
||||
block test_object:
|
||||
var u = parseJson("""{"color": 987}""")
|
||||
var v = u.to(MyObj)
|
||||
var w = u.to(MyDistObj)
|
||||
doAssert v.color == 987
|
||||
doAssert MyObj(w).color == 987
|
||||
|
||||
block test_ref_object:
|
||||
var u = parseJson("""{"name": "smith"}""")
|
||||
var v = u.to(MyRef)
|
||||
var w = u.to(MyDistRef)
|
||||
doAssert v.name == "smith"
|
||||
doAssert MyRef(w).name == "smith"
|
||||
|
||||
@@ -145,7 +145,7 @@ else:
|
||||
echo getLastModificationTime("a") == tm
|
||||
removeFile("a")
|
||||
|
||||
when defined(Linux) or defined(macosx):
|
||||
when defined(posix):
|
||||
|
||||
block normalizedPath:
|
||||
block relative:
|
||||
|
||||
18
tests/system/t7894.nim
Normal file
18
tests/system/t7894.nim
Normal file
@@ -0,0 +1,18 @@
|
||||
discard """
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
const size = 250000000
|
||||
var saved = newSeq[seq[int8]]()
|
||||
|
||||
for i in 0..22:
|
||||
# one of these is 0.25GB.
|
||||
#echo i
|
||||
var x = newSeq[int8](size)
|
||||
sleep(10)
|
||||
saved.add(x)
|
||||
|
||||
for x in saved:
|
||||
#echo x.len
|
||||
doAssert x.len == size
|
||||
@@ -1,54 +1,57 @@
|
||||
discard """
|
||||
"""
|
||||
|
||||
var x: ptr int
|
||||
|
||||
x = cast[ptr int](alloc(7))
|
||||
assert x != nil
|
||||
doAssert x != nil
|
||||
x = cast[ptr int](x.realloc(2))
|
||||
assert x != nil
|
||||
doAssert x != nil
|
||||
x.dealloc()
|
||||
|
||||
x = createU(int, 3)
|
||||
assert x != nil
|
||||
doAssert x != nil
|
||||
x.dealloc()
|
||||
|
||||
x = create(int, 4)
|
||||
assert cast[ptr array[4, int]](x)[0] == 0
|
||||
assert cast[ptr array[4, int]](x)[1] == 0
|
||||
assert cast[ptr array[4, int]](x)[2] == 0
|
||||
assert cast[ptr array[4, int]](x)[3] == 0
|
||||
doAssert cast[ptr array[4, int]](x)[0] == 0
|
||||
doAssert cast[ptr array[4, int]](x)[1] == 0
|
||||
doAssert cast[ptr array[4, int]](x)[2] == 0
|
||||
doAssert cast[ptr array[4, int]](x)[3] == 0
|
||||
|
||||
x = x.resize(4)
|
||||
assert x != nil
|
||||
doAssert x != nil
|
||||
x.dealloc()
|
||||
|
||||
x = cast[ptr int](allocShared(100))
|
||||
assert x != nil
|
||||
doAssert x != nil
|
||||
deallocShared(x)
|
||||
|
||||
x = createSharedU(int, 3)
|
||||
assert x != nil
|
||||
doAssert x != nil
|
||||
x.deallocShared()
|
||||
|
||||
x = createShared(int, 3)
|
||||
assert x != nil
|
||||
assert cast[ptr array[3, int]](x)[0] == 0
|
||||
assert cast[ptr array[3, int]](x)[1] == 0
|
||||
assert cast[ptr array[3, int]](x)[2] == 0
|
||||
doAssert x != nil
|
||||
doAssert cast[ptr array[3, int]](x)[0] == 0
|
||||
doAssert cast[ptr array[3, int]](x)[1] == 0
|
||||
doAssert cast[ptr array[3, int]](x)[2] == 0
|
||||
|
||||
assert x != nil
|
||||
doAssert x != nil
|
||||
x = cast[ptr int](x.resizeShared(2))
|
||||
assert x != nil
|
||||
doAssert x != nil
|
||||
x.deallocShared()
|
||||
|
||||
x = create(int, 10)
|
||||
assert x != nil
|
||||
doAssert x != nil
|
||||
x = x.resize(12)
|
||||
assert x != nil
|
||||
doAssert x != nil
|
||||
x.dealloc()
|
||||
|
||||
x = createShared(int, 1)
|
||||
assert x != nil
|
||||
doAssert x != nil
|
||||
x = x.resizeShared(1)
|
||||
assert x != nil
|
||||
doAssert x != nil
|
||||
x.deallocShared()
|
||||
|
||||
x = cast[ptr int](alloc0(125 shl 23))
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
discard """
|
||||
"""
|
||||
|
||||
const
|
||||
nmax = 2*1024*1024*1024
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ proc main() =
|
||||
for val in table.values():
|
||||
if myObj2.isNil:
|
||||
myObj2 = val
|
||||
assert(myObj == myObj2) # passes
|
||||
doAssert(myObj == myObj2) # passes
|
||||
|
||||
var tableCopy: ListTableRef[int, SomeObj]
|
||||
deepCopy(tableCopy, table)
|
||||
@@ -80,7 +80,7 @@ proc main() =
|
||||
#echo cast[int](myObjCopy)
|
||||
#echo cast[int](myObjCopy2)
|
||||
|
||||
assert(myObjCopy == myObjCopy2) # fails
|
||||
doAssert(myObjCopy == myObjCopy2) # fails
|
||||
|
||||
|
||||
type
|
||||
@@ -88,7 +88,7 @@ type
|
||||
counter, max: int
|
||||
data: array[0..99, (pointer, pointer)]
|
||||
|
||||
assert(sizeof(PtrTable) == 2*sizeof(int)+sizeof(pointer)*2*100)
|
||||
doAssert(sizeof(PtrTable) == 2*sizeof(int)+sizeof(pointer)*2*100)
|
||||
|
||||
main()
|
||||
echo "ok"
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
discard """
|
||||
"""
|
||||
|
||||
import
|
||||
unittest, osproc, streams, os, strformat
|
||||
const STRING_DATA = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."
|
||||
@@ -36,7 +39,7 @@ proc verifyFileSize(sz: int64) =
|
||||
discard execProcess(&"dd if=/dev/zero of={fn} bs=1000000 count={size_in_mb}")
|
||||
|
||||
doAssert os.getFileSize(fn) == sz # Verify OS filesize by string
|
||||
|
||||
|
||||
var f = open(fn)
|
||||
doAssert f.getFileSize() == sz # Verify file handle filesize
|
||||
f.close()
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
discard """
|
||||
"""
|
||||
|
||||
import os
|
||||
import osproc
|
||||
import parseopt2
|
||||
@@ -7,12 +10,12 @@ let argv = commandLineParams()
|
||||
|
||||
if argv == @[]:
|
||||
# this won't work with spaces
|
||||
assert execShellCmd(getAppFilename() & " \"foo bar\" --aa:bar=a --a=c:d --ab -c --a[baz]:doo") == 0
|
||||
doAssert execShellCmd(getAppFilename() & " \"foo bar\" --aa:bar=a --a=c:d --ab -c --a[baz]:doo") == 0
|
||||
else:
|
||||
let f = toSeq(getopt())
|
||||
echo f.repr
|
||||
assert f[0].kind == cmdArgument and f[0].key == "foo bar" and f[0].val == ""
|
||||
assert f[1].kind == cmdLongOption and f[1].key == "aa" and f[1].val == "bar=a"
|
||||
assert f[2].kind == cmdLongOption and f[2].key == "a=c" and f[2].val == "d"
|
||||
assert f[3].kind == cmdLongOption and f[3].key == "ab" and f[3].val == ""
|
||||
assert f[4].kind == cmdShortOption and f[4].key == "c" and f[4].val == ""
|
||||
doAssert f[0].kind == cmdArgument and f[0].key == "foo bar" and f[0].val == ""
|
||||
doAssert f[1].kind == cmdLongOption and f[1].key == "aa" and f[1].val == "bar=a"
|
||||
doAssert f[2].kind == cmdLongOption and f[2].key == "a=c" and f[2].val == "d"
|
||||
doAssert f[3].kind == cmdLongOption and f[3].key == "ab" and f[3].val == ""
|
||||
doAssert f[4].kind == cmdShortOption and f[4].key == "c" and f[4].val == ""
|
||||
|
||||
@@ -54,4 +54,9 @@ static:
|
||||
new(s)
|
||||
var ss = s
|
||||
s[] = 1
|
||||
doAssert ss[] == 1
|
||||
doAssert ss[] == 1
|
||||
|
||||
static: # bug #8402
|
||||
type R = ref object
|
||||
var empty: R
|
||||
let otherEmpty = empty
|
||||
@@ -1,6 +1,5 @@
|
||||
|
||||
|
||||
import karax
|
||||
import fuzzysearch
|
||||
|
||||
proc findNodeWith(x: Element; tag, content: cstring): Element =
|
||||
if x.nodeName == tag and x.textContent == content:
|
||||
@@ -88,11 +87,11 @@ proc toHtml(x: TocEntry; isRoot=false): Element =
|
||||
if ul.len != 0: result.add ul
|
||||
if result.len == 0: result = nil
|
||||
|
||||
proc containsWord(a, b: cstring): bool {.asmNoStackFrame.} =
|
||||
{.emit: """
|
||||
var escaped = `b`.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
|
||||
return new RegExp("\\b" + escaped + "\\b").test(`a`);
|
||||
""".}
|
||||
#proc containsWord(a, b: cstring): bool {.asmNoStackFrame.} =
|
||||
#{.emit: """
|
||||
#var escaped = `b`.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
|
||||
#return new RegExp("\\b" + escaped + "\\b").test(`a`);
|
||||
#""".}
|
||||
|
||||
proc isWhitespace(text: cstring): bool {.asmNoStackFrame.} =
|
||||
{.emit: """
|
||||
@@ -252,24 +251,29 @@ proc dosearch(value: cstring): Element =
|
||||
|
||||
`stuff` = doc.documentElement;
|
||||
""".}
|
||||
db = stuff.getElementsByClass"reference external"
|
||||
db = stuff.getElementsByClass"reference"
|
||||
contents = @[]
|
||||
for ahref in db:
|
||||
contents.add ahref.textContent.normalize
|
||||
contents.add ahref.getAttribute("data-doc-search-tag")
|
||||
let ul = tree("UL")
|
||||
result = tree("DIV")
|
||||
result.setClass"search_results"
|
||||
var matches: seq[(Element, int)] = @[]
|
||||
let key = value.normalize
|
||||
for i in 0..<db.len:
|
||||
let c = contents[i]
|
||||
if c.containsWord(key):
|
||||
matches.add((db[i], -(30_000 - c.len)))
|
||||
elif c.contains(key):
|
||||
matches.add((db[i], c.len))
|
||||
if c == "Examples" or c == "PEG construction":
|
||||
# Some manual exclusions.
|
||||
# Ideally these should be fixed in the index to be more
|
||||
# descriptive of what they are.
|
||||
continue
|
||||
let (score, matched) = fuzzymatch(value, c)
|
||||
if matched:
|
||||
matches.add((db[i], score))
|
||||
|
||||
matches.sort do (a, b: auto) -> int:
|
||||
a[1] - b[1]
|
||||
for i in 0..min(<matches.len, 19):
|
||||
b[1] - a[1]
|
||||
for i in 0 ..< min(matches.len, 19):
|
||||
matches[i][0].innerHTML = matches[i][0].getAttribute("data-doc-search-tag")
|
||||
ul.add(tree("LI", matches[i][0]))
|
||||
if ul.len == 0:
|
||||
result.add tree("B", text"no search results")
|
||||
|
||||
139
tools/dochack/fuzzysearch.nim
Normal file
139
tools/dochack/fuzzysearch.nim
Normal file
@@ -0,0 +1,139 @@
|
||||
# A Fuzzy Match implementation inspired by the sublime text fuzzy match algorithm
|
||||
# as described here: https://blog.forrestthewoods.com/reverse-engineering-sublime-text-s-fuzzy-match-4cffeed33fdb
|
||||
# Heavily modified to provide more subjectively useful results
|
||||
# for on the Nim manual.
|
||||
#
|
||||
import strutils
|
||||
import math
|
||||
import macros
|
||||
|
||||
|
||||
const
|
||||
MaxUnmatchedLeadingChar = 3
|
||||
## Maximum number of times the penalty for unmatched leading chars is applied.
|
||||
|
||||
HeadingScaleFactor = 0.5
|
||||
## The score from before the colon Char is multiplied by this.
|
||||
## This is to weight function signatures and descriptions over module titles.
|
||||
|
||||
|
||||
type
|
||||
ScoreCard = enum
|
||||
StartMatch = -100 ## Start matching.
|
||||
LeadingCharDiff = -3 ## An unmatched, leading character was found.
|
||||
CharDiff = -1 ## An unmatched character was found.
|
||||
CharMatch = 0 ## A matched character was found.
|
||||
ConsecutiveMatch = 5 ## A consecutive match was found.
|
||||
LeadingCharMatch = 10 ## The character matches the begining of the
|
||||
## string or the first character of a word
|
||||
## or camel case boundry.
|
||||
WordBoundryMatch = 20 ## The last ConsecutiveCharMatch that
|
||||
## immediately precedes the end of the string,
|
||||
## end of the pattern, or a LeadingCharMatch.
|
||||
|
||||
|
||||
proc fuzzyMatch*(pattern, str: cstring) : tuple[score: int, matched: bool] =
|
||||
var
|
||||
scoreState = StartMatch
|
||||
headerMatched = false
|
||||
unmatchedLeadingCharCount = 0
|
||||
consecutiveMatchCount = 0
|
||||
strIndex = 0
|
||||
patIndex = 0
|
||||
score = 0
|
||||
|
||||
template transition(nextState) =
|
||||
scoreState = nextState
|
||||
score += ord(scoreState)
|
||||
|
||||
while (strIndex < str.len) and (patIndex < pattern.len):
|
||||
var
|
||||
patternChar = pattern[patIndex].toLowerAscii
|
||||
strChar = str[strIndex].toLowerAscii
|
||||
|
||||
# Ignore certain characters
|
||||
if patternChar in {'_', ' ', '.'}:
|
||||
patIndex += 1
|
||||
continue
|
||||
if strChar in {'_', ' ', '.'}:
|
||||
strIndex += 1
|
||||
continue
|
||||
|
||||
# Since this algorithm will be used to search against Nim documentation,
|
||||
# the below logic prioritizes headers.
|
||||
if not headerMatched and strChar == ':':
|
||||
headerMatched = true
|
||||
scoreState = StartMatch
|
||||
score = toInt(floor(HeadingScaleFactor * toFloat(score)))
|
||||
patIndex = 0
|
||||
strIndex += 1
|
||||
continue
|
||||
|
||||
if strChar == patternChar:
|
||||
case scoreState
|
||||
of StartMatch, WordBoundryMatch:
|
||||
scoreState = LeadingCharMatch
|
||||
|
||||
of CharMatch:
|
||||
transition(ConsecutiveMatch)
|
||||
|
||||
of LeadingCharMatch, ConsecutiveMatch:
|
||||
consecutiveMatchCount += 1
|
||||
scoreState = ConsecutiveMatch
|
||||
score += ord(ConsecutiveMatch) * consecutiveMatchCount
|
||||
|
||||
if scoreState == LeadingCharMatch:
|
||||
score += ord(LeadingCharMatch)
|
||||
|
||||
var onBoundary = (patIndex == high(pattern))
|
||||
if not onBoundary:
|
||||
let
|
||||
nextPatternChar = toLowerAscii(pattern[patIndex + 1])
|
||||
nextStrChar = toLowerAscii(str[strIndex + 1])
|
||||
|
||||
onBoundary = (
|
||||
nextStrChar notin {'a'..'z'} and
|
||||
nextStrChar != nextPatternChar
|
||||
)
|
||||
|
||||
if onBoundary:
|
||||
transition(WordBoundryMatch)
|
||||
|
||||
of CharDiff, LeadingCharDiff:
|
||||
var isLeadingChar = (
|
||||
str[strIndex - 1] notin Letters or
|
||||
str[strIndex - 1] in {'a'..'z'} and
|
||||
str[strIndex] in {'A'..'Z'}
|
||||
)
|
||||
|
||||
if isLeadingChar:
|
||||
scoreState = LeadingCharMatch
|
||||
#a non alpha or a camel case transition counts as a leading char.
|
||||
# Transition the state, but don't give the bonus yet; wait until we verify a consecutive match.
|
||||
else:
|
||||
transition(CharMatch)
|
||||
patIndex += 1
|
||||
|
||||
else:
|
||||
case scoreState
|
||||
of StartMatch:
|
||||
transition(LeadingCharDiff)
|
||||
|
||||
of ConsecutiveMatch:
|
||||
transition(CharDiff)
|
||||
consecutiveMatchCount = 0
|
||||
|
||||
of LeadingCharDiff:
|
||||
if unmatchedLeadingCharCount < MaxUnmatchedLeadingChar:
|
||||
transition(LeadingCharDiff)
|
||||
unmatchedLeadingCharCount += 1
|
||||
|
||||
else:
|
||||
transition(CharDiff)
|
||||
|
||||
strIndex += 1
|
||||
|
||||
result = (
|
||||
score: max(0, score),
|
||||
matched: (score > 0),
|
||||
)
|
||||
104
tools/nimweb.nim
104
tools/nimweb.nim
@@ -13,16 +13,18 @@ import
|
||||
|
||||
from xmltree import escape
|
||||
|
||||
const gitRepo = "https://github.com/nim-lang/Nim"
|
||||
|
||||
type
|
||||
TKeyValPair = tuple[key, id, val: string]
|
||||
TConfigData = object of RootObj
|
||||
tabs, links: seq[TKeyValPair]
|
||||
doc, srcdoc, srcdoc2, webdoc, pdf: seq[string]
|
||||
authors, projectName, projectTitle, logo, infile, outdir, ticker: string
|
||||
authors, projectName, projectTitle, logo, infile, ticker: string
|
||||
vars: StringTableRef
|
||||
nimCompiler: string
|
||||
nimArgs: string
|
||||
gitURL: string
|
||||
docHTMLOutput: string
|
||||
webUploadOutput: string
|
||||
quotations: Table[string, tuple[quote, author: string]]
|
||||
numProcessors: int # Set by parallelBuild:n, only works for values > 0.
|
||||
gaId: string # google analytics ID, nil means analytics are disabled
|
||||
@@ -51,8 +53,10 @@ proc initConfigData(c: var TConfigData) =
|
||||
c.webdoc = @[]
|
||||
c.pdf = @[]
|
||||
c.infile = ""
|
||||
c.outdir = ""
|
||||
c.nimArgs = "--hint[Conf]:off --hint[Path]:off --hint[Processing]:off -d:boot "
|
||||
c.gitURL = "https://github.com/nim-lang/Nim"
|
||||
c.docHTMLOutput = "doc/html"
|
||||
c.webUploadOutput = "web/upload"
|
||||
c.authors = ""
|
||||
c.projectTitle = ""
|
||||
c.projectName = ""
|
||||
@@ -79,14 +83,19 @@ const
|
||||
Usage:
|
||||
nimweb [options] ini-file[.ini] [compile_options]
|
||||
Options:
|
||||
-o, --output:dir set the output directory (default: same as ini-file)
|
||||
--var:name=value set the value of a variable
|
||||
-h, --help shows this help
|
||||
-v, --version shows the version
|
||||
-o, --output overrides output directory instead of default
|
||||
web/upload and doc/html
|
||||
--nimCompiler overrides nim compiler; default = bin/nim
|
||||
--var:name=value set the value of a variable
|
||||
--website only build the website, not the full documentation
|
||||
--pdf build the PDF version of the documentation
|
||||
--json2 build JSON of the documentation
|
||||
--onlyDocs build only the documentation
|
||||
--git.url override base url in generated doc links
|
||||
--git.commit override commit/branch in generated doc links 'source'
|
||||
--git.devel override devel branch in generated doc links 'edit'
|
||||
Compile_options:
|
||||
will be passed to the Nim compiler
|
||||
"""
|
||||
@@ -145,7 +154,11 @@ proc parseCmdLine(c: var TConfigData) =
|
||||
of "version", "v":
|
||||
stdout.write(version & "\n")
|
||||
quit(0)
|
||||
of "o", "output": c.outdir = val
|
||||
of "output", "o":
|
||||
c.webUploadOutput = val
|
||||
c.docHTMLOutput = val / "docs"
|
||||
of "nimcompiler":
|
||||
c.nimCompiler = val
|
||||
of "parallelbuild":
|
||||
try:
|
||||
let num = parseInt(val)
|
||||
@@ -163,8 +176,14 @@ proc parseCmdLine(c: var TConfigData) =
|
||||
of "googleanalytics":
|
||||
c.gaId = val
|
||||
c.nimArgs.add("--doc.googleAnalytics:" & val & " ")
|
||||
of "git.url":
|
||||
c.gitURL = val
|
||||
of "git.commit":
|
||||
c.nimArgs.add("--git.commit:" & val & " ")
|
||||
of "git.devel":
|
||||
c.nimArgs.add("--git.devel:" & val & " ")
|
||||
else:
|
||||
echo("Invalid argument $1" % [key])
|
||||
echo("Invalid argument '$1'" % [key])
|
||||
quit(usage)
|
||||
of cmdEnd: break
|
||||
if c.infile.len == 0: quit(usage)
|
||||
@@ -244,15 +263,14 @@ proc parseIniFile(c: var TConfigData) =
|
||||
close(p)
|
||||
if c.projectName.len == 0:
|
||||
c.projectName = changeFileExt(extractFilename(c.infile), "")
|
||||
if c.outdir.len == 0:
|
||||
c.outdir = splitFile(c.infile).dir
|
||||
|
||||
# ------------------- main ----------------------------------------------------
|
||||
|
||||
|
||||
proc exe(f: string): string = return addFileExt(f, ExeExt)
|
||||
|
||||
proc findNim(): string =
|
||||
proc findNim(c: TConfigData): string =
|
||||
if c.nimCompiler.len > 0: return c.nimCompiler
|
||||
var nim = "nim".exe
|
||||
result = "bin" / nim
|
||||
if existsFile(result): return
|
||||
@@ -289,9 +307,9 @@ proc buildDocSamples(c: var TConfigData, destPath: string) =
|
||||
## it didn't make much sense to integrate into the existing generic
|
||||
## documentation builders.
|
||||
const src = "doc"/"docgen_sample.nim"
|
||||
exec(findNim() & " doc $# -o:$# $#" %
|
||||
exec(findNim(c) & " doc $# -o:$# $#" %
|
||||
[c.nimArgs, destPath / "docgen_sample.html", src])
|
||||
exec(findNim() & " doc2 $# -o:$# $#" %
|
||||
exec(findNim(c) & " doc2 $# -o:$# $#" %
|
||||
[c.nimArgs, destPath / "docgen_sample2.html", src])
|
||||
|
||||
proc pathPart(d: string): string = splitFile(d).dir.replace('\\', '/')
|
||||
@@ -302,23 +320,23 @@ proc buildDoc(c: var TConfigData, destPath: string) =
|
||||
commands = newSeq[string](len(c.doc) + len(c.srcdoc) + len(c.srcdoc2))
|
||||
i = 0
|
||||
for d in items(c.doc):
|
||||
commands[i] = findNim() & " rst2html $# --git.url:$# -o:$# --index:on $#" %
|
||||
[c.nimArgs, gitRepo,
|
||||
commands[i] = findNim(c) & " rst2html $# --git.url:$# -o:$# --index:on $#" %
|
||||
[c.nimArgs, c.gitURL,
|
||||
destPath / changeFileExt(splitFile(d).name, "html"), d]
|
||||
i.inc
|
||||
for d in items(c.srcdoc):
|
||||
commands[i] = findNim() & " doc0 $# --git.url:$# -o:$# --index:on $#" %
|
||||
[c.nimArgs, gitRepo,
|
||||
commands[i] = findNim(c) & " doc0 $# --git.url:$# -o:$# --index:on $#" %
|
||||
[c.nimArgs, c.gitURL,
|
||||
destPath / changeFileExt(splitFile(d).name, "html"), d]
|
||||
i.inc
|
||||
for d in items(c.srcdoc2):
|
||||
commands[i] = findNim() & " doc2 $# --git.url:$# -o:$# --index:on $#" %
|
||||
[c.nimArgs, gitRepo,
|
||||
commands[i] = findNim(c) & " doc2 $# --git.url:$# -o:$# --index:on $#" %
|
||||
[c.nimArgs, c.gitURL,
|
||||
destPath / changeFileExt(splitFile(d).name, "html"), d]
|
||||
i.inc
|
||||
|
||||
mexec(commands, c.numProcessors)
|
||||
exec(findNim() & " buildIndex -o:$1/theindex.html $1" % [destPath])
|
||||
exec(findNim(c) & " buildIndex -o:$1/theindex.html $1" % [destPath])
|
||||
|
||||
proc buildPdfDoc(c: var TConfigData, destPath: string) =
|
||||
createDir(destPath)
|
||||
@@ -327,7 +345,7 @@ proc buildPdfDoc(c: var TConfigData, destPath: string) =
|
||||
else:
|
||||
const pdflatexcmd = "pdflatex -interaction=nonstopmode "
|
||||
for d in items(c.pdf):
|
||||
exec(findNim() & " rst2tex $# $#" % [c.nimArgs, d])
|
||||
exec(findNim(c) & " rst2tex $# $#" % [c.nimArgs, d])
|
||||
# call LaTeX twice to get cross references right:
|
||||
exec(pdflatexcmd & changeFileExt(d, "tex"))
|
||||
exec(pdflatexcmd & changeFileExt(d, "tex"))
|
||||
@@ -347,8 +365,8 @@ proc buildAddDoc(c: var TConfigData, destPath: string) =
|
||||
# build additional documentation (without the index):
|
||||
var commands = newSeq[string](c.webdoc.len)
|
||||
for i, doc in pairs(c.webdoc):
|
||||
commands[i] = findNim() & " doc2 $# --git.url:$# -o:$# $#" %
|
||||
[c.nimArgs, gitRepo,
|
||||
commands[i] = findNim(c) & " doc2 $# --git.url:$# -o:$# $#" %
|
||||
[c.nimArgs, c.gitURL,
|
||||
destPath / changeFileExt(splitFile(doc).name, "html"), doc]
|
||||
mexec(commands, c.numProcessors)
|
||||
|
||||
@@ -431,9 +449,9 @@ proc buildNewsRss(c: var TConfigData, destPath: string) =
|
||||
|
||||
generateRss(destFilename, parseNewsTitles(srcFilename))
|
||||
|
||||
proc buildJS(destPath: string) =
|
||||
exec(findNim() & " js -d:release --out:$1 web/nimblepkglist.nim" %
|
||||
[destPath / "nimblepkglist.js"])
|
||||
proc buildJS(c: TConfigData) =
|
||||
exec(findNim(c) & " js -d:release --out:$1 web/nimblepkglist.nim" %
|
||||
[c.webUploadOutput / "nimblepkglist.js"])
|
||||
|
||||
proc readSponsors(sponsorsFile: string): seq[Sponsor] =
|
||||
result = @[]
|
||||
@@ -464,7 +482,7 @@ const
|
||||
cmdRst2Html = " rst2html --compileonly $1 -o:web/$2.temp web/$2.rst"
|
||||
|
||||
proc buildPage(c: var TConfigData, file, title, rss: string, assetDir = "") =
|
||||
exec(findNim() & cmdRst2Html % [c.nimArgs, file])
|
||||
exec(findNim(c) & cmdRst2Html % [c.nimArgs, file])
|
||||
var temp = "web" / changeFileExt(file, "temp")
|
||||
var content: string
|
||||
try:
|
||||
@@ -472,7 +490,7 @@ proc buildPage(c: var TConfigData, file, title, rss: string, assetDir = "") =
|
||||
except IOError:
|
||||
quit("[Error] cannot open: " & temp)
|
||||
var f: File
|
||||
var outfile = "web/upload/$#.html" % file
|
||||
var outfile = c.webUploadOutput / "$#.html" % file
|
||||
if not existsDir(outfile.splitFile.dir):
|
||||
createDir(outfile.splitFile.dir)
|
||||
if open(f, outfile, fmWrite):
|
||||
@@ -502,27 +520,25 @@ proc buildWebsite(c: var TConfigData) =
|
||||
let rss = if file in ["news", "index"]: extractFilename(rssUrl) else: ""
|
||||
if '.' in file: continue
|
||||
buildPage(c, file, if file == "question": "FAQ" else: file, rss)
|
||||
copyDir("web/assets", "web/upload/assets")
|
||||
buildNewsRss(c, "web/upload")
|
||||
buildSponsors(c, "web/upload")
|
||||
buildNews(c, "web/news", "web/upload/news")
|
||||
copyDir("web/assets", c.webUploadOutput / "assets")
|
||||
buildNewsRss(c, c.webUploadOutput)
|
||||
buildSponsors(c, c.webUploadOutput)
|
||||
buildNews(c, "web/news", c.webUploadOutput / "news")
|
||||
|
||||
proc onlyDocs(c: var TConfigData) =
|
||||
createDir(c.docHTMLOutput)
|
||||
buildDocSamples(c, c.docHTMLOutput)
|
||||
buildDoc(c, c.docHTMLOutput)
|
||||
|
||||
proc main(c: var TConfigData) =
|
||||
buildWebsite(c)
|
||||
buildJS("web/upload")
|
||||
const docup = "web/upload/" & NimVersion
|
||||
buildJS(c)
|
||||
let docup = c.webUploadOutput / NimVersion
|
||||
createDir(docup)
|
||||
buildAddDoc(c, docup)
|
||||
buildDocSamples(c, docup)
|
||||
buildDoc(c, docup)
|
||||
createDir("doc/html")
|
||||
buildDocSamples(c, "doc/html")
|
||||
buildDoc(c, "doc/html")
|
||||
|
||||
proc onlyDocs(c: var TConfigData) =
|
||||
createDir("doc/html")
|
||||
buildDocSamples(c, "doc/html")
|
||||
buildDoc(c, "doc/html")
|
||||
onlyDocs(c)
|
||||
|
||||
proc json2(c: var TConfigData) =
|
||||
const destPath = "web/json2"
|
||||
@@ -530,8 +546,8 @@ proc json2(c: var TConfigData) =
|
||||
var i = 0
|
||||
for d in items(c.srcdoc2):
|
||||
createDir(destPath / splitFile(d).dir)
|
||||
commands[i] = findNim() & " jsondoc2 $# --git.url:$# -o:$# --index:on $#" %
|
||||
[c.nimArgs, gitRepo,
|
||||
commands[i] = findNim(c) & " jsondoc2 $# --git.url:$# -o:$# --index:on $#" %
|
||||
[c.nimArgs, c.gitURL,
|
||||
destPath / changeFileExt(d, "json"), d]
|
||||
i.inc
|
||||
|
||||
|
||||
Reference in New Issue
Block a user