mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-02 11:12:37 +00:00
Resolve conflic.
This commit is contained in:
@@ -82,7 +82,7 @@ template mdbg*: bool {.dirty.} =
|
||||
elif compiles(L.fileIdx):
|
||||
L.fileIdx == gProjectMainIdx
|
||||
else:
|
||||
false
|
||||
error()
|
||||
|
||||
# --------------------------- ident tables ----------------------------------
|
||||
proc idTableGet*(t: TIdTable, key: PIdObj): RootRef
|
||||
|
||||
@@ -604,6 +604,7 @@ proc generateHeaders(m: BModule) =
|
||||
else:
|
||||
addf(m.s[cfsHeaders], "#include $1$N", [rope(it)])
|
||||
add(m.s[cfsHeaders], "#undef linux" & tnl)
|
||||
add(m.s[cfsHeaders], "#undef near" & tnl)
|
||||
|
||||
proc initFrame(p: BProc, procname, filename: Rope): Rope =
|
||||
discard cgsym(p.module, "nimFrame")
|
||||
|
||||
@@ -229,6 +229,7 @@ proc genDispatcher(methods: TSymSeq, relevantCols: IntSet): PSym =
|
||||
var base = lastSon(methods[0].ast).sym
|
||||
result = base
|
||||
var paramLen = sonsLen(base.typ)
|
||||
var nilchecks = newNodeI(nkStmtList, base.info)
|
||||
var disp = newNodeI(nkIfStmt, base.info)
|
||||
var ands = getSysSym("and")
|
||||
var iss = getSysSym("of")
|
||||
@@ -239,7 +240,11 @@ proc genDispatcher(methods: TSymSeq, relevantCols: IntSet): PSym =
|
||||
if contains(relevantCols, col):
|
||||
var isn = newNodeIT(nkCall, base.info, getSysType(tyBool))
|
||||
addSon(isn, newSymNode(iss))
|
||||
addSon(isn, newSymNode(base.typ.n.sons[col].sym))
|
||||
let param = base.typ.n.sons[col].sym
|
||||
addSon(isn, newSymNode(param))
|
||||
if param.typ.skipTypes(abstractInst).kind in {tyRef, tyPtr}:
|
||||
addSon(nilchecks, newTree(nkCall,
|
||||
newSymNode(getCompilerProc"chckNilDisp"), newSymNode(param)))
|
||||
addSon(isn, newNodeIT(nkType, base.info, curr.typ.sons[col]))
|
||||
if cond != nil:
|
||||
var a = newNodeIT(nkCall, base.info, getSysType(tyBool))
|
||||
@@ -270,7 +275,8 @@ proc genDispatcher(methods: TSymSeq, relevantCols: IntSet): PSym =
|
||||
addSon(disp, a)
|
||||
else:
|
||||
disp = ret
|
||||
result.ast.sons[bodyPos] = disp
|
||||
nilchecks.add disp
|
||||
result.ast.sons[bodyPos] = nilchecks
|
||||
|
||||
proc generateMethodDispatchers*(g: ModuleGraph): PNode =
|
||||
result = newNode(nkStmtList)
|
||||
|
||||
@@ -785,14 +785,24 @@ proc writeJsonBuildInstructions*(projectfile: string) =
|
||||
else:
|
||||
lit "],\L"
|
||||
|
||||
proc linkfiles(f: File; buf, objfiles: var string; toLink: seq[string]) =
|
||||
for i, it in toLink:
|
||||
let objfile = addFileExt(it, CC[cCompiler].objExt)
|
||||
str(objfile)
|
||||
proc linkfiles(f: File; buf, objfiles: var string) =
|
||||
for i, it in externalToLink:
|
||||
let
|
||||
objFile = if noAbsolutePaths(): it.extractFilename else: it
|
||||
objStr = addFileExt(objFile, CC[cCompiler].objExt)
|
||||
add(objfiles, ' ')
|
||||
add(objfiles, quoteShell(objfile))
|
||||
|
||||
if i == toLink.high:
|
||||
add(objfiles, objStr)
|
||||
str objStr
|
||||
if toCompile.len == 0 and i == externalToLink.high:
|
||||
lit "\L"
|
||||
else:
|
||||
lit ",\L"
|
||||
for i, x in toCompile:
|
||||
let objStr = quoteShell(x.obj)
|
||||
add(objfiles, ' ')
|
||||
add(objfiles, objStr)
|
||||
str objStr
|
||||
if i == toCompile.high:
|
||||
lit "\L"
|
||||
else:
|
||||
lit ",\L"
|
||||
@@ -809,7 +819,7 @@ proc writeJsonBuildInstructions*(projectfile: string) =
|
||||
lit "],\L\"link\":[\L"
|
||||
var objfiles = ""
|
||||
# XXX add every file here that is to link
|
||||
linkfiles(f, buf, objfiles, externalToLink)
|
||||
linkfiles(f, buf, objfiles)
|
||||
|
||||
lit "],\L\"linkcmd\": "
|
||||
str getLinkCmd(projectfile, objfiles)
|
||||
|
||||
@@ -15,17 +15,28 @@ import
|
||||
|
||||
proc ensureNoMissingOrUnusedSymbols(scope: PScope)
|
||||
|
||||
proc considerQuotedIdent*(n: PNode): PIdent =
|
||||
proc noidentError(n, origin: PNode) =
|
||||
var m = ""
|
||||
if origin != nil:
|
||||
m.add "in expression '" & origin.renderTree & "': "
|
||||
m.add "identifier expected, but found '" & n.renderTree & "'"
|
||||
localError(n.info, m)
|
||||
|
||||
proc considerQuotedIdent*(n: PNode, origin: PNode = nil): PIdent =
|
||||
## Retrieve a PIdent from a PNode, taking into account accent nodes.
|
||||
## ``origin`` can be nil. If it is not nil, it is used for a better
|
||||
## error message.
|
||||
template handleError(n, origin: PNode) =
|
||||
noidentError(n, origin)
|
||||
result = getIdent"<Error>"
|
||||
|
||||
case n.kind
|
||||
of nkIdent: result = n.ident
|
||||
of nkSym: result = n.sym.name
|
||||
of nkAccQuoted:
|
||||
case n.len
|
||||
of 0:
|
||||
localError(n.info, errIdentifierExpected, renderTree(n))
|
||||
result = getIdent"<Error>"
|
||||
of 1: result = considerQuotedIdent(n.sons[0])
|
||||
of 0: handleError(n, origin)
|
||||
of 1: result = considerQuotedIdent(n.sons[0], origin)
|
||||
else:
|
||||
var id = ""
|
||||
for i in 0.. <n.len:
|
||||
@@ -33,14 +44,11 @@ proc considerQuotedIdent*(n: PNode): PIdent =
|
||||
case x.kind
|
||||
of nkIdent: id.add(x.ident.s)
|
||||
of nkSym: id.add(x.sym.name.s)
|
||||
else:
|
||||
localError(n.info, errIdentifierExpected, renderTree(n))
|
||||
return getIdent"<Error>"
|
||||
else: handleError(n, origin)
|
||||
result = getIdent(id)
|
||||
of nkOpenSymChoice, nkClosedSymChoice: result = n.sons[0].sym.name
|
||||
else:
|
||||
localError(n.info, errIdentifierExpected, renderTree(n))
|
||||
result = getIdent"<Error>"
|
||||
handleError(n, origin)
|
||||
|
||||
template addSym*(scope: PScope, s: PSym) =
|
||||
strTableAdd(scope.symbols, s)
|
||||
@@ -353,7 +361,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
if n.sons[1].kind == nkIdent:
|
||||
ident = n.sons[1].ident
|
||||
elif n.sons[1].kind == nkAccQuoted:
|
||||
ident = considerQuotedIdent(n.sons[1])
|
||||
ident = considerQuotedIdent(n.sons[1], n)
|
||||
if ident != nil:
|
||||
if o.m == c.module:
|
||||
# a module may access its private members:
|
||||
@@ -363,8 +371,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
else:
|
||||
result = initIdentIter(o.it, o.m.tab, ident).skipAlias(n)
|
||||
else:
|
||||
localError(n.sons[1].info, errIdentifierExpected,
|
||||
renderTree(n.sons[1]))
|
||||
noidentError(n.sons[1], n)
|
||||
result = errorSym(c, n.sons[1])
|
||||
of nkClosedSymChoice, nkOpenSymChoice:
|
||||
o.mode = oimSymChoice
|
||||
|
||||
@@ -272,7 +272,7 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) =
|
||||
if msgs.gErrorCounter == 0 and
|
||||
gCmd notin {cmdInterpret, cmdRun, cmdDump}:
|
||||
when declared(system.getMaxMem):
|
||||
let usedMem = formatSize(getMaxMem()) & " peekmem"
|
||||
let usedMem = formatSize(getMaxMem()) & " peakmem"
|
||||
else:
|
||||
let usedMem = formatSize(getTotalMem())
|
||||
rawMessage(hintSuccessX, [$gLinesCompiled,
|
||||
|
||||
@@ -355,7 +355,7 @@ proc semOpAux(c: PContext, n: PNode) =
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkExprEqExpr and sonsLen(a) == 2:
|
||||
var info = a.sons[0].info
|
||||
a.sons[0] = newIdentNode(considerQuotedIdent(a.sons[0]), info)
|
||||
a.sons[0] = newIdentNode(considerQuotedIdent(a.sons[0], a), info)
|
||||
a.sons[1] = semExprWithType(c, a.sons[1], flags)
|
||||
a.typ = a.sons[1].typ
|
||||
else:
|
||||
@@ -1076,7 +1076,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
|
||||
n.sons[0] = semExprWithType(c, n.sons[0], flags+{efDetermineType})
|
||||
#restoreOldStyleType(n.sons[0])
|
||||
var i = considerQuotedIdent(n.sons[1])
|
||||
var i = considerQuotedIdent(n.sons[1], n)
|
||||
var ty = n.sons[0].typ
|
||||
var f: PSym = nil
|
||||
result = nil
|
||||
@@ -1160,7 +1160,7 @@ proc dotTransformation(c: PContext, n: PNode): PNode =
|
||||
addSon(result, n.sons[1])
|
||||
addSon(result, copyTree(n[0]))
|
||||
else:
|
||||
var i = considerQuotedIdent(n.sons[1])
|
||||
var i = considerQuotedIdent(n.sons[1], n)
|
||||
result = newNodeI(nkDotCall, n.info)
|
||||
result.flags.incl nfDotField
|
||||
addSon(result, newIdentNode(i, n[1].info))
|
||||
@@ -1280,7 +1280,7 @@ proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
c.p.bracketExpr = oldBracketExpr
|
||||
|
||||
proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode =
|
||||
var id = considerQuotedIdent(a[1])
|
||||
var id = considerQuotedIdent(a[1], a)
|
||||
var setterId = newIdentNode(getIdent(id.s & '='), n.info)
|
||||
# a[0] is already checked for semantics, that does ``builtinFieldAccess``
|
||||
# this is ugly. XXX Semantic checking should use the ``nfSem`` flag for
|
||||
@@ -1433,7 +1433,6 @@ proc semReturn(c: PContext, n: PNode): PNode =
|
||||
|
||||
proc semProcBody(c: PContext, n: PNode): PNode =
|
||||
openScope(c)
|
||||
|
||||
result = semExpr(c, n)
|
||||
if c.p.resultSym != nil and not isEmptyType(result.typ):
|
||||
# transform ``expr`` to ``result = expr``, but not if the expr is already
|
||||
@@ -1530,7 +1529,7 @@ proc lookUpForDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PSym =
|
||||
checkSonsLen(n, 2)
|
||||
var m = lookUpForDefined(c, n.sons[0], onlyCurrentScope)
|
||||
if m != nil and m.kind == skModule:
|
||||
let ident = considerQuotedIdent(n[1])
|
||||
let ident = considerQuotedIdent(n[1], n)
|
||||
if m == c.module:
|
||||
result = strTableGet(c.topLevelScope.symbols, ident)
|
||||
else:
|
||||
@@ -1549,7 +1548,7 @@ proc semDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PNode =
|
||||
checkSonsLen(n, 2)
|
||||
# we replace this node by a 'true' or 'false' node:
|
||||
result = newIntNode(nkIntLit, 0)
|
||||
if not onlyCurrentScope and considerQuotedIdent(n[0]).s == "defined":
|
||||
if not onlyCurrentScope and considerQuotedIdent(n[0], n).s == "defined":
|
||||
if n.sons[1].kind != nkIdent:
|
||||
localError(n.info, "obsolete usage of 'defined', use 'declared' instead")
|
||||
elif condsyms.isDefined(n.sons[1].ident):
|
||||
@@ -2084,9 +2083,8 @@ proc checkInitialized(n: PNode, ids: IntSet, info: TLineInfo) =
|
||||
|
||||
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
var t = semTypeNode(c, n.sons[0], nil)
|
||||
result = n
|
||||
result.typ = t
|
||||
result.kind = nkObjConstr
|
||||
result = newNodeIT(nkObjConstr, n.info, t)
|
||||
result.add n.sons[0]
|
||||
t = skipTypes(t, {tyGenericInst, tyAlias})
|
||||
if t.kind == tyRef: t = skipTypes(t.sons[0], {tyGenericInst, tyAlias})
|
||||
if t.kind != tyObject:
|
||||
@@ -2099,7 +2097,7 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
if it.kind != nkExprColonExpr:
|
||||
localError(n.info, errNamedExprExpected)
|
||||
break
|
||||
let id = considerQuotedIdent(it.sons[0])
|
||||
let id = considerQuotedIdent(it.sons[0], it)
|
||||
|
||||
if containsOrIncl(ids, id.id):
|
||||
localError(it.info, errFieldInitTwice, id.s)
|
||||
@@ -2125,6 +2123,7 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
else:
|
||||
localError(it.info, errUndeclaredFieldX, id.s)
|
||||
it.sons[1] = e
|
||||
result.add it
|
||||
# XXX object field name check for 'case objects' if the kind is static?
|
||||
if tfNeedsInit in objType.flags:
|
||||
while true:
|
||||
|
||||
@@ -51,10 +51,10 @@ template macroToExpand(s): untyped =
|
||||
s.kind in {skMacro, skTemplate} and (s.typ.len == 1 or sfAllUntyped in s.flags)
|
||||
|
||||
template macroToExpandSym(s): untyped =
|
||||
s.kind in {skMacro, skTemplate} and (s.typ.len == 1)
|
||||
s.kind in {skMacro, skTemplate} and (s.typ.len == 1) and not fromDotExpr
|
||||
|
||||
proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
|
||||
ctx: var GenericCtx): PNode =
|
||||
ctx: var GenericCtx; fromDotExpr=false): PNode =
|
||||
semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody)
|
||||
incl(s.flags, sfUsed)
|
||||
case s.kind
|
||||
@@ -145,7 +145,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||
elif s.name.id in ctx.toMixin:
|
||||
result = newDot(result, symChoice(c, n, s, scForceOpen))
|
||||
else:
|
||||
let syms = semGenericStmtSymbol(c, n, s, ctx)
|
||||
let syms = semGenericStmtSymbol(c, n, s, ctx, fromDotExpr=true)
|
||||
if syms.kind == nkSym:
|
||||
let choice = symChoice(c, n, s, scForceOpen)
|
||||
choice.kind = nkClosedSymChoice
|
||||
|
||||
@@ -125,6 +125,11 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind)
|
||||
|
||||
proc instantiateBody(c: PContext, n, params: PNode, result, orig: PSym) =
|
||||
if n.sons[bodyPos].kind != nkEmpty:
|
||||
let procParams = result.typ.n
|
||||
for i in 1 .. <procParams.len:
|
||||
addDecl(c, procParams[i].sym)
|
||||
maybeAddResult(c, result, result.ast)
|
||||
|
||||
inc c.inGenericInst
|
||||
# add it here, so that recursive generic procs are possible:
|
||||
var b = n.sons[bodyPos]
|
||||
@@ -147,13 +152,17 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
|
||||
for i in countup(0, c.generics.len - 1):
|
||||
if c.generics[i].genericSym.id == s.id:
|
||||
var oldPrc = c.generics[i].inst.sym
|
||||
pushProcCon(c, oldPrc)
|
||||
pushOwner(c, oldPrc)
|
||||
pushInfoContext(oldPrc.info)
|
||||
openScope(c)
|
||||
var n = oldPrc.ast
|
||||
n.sons[bodyPos] = copyTree(s.getBody)
|
||||
instantiateBody(c, n, nil, oldPrc, s)
|
||||
instantiateBody(c, n, oldPrc.typ.n, oldPrc, s)
|
||||
closeScope(c)
|
||||
popInfoContext()
|
||||
popOwner(c)
|
||||
popProcCon(c)
|
||||
|
||||
proc sideEffectsCheck(c: PContext, s: PSym) =
|
||||
when false:
|
||||
@@ -173,7 +182,7 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
|
||||
result = replaceTypeVarsT(cl, header)
|
||||
|
||||
proc instantiateProcType(c: PContext, pt: TIdTable,
|
||||
prc: PSym, info: TLineInfo) =
|
||||
prc: PSym, info: TLineInfo) =
|
||||
# XXX: Instantiates a generic proc signature, while at the same
|
||||
# time adding the instantiated proc params into the current scope.
|
||||
# This is necessary, because the instantiation process may refer to
|
||||
@@ -229,7 +238,6 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
|
||||
skipIntLiteralParams(result)
|
||||
|
||||
prc.typ = result
|
||||
maybeAddResult(c, prc, prc.ast)
|
||||
popInfoContext()
|
||||
|
||||
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||
|
||||
@@ -160,10 +160,11 @@ proc discardCheck(c: PContext, result: PNode) =
|
||||
else:
|
||||
var n = result
|
||||
while n.kind in skipForDiscardable: n = n.lastSon
|
||||
var s = "expression '" & $n & "' is of type '" &
|
||||
result.typ.typeToString & "' and has to be discarded"
|
||||
if result.typ.kind == tyProc:
|
||||
localError(n.info, "value of type '" & result.typ.typeToString & "' has to be discarded; for a function call use ()")
|
||||
else:
|
||||
localError(n.info, errDiscardValueX, result.typ.typeToString)
|
||||
s.add "; for a function call use ()"
|
||||
localError(n.info, s)
|
||||
|
||||
proc semIf(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
|
||||
@@ -350,6 +350,14 @@ proc handleFloatRange(f, a: PType): TTypeRelation =
|
||||
else: result = isIntConv
|
||||
else: result = isNone
|
||||
|
||||
proc genericParamPut(c: var TCandidate; last, fGenericOrigin: PType) =
|
||||
if fGenericOrigin != nil and last.kind == tyGenericInst and
|
||||
last.len-1 == fGenericOrigin.len:
|
||||
for i in countup(1, sonsLen(fGenericOrigin) - 1):
|
||||
let x = PType(idTableGet(c.bindings, fGenericOrigin.sons[i]))
|
||||
if x == nil:
|
||||
put(c, fGenericOrigin.sons[i], last.sons[i])
|
||||
|
||||
proc isObjectSubtype(c: var TCandidate; a, f, fGenericOrigin: PType): int =
|
||||
var t = a
|
||||
assert t.kind == tyObject
|
||||
@@ -363,12 +371,7 @@ proc isObjectSubtype(c: var TCandidate; a, f, fGenericOrigin: PType): int =
|
||||
t = skipTypes(t, skipPtrs)
|
||||
inc depth
|
||||
if t != nil:
|
||||
if fGenericOrigin != nil and last.kind == tyGenericInst and
|
||||
last.len-1 == fGenericOrigin.len:
|
||||
for i in countup(1, sonsLen(fGenericOrigin) - 1):
|
||||
let x = PType(idTableGet(c.bindings, fGenericOrigin.sons[i]))
|
||||
if x == nil:
|
||||
put(c, fGenericOrigin.sons[i], last.sons[i])
|
||||
genericParamPut(c, last, fGenericOrigin)
|
||||
result = depth
|
||||
else:
|
||||
result = -1
|
||||
@@ -398,7 +401,7 @@ proc skipToObject(t: PType; skipped: var SkippedPtr): PType =
|
||||
break
|
||||
if r.kind == tyObject and ptrs <= 1: result = r
|
||||
|
||||
proc isGenericSubtype(a, f: PType, d: var int): bool =
|
||||
proc isGenericSubtype(c: var TCandidate; a, f: PType, d: var int, fGenericOrigin: PType = nil): bool =
|
||||
assert f.kind in {tyGenericInst, tyGenericInvocation, tyGenericBody}
|
||||
var askip = skippedNone
|
||||
var fskip = skippedNone
|
||||
@@ -406,14 +409,17 @@ proc isGenericSubtype(a, f: PType, d: var int): bool =
|
||||
let r = f.skipToObject(fskip)
|
||||
if r == nil: return false
|
||||
var depth = 0
|
||||
var last = a
|
||||
# XXX sameObjectType can return false here. Need to investigate
|
||||
# why that is but sameObjectType does way too much work here anyway.
|
||||
while t != nil and r.sym != t.sym and askip == fskip:
|
||||
t = t.sons[0]
|
||||
if t != nil: t = t.skipToObject(askip)
|
||||
else: break
|
||||
if t == nil: break
|
||||
last = t
|
||||
t = t.skipToObject(askip)
|
||||
inc depth
|
||||
if t != nil and askip == fskip:
|
||||
genericParamPut(c, last, fGenericOrigin)
|
||||
d = depth
|
||||
result = true
|
||||
|
||||
@@ -999,7 +1005,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
# simply no match for now:
|
||||
discard
|
||||
elif x.kind == tyGenericInst and
|
||||
((f.sons[0] == x.sons[0]) or isGenericSubtype(x, f, depth)) and
|
||||
((f.sons[0] == x.sons[0]) or isGenericSubType(c, x, f, depth)) and
|
||||
(sonsLen(x) - 1 == sonsLen(f)):
|
||||
for i in countup(1, sonsLen(f) - 1):
|
||||
if x.sons[i].kind == tyGenericParam:
|
||||
@@ -1039,6 +1045,14 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
else:
|
||||
put(c, f.sons[i], x)
|
||||
|
||||
if result == isNone:
|
||||
# Here object inheriting from generic/specialized generic object
|
||||
# crossing path with metatypes/aliases, so we need to separate them
|
||||
# by checking sym.id
|
||||
let genericSubtype = isGenericSubType(c, x, f, depth, f)
|
||||
if not (genericSubtype and aobj.sym.id != fobj.sym.id):
|
||||
depth = -1
|
||||
|
||||
if depth >= 0:
|
||||
c.inheritancePenalty += depth
|
||||
# bug #4863: We still need to bind generic alias crap, so
|
||||
|
||||
23
doc/tut1.rst
23
doc/tut1.rst
@@ -407,7 +407,7 @@ or
|
||||
...
|
||||
|
||||
Other useful iterators for collections (like arrays and sequences) are
|
||||
* ``items`` and ``mitems``, which provides immutable and mutable elements respectively, and
|
||||
* ``items`` and ``mitems``, which provides immutable and mutable elements respectively, and
|
||||
* ``pairs`` and ``mpairs`` which provides the element and an index number (immutable and mutable respectively)
|
||||
|
||||
.. code-block:: nim
|
||||
@@ -1394,6 +1394,27 @@ slice's bounds can hold any value supported by
|
||||
their type, but it is the proc using the slice object which defines what values
|
||||
are accepted.
|
||||
|
||||
To understand some of the different ways of specifying the indices of strings, arrays, sequences, etc.,
|
||||
it must be remembered that Nim uses zero-based indices.
|
||||
|
||||
So the string ``b`` is of length 19, and two different ways of specifying the indices are
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
"Slices are useless."
|
||||
| | |
|
||||
0 11 17 using indices
|
||||
^19 ^8 ^2 using ^ syntax
|
||||
|
||||
where ``b[0..^1]`` is equivalent to ``b[0..b.len-1]`` and ``b[0..<b.len]``, and it can be seen that the ``^1`` provides a short-hand way of specifying the ``b.len-1``
|
||||
|
||||
In the above example, because the string ends in a period, to get the portion of the string that is "useless" and replace it with "useful"
|
||||
|
||||
``b[11..^2]`` is the portion "useless", and
|
||||
``b[11..^2] = "useful"`` replaces the "useless" portion with "useful",
|
||||
giving the result "Slices are useful."
|
||||
|
||||
Note: alternate ways of writing this are ``b[^8..^2] = "useful"`` or as ``b[11..b.len-2] = "useful"`` or as ``b[11..<b.len-1] = "useful"`` or as ....
|
||||
|
||||
Tuples
|
||||
------
|
||||
|
||||
38
koch.nim
38
koch.nim
@@ -41,30 +41,26 @@ Options:
|
||||
Possible Commands:
|
||||
boot [options] bootstraps with given command line options
|
||||
distrohelper [bindir] helper for distro packagers
|
||||
geninstall generate ./install.sh; Unix only!
|
||||
testinstall test tar.xz package; Unix only! Only for devs!
|
||||
clean cleans Nim project; removes generated files
|
||||
web [options] generates the website and the full documentation
|
||||
website [options] generates only the website
|
||||
csource [options] builds the C sources for installation
|
||||
pdf builds the PDF documentation
|
||||
zip builds the installation ZIP package
|
||||
xz builds the installation XZ package
|
||||
nsis [options] builds the NSIS Setup installer (for Windows)
|
||||
tests [options] run the testsuite
|
||||
temp options creates a temporary compiler for testing
|
||||
winrelease creates a release (for coredevs only)
|
||||
nimble builds the Nimble tool
|
||||
tools builds Nim related tools
|
||||
pushcsource push generated C sources to its repo! Only for devs!
|
||||
nimble builds the Nimble tool
|
||||
Boot options:
|
||||
-d:release produce a release version of the compiler
|
||||
-d:tinyc include the Tiny C backend (not supported on Windows)
|
||||
-d:useLinenoise use the linenoise library for interactive mode
|
||||
(not needed on Windows)
|
||||
-d:nativeStacktrace use native stack traces (only for Mac OS X or Linux)
|
||||
-d:noCaas build Nim without CAAS support
|
||||
-d:avoidTimeMachine only for Mac OS X, excludes nimcache dir from backups
|
||||
|
||||
Commands for core developers:
|
||||
web [options] generates the website and the full documentation
|
||||
website [options] generates only the website
|
||||
csource -d:release builds the C sources for installation
|
||||
pdf builds the PDF documentation
|
||||
zip builds the installation zip package
|
||||
xz builds the installation tar.xz package
|
||||
testinstall test tar.xz package; Unix only!
|
||||
tests [options] run the testsuite
|
||||
temp options creates a temporary compiler for testing
|
||||
winrelease creates a Windows release
|
||||
pushcsource push generated C sources to its repo
|
||||
Web options:
|
||||
--googleAnalytics:UA-... add the given google analytics code to the docs. To
|
||||
build the official docs, use UA-48159761-1
|
||||
@@ -218,11 +214,14 @@ proc bundleNimsuggest(buildExe: bool) =
|
||||
copyExe("nimsuggest/nimsuggest".exe, "bin/nimsuggest".exe)
|
||||
removeFile("nimsuggest/nimsuggest".exe)
|
||||
|
||||
proc buildVccTool() =
|
||||
nimexec("c -o:bin/vccexe.exe tools/vccenv/vccexe")
|
||||
|
||||
proc bundleWinTools() =
|
||||
nimexec("c tools/finish.nim")
|
||||
copyExe("tools/finish".exe, "finish".exe)
|
||||
removeFile("tools/finish".exe)
|
||||
nimexec("c -o:bin/vccexe.exe tools/vccenv/vccexe")
|
||||
buildVccTool()
|
||||
nimexec("c -o:bin/nimgrab.exe -d:ssl tools/nimgrab.nim")
|
||||
when false:
|
||||
# not yet a tool worth including
|
||||
@@ -257,6 +256,7 @@ proc buildTools(latest: bool) =
|
||||
|
||||
let nimgrepExe = "bin/nimgrep".exe
|
||||
nimexec "c -o:" & nimgrepExe & " tools/nimgrep.nim"
|
||||
when defined(windows): buildVccTool()
|
||||
buildNimble(latest)
|
||||
|
||||
proc nsis(args: string) =
|
||||
|
||||
@@ -173,17 +173,33 @@ iterator fastRows*(db: DbConn, query: SqlQuery,
|
||||
rawExec(db, query, args)
|
||||
var sqlres = mysql.useResult(db)
|
||||
if sqlres != nil:
|
||||
var L = int(mysql.numFields(sqlres))
|
||||
var result = newRow(L)
|
||||
var row: cstringArray
|
||||
var
|
||||
L = int(mysql.numFields(sqlres))
|
||||
row: cstringArray
|
||||
result: Row
|
||||
backup: Row
|
||||
newSeq(result, L)
|
||||
while true:
|
||||
row = mysql.fetchRow(sqlres)
|
||||
if row == nil: break
|
||||
for i in 0..L-1:
|
||||
setLen(result[i], 0)
|
||||
if row[i] == nil:
|
||||
if backup == nil:
|
||||
newSeq(backup, L)
|
||||
if backup[i] == nil and result[i] != nil:
|
||||
shallowCopy(backup[i], result[i])
|
||||
result[i] = nil
|
||||
else:
|
||||
if result[i] == nil:
|
||||
if backup != nil:
|
||||
if backup[i] == nil:
|
||||
backup[i] = ""
|
||||
shallowCopy(result[i], backup[i])
|
||||
setLen(result[i], 0)
|
||||
else:
|
||||
result[i] = ""
|
||||
else:
|
||||
setLen(result[i], 0)
|
||||
add(result[i], row[i])
|
||||
yield result
|
||||
properFreeResult(sqlres, row)
|
||||
|
||||
@@ -406,6 +406,8 @@ proc setInterval*(w: Window, function: proc (), pause: int): ref TInterval
|
||||
proc setTimeout*(w: Window, code: cstring, pause: int): ref TTimeOut
|
||||
proc setTimeout*(w: Window, function: proc (), pause: int): ref TInterval
|
||||
proc stop*(w: Window)
|
||||
proc requestAnimationFrame*(w: Window, function: proc (time: float)): int
|
||||
proc cancelAnimationFrame*(w: Window, id: int)
|
||||
|
||||
# Node "methods"
|
||||
proc appendChild*(n, child: Node)
|
||||
|
||||
@@ -489,3 +489,13 @@ proc writeFromStream*(f: AsyncFile, fs: FutureStream[string]) {.async.} =
|
||||
await f.write(value)
|
||||
else:
|
||||
break
|
||||
|
||||
proc readToStream*(f: AsyncFile, fs: FutureStream[string]) {.async.} =
|
||||
## Writes data to the specified future stream as the file is read.
|
||||
while true:
|
||||
let data = await read(f, 4000)
|
||||
if data.len == 0:
|
||||
break
|
||||
await fs.write(data)
|
||||
|
||||
fs.complete()
|
||||
@@ -80,7 +80,7 @@ proc `[]`*[T](deq: Deque[T], i: Natural) : T {.inline.} =
|
||||
## Access the i-th element of `deq` by order from first to last.
|
||||
## deq[0] is the first, deq[^1] is the last.
|
||||
xBoundsCheck(deq, i)
|
||||
return deq.data[(deq.first + i) and deq.mask]
|
||||
return deq.data[(deq.head + i) and deq.mask]
|
||||
|
||||
proc `[]`*[T](deq: var Deque[T], i: Natural): var T {.inline.} =
|
||||
## Access the i-th element of `deq` and returns a mutable
|
||||
@@ -266,4 +266,4 @@ when isMainModule:
|
||||
foo(1,1)
|
||||
foo(2,1)
|
||||
foo(1,5)
|
||||
foo(3,2)
|
||||
foo(3,2)
|
||||
|
||||
@@ -617,20 +617,6 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
|
||||
flushFile(d)
|
||||
close(d)
|
||||
|
||||
proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
|
||||
tags: [ReadIOEffect, WriteIOEffect].} =
|
||||
## Moves a file from `source` to `dest`. If this fails, `OSError` is raised.
|
||||
when defined(Windows):
|
||||
when useWinUnicode:
|
||||
let s = newWideCString(source)
|
||||
let d = newWideCString(dest)
|
||||
if moveFileW(s, d) == 0'i32: raiseOSError(osLastError())
|
||||
else:
|
||||
if moveFileA(source, dest) == 0'i32: raiseOSError(osLastError())
|
||||
else:
|
||||
if c_rename(source, dest) != 0'i32:
|
||||
raiseOSError(osLastError(), $strerror(errno))
|
||||
|
||||
when not declared(ENOENT) and not defined(Windows):
|
||||
when NoFakeVars:
|
||||
const ENOENT = cint(2) # 2 on most systems including Solaris
|
||||
@@ -647,25 +633,63 @@ when defined(Windows):
|
||||
template setFileAttributes(file, attrs: untyped): untyped =
|
||||
setFileAttributesA(file, attrs)
|
||||
|
||||
proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].} =
|
||||
## Removes the `file`. If this fails, `OSError` is raised. This does not fail
|
||||
proc tryRemoveFile*(file: string): bool {.rtl, extern: "nos$1", tags: [WriteDirEffect].} =
|
||||
## Removes the `file`. If this fails, returns `false`. This does not fail
|
||||
## if the file never existed in the first place.
|
||||
## On Windows, ignores the read-only attribute.
|
||||
result = true
|
||||
when defined(Windows):
|
||||
when useWinUnicode:
|
||||
let f = newWideCString(file)
|
||||
else:
|
||||
let f = file
|
||||
if deleteFile(f) == 0:
|
||||
if getLastError() == ERROR_ACCESS_DENIED:
|
||||
if setFileAttributes(f, FILE_ATTRIBUTE_NORMAL) == 0:
|
||||
raiseOSError(osLastError())
|
||||
if deleteFile(f) == 0:
|
||||
raiseOSError(osLastError())
|
||||
result = false
|
||||
let err = getLastError()
|
||||
if err == ERROR_FILE_NOT_FOUND or err == ERROR_PATH_NOT_FOUND:
|
||||
result = true
|
||||
elif err == ERROR_ACCESS_DENIED and
|
||||
setFileAttributes(f, FILE_ATTRIBUTE_NORMAL) != 0 and
|
||||
deleteFile(f) != 0:
|
||||
result = true
|
||||
else:
|
||||
if c_remove(file) != 0'i32 and errno != ENOENT:
|
||||
result = false
|
||||
|
||||
proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].} =
|
||||
## Removes the `file`. If this fails, `OSError` is raised. This does not fail
|
||||
## if the file never existed in the first place.
|
||||
## On Windows, ignores the read-only attribute.
|
||||
if not tryRemoveFile(file):
|
||||
when defined(Windows):
|
||||
raiseOSError(osLastError())
|
||||
else:
|
||||
raiseOSError(osLastError(), $strerror(errno))
|
||||
|
||||
proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
|
||||
tags: [ReadIOEffect, WriteIOEffect].} =
|
||||
## Moves a file from `source` to `dest`. If this fails, `OSError` is raised.
|
||||
when defined(Windows):
|
||||
when useWinUnicode:
|
||||
let s = newWideCString(source)
|
||||
let d = newWideCString(dest)
|
||||
if moveFileW(s, d) == 0'i32: raiseOSError(osLastError())
|
||||
else:
|
||||
if moveFileA(source, dest) == 0'i32: raiseOSError(osLastError())
|
||||
else:
|
||||
if c_rename(source, dest) != 0'i32:
|
||||
let err = osLastError()
|
||||
if err == EXDEV.OSErrorCode:
|
||||
# Fallback to copy & del
|
||||
copyFile(source, dest)
|
||||
try:
|
||||
removeFile(source)
|
||||
except:
|
||||
discard tryRemoveFile(dest)
|
||||
raise
|
||||
else:
|
||||
raiseOSError(err, $strerror(errno))
|
||||
|
||||
proc execShellCmd*(command: string): int {.rtl, extern: "nos$1",
|
||||
tags: [ExecIOEffect].} =
|
||||
## Executes a `shell command`:idx:.
|
||||
@@ -1616,7 +1640,8 @@ proc sleep*(milsecs: int) {.rtl, extern: "nos$1", tags: [TimeEffect].} =
|
||||
|
||||
proc getFileSize*(file: string): BiggestInt {.rtl, extern: "nos$1",
|
||||
tags: [ReadIOEffect].} =
|
||||
## returns the file size of `file`. Can raise ``OSError``.
|
||||
## returns the file size of `file` (in bytes). An ``OSError`` exception is
|
||||
## raised in case of an error.
|
||||
when defined(windows):
|
||||
var a: WIN32_FIND_DATA
|
||||
var resA = findFirstFile(file, a)
|
||||
|
||||
@@ -13,10 +13,6 @@
|
||||
##
|
||||
## Tested on these OSes: Linux, Windows, OSX
|
||||
|
||||
type
|
||||
NilAccessError* = object of SystemError ## \
|
||||
## Raised on dereferences of ``nil`` pointers.
|
||||
|
||||
# do allocate memory upfront:
|
||||
var se: ref NilAccessError
|
||||
new(se)
|
||||
|
||||
@@ -597,9 +597,12 @@ elif defined(JS):
|
||||
result.month = Month(t.getMonth())
|
||||
result.year = t.getFullYear()
|
||||
result.weekday = weekDays[t.getDay()]
|
||||
result.yearday = 0
|
||||
result.timezone = getTimezone()
|
||||
|
||||
result.yearday = result.monthday - 1
|
||||
for month in mJan..<result.month:
|
||||
result.yearday += getDaysInMonth(month, result.year)
|
||||
|
||||
proc getGMTime(t: Time): TimeInfo =
|
||||
result.second = t.getUTCSeconds()
|
||||
result.minute = t.getUTCMinutes()
|
||||
@@ -608,7 +611,10 @@ elif defined(JS):
|
||||
result.month = Month(t.getUTCMonth())
|
||||
result.year = t.getUTCFullYear()
|
||||
result.weekday = weekDays[t.getUTCDay()]
|
||||
result.yearday = 0
|
||||
|
||||
result.yearday = result.monthday - 1
|
||||
for month in mJan..<result.month:
|
||||
result.yearday += getDaysInMonth(month, result.year)
|
||||
|
||||
proc timeInfoToTime(timeInfo: TimeInfo): Time = toTime(timeInfo)
|
||||
|
||||
|
||||
@@ -375,7 +375,6 @@ template test*(name, body) {.dirty.} =
|
||||
ensureFormattersInitialized()
|
||||
|
||||
if shouldRun(name):
|
||||
var stackTrace {.inject.}: string
|
||||
checkpoints = @[]
|
||||
var testStatusIMPL {.inject.} = OK
|
||||
|
||||
@@ -391,7 +390,7 @@ template test*(name, body) {.dirty.} =
|
||||
except:
|
||||
when not defined(js):
|
||||
checkpoint("Unhandled exception: " & getCurrentExceptionMsg())
|
||||
stackTrace = getCurrentException().getStackTrace()
|
||||
var stackTrace {.inject.} = getCurrentException().getStackTrace()
|
||||
fail()
|
||||
|
||||
finally:
|
||||
|
||||
@@ -154,9 +154,13 @@ proc `addr`*[T](x: var T): ptr T {.magic: "Addr", noSideEffect.} =
|
||||
discard
|
||||
|
||||
proc unsafeAddr*[T](x: T): ptr T {.magic: "Addr", noSideEffect.} =
|
||||
## Builtin 'addr' operator for taking the address of a memory location.
|
||||
## This works even for ``let`` variables or parameters for better interop
|
||||
## with C and so it is considered even more unsafe than the ordinary ``addr``.
|
||||
## Builtin 'addr' operator for taking the address of a memory
|
||||
## location. This works even for ``let`` variables or parameters
|
||||
## for better interop with C and so it is considered even more
|
||||
## unsafe than the ordinary ``addr``. When you use it to write a
|
||||
## wrapper for a C library, you should always check that the
|
||||
## original library does never write to data behind the pointer that
|
||||
## is returned from this procedure.
|
||||
## Cannot be overloaded.
|
||||
discard
|
||||
|
||||
@@ -554,6 +558,10 @@ type
|
||||
## Raised if it is attempted to send a message to a dead thread.
|
||||
##
|
||||
## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
|
||||
NilAccessError* = object of SystemError ## \
|
||||
## Raised on dereferences of ``nil`` pointers.
|
||||
##
|
||||
## This is only raised if the ``segfaults.nim`` module was imported!
|
||||
|
||||
{.deprecated: [TObject: RootObj, PObject: RootRef, TEffect: RootEffect,
|
||||
FTime: TimeEffect, FIO: IOEffect, FReadIO: ReadIOEffect,
|
||||
@@ -2463,8 +2471,8 @@ template accumulateResult*(iter: untyped) =
|
||||
const NimStackTrace = compileOption("stacktrace")
|
||||
|
||||
template coroutinesSupportedPlatform(): bool =
|
||||
when defined(sparc) or defined(ELATE) or compileOption("gc", "v2") or
|
||||
defined(boehmgc) or defined(gogc) or defined(nogc) or defined(gcStack) or
|
||||
when defined(sparc) or defined(ELATE) or compileOption("gc", "v2") or
|
||||
defined(boehmgc) or defined(gogc) or defined(nogc) or defined(gcStack) or
|
||||
defined(gcMarkAndSweep):
|
||||
false
|
||||
else:
|
||||
|
||||
@@ -763,6 +763,8 @@ proc getOccupiedMem(a: MemRegion): int {.inline.} =
|
||||
# ---------------------- thread memory region -------------------------------
|
||||
|
||||
template instantiateForRegion(allocator: untyped) =
|
||||
{.push stackTrace: off.}
|
||||
|
||||
when defined(fulldebug):
|
||||
proc interiorAllocatedPtr*(p: pointer): pointer =
|
||||
result = interiorAllocatedPtr(allocator, p)
|
||||
@@ -850,5 +852,6 @@ template instantiateForRegion(allocator: untyped) =
|
||||
|
||||
proc getOccupiedSharedMem(): int =
|
||||
sharedMemStatsShared(sharedHeap.currMem - sharedHeap.freeMem)
|
||||
{.pop.}
|
||||
|
||||
{.pop.}
|
||||
|
||||
@@ -50,7 +50,11 @@ proc chckRangeF(x, a, b: float): float =
|
||||
|
||||
proc chckNil(p: pointer) =
|
||||
if p == nil:
|
||||
sysFatal(ValueError, "attempt to write to a nil address")
|
||||
sysFatal(NilAccessError, "attempt to write to a nil address")
|
||||
|
||||
proc chckNilDisp(p: pointer) {.compilerproc.} =
|
||||
if p == nil:
|
||||
sysFatal(NilAccessError, "cannot dispatch; dispatcher is nil")
|
||||
|
||||
proc chckObj(obj, subclass: PNimType) {.compilerproc.} =
|
||||
# checks if obj is of type subclass:
|
||||
|
||||
@@ -642,6 +642,10 @@ proc toU32*(a: int64): int32 {.asmNoStackFrame, compilerproc.} =
|
||||
proc nimMin(a, b: int): int {.compilerproc.} = return if a <= b: a else: b
|
||||
proc nimMax(a, b: int): int {.compilerproc.} = return if a >= b: a else: b
|
||||
|
||||
proc chckNilDisp(p: pointer) {.compilerproc.} =
|
||||
if p == nil:
|
||||
sysFatal(NilAccessError, "cannot dispatch; dispatcher is nil")
|
||||
|
||||
type NimString = string # hack for hti.nim
|
||||
include "system/hti"
|
||||
|
||||
|
||||
@@ -242,7 +242,6 @@ type
|
||||
|
||||
PGcThread = ptr GcThread
|
||||
GcThread {.pure, inheritable.} = object
|
||||
sys: SysThread
|
||||
when emulatedThreadVars and not useStackMaskHack:
|
||||
tls: ThreadLocalStorage
|
||||
else:
|
||||
@@ -345,18 +344,16 @@ when not defined(useNimRtl):
|
||||
# use ``stdcall`` since it is mapped to ``noconv`` on UNIX anyway.
|
||||
|
||||
type
|
||||
Thread* {.pure, final.}[TArg] =
|
||||
object of GcThread ## Nim thread. A thread is a heavy object (~14K)
|
||||
## that **must not** be part of a message! Use
|
||||
## a ``ThreadId`` for that.
|
||||
Thread* {.pure, final.}[TArg] = object
|
||||
core: PGcThread
|
||||
sys: SysThread
|
||||
when TArg is void:
|
||||
dataFn: proc () {.nimcall, gcsafe.}
|
||||
else:
|
||||
dataFn: proc (m: TArg) {.nimcall, gcsafe.}
|
||||
data: TArg
|
||||
ThreadId*[TArg] = ptr Thread[TArg] ## the current implementation uses
|
||||
## a pointer as a thread ID.
|
||||
{.deprecated: [TThread: Thread, TThreadId: ThreadId].}
|
||||
|
||||
{.deprecated: [TThread: Thread].}
|
||||
|
||||
var
|
||||
threadDestructionHandlers {.rtlThreadVar.}: seq[proc () {.closure, gcsafe.}]
|
||||
@@ -423,19 +420,20 @@ proc threadProcWrapStackFrame[TArg](thrd: ptr Thread[TArg]) =
|
||||
when declared(threadType):
|
||||
threadType = ThreadType.NimThread
|
||||
when declared(registerThread):
|
||||
thrd.stackBottom = addr(thrd)
|
||||
registerThread(thrd)
|
||||
thrd.core.stackBottom = addr(thrd)
|
||||
registerThread(thrd.core)
|
||||
p(thrd)
|
||||
when declared(registerThread): unregisterThread(thrd)
|
||||
when declared(registerThread): unregisterThread(thrd.core)
|
||||
when declared(deallocOsPages): deallocOsPages()
|
||||
else:
|
||||
threadProcWrapDispatch(thrd)
|
||||
|
||||
template threadProcWrapperBody(closure: expr) {.immediate.} =
|
||||
when declared(globalsSlot): threadVarSetValue(globalsSlot, closure)
|
||||
var thrd = cast[ptr Thread[TArg]](closure)
|
||||
var core = thrd.core
|
||||
when declared(globalsSlot): threadVarSetValue(globalsSlot, thrd.core)
|
||||
when declared(initAllocator):
|
||||
initAllocator()
|
||||
var thrd = cast[ptr Thread[TArg]](closure)
|
||||
threadProcWrapStackFrame(thrd)
|
||||
# Since an unhandled exception terminates the whole process (!), there is
|
||||
# no need for a ``try finally`` here, nor would it be correct: The current
|
||||
@@ -444,7 +442,9 @@ template threadProcWrapperBody(closure: expr) {.immediate.} =
|
||||
# page!
|
||||
|
||||
# mark as not running anymore:
|
||||
thrd.core = nil
|
||||
thrd.dataFn = nil
|
||||
deallocShared(cast[pointer](core))
|
||||
|
||||
{.push stack_trace:off.}
|
||||
when defined(windows):
|
||||
@@ -502,6 +502,10 @@ when false:
|
||||
discard pthread_cancel(t.sys)
|
||||
when declared(registerThread): unregisterThread(addr(t))
|
||||
t.dataFn = nil
|
||||
## if thread `t` already exited, `t.core` will be `null`.
|
||||
if not isNil(t.core):
|
||||
deallocShared(t.core)
|
||||
t.core = nil
|
||||
|
||||
when hostOS == "windows":
|
||||
proc createThread*[TArg](t: var Thread[TArg],
|
||||
@@ -510,9 +514,11 @@ when hostOS == "windows":
|
||||
## creates a new thread `t` and starts its execution. Entry point is the
|
||||
## proc `tp`. `param` is passed to `tp`. `TArg` can be ``void`` if you
|
||||
## don't need to pass any data to the thread.
|
||||
t.core = cast[PGcThread](allocShared0(sizeof(GcThread)))
|
||||
|
||||
when TArg isnot void: t.data = param
|
||||
t.dataFn = tp
|
||||
when hasSharedHeap: t.stackSize = ThreadStackSize
|
||||
when hasSharedHeap: t.core.stackSize = ThreadStackSize
|
||||
var dummyThreadId: int32
|
||||
t.sys = createThread(nil, ThreadStackSize, threadProcWrapper[TArg],
|
||||
addr(t), 0'i32, dummyThreadId)
|
||||
@@ -532,9 +538,11 @@ else:
|
||||
## creates a new thread `t` and starts its execution. Entry point is the
|
||||
## proc `tp`. `param` is passed to `tp`. `TArg` can be ``void`` if you
|
||||
## don't need to pass any data to the thread.
|
||||
t.core = cast[PGcThread](allocShared0(sizeof(GcThread)))
|
||||
|
||||
when TArg isnot void: t.data = param
|
||||
t.dataFn = tp
|
||||
when hasSharedHeap: t.stackSize = ThreadStackSize
|
||||
when hasSharedHeap: t.core.stackSize = ThreadStackSize
|
||||
var a {.noinit.}: PthreadAttr
|
||||
pthread_attr_init(a)
|
||||
pthread_attr_setstacksize(a, ThreadStackSize)
|
||||
@@ -554,10 +562,6 @@ else:
|
||||
proc createThread*(t: var Thread[void], tp: proc () {.thread, nimcall.}) =
|
||||
createThread[void](t, tp)
|
||||
|
||||
proc threadId*[TArg](t: var Thread[TArg]): ThreadId[TArg] {.inline.} =
|
||||
## returns the thread ID of `t`.
|
||||
result = addr(t)
|
||||
|
||||
when false:
|
||||
proc mainThreadId*[TArg](): ThreadId[TArg] =
|
||||
## returns the thread ID of the main thread.
|
||||
|
||||
@@ -667,6 +667,8 @@ const
|
||||
|
||||
# Error Constants
|
||||
const
|
||||
ERROR_FILE_NOT_FOUND* = 2
|
||||
ERROR_PATH_NOT_FOUND* = 3
|
||||
ERROR_ACCESS_DENIED* = 5
|
||||
ERROR_HANDLE_EOF* = 38
|
||||
ERROR_BAD_ARGUMENTS* = 165
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
/* linenoise.c -- VERSION 1.0
|
||||
*
|
||||
* Guerrilla line editing library against the idea that a line editing lib
|
||||
* needs to be 20,000 lines of C code.
|
||||
/* linenoise.c -- guerrilla line editing library against the idea that a
|
||||
* line editing lib needs to be 20,000 lines of C code.
|
||||
*
|
||||
* You can find the latest source code at:
|
||||
*
|
||||
@@ -12,7 +10,7 @@
|
||||
*
|
||||
* ------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2010-2014, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2010-2016, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
@@ -113,17 +111,18 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#ifndef __LINENOISE_H
|
||||
# include "clinenoise.h"
|
||||
#endif
|
||||
#include "linenoise.h"
|
||||
|
||||
#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
|
||||
#define LINENOISE_MAX_LINE 4096
|
||||
static char *unsupported_term[] = {"dumb","cons25","emacs",NULL};
|
||||
static linenoiseCompletionCallback *completionCallback = NULL;
|
||||
static linenoiseHintsCallback *hintsCallback = NULL;
|
||||
static linenoiseFreeHintsCallback *freeHintsCallback = NULL;
|
||||
|
||||
static struct termios orig_termios; /* In order to restore at exit.*/
|
||||
static int rawmode = 0; /* For atexit() function to check if restore is needed*/
|
||||
@@ -141,7 +140,7 @@ struct linenoiseState {
|
||||
int ofd; /* Terminal stdout file descriptor. */
|
||||
char *buf; /* Edited line buffer. */
|
||||
size_t buflen; /* Edited line buffer size. */
|
||||
char *prompt; /* Prompt to display. */
|
||||
const char *prompt; /* Prompt to display. */
|
||||
size_t plen; /* Prompt length. */
|
||||
size_t pos; /* Current cursor position. */
|
||||
size_t oldpos; /* Previous refresh cursor position. */
|
||||
@@ -174,7 +173,7 @@ enum KEY_ACTION{
|
||||
};
|
||||
|
||||
static void linenoiseAtExit(void);
|
||||
int linenoiseHistoryAdd(char *line);
|
||||
int linenoiseHistoryAdd(const char *line);
|
||||
static void refreshLine(struct linenoiseState *l);
|
||||
|
||||
/* Debugging macro. */
|
||||
@@ -411,18 +410,30 @@ void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) {
|
||||
completionCallback = fn;
|
||||
}
|
||||
|
||||
/* Register a hits function to be called to show hits to the user at the
|
||||
* right of the prompt. */
|
||||
void linenoiseSetHintsCallback(linenoiseHintsCallback *fn) {
|
||||
hintsCallback = fn;
|
||||
}
|
||||
|
||||
/* Register a function to free the hints returned by the hints callback
|
||||
* registered with linenoiseSetHintsCallback(). */
|
||||
void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *fn) {
|
||||
freeHintsCallback = fn;
|
||||
}
|
||||
|
||||
/* This function is used by the callback function registered by the user
|
||||
* in order to add completion options given the input string when the
|
||||
* user typed <tab>. See the example.c source code for a very easy to
|
||||
* understand example. */
|
||||
void linenoiseAddCompletion(linenoiseCompletions *lc, char *str) {
|
||||
void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) {
|
||||
size_t len = strlen(str);
|
||||
char *copy, **cvec;
|
||||
|
||||
copy = (char*)malloc(len+1);
|
||||
copy = malloc(len+1);
|
||||
if (copy == NULL) return;
|
||||
memcpy(copy,str,len+1);
|
||||
cvec = (char**)realloc(lc->cvec,sizeof(char*)*(lc->len+1));
|
||||
cvec = realloc(lc->cvec,sizeof(char*)*(lc->len+1));
|
||||
if (cvec == NULL) {
|
||||
free(copy);
|
||||
return;
|
||||
@@ -447,12 +458,12 @@ static void abInit(struct abuf *ab) {
|
||||
ab->len = 0;
|
||||
}
|
||||
|
||||
static void abAppend(struct abuf *ab, char *s, int len) {
|
||||
char *neww = (char*)realloc(ab->b,ab->len+len);
|
||||
static void abAppend(struct abuf *ab, const char *s, int len) {
|
||||
char *new = realloc(ab->b,ab->len+len);
|
||||
|
||||
if (neww == NULL) return;
|
||||
memcpy(neww+ab->len,s,len);
|
||||
ab->b = neww;
|
||||
if (new == NULL) return;
|
||||
memcpy(new+ab->len,s,len);
|
||||
ab->b = new;
|
||||
ab->len += len;
|
||||
}
|
||||
|
||||
@@ -460,6 +471,30 @@ static void abFree(struct abuf *ab) {
|
||||
free(ab->b);
|
||||
}
|
||||
|
||||
/* Helper of refreshSingleLine() and refreshMultiLine() to show hints
|
||||
* to the right of the prompt. */
|
||||
void refreshShowHints(struct abuf *ab, struct linenoiseState *l, int plen) {
|
||||
char seq[64];
|
||||
if (hintsCallback && plen+l->len < l->cols) {
|
||||
int color = -1, bold = 0;
|
||||
char *hint = hintsCallback(l->buf,&color,&bold);
|
||||
if (hint) {
|
||||
int hintlen = strlen(hint);
|
||||
int hintmaxlen = l->cols-(plen+l->len);
|
||||
if (hintlen > hintmaxlen) hintlen = hintmaxlen;
|
||||
if (bold == 1 && color == -1) color = 37;
|
||||
if (color != -1 || bold != 0)
|
||||
snprintf(seq,64,"\033[%d;%d;49m",bold,color);
|
||||
abAppend(ab,seq,strlen(seq));
|
||||
abAppend(ab,hint,hintlen);
|
||||
if (color != -1 || bold != 0)
|
||||
abAppend(ab,"\033[0m",4);
|
||||
/* Call the function to free the hint returned. */
|
||||
if (freeHintsCallback) freeHintsCallback(hint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Single line low level line refresh.
|
||||
*
|
||||
* Rewrite the currently edited line accordingly to the buffer content,
|
||||
@@ -489,6 +524,8 @@ static void refreshSingleLine(struct linenoiseState *l) {
|
||||
/* Write the prompt and the current buffer content */
|
||||
abAppend(&ab,l->prompt,strlen(l->prompt));
|
||||
abAppend(&ab,buf,len);
|
||||
/* Show hits if any. */
|
||||
refreshShowHints(&ab,l,plen);
|
||||
/* Erase to right */
|
||||
snprintf(seq,64,"\x1b[0K");
|
||||
abAppend(&ab,seq,strlen(seq));
|
||||
@@ -542,6 +579,9 @@ static void refreshMultiLine(struct linenoiseState *l) {
|
||||
abAppend(&ab,l->prompt,strlen(l->prompt));
|
||||
abAppend(&ab,l->buf,l->len);
|
||||
|
||||
/* Show hits if any. */
|
||||
refreshShowHints(&ab,l,plen);
|
||||
|
||||
/* If we are at the very end of the screen with our prompt, we need to
|
||||
* emit a newline and move the prompt to the first column. */
|
||||
if (l->pos &&
|
||||
@@ -602,7 +642,7 @@ int linenoiseEditInsert(struct linenoiseState *l, char c) {
|
||||
l->pos++;
|
||||
l->len++;
|
||||
l->buf[l->len] = '\0';
|
||||
if ((!mlmode && l->plen+l->len < l->cols) /* || mlmode */) {
|
||||
if ((!mlmode && l->plen+l->len < l->cols && !hintsCallback)) {
|
||||
/* Avoid a full update of the line in the
|
||||
* trivial case. */
|
||||
if (write(l->ofd,&c,1) == -1) return -1;
|
||||
@@ -725,7 +765,7 @@ void linenoiseEditDeletePrevWord(struct linenoiseState *l) {
|
||||
* when ctrl+d is typed.
|
||||
*
|
||||
* The function returns the length of the current buffer. */
|
||||
static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, char *prompt)
|
||||
static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt)
|
||||
{
|
||||
struct linenoiseState l;
|
||||
|
||||
@@ -776,6 +816,14 @@ static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen,
|
||||
history_len--;
|
||||
free(history[history_len]);
|
||||
if (mlmode) linenoiseEditMoveEnd(&l);
|
||||
if (hintsCallback) {
|
||||
/* Force a refresh without hints to leave the previous
|
||||
* line as the user typed it after a newline. */
|
||||
linenoiseHintsCallback *hc = hintsCallback;
|
||||
hintsCallback = NULL;
|
||||
refreshLine(&l);
|
||||
hintsCallback = hc;
|
||||
}
|
||||
return (int)l.len;
|
||||
case CTRL_C: /* ctrl-c */
|
||||
errno = EAGAIN;
|
||||
@@ -931,41 +979,71 @@ void linenoisePrintKeyCodes(void) {
|
||||
|
||||
/* This function calls the line editing function linenoiseEdit() using
|
||||
* the STDIN file descriptor set in raw mode. */
|
||||
static int linenoiseRaw(char *buf, size_t buflen, char *prompt) {
|
||||
static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) {
|
||||
int count;
|
||||
|
||||
if (buflen == 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (!isatty(STDIN_FILENO)) {
|
||||
/* Not a tty: read from file / pipe. */
|
||||
if (fgets(buf, buflen, stdin) == NULL) return -1;
|
||||
count = strlen(buf);
|
||||
if (count && buf[count-1] == '\n') {
|
||||
count--;
|
||||
buf[count] = '\0';
|
||||
}
|
||||
} else {
|
||||
/* Interactive editing. */
|
||||
if (enableRawMode(STDIN_FILENO) == -1) return -1;
|
||||
count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt);
|
||||
disableRawMode(STDIN_FILENO);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (enableRawMode(STDIN_FILENO) == -1) return -1;
|
||||
count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt);
|
||||
disableRawMode(STDIN_FILENO);
|
||||
printf("\n");
|
||||
return count;
|
||||
}
|
||||
|
||||
/* This function is called when linenoise() is called with the standard
|
||||
* input file descriptor not attached to a TTY. So for example when the
|
||||
* program using linenoise is called in pipe or with a file redirected
|
||||
* to its standard input. In this case, we want to be able to return the
|
||||
* line regardless of its length (by default we are limited to 4k). */
|
||||
static char *linenoiseNoTTY(void) {
|
||||
char *line = NULL;
|
||||
size_t len = 0, maxlen = 0;
|
||||
|
||||
while(1) {
|
||||
if (len == maxlen) {
|
||||
if (maxlen == 0) maxlen = 16;
|
||||
maxlen *= 2;
|
||||
char *oldval = line;
|
||||
line = realloc(line,maxlen);
|
||||
if (line == NULL) {
|
||||
if (oldval) free(oldval);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
int c = fgetc(stdin);
|
||||
if (c == EOF || c == '\n') {
|
||||
if (c == EOF && len == 0) {
|
||||
free(line);
|
||||
return NULL;
|
||||
} else {
|
||||
line[len] = '\0';
|
||||
return line;
|
||||
}
|
||||
} else {
|
||||
line[len] = c;
|
||||
len++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* The high level function that is the main API of the linenoise library.
|
||||
* This function checks if the terminal has basic capabilities, just checking
|
||||
* for a blacklist of stupid terminals, and later either calls the line
|
||||
* editing function or uses dummy fgets() so that you will be able to type
|
||||
* something even in the most desperate of the conditions. */
|
||||
char *linenoise(char *prompt) {
|
||||
char *linenoise(const char *prompt) {
|
||||
char buf[LINENOISE_MAX_LINE];
|
||||
int count;
|
||||
|
||||
if (isUnsupportedTerm()) {
|
||||
if (!isatty(STDIN_FILENO)) {
|
||||
/* Not a tty: read from file / pipe. In this mode we don't want any
|
||||
* limit to the line size, so we call a function to handle that. */
|
||||
return linenoiseNoTTY();
|
||||
} else if (isUnsupportedTerm()) {
|
||||
size_t len;
|
||||
|
||||
printf("%s",prompt);
|
||||
@@ -984,6 +1062,14 @@ char *linenoise(char *prompt) {
|
||||
}
|
||||
}
|
||||
|
||||
/* This is just a wrapper the user may want to call in order to make sure
|
||||
* the linenoise returned buffer is freed with the same allocator it was
|
||||
* created with. Useful when the main program is using an alternative
|
||||
* allocator. */
|
||||
void linenoiseFree(void *ptr) {
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
/* ================================ History ================================= */
|
||||
|
||||
/* Free the history, but does not reset it. Only used when we have to
|
||||
@@ -1011,14 +1097,14 @@ static void linenoiseAtExit(void) {
|
||||
* histories, but will work well for a few hundred of entries.
|
||||
*
|
||||
* Using a circular buffer is smarter, but a bit more complex to handle. */
|
||||
int linenoiseHistoryAdd(char *line) {
|
||||
int linenoiseHistoryAdd(const char *line) {
|
||||
char *linecopy;
|
||||
|
||||
if (history_max_len == 0) return 0;
|
||||
|
||||
/* Initialization on first call. */
|
||||
if (history == NULL) {
|
||||
history = (char**)malloc(sizeof(char*)*history_max_len);
|
||||
history = malloc(sizeof(char*)*history_max_len);
|
||||
if (history == NULL) return 0;
|
||||
memset(history,0,(sizeof(char*)*history_max_len));
|
||||
}
|
||||
@@ -1045,14 +1131,14 @@ int linenoiseHistoryAdd(char *line) {
|
||||
* just the latest 'len' elements if the new history length value is smaller
|
||||
* than the amount of items already inside the history. */
|
||||
int linenoiseHistorySetMaxLen(int len) {
|
||||
char **neww;
|
||||
char **new;
|
||||
|
||||
if (len < 1) return 0;
|
||||
if (history) {
|
||||
int tocopy = history_len;
|
||||
|
||||
neww = (char**)malloc(sizeof(char*)*len);
|
||||
if (neww == NULL) return 0;
|
||||
new = malloc(sizeof(char*)*len);
|
||||
if (new == NULL) return 0;
|
||||
|
||||
/* If we can't copy everything, free the elements we'll not use. */
|
||||
if (len < tocopy) {
|
||||
@@ -1061,10 +1147,10 @@ int linenoiseHistorySetMaxLen(int len) {
|
||||
for (j = 0; j < tocopy-len; j++) free(history[j]);
|
||||
tocopy = len;
|
||||
}
|
||||
memset(neww,0,sizeof(char*)*len);
|
||||
memcpy(neww,history+(history_len-tocopy), sizeof(char*)*tocopy);
|
||||
memset(new,0,sizeof(char*)*len);
|
||||
memcpy(new,history+(history_len-tocopy), sizeof(char*)*tocopy);
|
||||
free(history);
|
||||
history = neww;
|
||||
history = new;
|
||||
}
|
||||
history_max_len = len;
|
||||
if (history_len > history_max_len)
|
||||
@@ -1074,11 +1160,15 @@ int linenoiseHistorySetMaxLen(int len) {
|
||||
|
||||
/* Save the history in the specified file. On success 0 is returned
|
||||
* otherwise -1 is returned. */
|
||||
int linenoiseHistorySave(char *filename) {
|
||||
FILE *fp = fopen(filename,"w");
|
||||
int linenoiseHistorySave(const char *filename) {
|
||||
mode_t old_umask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
|
||||
FILE *fp;
|
||||
int j;
|
||||
|
||||
fp = fopen(filename,"w");
|
||||
umask(old_umask);
|
||||
if (fp == NULL) return -1;
|
||||
chmod(filename,S_IRUSR|S_IWUSR);
|
||||
for (j = 0; j < history_len; j++)
|
||||
fprintf(fp,"%s\n",history[j]);
|
||||
fclose(fp);
|
||||
@@ -1090,7 +1180,7 @@ int linenoiseHistorySave(char *filename) {
|
||||
*
|
||||
* If the file exists and the operation succeeded 0 is returned, otherwise
|
||||
* on error -1 is returned. */
|
||||
int linenoiseHistoryLoad(char *filename) {
|
||||
int linenoiseHistoryLoad(const char *filename) {
|
||||
FILE *fp = fopen(filename,"r");
|
||||
char buf[LINENOISE_MAX_LINE];
|
||||
|
||||
@@ -39,22 +39,35 @@
|
||||
#ifndef __LINENOISE_H
|
||||
#define __LINENOISE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct linenoiseCompletions {
|
||||
size_t len;
|
||||
char **cvec;
|
||||
} linenoiseCompletions;
|
||||
|
||||
typedef void(linenoiseCompletionCallback)(char *, linenoiseCompletions *);
|
||||
typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *);
|
||||
typedef char*(linenoiseHintsCallback)(const char *, int *color, int *bold);
|
||||
typedef void(linenoiseFreeHintsCallback)(void *);
|
||||
void linenoiseSetCompletionCallback(linenoiseCompletionCallback *);
|
||||
void linenoiseAddCompletion(linenoiseCompletions *, char *);
|
||||
void linenoiseSetHintsCallback(linenoiseHintsCallback *);
|
||||
void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *);
|
||||
void linenoiseAddCompletion(linenoiseCompletions *, const char *);
|
||||
|
||||
char *linenoise(char *prompt);
|
||||
int linenoiseHistoryAdd(char *line);
|
||||
char *linenoise(const char *prompt);
|
||||
void linenoiseFree(void *ptr);
|
||||
int linenoiseHistoryAdd(const char *line);
|
||||
int linenoiseHistorySetMaxLen(int len);
|
||||
int linenoiseHistorySave(char *filename);
|
||||
int linenoiseHistoryLoad(char *filename);
|
||||
int linenoiseHistorySave(const char *filename);
|
||||
int linenoiseHistoryLoad(const char *filename);
|
||||
void linenoiseClearScreen(void);
|
||||
void linenoiseSetMultiLine(int ml);
|
||||
void linenoisePrintKeyCodes(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __LINENOISE_H */
|
||||
@@ -14,8 +14,7 @@ type
|
||||
|
||||
CompletionCallback* = proc (a2: cstring; a3: ptr Completions) {.cdecl.}
|
||||
|
||||
{.emit: staticRead"clinenoise.h".}
|
||||
{.emit: staticRead"clinenoise.c".}
|
||||
{.compile: "linenoise.c".}
|
||||
|
||||
proc setCompletionCallback*(a2: ptr CompletionCallback) {.
|
||||
importc: "linenoiseSetCompletionCallback".}
|
||||
|
||||
@@ -485,6 +485,10 @@ proc mainCommand(graph: ModuleGraph; cache: IdentCache) =
|
||||
incl gGlobalOptions, optCaasEnabled
|
||||
isServing = true
|
||||
wantMainModule()
|
||||
|
||||
if not fileExists(gProjectFull):
|
||||
quit "cannot find file: " & gProjectFull
|
||||
|
||||
add(searchPaths, options.libpath)
|
||||
|
||||
# do not stop after the first error:
|
||||
|
||||
17
tests/collections/tdeques.nim
Normal file
17
tests/collections/tdeques.nim
Normal file
@@ -0,0 +1,17 @@
|
||||
discard """
|
||||
output: '''true'''
|
||||
"""
|
||||
|
||||
import deques
|
||||
|
||||
|
||||
proc index(self: Deque[int], idx: Natural): int =
|
||||
self[idx]
|
||||
|
||||
proc main =
|
||||
var testDeque = initDeque[int]()
|
||||
testDeque.addFirst(1)
|
||||
assert testDeque.index(0) == 1
|
||||
|
||||
main()
|
||||
echo "true"
|
||||
@@ -1,10 +1,10 @@
|
||||
discard """
|
||||
line: 10
|
||||
errormsg: "value of type 'bool' has to be discarded"
|
||||
errormsg: '''expression 'open(f, "arg.txt", fmRead, -1)' is of type 'bool' and has to be discarded'''
|
||||
"""
|
||||
|
||||
proc p =
|
||||
var f: TFile
|
||||
var f: File
|
||||
echo "hi"
|
||||
|
||||
open(f, "arg.txt")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
discard """
|
||||
errormsg: "value of type 'string' has to be discarded"
|
||||
errormsg: '''expression '"invalid"' is of type 'string' and has to be discarded'''
|
||||
line: 12
|
||||
"""
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
discard """
|
||||
errormsg: "value of type 'bool' has to be discarded"
|
||||
errormsg: "expression 'true' is of type 'bool' and has to be discarded"
|
||||
line: 13
|
||||
file: "tdont_show_system.nim"
|
||||
"""
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
discard """
|
||||
line: 10
|
||||
errormsg: "value of type 'string' has to be discarded"
|
||||
errormsg: "expression 'result[1 .. -(len(result), 1)]' is of type 'string' and has to be discarded"
|
||||
"""
|
||||
|
||||
# bug #578
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
discard """
|
||||
file: "tstmtexp.nim"
|
||||
line: 8
|
||||
errormsg: "value of type 'int literal(5)' has to be discarded"
|
||||
errormsg: "expression '5' is of type 'int literal(5)' and has to be discarded"
|
||||
"""
|
||||
# Test 3
|
||||
|
||||
|
||||
@@ -14,3 +14,16 @@ proc arrayItem(a: ArrayType): auto =
|
||||
var arr: ArrayType[int]
|
||||
echo arrayItem(arr)
|
||||
|
||||
# bug #5597
|
||||
|
||||
template fail() = "what"
|
||||
|
||||
proc g[T](x: var T) =
|
||||
x.fail = 3
|
||||
|
||||
type
|
||||
Obj = object
|
||||
fail: int
|
||||
|
||||
var y: Obj
|
||||
g y
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
discard """
|
||||
output: '''b()
|
||||
720 120.0
|
||||
720 120.0'''
|
||||
"""
|
||||
|
||||
@@ -16,13 +17,12 @@ proc fac[T](x: T): T =
|
||||
|
||||
echo fac(6), " ", fac(5.0)
|
||||
|
||||
when false:
|
||||
# This still doesn't work...
|
||||
# test recursive generic with forwarding:
|
||||
proc fac2[T](x: T): T
|
||||
# test recursive generic with forwarding:
|
||||
proc fac2[T](x: T): T
|
||||
|
||||
echo fac2(6), " ", fac2(5.0)
|
||||
echo fac2(6), " ", fac2(5.0)
|
||||
|
||||
proc fac2[T](x: T): T =
|
||||
if x == 0: return 1
|
||||
else: return fac2(x-1)*x
|
||||
|
||||
proc fac2[T](x: T): T =
|
||||
if x == 0: return 1
|
||||
else: return fac2(x-1)*x
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
discard """
|
||||
output: "1.1000000000000001e+00 11"
|
||||
output: "1.1 11\n42\n0"
|
||||
ccodecheck: "!@'ClEnv'"
|
||||
disabled: "true"
|
||||
"""
|
||||
|
||||
proc p[T](a, b: T): T
|
||||
@@ -12,3 +11,18 @@ proc p[T](a, b: T): T =
|
||||
let c = b
|
||||
result = a + b + c
|
||||
|
||||
# https://github.com/nim-lang/Nim/issues/4908
|
||||
proc foo(t: typedesc[int]): int
|
||||
proc bar(): int = foo(int)
|
||||
proc foo(t: typedesc[int]): int =
|
||||
return 0
|
||||
|
||||
# https://github.com/nim-lang/Nim/issues/4104
|
||||
proc print[T](t: T) # Error: implementation of 'print.print(t: int)' expected
|
||||
print 42 # moving this line after the implementation fixes the error,
|
||||
# but such behaviour makes forward declaration pointless
|
||||
proc print[T](t: T) =
|
||||
echo t
|
||||
|
||||
echo bar()
|
||||
|
||||
|
||||
65
tests/generics/tobjecttyperel.nim
Normal file
65
tests/generics/tobjecttyperel.nim
Normal file
@@ -0,0 +1,65 @@
|
||||
discard """
|
||||
output: '''(peel: 0, color: 15)
|
||||
(color: 15)
|
||||
17
|
||||
(width: 0.0, taste: nil, color: 13)
|
||||
(width: 0.0, taste: nil, color: 15)
|
||||
cool'''
|
||||
"""
|
||||
|
||||
# bug #5241
|
||||
type
|
||||
BaseFruit[T] = object of RootObj
|
||||
color: T
|
||||
|
||||
MidLevel[T] = object of BaseFruit[T]
|
||||
|
||||
Mango = object of MidLevel[int]
|
||||
peel: int
|
||||
|
||||
Peach[X, T, Y] = object of T
|
||||
width: X
|
||||
taste: Y
|
||||
|
||||
proc setColor[T](self: var BaseFruit[T]) =
|
||||
self.color = 15
|
||||
|
||||
proc setColor[T](self: var BaseFruit[T], c: int) =
|
||||
self.color = c
|
||||
|
||||
var c: Mango
|
||||
setColor(c)
|
||||
echo c
|
||||
|
||||
var d: MidLevel[int]
|
||||
setColor(d)
|
||||
echo d
|
||||
|
||||
type
|
||||
FooBase[T] = ref object of RootRef
|
||||
v: T
|
||||
BarClient = ref object of FooBase[int]
|
||||
|
||||
proc getColor[T](f: FooBase[T]): T = 17
|
||||
var b: BarClient
|
||||
echo getColor(b)
|
||||
|
||||
var z: Peach[float64, BaseFruit[int], string]
|
||||
z.setColor(13)
|
||||
echo z
|
||||
|
||||
z.setColor()
|
||||
echo z
|
||||
|
||||
# bug #5411
|
||||
type
|
||||
Foo[T] = ref object of RootRef
|
||||
v: T
|
||||
Bar = ref object of Foo[int]
|
||||
|
||||
method m(o: RootRef) {.base.} = assert(false, "Abstract method called")
|
||||
method m[T](o: Foo[T]) = echo "cool"
|
||||
|
||||
var v: Bar
|
||||
v.new()
|
||||
v.m() # Abstract method not called anymore
|
||||
13
tests/js/ttimes.nim
Normal file
13
tests/js/ttimes.nim
Normal file
@@ -0,0 +1,13 @@
|
||||
# test times module with js
|
||||
discard """
|
||||
action: run
|
||||
"""
|
||||
|
||||
import times
|
||||
|
||||
# $ date --date='@2147483647'
|
||||
# Tue 19 Jan 03:14:07 GMT 2038
|
||||
|
||||
block yeardayTest:
|
||||
# check if yearday attribute is properly set on TimeInfo creation
|
||||
doAssert fromSeconds(2147483647).getGMTime().yearday == 18
|
||||
@@ -35,5 +35,6 @@ except:
|
||||
echo "Second readLine raised an exception"
|
||||
|
||||
echo line
|
||||
f.close()
|
||||
|
||||
removeFile(fn)
|
||||
|
||||
@@ -96,5 +96,12 @@ suite "bug #4494":
|
||||
check:
|
||||
allIt(0..3, tags[it] != tags[it + 1])
|
||||
|
||||
suite "bug #5571":
|
||||
test "can define gcsafe procs within tests":
|
||||
proc doTest {.gcsafe.} =
|
||||
let line = "a"
|
||||
check: line == "a"
|
||||
doTest()
|
||||
|
||||
static:
|
||||
echo "compile end"
|
||||
|
||||
@@ -186,25 +186,11 @@ proc longGCTests(r: var TResults, cat: Category, options: string) =
|
||||
|
||||
proc threadTests(r: var TResults, cat: Category, options: string) =
|
||||
template test(filename: untyped) =
|
||||
testSpec r, makeTest("tests/threads" / filename, options, cat, actionRun)
|
||||
testSpec r, makeTest("tests/threads" / filename, options &
|
||||
" -d:release", cat, actionRun)
|
||||
testSpec r, makeTest("tests/threads" / filename, options &
|
||||
" --tlsEmulation:on", cat, actionRun)
|
||||
|
||||
test "tactors"
|
||||
test "tactors2"
|
||||
test "threadex"
|
||||
# deactivated because output capturing still causes problems sometimes:
|
||||
#test "trecursive_actor"
|
||||
#test "threadring"
|
||||
#test "tthreadanalysis"
|
||||
#test "tthreadsort"
|
||||
test "tthreadanalysis2"
|
||||
#test "tthreadanalysis3"
|
||||
test "tthreadheapviolation1"
|
||||
test "tonthreadcreation"
|
||||
test "tracy_allocator"
|
||||
testSpec r, makeTest(filename, options, cat, actionRun)
|
||||
testSpec r, makeTest(filename, options & " -d:release", cat, actionRun)
|
||||
testSpec r, makeTest(filename, options & " --tlsEmulation:on", cat, actionRun)
|
||||
for t in os.walkFiles("tests/threads/t*.nim"):
|
||||
test(t)
|
||||
|
||||
# ------------------------- IO tests ------------------------------------------
|
||||
|
||||
|
||||
30
tests/threads/tmanyjoin.nim
Normal file
30
tests/threads/tmanyjoin.nim
Normal file
@@ -0,0 +1,30 @@
|
||||
discard """
|
||||
outputsub: "129"
|
||||
"""
|
||||
|
||||
import os, locks
|
||||
|
||||
type
|
||||
MarkerObj = object
|
||||
lock: Lock
|
||||
counter: int
|
||||
Marker = ptr MarkerObj
|
||||
|
||||
const
|
||||
ThreadsCount = 129
|
||||
SleepTime = 1000
|
||||
|
||||
proc worker(p: Marker) {.thread.} =
|
||||
acquire(p.lock)
|
||||
inc(p.counter)
|
||||
release(p.lock)
|
||||
sleep(SleepTime)
|
||||
|
||||
var p = cast[Marker](allocShared0(sizeof(MarkerObj)))
|
||||
initLock(p.lock)
|
||||
var ts = newSeq[Thread[Marker]](ThreadsCount)
|
||||
for i in 0..<ts.len:
|
||||
createThread(ts[i], worker, p)
|
||||
|
||||
joinThreads(ts)
|
||||
echo p.counter
|
||||
@@ -1,4 +1,5 @@
|
||||
discard """
|
||||
disabled: yes
|
||||
outputsub: "0"
|
||||
"""
|
||||
|
||||
|
||||
28
tests/threads/treusetvar.nim
Normal file
28
tests/threads/treusetvar.nim
Normal file
@@ -0,0 +1,28 @@
|
||||
discard """
|
||||
outputsub: "129"
|
||||
"""
|
||||
|
||||
import os, locks
|
||||
|
||||
type
|
||||
MarkerObj = object
|
||||
lock: Lock
|
||||
counter: int
|
||||
Marker = ptr MarkerObj
|
||||
|
||||
const
|
||||
ThreadsCount = 129
|
||||
|
||||
proc worker(p: Marker) {.thread.} =
|
||||
acquire(p.lock)
|
||||
inc(p.counter)
|
||||
release(p.lock)
|
||||
|
||||
var p = cast[Marker](allocShared0(sizeof(MarkerObj)))
|
||||
initLock(p.lock)
|
||||
|
||||
for i in 0..(ThreadsCount - 1):
|
||||
var thread: Thread[Marker]
|
||||
createThread(thread, worker, p)
|
||||
joinThread(thread)
|
||||
echo p.counter
|
||||
@@ -1,4 +1,5 @@
|
||||
discard """
|
||||
disabled: yes
|
||||
outputsub: "101"
|
||||
errormsg: "'threadFunc' is not GC-safe"
|
||||
line: 39
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
discard """
|
||||
disabled: yes
|
||||
outputsub: "channel is empty"
|
||||
"""
|
||||
|
||||
|
||||
@@ -52,13 +52,13 @@ test(OrderR, OrderG)
|
||||
test(OrderR, OrderAlias)
|
||||
test(OrderG, OrderAlias)
|
||||
|
||||
typeRep(OrderAlias, Order) # true
|
||||
typeRep(OrderR, Order) # true
|
||||
typeRep(OrderG, Order) # true
|
||||
typeRep(OrderAlias.R, Order.R) # true
|
||||
typeRep(OrderR.R, Order.R) # true
|
||||
typeRep(OrderG.R, Order.R) # true
|
||||
|
||||
typeRep(OrderR, OrderAlias) # true
|
||||
typeRep(OrderG, OrderAlias) # true
|
||||
typeRep(OrderR, OrderG) # true
|
||||
typeRep(OrderR.R, OrderAlias.R) # true
|
||||
typeRep(OrderG.R, OrderAlias.R) # true
|
||||
typeRep(OrderR.R, OrderG.R) # true
|
||||
|
||||
echo OrderR.R # R
|
||||
echo OrderG.R # R
|
||||
|
||||
@@ -42,6 +42,9 @@ Changes affecting backwards compatibility
|
||||
AST that is the same as what is used to define an enum. Previously the AST
|
||||
returned had a repeated ``EnumTy`` node and was missing the initial pragma
|
||||
node (which is currently empty for an enum).
|
||||
- If the dispatcher parameter's value used in multi method is ``nil``,
|
||||
a ``NilError`` exception is raised. The old behavior was that the method
|
||||
would be a ``nop`` then.
|
||||
|
||||
|
||||
Library Additions
|
||||
|
||||
Reference in New Issue
Block a user