Merge branch 'devel' into araq-fixes-7833
This commit is contained in:
commit
9235f7a3b3
28 changed files with 399 additions and 173 deletions
10
changelog.md
10
changelog.md
|
|
@ -22,7 +22,8 @@
|
||||||
become an error in the future.
|
become an error in the future.
|
||||||
- The ``'c`` and ``'C'`` prefix for octal literals is now deprecated to
|
- The ``'c`` and ``'C'`` prefix for octal literals is now deprecated to
|
||||||
bring the language in line with the standard library (e.g. ``parseOct``).
|
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
|
#### Breaking changes in the standard library
|
||||||
|
|
||||||
|
|
@ -59,6 +60,8 @@
|
||||||
1-based coordinates on POSIX for correct behaviour; the Windows behaviour
|
1-based coordinates on POSIX for correct behaviour; the Windows behaviour
|
||||||
was always correct).
|
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
|
#### 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)
|
- Nintendo Switch was added as a new platform target. See [the compiler user guide](https://nim-lang.org/docs/nimc.html)
|
||||||
for more info.
|
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
|
### Bugfixes
|
||||||
|
|
|
||||||
|
|
@ -517,12 +517,11 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
|
||||||
path = path[cwd.len+1 .. ^1].replace('\\', '/')
|
path = path[cwd.len+1 .. ^1].replace('\\', '/')
|
||||||
let gitUrl = getConfigVar(d.conf, "git.url")
|
let gitUrl = getConfigVar(d.conf, "git.url")
|
||||||
if gitUrl.len > 0:
|
if gitUrl.len > 0:
|
||||||
var commit = getConfigVar(d.conf, "git.commit")
|
let commit = getConfigVar(d.conf, "git.commit", "master")
|
||||||
if commit.len == 0: commit = "master"
|
let develBranch = getConfigVar(d.conf, "git.devel", "devel")
|
||||||
dispA(d.conf, seeSrcRope, "$1", "", [ropeFormatNamedVars(d.conf, docItemSeeSrc,
|
dispA(d.conf, seeSrcRope, "$1", "", [ropeFormatNamedVars(d.conf, docItemSeeSrc,
|
||||||
["path", "line", "url", "commit"], [rope path,
|
["path", "line", "url", "commit", "devel"], [rope path,
|
||||||
rope($n.info.line), rope gitUrl,
|
rope($n.info.line), rope gitUrl, rope commit, rope develBranch])])
|
||||||
rope commit])])
|
|
||||||
|
|
||||||
add(d.section[k], ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.item"),
|
add(d.section[k], ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.item"),
|
||||||
["name", "header", "desc", "itemID", "header_plain", "itemSym",
|
["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:
|
if optCompileOnly notin conf.globalOptions:
|
||||||
add(cmds, compileCmd)
|
add(cmds, compileCmd)
|
||||||
let (_, name, _) = splitFile(it.cname)
|
let (_, name, _) = splitFile(it.cname)
|
||||||
add(prettyCmds, "CC: " & name)
|
add(prettyCmds, if hintCC in conf.notes: "CC: " & name else: "")
|
||||||
if optGenScript in conf.globalOptions:
|
if optGenScript in conf.globalOptions:
|
||||||
add(script, compileCmd)
|
add(script, compileCmd)
|
||||||
add(script, "\n")
|
add(script, "\n")
|
||||||
|
|
@ -659,7 +659,7 @@ proc getLinkCmd(conf: ConfigRef; projectfile, objfiles: string): string =
|
||||||
libname = getCurrentDir() / libname
|
libname = getCurrentDir() / libname
|
||||||
else:
|
else:
|
||||||
libname = (libNameTmpl(conf) % splitFile(conf.projectName).name)
|
libname = (libNameTmpl(conf) % splitFile(conf.projectName).name)
|
||||||
result = CC[conf.cCompiler].buildLib % ["libfile", libname,
|
result = CC[conf.cCompiler].buildLib % ["libfile", quoteShell(libname),
|
||||||
"objfiles", objfiles]
|
"objfiles", objfiles]
|
||||||
else:
|
else:
|
||||||
var linkerExe = getConfigVar(conf, conf.cCompiler, ".linkerexe")
|
var linkerExe = getConfigVar(conf, conf.cCompiler, ".linkerexe")
|
||||||
|
|
@ -773,7 +773,8 @@ proc callCCompiler*(conf: ConfigRef; projectfile: string) =
|
||||||
var prettyCmds: TStringSeq = @[]
|
var prettyCmds: TStringSeq = @[]
|
||||||
let prettyCb = proc (idx: int) =
|
let prettyCb = proc (idx: int) =
|
||||||
when declared(echo):
|
when declared(echo):
|
||||||
echo prettyCmds[idx]
|
let cmd = prettyCmds[idx]
|
||||||
|
if cmd != "": echo cmd
|
||||||
compileCFile(conf, conf.toCompile, script, cmds, prettyCmds)
|
compileCFile(conf, conf.toCompile, script, cmds, prettyCmds)
|
||||||
if optCompileOnly notin conf.globalOptions:
|
if optCompileOnly notin conf.globalOptions:
|
||||||
execCmdsInParallel(conf, cmds, prettyCb)
|
execCmdsInParallel(conf, cmds, prettyCb)
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ type
|
||||||
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
|
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
|
||||||
warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
|
warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
|
||||||
warnInconsistentSpacing, warnUser,
|
warnInconsistentSpacing, warnUser,
|
||||||
hintSuccess, hintSuccessX,
|
hintSuccess, hintSuccessX, hintCC,
|
||||||
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
|
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
|
||||||
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
|
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
|
||||||
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
|
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
|
||||||
|
|
@ -94,6 +94,7 @@ const
|
||||||
warnUser: "$1",
|
warnUser: "$1",
|
||||||
hintSuccess: "operation successful",
|
hintSuccess: "operation successful",
|
||||||
hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#)",
|
hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#)",
|
||||||
|
hintCC: "CC: \'$1\'", # unused
|
||||||
hintLineTooLong: "line too long",
|
hintLineTooLong: "line too long",
|
||||||
hintXDeclaredButNotUsed: "'$1' is declared but not used",
|
hintXDeclaredButNotUsed: "'$1' is declared but not used",
|
||||||
hintConvToBaseNotNeeded: "conversion to base object is not needed",
|
hintConvToBaseNotNeeded: "conversion to base object is not needed",
|
||||||
|
|
@ -136,7 +137,7 @@ const
|
||||||
"Spacing", "User"]
|
"Spacing", "User"]
|
||||||
|
|
||||||
HintsToStr* = [
|
HintsToStr* = [
|
||||||
"Success", "SuccessX", "LineTooLong",
|
"Success", "SuccessX", "CC", "LineTooLong",
|
||||||
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
|
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
|
||||||
"ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
|
"ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
|
||||||
"Path", "CondTrue", "Name", "Pattern", "Exec", "Link", "Dependency",
|
"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':
|
# hacky way to implement 'x / y /../ z':
|
||||||
result = renderTree(n, {renderNoComments}).replace(" ")
|
result = renderTree(n, {renderNoComments}).replace(" ")
|
||||||
of nkDotExpr:
|
of nkDotExpr:
|
||||||
|
localError(conf, n.info, warnDeprecated, "using '.' instead of '/' in import paths")
|
||||||
result = renderTree(n, {renderNoComments}).replace(".", "/")
|
result = renderTree(n, {renderNoComments}).replace(".", "/")
|
||||||
of nkImportAs:
|
of nkImportAs:
|
||||||
result = getModuleName(conf, n.sons[0])
|
result = getModuleName(conf, n.sons[0])
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,8 @@ type
|
||||||
callOperator,
|
callOperator,
|
||||||
parallel,
|
parallel,
|
||||||
destructor,
|
destructor,
|
||||||
notnil
|
notnil,
|
||||||
|
dynamicBindSym
|
||||||
|
|
||||||
SymbolFilesOption* = enum
|
SymbolFilesOption* = enum
|
||||||
disabledSf, writeOnlySf, readOnlySf, v2Sf
|
disabledSf, writeOnlySf, readOnlySf, v2Sf
|
||||||
|
|
@ -406,8 +407,8 @@ proc mainCommandArg*(conf: ConfigRef): string =
|
||||||
proc existsConfigVar*(conf: ConfigRef; key: string): bool =
|
proc existsConfigVar*(conf: ConfigRef; key: string): bool =
|
||||||
result = hasKey(conf.configVars, key)
|
result = hasKey(conf.configVars, key)
|
||||||
|
|
||||||
proc getConfigVar*(conf: ConfigRef; key: string): string =
|
proc getConfigVar*(conf: ConfigRef; key: string, default = ""): string =
|
||||||
result = conf.configVars.getOrDefault key
|
result = conf.configVars.getOrDefault(key, default)
|
||||||
|
|
||||||
proc setConfigVar*(conf: ConfigRef; key, val: string) =
|
proc setConfigVar*(conf: ConfigRef; key, val: string) =
|
||||||
conf.configVars[key] = val
|
conf.configVars[key] = val
|
||||||
|
|
|
||||||
|
|
@ -207,6 +207,67 @@ proc semBindSym(c: PContext, n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
errorUndeclaredIdentifier(c, n.sons[1].info, sl.strVal)
|
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 semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode
|
||||||
|
|
||||||
proc semOf(c: PContext, n: PNode): 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 mOf: result = semOf(c, n)
|
||||||
of mHigh, mLow: result = semLowHigh(c, n, n[0].sym.magic)
|
of mHigh, mLow: result = semLowHigh(c, n, n[0].sym.magic)
|
||||||
of mShallowCopy: result = semShallowCopy(c, n, flags)
|
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:
|
of mProcCall:
|
||||||
result = n
|
result = n
|
||||||
result.typ = n[1].typ
|
result.typ = n[1].typ
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
# included from sem.nim
|
# included from sem.nim
|
||||||
|
|
||||||
const
|
const
|
||||||
|
errStringOrIdentNodeExpected = "string or ident node expected"
|
||||||
errStringLiteralExpected = "string literal expected"
|
errStringLiteralExpected = "string literal expected"
|
||||||
errIntLiteralExpected = "integer literal expected"
|
errIntLiteralExpected = "integer literal expected"
|
||||||
errWrongNumberOfVariables = "wrong number of variables"
|
errWrongNumberOfVariables = "wrong number of variables"
|
||||||
|
|
|
||||||
|
|
@ -616,19 +616,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
let rc = instr.regC
|
let rc = instr.regC
|
||||||
case regs[ra].kind
|
case regs[ra].kind
|
||||||
of rkNodeAddr:
|
of rkNodeAddr:
|
||||||
# XXX: Workaround for vmgen bug:
|
|
||||||
let n = regs[rc].regToNode
|
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
|
# `var object` parameters are sent as rkNodeAddr. When they are mutated
|
||||||
# vmgen generates opcWrDeref, which means that we must dereference
|
# vmgen generates opcWrDeref, which means that we must dereference
|
||||||
# twice.
|
# twice.
|
||||||
# TODO: This should likely be handled differently in vmgen.
|
# 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):
|
nfIsRef notin n.flags):
|
||||||
regs[ra].nodeAddr[][] = n[]
|
regs[ra].nodeAddr[][] = n[]
|
||||||
else:
|
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.typ.callConv == ccClosure and node.sons[0].kind == nkNilLit and
|
||||||
node.sons[1].kind == nkNilLit))
|
node.sons[1].kind == nkNilLit))
|
||||||
of opcNBindSym:
|
of opcNBindSym:
|
||||||
|
# cannot use this simple check
|
||||||
|
# if dynamicBindSym notin c.config.features:
|
||||||
|
|
||||||
|
# bindSym with static input
|
||||||
decodeBx(rkNode)
|
decodeBx(rkNode)
|
||||||
regs[ra].node = copyTree(c.constants.sons[rbx])
|
regs[ra].node = copyTree(c.constants.sons[rbx])
|
||||||
regs[ra].node.flags.incl nfIsRef
|
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:
|
of opcNChild:
|
||||||
decodeBC(rkNode)
|
decodeBC(rkNode)
|
||||||
let idx = regs[rc].intVal.int
|
let idx = regs[rc].intVal.int
|
||||||
|
|
@ -1416,7 +1425,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
of opcNGetFile:
|
of opcNGetFile:
|
||||||
decodeB(rkNode)
|
decodeB(rkNode)
|
||||||
let n = regs[rb].node
|
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.info = n.info
|
||||||
regs[ra].node.typ = n.typ
|
regs[ra].node.typ = n.typ
|
||||||
of opcNGetLine:
|
of opcNGetLine:
|
||||||
|
|
@ -1780,7 +1789,7 @@ proc getGlobalValue*(c: PCtx; s: PSym): PNode =
|
||||||
|
|
||||||
include vmops
|
include vmops
|
||||||
|
|
||||||
proc setupGlobalCtx(module: PSym; graph: ModuleGraph) =
|
proc setupGlobalCtx*(module: PSym; graph: ModuleGraph) =
|
||||||
if graph.vm.isNil:
|
if graph.vm.isNil:
|
||||||
graph.vm = newCtx(module, graph.cache, graph)
|
graph.vm = newCtx(module, graph.cache, graph)
|
||||||
registerAdditionalOps(PCtx graph.vm)
|
registerAdditionalOps(PCtx graph.vm)
|
||||||
|
|
|
||||||
|
|
@ -136,7 +136,7 @@ type
|
||||||
opcLdGlobalAddr, # dest = addr(globals[Bx])
|
opcLdGlobalAddr, # dest = addr(globals[Bx])
|
||||||
|
|
||||||
opcLdImmInt, # dest = immediate value
|
opcLdImmInt, # dest = immediate value
|
||||||
opcNBindSym,
|
opcNBindSym, opcNDynBindSym,
|
||||||
opcSetType, # dest.typ = types[Bx]
|
opcSetType, # dest.typ = types[Bx]
|
||||||
opcTypeTrait,
|
opcTypeTrait,
|
||||||
opcMarshalLoad, opcMarshalStore,
|
opcMarshalLoad, opcMarshalStore,
|
||||||
|
|
@ -229,7 +229,8 @@ proc refresh*(c: PCtx, module: PSym) =
|
||||||
c.prc = PProc(blocks: @[])
|
c.prc = PProc(blocks: @[])
|
||||||
c.loopIterations = MaxLoopIterations
|
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))
|
c.callbacks.add((name, callback))
|
||||||
|
|
||||||
const
|
const
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,9 @@ when hasFFI:
|
||||||
import evalffi
|
import evalffi
|
||||||
|
|
||||||
type
|
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]
|
TGenFlags = set[TGenFlag]
|
||||||
|
|
||||||
proc debugInfo(c: PCtx; info: TLineInfo): string =
|
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) =
|
proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
|
||||||
case le.kind
|
case le.kind
|
||||||
of nkBracketExpr:
|
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 idx = c.genIndex(le.sons[1], le.sons[0].typ)
|
||||||
c.gABC(le, opcWrArr, dest, idx, value)
|
c.gABC(le, opcWrArr, dest, idx, value)
|
||||||
c.freeTemp(dest)
|
c.freeTemp(dest)
|
||||||
|
|
@ -571,17 +573,17 @@ proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
|
||||||
of nkDotExpr, nkCheckedFieldExpr:
|
of nkDotExpr, nkCheckedFieldExpr:
|
||||||
# XXX field checks here
|
# XXX field checks here
|
||||||
let left = if le.kind == nkDotExpr: le else: le.sons[0]
|
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 idx = genField(c, left.sons[1])
|
||||||
c.gABC(left, opcWrObj, dest, idx, value)
|
c.gABC(left, opcWrObj, dest, idx, value)
|
||||||
c.freeTemp(dest)
|
c.freeTemp(dest)
|
||||||
of nkDerefExpr, nkHiddenDeref:
|
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.gABC(le, opcWrDeref, dest, 0, value)
|
||||||
c.freeTemp(dest)
|
c.freeTemp(dest)
|
||||||
of nkSym:
|
of nkSym:
|
||||||
if le.sym.isGlobal:
|
if le.sym.isGlobal:
|
||||||
let dest = c.genx(le, {gfAddrOf})
|
let dest = c.genx(le, {gfNodeAddr})
|
||||||
c.gABC(le, opcWrDeref, dest, 0, value)
|
c.gABC(le, opcWrDeref, dest, 0, value)
|
||||||
c.freeTemp(dest)
|
c.freeTemp(dest)
|
||||||
else:
|
else:
|
||||||
|
|
@ -815,6 +817,43 @@ proc genVoidABC(c: PCtx, n: PNode, dest: TDest, opcode: TOpcode) =
|
||||||
c.freeTemp(tmp2)
|
c.freeTemp(tmp2)
|
||||||
c.freeTemp(tmp3)
|
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) =
|
proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||||
case m
|
case m
|
||||||
of mAnd: c.genAndOr(n, opcFJmp, dest)
|
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 mNNewNimNode: genBinaryABC(c, n, dest, opcNNewNimNode)
|
||||||
of mNCopyNimNode: genUnaryABC(c, n, dest, opcNCopyNimNode)
|
of mNCopyNimNode: genUnaryABC(c, n, dest, opcNCopyNimNode)
|
||||||
of mNCopyNimTree: genUnaryABC(c, n, dest, opcNCopyNimTree)
|
of mNCopyNimTree: genUnaryABC(c, n, dest, opcNCopyNimTree)
|
||||||
of mNBindSym:
|
of mNBindSym: genBindSym(c, n, dest)
|
||||||
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 mStrToIdent: genUnaryABC(c, n, dest, opcStrToIdent)
|
of mStrToIdent: genUnaryABC(c, n, dest, opcStrToIdent)
|
||||||
of mEqIdent: genBinaryABC(c, n, dest, opcEqIdent)
|
of mEqIdent: genBinaryABC(c, n, dest, opcEqIdent)
|
||||||
of mEqNimrodNode: genBinaryABC(c, n, dest, opcEqNimrodNode)
|
of mEqNimrodNode: genBinaryABC(c, n, dest, opcEqNimrodNode)
|
||||||
|
|
@ -1252,41 +1285,21 @@ proc canElimAddr(n: PNode): PNode =
|
||||||
# addr ( deref ( x )) --> x
|
# addr ( deref ( x )) --> x
|
||||||
result = n.sons[0].sons[0]
|
result = n.sons[0].sons[0]
|
||||||
|
|
||||||
proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
|
proc genAddr(c: PCtx, n: PNode, dest: var TDest, flags: TGenFlags) =
|
||||||
flags: TGenFlags) =
|
if (let m = canElimAddr(n); m != nil):
|
||||||
# a nop for certain types
|
|
||||||
let isAddr = opc in {opcAddrNode, opcAddrReg}
|
|
||||||
if isAddr and (let m = canElimAddr(n); m != nil):
|
|
||||||
gen(c, m, dest, flags)
|
gen(c, m, dest, flags)
|
||||||
return
|
return
|
||||||
|
|
||||||
let af = if n[0].kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr}: {gfAddrOf, gfFieldAccess}
|
let af = if n[0].kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr}: {gfNode}
|
||||||
else: {gfAddrOf}
|
else: {gfNodeAddr}
|
||||||
let newflags = if isAddr: flags+af else: flags
|
let newflags = flags-{gfNode, gfNodeAddr}+af
|
||||||
# consider:
|
|
||||||
# proc foo(f: var ref int) =
|
if isGlobal(n.sons[0]):
|
||||||
# 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]):
|
|
||||||
gen(c, n.sons[0], dest, flags+af)
|
gen(c, n.sons[0], dest, flags+af)
|
||||||
else:
|
else:
|
||||||
let tmp = c.genx(n.sons[0], newflags)
|
let tmp = c.genx(n.sons[0], newflags)
|
||||||
if dest < 0: dest = c.getTemp(n.typ)
|
if dest < 0: dest = c.getTemp(n.typ)
|
||||||
if not isAddr:
|
if c.prc.slots[tmp].kind >= slotTempUnknown:
|
||||||
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:
|
|
||||||
gABC(c, n, opcAddrNode, dest, tmp)
|
gABC(c, n, opcAddrNode, dest, tmp)
|
||||||
# hack ahead; in order to fix bug #1781 we mark the temporary as
|
# hack ahead; in order to fix bug #1781 we mark the temporary as
|
||||||
# permanent, so that it's not used for anything else:
|
# 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)
|
gABC(c, n, opcAddrReg, dest, tmp)
|
||||||
c.freeTemp(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 =
|
proc whichAsgnOpc(n: PNode): TOpcode =
|
||||||
case n.typ.skipTypes(abstractRange-{tyTypeDesc}).kind
|
case n.typ.skipTypes(abstractRange-{tyTypeDesc}).kind
|
||||||
of tyBool, tyChar, tyEnum, tyOrdinal, tyInt..tyInt64, tyUInt..tyUInt64:
|
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) =
|
proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
|
||||||
case le.kind
|
case le.kind
|
||||||
of nkBracketExpr:
|
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 idx = c.genIndex(le.sons[1], le.sons[0].typ)
|
||||||
let tmp = c.genx(ri)
|
let tmp = c.genx(ri)
|
||||||
if le.sons[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind in {
|
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:
|
of nkDotExpr, nkCheckedFieldExpr:
|
||||||
# XXX field checks here
|
# XXX field checks here
|
||||||
let left = if le.kind == nkDotExpr: le else: le.sons[0]
|
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 idx = genField(c, left.sons[1])
|
||||||
let tmp = c.genx(ri)
|
let tmp = c.genx(ri)
|
||||||
c.preventFalseAlias(left, opcWrObj, dest, idx, tmp)
|
c.preventFalseAlias(left, opcWrObj, dest, idx, tmp)
|
||||||
c.freeTemp(tmp)
|
c.freeTemp(tmp)
|
||||||
of nkDerefExpr, nkHiddenDeref:
|
of nkDerefExpr, nkHiddenDeref:
|
||||||
let dest = c.genx(le.sons[0], {gfAddrOf})
|
let dest = c.genx(le.sons[0], {gfNode})
|
||||||
let tmp = c.genx(ri)
|
let tmp = c.genx(ri)
|
||||||
c.preventFalseAlias(le, opcWrDeref, dest, 0, tmp)
|
c.preventFalseAlias(le, opcWrDeref, dest, 0, tmp)
|
||||||
c.freeTemp(tmp)
|
c.freeTemp(tmp)
|
||||||
|
|
@ -1409,7 +1435,7 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
|
||||||
checkCanEval(c, le)
|
checkCanEval(c, le)
|
||||||
if s.isGlobal:
|
if s.isGlobal:
|
||||||
withTemp(tmp, le.typ):
|
withTemp(tmp, le.typ):
|
||||||
c.gen(le, tmp, {gfAddrOf})
|
c.gen(le, tmp, {gfNodeAddr})
|
||||||
let val = c.genx(ri)
|
let val = c.genx(ri)
|
||||||
c.preventFalseAlias(le, opcWrDeref, tmp, 0, val)
|
c.preventFalseAlias(le, opcWrDeref, tmp, 0, val)
|
||||||
c.freeTemp(val)
|
c.freeTemp(val)
|
||||||
|
|
@ -1427,7 +1453,7 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
|
||||||
else:
|
else:
|
||||||
gen(c, ri, dest)
|
gen(c, ri, dest)
|
||||||
else:
|
else:
|
||||||
let dest = c.genx(le, {gfAddrOf})
|
let dest = c.genx(le, {gfNodeAddr})
|
||||||
genAsgn(c, dest, ri, requiresCopy)
|
genAsgn(c, dest, ri, requiresCopy)
|
||||||
|
|
||||||
proc genTypeLit(c: PCtx; t: PType; dest: var TDest) =
|
proc genTypeLit(c: PCtx; t: PType; dest: var TDest) =
|
||||||
|
|
@ -1463,6 +1489,8 @@ proc genGlobalInit(c: PCtx; n: PNode; s: PSym) =
|
||||||
c.freeTemp(tmp)
|
c.freeTemp(tmp)
|
||||||
|
|
||||||
proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
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
|
let s = n.sym
|
||||||
if s.isGlobal:
|
if s.isGlobal:
|
||||||
if sfCompileTime in s.flags or c.mode == emRepl:
|
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)
|
else: genGlobalInit(c, n, s)
|
||||||
if dest < 0: dest = c.getTemp(n.typ)
|
if dest < 0: dest = c.getTemp(n.typ)
|
||||||
assert s.typ != nil
|
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)
|
var cc = c.getTemp(n.typ)
|
||||||
c.gABx(n, opcLdGlobal, cc, s.position)
|
c.gABx(n, opcLdGlobal, cc, s.position)
|
||||||
c.gABC(n, opcNodeToReg, dest, cc)
|
c.gABC(n, opcNodeToReg, dest, cc)
|
||||||
c.freeTemp(cc)
|
c.freeTemp(cc)
|
||||||
elif {gfAddrOf, gfFieldAccess} * flags == {gfAddrOf}:
|
|
||||||
c.gABx(n, opcLdGlobalAddr, dest, s.position)
|
|
||||||
else:
|
else:
|
||||||
c.gABx(n, opcLdGlobal, dest, s.position)
|
c.gABx(n, opcLdGlobal, dest, s.position)
|
||||||
else:
|
else:
|
||||||
|
|
@ -1498,7 +1526,8 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
||||||
cannotEval(c, n)
|
cannotEval(c, n)
|
||||||
|
|
||||||
template needsRegLoad(): untyped =
|
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;
|
proc genArrAccess2(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
|
||||||
flags: TGenFlags) =
|
flags: TGenFlags) =
|
||||||
|
|
@ -1634,7 +1663,7 @@ proc genVarSection(c: PCtx; n: PNode) =
|
||||||
c.globals.add(sa)
|
c.globals.add(sa)
|
||||||
s.position = c.globals.len
|
s.position = c.globals.len
|
||||||
if a.sons[2].kind != nkEmpty:
|
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])
|
let val = c.genx(a.sons[2])
|
||||||
c.genAdditionalCopy(a.sons[2], opcWrDeref, tmp, 0, val)
|
c.genAdditionalCopy(a.sons[2], opcWrDeref, tmp, 0, val)
|
||||||
c.freeTemp(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 nkDotExpr: genObjAccess(c, n, dest, flags)
|
||||||
of nkCheckedFieldExpr: genCheckedObjAccess(c, n, dest, flags)
|
of nkCheckedFieldExpr: genCheckedObjAccess(c, n, dest, flags)
|
||||||
of nkBracketExpr: genArrAccess(c, n, dest, flags)
|
of nkBracketExpr: genArrAccess(c, n, dest, flags)
|
||||||
of nkDerefExpr, nkHiddenDeref: genAddrDeref(c, n, dest, opcLdDeref, flags)
|
of nkDerefExpr, nkHiddenDeref: genDeref(c, n, dest, flags)
|
||||||
of nkAddr, nkHiddenAddr: genAddrDeref(c, n, dest, opcAddrNode, flags)
|
of nkAddr, nkHiddenAddr: genAddr(c, n, dest, flags)
|
||||||
of nkIfStmt, nkIfExpr: genIf(c, n, dest)
|
of nkIfStmt, nkIfExpr: genIf(c, n, dest)
|
||||||
of nkWhenStmt:
|
of nkWhenStmt:
|
||||||
# This is "when nimvm" node. Chose the first branch.
|
# 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
|
# 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
|
# the empty string if you don't pass anything through --docSeeSrcURL. Available
|
||||||
# substitutaion variables here are:
|
# 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.
|
# * $path: relative path to the file being processed.
|
||||||
# * $line: line of the item in the original source file.
|
# * $line: line of the item in the original source file.
|
||||||
# * $url: whatever you did pass through the --docSeeSrcUrl switch (which also
|
# * $url: whatever you did pass through the --docSeeSrcUrl switch (which also
|
||||||
|
|
@ -62,7 +64,7 @@ doc.item.toc = """
|
||||||
doc.item.seesrc = """ <a
|
doc.item.seesrc = """ <a
|
||||||
href="${url}/tree/${commit}/${path}#L${line}"
|
href="${url}/tree/${commit}/${path}#L${line}"
|
||||||
class="link-seesrc" target="_blank">Source</a>
|
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 = """
|
doc.toc = """
|
||||||
|
|
|
||||||
|
|
@ -6229,10 +6229,10 @@ imported:
|
||||||
:test: "nim c $1"
|
:test: "nim c $1"
|
||||||
:status: 1
|
:status: 1
|
||||||
|
|
||||||
import strutils except `%`, toUpper
|
import strutils except `%`, toUpperAscii
|
||||||
|
|
||||||
# doesn't work then:
|
# 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.
|
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")
|
echo su.format("$1", "lalelu")
|
||||||
|
|
||||||
The original module name is then not accessible. The
|
The original module name is then not accessible. The notations
|
||||||
notations ``path/to/module`` or ``path.to.module`` or ``"path/to/module"``
|
``path/to/module`` or ``"path/to/module"`` can be used to refer to a module
|
||||||
can be used to refer to a module in subdirectories:
|
in subdirectories:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. 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:
|
and so one **cannot** do:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
import lib.pure.strutils
|
import lib/pure/strutils
|
||||||
echo lib.pure.strutils
|
echo lib/pure/strutils.toUpperAscii("abc")
|
||||||
|
|
||||||
Likewise the following does not make sense as the name is ``strutils`` already:
|
Likewise the following does not make sense as the name is ``strutils`` already:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
import lib.pure.strutils as strutils
|
import lib/pure/strutils as strutils
|
||||||
|
|
||||||
|
|
||||||
Collective imports from a directory
|
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
|
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:
|
There are two pseudo directories:
|
||||||
|
|
||||||
|
|
|
||||||
1
koch.nim
1
koch.nim
|
|
@ -50,6 +50,7 @@ Boot options:
|
||||||
|
|
||||||
Commands for core developers:
|
Commands for core developers:
|
||||||
web [options] generates the website and the full documentation
|
web [options] generates the website and the full documentation
|
||||||
|
(see `nimweb.nim` for cmd line options)
|
||||||
website [options] generates only the website
|
website [options] generates only the website
|
||||||
csource -d:release builds the C sources for installation
|
csource -d:release builds the C sources for installation
|
||||||
pdf builds the PDF documentation
|
pdf builds the PDF documentation
|
||||||
|
|
|
||||||
|
|
@ -382,16 +382,24 @@ type
|
||||||
|
|
||||||
{.deprecated: [TBindSymRule: BindSymRule].}
|
{.deprecated: [TBindSymRule: BindSymRule].}
|
||||||
|
|
||||||
proc bindSym*(ident: static[string], rule: BindSymRule = brClosed): NimNode {.
|
proc bindSym*(ident: string | NimNode, rule: BindSymRule = brClosed): NimNode {.
|
||||||
magic: "NBindSym", noSideEffect.}
|
magic: "NBindSym", noSideEffect.}
|
||||||
## creates a node that binds `ident` to a symbol node. The bound symbol
|
## creates a node that binds `ident` to a symbol node. The bound symbol
|
||||||
## may be an overloaded symbol.
|
## may be an overloaded symbol.
|
||||||
|
## if `ident` is a NimNode, it must have nkIdent kind.
|
||||||
## If ``rule == brClosed`` either an ``nkClosedSymChoice`` tree is
|
## If ``rule == brClosed`` either an ``nkClosedSymChoice`` tree is
|
||||||
## returned or ``nkSym`` if the symbol is not ambiguous.
|
## returned or ``nkSym`` if the symbol is not ambiguous.
|
||||||
## If ``rule == brOpen`` either an ``nkOpenSymChoice`` tree is
|
## If ``rule == brOpen`` either an ``nkOpenSymChoice`` tree is
|
||||||
## returned or ``nkSym`` if the symbol is not ambiguous.
|
## returned or ``nkSym`` if the symbol is not ambiguous.
|
||||||
## If ``rule == brForceOpen`` always an ``nkOpenSymChoice`` tree is
|
## If ``rule == brForceOpen`` always an ``nkOpenSymChoice`` tree is
|
||||||
## returned even if the symbol is not ambiguous.
|
## 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 {.
|
proc genSym*(kind: NimSymKind = nskLet; ident = ""): NimNode {.
|
||||||
magic: "NGenSym", noSideEffect.}
|
magic: "NGenSym", noSideEffect.}
|
||||||
|
|
@ -425,6 +433,7 @@ proc getColumn(arg: NimNode): int {.magic: "NLineInfo", noSideEffect.}
|
||||||
proc getFile(arg: NimNode): string {.magic: "NLineInfo", noSideEffect.}
|
proc getFile(arg: NimNode): string {.magic: "NLineInfo", noSideEffect.}
|
||||||
|
|
||||||
proc lineInfoObj*(n: NimNode): LineInfo {.compileTime.} =
|
proc lineInfoObj*(n: NimNode): LineInfo {.compileTime.} =
|
||||||
|
## returns ``LineInfo`` of ``n``, using absolute path for ``filename``
|
||||||
result.filename = n.getFile
|
result.filename = n.getFile
|
||||||
result.line = n.getLine
|
result.line = n.getLine
|
||||||
result.column = n.getColumn
|
result.column = n.getColumn
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@
|
||||||
## immediately.
|
## immediately.
|
||||||
##
|
##
|
||||||
## .. code-block:: Nim
|
## .. 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")
|
## socket.sendTo("192.168.0.1", Port(27960), "status\n")
|
||||||
##
|
##
|
||||||
## Creating a server
|
## Creating a server
|
||||||
|
|
|
||||||
|
|
@ -436,8 +436,9 @@ proc requestOsChunks(a: var MemRegion, size: int): PBigChunk =
|
||||||
a.nextChunkSize = PageSize*4
|
a.nextChunkSize = PageSize*4
|
||||||
else:
|
else:
|
||||||
a.nextChunkSize = min(roundup(usedMem shr 2, PageSize), a.nextChunkSize * 2)
|
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:
|
if size > a.nextChunkSize:
|
||||||
result = cast[PBigChunk](osAllocPages(size))
|
result = cast[PBigChunk](osAllocPages(size))
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,12 @@ proc main =
|
||||||
dealloc p
|
dealloc p
|
||||||
# c_fprintf(stdout, "iteration: %ld size: %ld\n", i, size)
|
# c_fprintf(stdout, "iteration: %ld size: %ld\n", i, size)
|
||||||
when defined(cpu64):
|
when defined(cpu64):
|
||||||
# bug #7120
|
# see https://github.com/nim-lang/Nim/issues/8509
|
||||||
var x = alloc(((1 shl 29) - 4) * 8)
|
# this often made appveyor (on windows) fail with out of memory
|
||||||
dealloc x
|
when defined(posix):
|
||||||
|
# bug #7120
|
||||||
|
var x = alloc(((1 shl 29) - 4) * 8)
|
||||||
|
dealloc x
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
discard """
|
discard """
|
||||||
|
msg: '''initApple
|
||||||
|
deinitApple
|
||||||
|
Coral
|
||||||
|
enum
|
||||||
|
redCoral, blackCoral'''
|
||||||
output: '''TFoo
|
output: '''TFoo
|
||||||
TBar'''
|
TBar'''
|
||||||
"""
|
"""
|
||||||
|
|
@ -23,3 +28,40 @@ macro test: untyped =
|
||||||
bindSym("TBar"))
|
bindSym("TBar"))
|
||||||
|
|
||||||
test()
|
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
|
echo getLastModificationTime("a") == tm
|
||||||
removeFile("a")
|
removeFile("a")
|
||||||
|
|
||||||
when defined(Linux) or defined(osx):
|
when defined(posix):
|
||||||
|
|
||||||
block normalizedPath:
|
block normalizedPath:
|
||||||
block relative:
|
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
|
var x: ptr int
|
||||||
|
|
||||||
x = cast[ptr int](alloc(7))
|
x = cast[ptr int](alloc(7))
|
||||||
assert x != nil
|
doAssert x != nil
|
||||||
x = cast[ptr int](x.realloc(2))
|
x = cast[ptr int](x.realloc(2))
|
||||||
assert x != nil
|
doAssert x != nil
|
||||||
x.dealloc()
|
x.dealloc()
|
||||||
|
|
||||||
x = createU(int, 3)
|
x = createU(int, 3)
|
||||||
assert x != nil
|
doAssert x != nil
|
||||||
x.dealloc()
|
x.dealloc()
|
||||||
|
|
||||||
x = create(int, 4)
|
x = create(int, 4)
|
||||||
assert cast[ptr array[4, int]](x)[0] == 0
|
doAssert cast[ptr array[4, int]](x)[0] == 0
|
||||||
assert cast[ptr array[4, int]](x)[1] == 0
|
doAssert cast[ptr array[4, int]](x)[1] == 0
|
||||||
assert cast[ptr array[4, int]](x)[2] == 0
|
doAssert cast[ptr array[4, int]](x)[2] == 0
|
||||||
assert cast[ptr array[4, int]](x)[3] == 0
|
doAssert cast[ptr array[4, int]](x)[3] == 0
|
||||||
|
|
||||||
x = x.resize(4)
|
x = x.resize(4)
|
||||||
assert x != nil
|
doAssert x != nil
|
||||||
x.dealloc()
|
x.dealloc()
|
||||||
|
|
||||||
x = cast[ptr int](allocShared(100))
|
x = cast[ptr int](allocShared(100))
|
||||||
assert x != nil
|
doAssert x != nil
|
||||||
deallocShared(x)
|
deallocShared(x)
|
||||||
|
|
||||||
x = createSharedU(int, 3)
|
x = createSharedU(int, 3)
|
||||||
assert x != nil
|
doAssert x != nil
|
||||||
x.deallocShared()
|
x.deallocShared()
|
||||||
|
|
||||||
x = createShared(int, 3)
|
x = createShared(int, 3)
|
||||||
assert x != nil
|
doAssert x != nil
|
||||||
assert cast[ptr array[3, int]](x)[0] == 0
|
doAssert cast[ptr array[3, int]](x)[0] == 0
|
||||||
assert cast[ptr array[3, int]](x)[1] == 0
|
doAssert cast[ptr array[3, int]](x)[1] == 0
|
||||||
assert cast[ptr array[3, int]](x)[2] == 0
|
doAssert cast[ptr array[3, int]](x)[2] == 0
|
||||||
|
|
||||||
assert x != nil
|
doAssert x != nil
|
||||||
x = cast[ptr int](x.resizeShared(2))
|
x = cast[ptr int](x.resizeShared(2))
|
||||||
assert x != nil
|
doAssert x != nil
|
||||||
x.deallocShared()
|
x.deallocShared()
|
||||||
|
|
||||||
x = create(int, 10)
|
x = create(int, 10)
|
||||||
assert x != nil
|
doAssert x != nil
|
||||||
x = x.resize(12)
|
x = x.resize(12)
|
||||||
assert x != nil
|
doAssert x != nil
|
||||||
x.dealloc()
|
x.dealloc()
|
||||||
|
|
||||||
x = createShared(int, 1)
|
x = createShared(int, 1)
|
||||||
assert x != nil
|
doAssert x != nil
|
||||||
x = x.resizeShared(1)
|
x = x.resizeShared(1)
|
||||||
assert x != nil
|
doAssert x != nil
|
||||||
x.deallocShared()
|
x.deallocShared()
|
||||||
|
|
||||||
x = cast[ptr int](alloc0(125 shl 23))
|
x = cast[ptr int](alloc0(125 shl 23))
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
discard """
|
||||||
|
"""
|
||||||
|
|
||||||
const
|
const
|
||||||
nmax = 2*1024*1024*1024
|
nmax = 2*1024*1024*1024
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ proc main() =
|
||||||
for val in table.values():
|
for val in table.values():
|
||||||
if myObj2.isNil:
|
if myObj2.isNil:
|
||||||
myObj2 = val
|
myObj2 = val
|
||||||
assert(myObj == myObj2) # passes
|
doAssert(myObj == myObj2) # passes
|
||||||
|
|
||||||
var tableCopy: ListTableRef[int, SomeObj]
|
var tableCopy: ListTableRef[int, SomeObj]
|
||||||
deepCopy(tableCopy, table)
|
deepCopy(tableCopy, table)
|
||||||
|
|
@ -80,7 +80,7 @@ proc main() =
|
||||||
#echo cast[int](myObjCopy)
|
#echo cast[int](myObjCopy)
|
||||||
#echo cast[int](myObjCopy2)
|
#echo cast[int](myObjCopy2)
|
||||||
|
|
||||||
assert(myObjCopy == myObjCopy2) # fails
|
doAssert(myObjCopy == myObjCopy2) # fails
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
@ -88,7 +88,7 @@ type
|
||||||
counter, max: int
|
counter, max: int
|
||||||
data: array[0..99, (pointer, pointer)]
|
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()
|
main()
|
||||||
echo "ok"
|
echo "ok"
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
discard """
|
||||||
|
"""
|
||||||
|
|
||||||
import
|
import
|
||||||
unittest, osproc, streams, os, strformat
|
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."
|
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}")
|
discard execProcess(&"dd if=/dev/zero of={fn} bs=1000000 count={size_in_mb}")
|
||||||
|
|
||||||
doAssert os.getFileSize(fn) == sz # Verify OS filesize by string
|
doAssert os.getFileSize(fn) == sz # Verify OS filesize by string
|
||||||
|
|
||||||
var f = open(fn)
|
var f = open(fn)
|
||||||
doAssert f.getFileSize() == sz # Verify file handle filesize
|
doAssert f.getFileSize() == sz # Verify file handle filesize
|
||||||
f.close()
|
f.close()
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
discard """
|
||||||
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import osproc
|
import osproc
|
||||||
import parseopt2
|
import parseopt2
|
||||||
|
|
@ -7,12 +10,12 @@ let argv = commandLineParams()
|
||||||
|
|
||||||
if argv == @[]:
|
if argv == @[]:
|
||||||
# this won't work with spaces
|
# 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:
|
else:
|
||||||
let f = toSeq(getopt())
|
let f = toSeq(getopt())
|
||||||
echo f.repr
|
echo f.repr
|
||||||
assert f[0].kind == cmdArgument and f[0].key == "foo bar" and f[0].val == ""
|
doAssert 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"
|
doAssert 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"
|
doAssert 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 == ""
|
doAssert 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[4].kind == cmdShortOption and f[4].key == "c" and f[4].val == ""
|
||||||
|
|
|
||||||
|
|
@ -54,4 +54,9 @@ static:
|
||||||
new(s)
|
new(s)
|
||||||
var ss = s
|
var ss = s
|
||||||
s[] = 1
|
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
|
from xmltree import escape
|
||||||
|
|
||||||
const gitRepo = "https://github.com/nim-lang/Nim"
|
|
||||||
|
|
||||||
type
|
type
|
||||||
TKeyValPair = tuple[key, id, val: string]
|
TKeyValPair = tuple[key, id, val: string]
|
||||||
TConfigData = object of RootObj
|
TConfigData = object of RootObj
|
||||||
tabs, links: seq[TKeyValPair]
|
tabs, links: seq[TKeyValPair]
|
||||||
doc, srcdoc, srcdoc2, webdoc, pdf: seq[string]
|
doc, srcdoc, srcdoc2, webdoc, pdf: seq[string]
|
||||||
authors, projectName, projectTitle, logo, infile, outdir, ticker: string
|
authors, projectName, projectTitle, logo, infile, ticker: string
|
||||||
vars: StringTableRef
|
vars: StringTableRef
|
||||||
|
nimCompiler: string
|
||||||
nimArgs: string
|
nimArgs: string
|
||||||
|
gitURL: string
|
||||||
|
docHTMLOutput: string
|
||||||
|
webUploadOutput: string
|
||||||
quotations: Table[string, tuple[quote, author: string]]
|
quotations: Table[string, tuple[quote, author: string]]
|
||||||
numProcessors: int # Set by parallelBuild:n, only works for values > 0.
|
numProcessors: int # Set by parallelBuild:n, only works for values > 0.
|
||||||
gaId: string # google analytics ID, nil means analytics are disabled
|
gaId: string # google analytics ID, nil means analytics are disabled
|
||||||
|
|
@ -51,8 +53,10 @@ proc initConfigData(c: var TConfigData) =
|
||||||
c.webdoc = @[]
|
c.webdoc = @[]
|
||||||
c.pdf = @[]
|
c.pdf = @[]
|
||||||
c.infile = ""
|
c.infile = ""
|
||||||
c.outdir = ""
|
|
||||||
c.nimArgs = "--hint[Conf]:off --hint[Path]:off --hint[Processing]:off -d:boot "
|
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.authors = ""
|
||||||
c.projectTitle = ""
|
c.projectTitle = ""
|
||||||
c.projectName = ""
|
c.projectName = ""
|
||||||
|
|
@ -79,14 +83,19 @@ const
|
||||||
Usage:
|
Usage:
|
||||||
nimweb [options] ini-file[.ini] [compile_options]
|
nimweb [options] ini-file[.ini] [compile_options]
|
||||||
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
|
-h, --help shows this help
|
||||||
-v, --version shows the version
|
-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
|
--website only build the website, not the full documentation
|
||||||
--pdf build the PDF version of the documentation
|
--pdf build the PDF version of the documentation
|
||||||
--json2 build JSON of the documentation
|
--json2 build JSON of the documentation
|
||||||
--onlyDocs build only 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:
|
Compile_options:
|
||||||
will be passed to the Nim compiler
|
will be passed to the Nim compiler
|
||||||
"""
|
"""
|
||||||
|
|
@ -145,7 +154,11 @@ proc parseCmdLine(c: var TConfigData) =
|
||||||
of "version", "v":
|
of "version", "v":
|
||||||
stdout.write(version & "\n")
|
stdout.write(version & "\n")
|
||||||
quit(0)
|
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":
|
of "parallelbuild":
|
||||||
try:
|
try:
|
||||||
let num = parseInt(val)
|
let num = parseInt(val)
|
||||||
|
|
@ -163,8 +176,14 @@ proc parseCmdLine(c: var TConfigData) =
|
||||||
of "googleanalytics":
|
of "googleanalytics":
|
||||||
c.gaId = val
|
c.gaId = val
|
||||||
c.nimArgs.add("--doc.googleAnalytics:" & 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:
|
else:
|
||||||
echo("Invalid argument $1" % [key])
|
echo("Invalid argument '$1'" % [key])
|
||||||
quit(usage)
|
quit(usage)
|
||||||
of cmdEnd: break
|
of cmdEnd: break
|
||||||
if c.infile.len == 0: quit(usage)
|
if c.infile.len == 0: quit(usage)
|
||||||
|
|
@ -244,15 +263,14 @@ proc parseIniFile(c: var TConfigData) =
|
||||||
close(p)
|
close(p)
|
||||||
if c.projectName.len == 0:
|
if c.projectName.len == 0:
|
||||||
c.projectName = changeFileExt(extractFilename(c.infile), "")
|
c.projectName = changeFileExt(extractFilename(c.infile), "")
|
||||||
if c.outdir.len == 0:
|
|
||||||
c.outdir = splitFile(c.infile).dir
|
|
||||||
|
|
||||||
# ------------------- main ----------------------------------------------------
|
# ------------------- main ----------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
proc exe(f: string): string = return addFileExt(f, ExeExt)
|
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
|
var nim = "nim".exe
|
||||||
result = "bin" / nim
|
result = "bin" / nim
|
||||||
if existsFile(result): return
|
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
|
## it didn't make much sense to integrate into the existing generic
|
||||||
## documentation builders.
|
## documentation builders.
|
||||||
const src = "doc"/"docgen_sample.nim"
|
const src = "doc"/"docgen_sample.nim"
|
||||||
exec(findNim() & " doc $# -o:$# $#" %
|
exec(findNim(c) & " doc $# -o:$# $#" %
|
||||||
[c.nimArgs, destPath / "docgen_sample.html", src])
|
[c.nimArgs, destPath / "docgen_sample.html", src])
|
||||||
exec(findNim() & " doc2 $# -o:$# $#" %
|
exec(findNim(c) & " doc2 $# -o:$# $#" %
|
||||||
[c.nimArgs, destPath / "docgen_sample2.html", src])
|
[c.nimArgs, destPath / "docgen_sample2.html", src])
|
||||||
|
|
||||||
proc pathPart(d: string): string = splitFile(d).dir.replace('\\', '/')
|
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))
|
commands = newSeq[string](len(c.doc) + len(c.srcdoc) + len(c.srcdoc2))
|
||||||
i = 0
|
i = 0
|
||||||
for d in items(c.doc):
|
for d in items(c.doc):
|
||||||
commands[i] = findNim() & " rst2html $# --git.url:$# -o:$# --index:on $#" %
|
commands[i] = findNim(c) & " rst2html $# --git.url:$# -o:$# --index:on $#" %
|
||||||
[c.nimArgs, gitRepo,
|
[c.nimArgs, c.gitURL,
|
||||||
destPath / changeFileExt(splitFile(d).name, "html"), d]
|
destPath / changeFileExt(splitFile(d).name, "html"), d]
|
||||||
i.inc
|
i.inc
|
||||||
for d in items(c.srcdoc):
|
for d in items(c.srcdoc):
|
||||||
commands[i] = findNim() & " doc0 $# --git.url:$# -o:$# --index:on $#" %
|
commands[i] = findNim(c) & " doc0 $# --git.url:$# -o:$# --index:on $#" %
|
||||||
[c.nimArgs, gitRepo,
|
[c.nimArgs, c.gitURL,
|
||||||
destPath / changeFileExt(splitFile(d).name, "html"), d]
|
destPath / changeFileExt(splitFile(d).name, "html"), d]
|
||||||
i.inc
|
i.inc
|
||||||
for d in items(c.srcdoc2):
|
for d in items(c.srcdoc2):
|
||||||
commands[i] = findNim() & " doc2 $# --git.url:$# -o:$# --index:on $#" %
|
commands[i] = findNim(c) & " doc2 $# --git.url:$# -o:$# --index:on $#" %
|
||||||
[c.nimArgs, gitRepo,
|
[c.nimArgs, c.gitURL,
|
||||||
destPath / changeFileExt(splitFile(d).name, "html"), d]
|
destPath / changeFileExt(splitFile(d).name, "html"), d]
|
||||||
i.inc
|
i.inc
|
||||||
|
|
||||||
mexec(commands, c.numProcessors)
|
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) =
|
proc buildPdfDoc(c: var TConfigData, destPath: string) =
|
||||||
createDir(destPath)
|
createDir(destPath)
|
||||||
|
|
@ -327,7 +345,7 @@ proc buildPdfDoc(c: var TConfigData, destPath: string) =
|
||||||
else:
|
else:
|
||||||
const pdflatexcmd = "pdflatex -interaction=nonstopmode "
|
const pdflatexcmd = "pdflatex -interaction=nonstopmode "
|
||||||
for d in items(c.pdf):
|
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:
|
# call LaTeX twice to get cross references right:
|
||||||
exec(pdflatexcmd & changeFileExt(d, "tex"))
|
exec(pdflatexcmd & changeFileExt(d, "tex"))
|
||||||
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):
|
# build additional documentation (without the index):
|
||||||
var commands = newSeq[string](c.webdoc.len)
|
var commands = newSeq[string](c.webdoc.len)
|
||||||
for i, doc in pairs(c.webdoc):
|
for i, doc in pairs(c.webdoc):
|
||||||
commands[i] = findNim() & " doc2 $# --git.url:$# -o:$# $#" %
|
commands[i] = findNim(c) & " doc2 $# --git.url:$# -o:$# $#" %
|
||||||
[c.nimArgs, gitRepo,
|
[c.nimArgs, c.gitURL,
|
||||||
destPath / changeFileExt(splitFile(doc).name, "html"), doc]
|
destPath / changeFileExt(splitFile(doc).name, "html"), doc]
|
||||||
mexec(commands, c.numProcessors)
|
mexec(commands, c.numProcessors)
|
||||||
|
|
||||||
|
|
@ -431,9 +449,9 @@ proc buildNewsRss(c: var TConfigData, destPath: string) =
|
||||||
|
|
||||||
generateRss(destFilename, parseNewsTitles(srcFilename))
|
generateRss(destFilename, parseNewsTitles(srcFilename))
|
||||||
|
|
||||||
proc buildJS(destPath: string) =
|
proc buildJS(c: TConfigData) =
|
||||||
exec(findNim() & " js -d:release --out:$1 web/nimblepkglist.nim" %
|
exec(findNim(c) & " js -d:release --out:$1 web/nimblepkglist.nim" %
|
||||||
[destPath / "nimblepkglist.js"])
|
[c.webUploadOutput / "nimblepkglist.js"])
|
||||||
|
|
||||||
proc readSponsors(sponsorsFile: string): seq[Sponsor] =
|
proc readSponsors(sponsorsFile: string): seq[Sponsor] =
|
||||||
result = @[]
|
result = @[]
|
||||||
|
|
@ -464,7 +482,7 @@ const
|
||||||
cmdRst2Html = " rst2html --compileonly $1 -o:web/$2.temp web/$2.rst"
|
cmdRst2Html = " rst2html --compileonly $1 -o:web/$2.temp web/$2.rst"
|
||||||
|
|
||||||
proc buildPage(c: var TConfigData, file, title, rss: string, assetDir = "") =
|
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 temp = "web" / changeFileExt(file, "temp")
|
||||||
var content: string
|
var content: string
|
||||||
try:
|
try:
|
||||||
|
|
@ -472,7 +490,7 @@ proc buildPage(c: var TConfigData, file, title, rss: string, assetDir = "") =
|
||||||
except IOError:
|
except IOError:
|
||||||
quit("[Error] cannot open: " & temp)
|
quit("[Error] cannot open: " & temp)
|
||||||
var f: File
|
var f: File
|
||||||
var outfile = "web/upload/$#.html" % file
|
var outfile = c.webUploadOutput / "$#.html" % file
|
||||||
if not existsDir(outfile.splitFile.dir):
|
if not existsDir(outfile.splitFile.dir):
|
||||||
createDir(outfile.splitFile.dir)
|
createDir(outfile.splitFile.dir)
|
||||||
if open(f, outfile, fmWrite):
|
if open(f, outfile, fmWrite):
|
||||||
|
|
@ -502,27 +520,25 @@ proc buildWebsite(c: var TConfigData) =
|
||||||
let rss = if file in ["news", "index"]: extractFilename(rssUrl) else: ""
|
let rss = if file in ["news", "index"]: extractFilename(rssUrl) else: ""
|
||||||
if '.' in file: continue
|
if '.' in file: continue
|
||||||
buildPage(c, file, if file == "question": "FAQ" else: file, rss)
|
buildPage(c, file, if file == "question": "FAQ" else: file, rss)
|
||||||
copyDir("web/assets", "web/upload/assets")
|
copyDir("web/assets", c.webUploadOutput / "assets")
|
||||||
buildNewsRss(c, "web/upload")
|
buildNewsRss(c, c.webUploadOutput)
|
||||||
buildSponsors(c, "web/upload")
|
buildSponsors(c, c.webUploadOutput)
|
||||||
buildNews(c, "web/news", "web/upload/news")
|
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) =
|
proc main(c: var TConfigData) =
|
||||||
buildWebsite(c)
|
buildWebsite(c)
|
||||||
buildJS("web/upload")
|
buildJS(c)
|
||||||
const docup = "web/upload/" & NimVersion
|
let docup = c.webUploadOutput / NimVersion
|
||||||
createDir(docup)
|
createDir(docup)
|
||||||
buildAddDoc(c, docup)
|
buildAddDoc(c, docup)
|
||||||
buildDocSamples(c, docup)
|
buildDocSamples(c, docup)
|
||||||
buildDoc(c, docup)
|
buildDoc(c, docup)
|
||||||
createDir("doc/html")
|
onlyDocs(c)
|
||||||
buildDocSamples(c, "doc/html")
|
|
||||||
buildDoc(c, "doc/html")
|
|
||||||
|
|
||||||
proc onlyDocs(c: var TConfigData) =
|
|
||||||
createDir("doc/html")
|
|
||||||
buildDocSamples(c, "doc/html")
|
|
||||||
buildDoc(c, "doc/html")
|
|
||||||
|
|
||||||
proc json2(c: var TConfigData) =
|
proc json2(c: var TConfigData) =
|
||||||
const destPath = "web/json2"
|
const destPath = "web/json2"
|
||||||
|
|
@ -530,8 +546,8 @@ proc json2(c: var TConfigData) =
|
||||||
var i = 0
|
var i = 0
|
||||||
for d in items(c.srcdoc2):
|
for d in items(c.srcdoc2):
|
||||||
createDir(destPath / splitFile(d).dir)
|
createDir(destPath / splitFile(d).dir)
|
||||||
commands[i] = findNim() & " jsondoc2 $# --git.url:$# -o:$# --index:on $#" %
|
commands[i] = findNim(c) & " jsondoc2 $# --git.url:$# -o:$# --index:on $#" %
|
||||||
[c.nimArgs, gitRepo,
|
[c.nimArgs, c.gitURL,
|
||||||
destPath / changeFileExt(d, "json"), d]
|
destPath / changeFileExt(d, "json"), d]
|
||||||
i.inc
|
i.inc
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue