Merge branch 'devel' into araq-fixes-7833

This commit is contained in:
Araq 2018-08-04 15:52:34 +02:00
commit 9235f7a3b3
28 changed files with 399 additions and 173 deletions

View file

@ -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

View file

@ -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",

View file

@ -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)

View file

@ -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",

View file

@ -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])

View file

@ -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

View file

@ -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

View file

@ -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"

View file

@ -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)

View file

@ -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

View file

@ -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.

View file

@ -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 = """&nbsp;&nbsp;<a doc.item.seesrc = """&nbsp;&nbsp;<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 = """

View file

@ -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:

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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:

View file

@ -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()

View file

@ -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()

View file

@ -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
View 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

View file

@ -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))

View file

@ -1,3 +1,6 @@
discard """
"""
const const
nmax = 2*1024*1024*1024 nmax = 2*1024*1024*1024

View file

@ -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"

View file

@ -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."

View file

@ -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 == ""

View file

@ -55,3 +55,8 @@ static:
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

View file

@ -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