mirror of
https://github.com/nim-lang/Nim.git
synced 2026-06-12 06:38:11 +00:00
Merge branch 'devel' into araq-fixes-7833
This commit is contained in:
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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
1
koch.nim
1
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -145,7 +145,7 @@ else:
|
||||
echo getLastModificationTime("a") == tm
|
||||
removeFile("a")
|
||||
|
||||
when defined(Linux) or defined(osx):
|
||||
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
|
||||
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