diff --git a/changelog.md b/changelog.md index 43b351ef11..045286ef9c 100644 --- a/changelog.md +++ b/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 diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 2c0208b36e..8d233566c1 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -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", diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index f4ef930707..16b0d614da 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -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") @@ -773,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) diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index b8678e6ba7..261dcb44e2 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -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", diff --git a/compiler/modulepaths.nim b/compiler/modulepaths.nim index ef0831ad6f..e5cbf3a2c7 100644 --- a/compiler/modulepaths.nim +++ b/compiler/modulepaths.nim @@ -155,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]) diff --git a/compiler/options.nim b/compiler/options.nim index 7cca403212..598adf27d2 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -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 diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index b5875c67a9..8bfa5545e6 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -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 diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 24896e9444..972c8c709b 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -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" diff --git a/compiler/vm.nim b/compiler/vm.nim index 373a64e39d..a6ec4788b3 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -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) diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index f7466b3929..866b79568f 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -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 diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index d2243376c1..3b5ea4beb1 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -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.. 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. diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index 6b6ec2d833..96e91283a4 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -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 = """  Source -Edit +Edit """ doc.toc = """ diff --git a/doc/manual.rst b/doc/manual.rst index 7298b02a30..abdc4ce695 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -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: diff --git a/koch.nim b/koch.nim index 9411a95de3..133c7e32bd 100644 --- a/koch.nim +++ b/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 diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 345c53b088..d4e8ada0a0 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -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 diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 5d2efebee6..771e7de10d 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -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 diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index ca2d76225b..ffb7aaf86c 100644 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -436,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: diff --git a/tests/fragmentation/tfragment_alloc.nim b/tests/fragmentation/tfragment_alloc.nim index 5a44b7434d..80341d2dcb 100644 --- a/tests/fragmentation/tfragment_alloc.nim +++ b/tests/fragmentation/tfragment_alloc.nim @@ -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() diff --git a/tests/macros/tbindsym.nim b/tests/macros/tbindsym.nim index 6289d3eb26..2abcd98ce2 100644 --- a/tests/macros/tbindsym.nim +++ b/tests/macros/tbindsym.nim @@ -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() diff --git a/tests/stdlib/tos.nim b/tests/stdlib/tos.nim index 6ccc29bf65..10f439dfad 100644 --- a/tests/stdlib/tos.nim +++ b/tests/stdlib/tos.nim @@ -145,7 +145,7 @@ else: echo getLastModificationTime("a") == tm removeFile("a") -when defined(Linux) or defined(osx): +when defined(posix): block normalizedPath: block relative: diff --git a/tests/system/t7894.nim b/tests/system/t7894.nim new file mode 100644 index 0000000000..2808e50200 --- /dev/null +++ b/tests/system/t7894.nim @@ -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 diff --git a/tests/system/talloc.nim b/tests/system/talloc.nim index 18396041d0..bf2cd97a86 100644 --- a/tests/system/talloc.nim +++ b/tests/system/talloc.nim @@ -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)) diff --git a/tests/system/talloc2.nim b/tests/system/talloc2.nim index c8cab78a1c..0757c07246 100644 --- a/tests/system/talloc2.nim +++ b/tests/system/talloc2.nim @@ -1,3 +1,6 @@ +discard """ +""" + const nmax = 2*1024*1024*1024 diff --git a/tests/system/tdeepcopy.nim b/tests/system/tdeepcopy.nim index f7a6e87fa4..383d2e8d13 100644 --- a/tests/system/tdeepcopy.nim +++ b/tests/system/tdeepcopy.nim @@ -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" diff --git a/tests/system/tio.nim b/tests/system/tio.nim index 3d4df806bd..7e9e189500 100644 --- a/tests/system/tio.nim +++ b/tests/system/tio.nim @@ -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() diff --git a/tests/system/tparams.nim b/tests/system/tparams.nim index 1358212f2f..dd5511b8f7 100644 --- a/tests/system/tparams.nim +++ b/tests/system/tparams.nim @@ -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 == "" diff --git a/tests/vm/tref.nim b/tests/vm/tref.nim index 27b7bf3132..f5cd23da5d 100644 --- a/tests/vm/tref.nim +++ b/tests/vm/tref.nim @@ -54,4 +54,9 @@ static: new(s) var ss = s s[] = 1 - doAssert ss[] == 1 \ No newline at end of file + doAssert ss[] == 1 + +static: # bug #8402 + type R = ref object + var empty: R + let otherEmpty = empty \ No newline at end of file diff --git a/tools/nimweb.nim b/tools/nimweb.nim index 6e1d9d3596..e74b081eaf 100644 --- a/tools/nimweb.nim +++ b/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