mirror of
https://github.com/nim-lang/Nim.git
synced 2026-06-09 05:14:20 +00:00
Merge branch 'devel' into araq
This commit is contained in:
23
changelog.md
23
changelog.md
@@ -39,5 +39,26 @@
|
||||
- Added ``typetraits.$`` as an alias for ``typetraits.name``.
|
||||
- ``os.getEnv`` now takes an optional ``default`` parameter that tells ``getEnv``
|
||||
what to return if the environment variable does not exist.
|
||||
- Removed PDCurses wrapper from the stdlib and published it as a separate
|
||||
- Removed PDCurses wrapper from the stdlib and published it as a separate
|
||||
Nimble package.
|
||||
- Bodies of ``for`` loops now get their own scope:
|
||||
|
||||
.. code-block:: nim
|
||||
# now compiles:
|
||||
for i in 0..4:
|
||||
let i = i + 1
|
||||
echo i
|
||||
|
||||
- The parsing rules of ``if`` expressions were changed so that multiple
|
||||
statements are allowed in the branches. We found few code examples that
|
||||
now fail because of this change, but here is one:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
t[ti] = if exp_negative: '-' else: '+'; inc(ti)
|
||||
|
||||
This now needs to be written as:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
t[ti] = (if exp_negative: '-' else: '+'); inc(ti)
|
||||
|
||||
@@ -1067,7 +1067,7 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
else:
|
||||
r.res = "chckIndx($1, $2, strlen($3))-$2" % [b.res, rope(first), a.res]
|
||||
else:
|
||||
r.res = "chckIndx($1, $2, $3.length-1)-$2" % [b.res, rope(first), a.res]
|
||||
r.res = "chckIndx($1, $2, $3.length+$2-1)-$2" % [b.res, rope(first), a.res]
|
||||
elif first != 0:
|
||||
r.res = "($1)-$2" % [b.res, rope(first)]
|
||||
else:
|
||||
|
||||
@@ -764,7 +764,10 @@ proc semCaptureSym*(s, owner: PSym) =
|
||||
var o = owner.skipGenericOwner
|
||||
while o.kind != skModule and o != nil:
|
||||
if s.owner == o:
|
||||
owner.typ.callConv = ccClosure
|
||||
if owner.typ.callConv in {ccClosure, ccDefault} or owner.kind == skIterator:
|
||||
owner.typ.callConv = ccClosure
|
||||
else:
|
||||
discard "do not produce an error here, but later"
|
||||
#echo "computing .closure for ", owner.name.s, " ", owner.info, " because of ", s.name.s
|
||||
o = o.skipGenericOwner
|
||||
# since the analysis is not entirely correct, we don't set 'tfCapturesEnv'
|
||||
|
||||
@@ -52,17 +52,19 @@ proc lookupParam(params, dest: PNode): PSym =
|
||||
if params[i].kind == nkSym and params[i].sym.name.id == dest.ident.id:
|
||||
return params[i].sym
|
||||
|
||||
proc liftLocalsIfRequested*(prc: PSym) =
|
||||
proc liftLocalsIfRequested*(prc: PSym; n: PNode): PNode =
|
||||
let liftDest = getPragmaVal(prc.ast, wLiftLocals)
|
||||
if liftDest == nil: return
|
||||
if liftDest == nil: return n
|
||||
let partialParam = lookupParam(prc.typ.n, liftDest)
|
||||
if partialParam.isNil:
|
||||
localError(liftDest.info, "'$1' is not a parameter of '$2'" %
|
||||
[$liftDest, prc.name.s])
|
||||
return
|
||||
return n
|
||||
let objType = partialParam.typ.skipTypes(abstractPtrs)
|
||||
if objType.kind != tyObject or tfPartial notin objType.flags:
|
||||
localError(liftDest.info, "parameter '$1' is not a pointer to a partial object" % $liftDest)
|
||||
return
|
||||
return n
|
||||
var c = Ctx(partialParam: partialParam, objType: objType)
|
||||
liftLocals(prc.ast, bodyPos, c)
|
||||
let w = newTree(nkStmtList, n)
|
||||
liftLocals(w, 0, c)
|
||||
result = w[0]
|
||||
|
||||
@@ -98,6 +98,7 @@ proc resolveDollar(project, source, pkg, subdir: string; info: TLineInfo): strin
|
||||
|
||||
proc scriptableImport(pkg, sub: string; info: TLineInfo): string =
|
||||
result = resolveDollar(gProjectFull, info.toFullPath(), pkg, sub, info)
|
||||
if result.isNil: result = ""
|
||||
|
||||
proc lookupPackage(pkg, subdir: PNode): string =
|
||||
let sub = if subdir != nil: renderTree(subdir, {renderNoComments}).replace(" ") else: ""
|
||||
@@ -166,7 +167,8 @@ proc checkModuleName*(n: PNode; doLocalError=true): int32 =
|
||||
let fullPath = findModule(modulename, n.info.toFullPath)
|
||||
if fullPath.len == 0:
|
||||
if doLocalError:
|
||||
localError(n.info, errCannotOpenFile, modulename)
|
||||
let m = if modulename.len > 0: modulename else: $n
|
||||
localError(n.info, errCannotOpenFile, m)
|
||||
result = InvalidFileIDX
|
||||
else:
|
||||
result = fullPath.fileInfoIdx
|
||||
result = fullPath.fileInfoIdx
|
||||
|
||||
@@ -61,7 +61,7 @@ type
|
||||
errBaseTypeMustBeOrdinal, errInheritanceOnlyWithNonFinalObjects,
|
||||
errInheritanceOnlyWithEnums, errIllegalRecursionInTypeX,
|
||||
errCannotInstantiateX, errExprHasNoAddress, errXStackEscape,
|
||||
errVarForOutParamNeeded,
|
||||
errVarForOutParamNeededX,
|
||||
errPureTypeMismatch, errTypeMismatch, errButExpected, errButExpectedX,
|
||||
errAmbiguousCallXYZ, errWrongNumberOfArguments,
|
||||
errWrongNumberOfArgumentsInCall,
|
||||
@@ -268,7 +268,7 @@ const
|
||||
errCannotInstantiateX: "cannot instantiate: \'$1\'",
|
||||
errExprHasNoAddress: "expression has no address",
|
||||
errXStackEscape: "address of '$1' may not escape its stack frame",
|
||||
errVarForOutParamNeeded: "for a \'var\' type a variable needs to be passed",
|
||||
errVarForOutParamNeededX: "for a \'var\' type a variable needs to be passed; but '$1' is immutable",
|
||||
errPureTypeMismatch: "type mismatch",
|
||||
errTypeMismatch: "type mismatch: got (",
|
||||
errButExpected: "but expected one of: ",
|
||||
|
||||
@@ -785,21 +785,58 @@ proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode =
|
||||
#| 'else' colcom expr
|
||||
#| ifExpr = 'if' condExpr
|
||||
#| whenExpr = 'when' condExpr
|
||||
result = newNodeP(kind, p)
|
||||
while true:
|
||||
getTok(p) # skip `if`, `elif`
|
||||
var branch = newNodeP(nkElifExpr, p)
|
||||
when true:
|
||||
result = newNodeP(kind, p)
|
||||
while true:
|
||||
getTok(p) # skip `if`, `when`, `elif`
|
||||
var branch = newNodeP(nkElifExpr, p)
|
||||
optInd(p, branch)
|
||||
addSon(branch, parseExpr(p))
|
||||
colcom(p, branch)
|
||||
addSon(branch, parseStmt(p))
|
||||
skipComment(p, branch)
|
||||
addSon(result, branch)
|
||||
if p.tok.tokType != tkElif: break # or not sameOrNoInd(p): break
|
||||
if p.tok.tokType == tkElse: # and sameOrNoInd(p):
|
||||
var branch = newNodeP(nkElseExpr, p)
|
||||
eat(p, tkElse)
|
||||
colcom(p, branch)
|
||||
addSon(branch, parseStmt(p))
|
||||
addSon(result, branch)
|
||||
else:
|
||||
var
|
||||
b: PNode
|
||||
wasIndented = false
|
||||
result = newNodeP(kind, p)
|
||||
|
||||
getTok(p)
|
||||
let branch = newNodeP(nkElifExpr, p)
|
||||
addSon(branch, parseExpr(p))
|
||||
colcom(p, branch)
|
||||
let oldInd = p.currInd
|
||||
if realInd(p):
|
||||
p.currInd = p.tok.indent
|
||||
wasIndented = true
|
||||
echo result.info, " yes ", p.currInd
|
||||
addSon(branch, parseExpr(p))
|
||||
optInd(p, branch)
|
||||
addSon(result, branch)
|
||||
if p.tok.tokType != tkElif: break
|
||||
var branch = newNodeP(nkElseExpr, p)
|
||||
eat(p, tkElse)
|
||||
colcom(p, branch)
|
||||
addSon(branch, parseExpr(p))
|
||||
addSon(result, branch)
|
||||
result.add branch
|
||||
while sameInd(p) or not wasIndented:
|
||||
case p.tok.tokType
|
||||
of tkElif:
|
||||
b = newNodeP(nkElifExpr, p)
|
||||
getTok(p)
|
||||
optInd(p, b)
|
||||
addSon(b, parseExpr(p))
|
||||
of tkElse:
|
||||
b = newNodeP(nkElseExpr, p)
|
||||
getTok(p)
|
||||
else: break
|
||||
colcom(p, b)
|
||||
addSon(b, parseStmt(p))
|
||||
addSon(result, b)
|
||||
if b.kind == nkElseExpr: break
|
||||
if wasIndented:
|
||||
p.currInd = oldInd
|
||||
|
||||
proc parsePragma(p: var TParser): PNode =
|
||||
#| pragma = '{.' optInd (exprColonExpr comma?)* optPar ('.}' | '}')
|
||||
@@ -2036,8 +2073,13 @@ proc parseStmt(p: var TParser): PNode =
|
||||
if a.kind != nkEmpty:
|
||||
addSon(result, a)
|
||||
else:
|
||||
parMessage(p, errExprExpected, p.tok)
|
||||
getTok(p)
|
||||
# This is done to make the new 'if' expressions work better.
|
||||
# XXX Eventually we need to be more strict here.
|
||||
if p.tok.tokType notin {tkElse, tkElif}:
|
||||
parMessage(p, errExprExpected, p.tok)
|
||||
getTok(p)
|
||||
else:
|
||||
break
|
||||
if not p.hasProgress and p.tok.tokType == tkEof: break
|
||||
else:
|
||||
# the case statement is only needed for better error messages:
|
||||
|
||||
@@ -465,7 +465,7 @@ proc newHiddenAddrTaken(c: PContext, n: PNode): PNode =
|
||||
result = newNodeIT(nkHiddenAddr, n.info, makeVarType(c, n.typ))
|
||||
addSon(result, n)
|
||||
if isAssignable(c, n) notin {arLValue, arLocalLValue}:
|
||||
localError(n.info, errVarForOutParamNeeded)
|
||||
localError(n.info, errVarForOutParamNeededX, $n)
|
||||
|
||||
proc analyseIfAddressTaken(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
@@ -509,9 +509,10 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
if i < sonsLen(t) and t.sons[i] != nil and
|
||||
skipTypes(t.sons[i], abstractInst-{tyTypeDesc}).kind == tyVar:
|
||||
if isAssignable(c, n.sons[i]) notin {arLValue, arLocalLValue}:
|
||||
if n.sons[i].kind != nkHiddenAddr:
|
||||
localError(n.sons[i].info, errVarForOutParamNeeded)
|
||||
let it = n[i]
|
||||
if isAssignable(c, it) notin {arLValue, arLocalLValue}:
|
||||
if it.kind != nkHiddenAddr:
|
||||
localError(it.info, errVarForOutParamNeededX, $it)
|
||||
return
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
if n.sons[i].kind == nkHiddenCallConv:
|
||||
|
||||
@@ -335,8 +335,10 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
n.sons[L - 2] = semGenericStmt(c, n.sons[L-2], flags, ctx)
|
||||
for i in countup(0, L - 3):
|
||||
addTempDecl(c, n.sons[i], skForVar)
|
||||
openScope(c)
|
||||
n.sons[L - 1] = semGenericStmt(c, n.sons[L-1], flags, ctx)
|
||||
closeScope(c)
|
||||
closeScope(c)
|
||||
of nkBlockStmt, nkBlockExpr, nkBlockType:
|
||||
checkSonsLen(n, 2)
|
||||
openScope(c)
|
||||
|
||||
@@ -697,7 +697,9 @@ proc semForVars(c: PContext, n: PNode): PNode =
|
||||
if sfGenSym notin v.flags and not isDiscardUnderscore(v):
|
||||
addForVarDecl(c, v)
|
||||
inc(c.p.nestedLoopCounter)
|
||||
openScope(c)
|
||||
n.sons[length-1] = semStmt(c, n.sons[length-1])
|
||||
closeScope(c)
|
||||
dec(c.p.nestedLoopCounter)
|
||||
|
||||
proc implicitIterator(c: PContext, it: string, arg: PNode): PNode =
|
||||
|
||||
@@ -366,8 +366,10 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
|
||||
n.sons[L-2] = semTemplBody(c, n.sons[L-2])
|
||||
for i in countup(0, L - 3):
|
||||
addLocalDecl(c, n.sons[i], skForVar)
|
||||
openScope(c)
|
||||
n.sons[L-1] = semTemplBody(c, n.sons[L-1])
|
||||
closeScope(c)
|
||||
closeScope(c)
|
||||
of nkBlockStmt, nkBlockExpr, nkBlockType:
|
||||
checkSonsLen(n, 2)
|
||||
openScope(c)
|
||||
|
||||
@@ -1057,9 +1057,10 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
|
||||
else: isNone
|
||||
|
||||
of tyUserTypeClass, tyUserTypeClassInst:
|
||||
if c.c.matchedConcept != nil:
|
||||
if c.c.matchedConcept != nil and c.c.matchedConcept.depth <= 4:
|
||||
# consider this: 'var g: Node' *within* a concept where 'Node'
|
||||
# is a concept too (tgraph)
|
||||
inc c.c.matchedConcept.depth
|
||||
let x = typeRel(c, a, f, flags + {trDontBind})
|
||||
if x >= isGeneric:
|
||||
return isGeneric
|
||||
|
||||
@@ -978,7 +978,7 @@ proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode =
|
||||
liftDefer(c, result)
|
||||
#result = liftLambdas(prc, result)
|
||||
when useEffectSystem: trackProc(prc, result)
|
||||
liftLocalsIfRequested(prc)
|
||||
result = liftLocalsIfRequested(prc, result)
|
||||
if c.needsDestroyPass and newDestructors:
|
||||
result = injectDestructorCalls(prc, result)
|
||||
incl(result.flags, nfTransf)
|
||||
|
||||
@@ -98,7 +98,6 @@ path="$lib/pure"
|
||||
clang.options.linker = "-landroid-glob"
|
||||
clang.cpp.options.linker = "-landroid-glob"
|
||||
tcc.options.linker = "-landroid-glob"
|
||||
define:"useShPath:/system/bin/sh"
|
||||
@end
|
||||
@end
|
||||
|
||||
|
||||
@@ -316,7 +316,7 @@ factor.
|
||||
immediate pragma
|
||||
----------------
|
||||
|
||||
See `Ordinary vs immediate templates`_.
|
||||
See `Typed vs untyped parameters`_.
|
||||
|
||||
|
||||
compilation option pragmas
|
||||
|
||||
@@ -262,7 +262,7 @@ proc socket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
|
||||
|
||||
# TODO: Perhaps this should just raise EOS when an error occurs.
|
||||
when defined(Windows):
|
||||
result = newTSocket(winlean.socket(ord(domain), ord(typ), ord(protocol)), buffered)
|
||||
result = newTSocket(winlean.socket(cint(domain), cint(typ), cint(protocol)), buffered)
|
||||
else:
|
||||
result = newTSocket(posix.socket(toInt(domain), toInt(typ), toInt(protocol)), buffered)
|
||||
|
||||
|
||||
@@ -798,7 +798,8 @@ proc renderImage(d: PDoc, n: PRstNode, result: var string) =
|
||||
if arg.valid:
|
||||
let htmlOut = if isObject:
|
||||
"<object data=\"$1\" type=\"image/svg+xml\"$2 >" & content & "</object>"
|
||||
else: "<img src=\"$1\"$2 />"
|
||||
else:
|
||||
"<img src=\"$1\"$2 />"
|
||||
dispA(d.target, result, htmlOut, "\\includegraphics$2{$1}",
|
||||
[arg, options])
|
||||
if len(n) >= 3: renderRstToOut(d, n.sons[2], result)
|
||||
|
||||
@@ -767,7 +767,9 @@ elif not defined(useNimRtl):
|
||||
var sysCommand: string
|
||||
var sysArgsRaw: seq[string]
|
||||
if poEvalCommand in options:
|
||||
const useShPath {.strdefine.} = "/bin/sh"
|
||||
const useShPath {.strdefine.} =
|
||||
when not defined(android): "/bin/sh"
|
||||
else: "/system/bin/sh"
|
||||
sysCommand = useShPath
|
||||
sysArgsRaw = @[sysCommand, "-c", command]
|
||||
assert args.len == 0, "`args` has to be empty when using poEvalCommand."
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
## runtime efficiency.
|
||||
|
||||
include "system/inclrtl"
|
||||
import streams
|
||||
|
||||
{.deadCodeElim: on.}
|
||||
|
||||
@@ -130,7 +131,7 @@ proc insertInCache(s: string, tree: Rope): Rope =
|
||||
result.left = t
|
||||
t.right = nil
|
||||
|
||||
proc rope*(s: string): Rope {.rtl, extern: "nro$1Str".} =
|
||||
proc rope*(s: string = nil): Rope {.rtl, extern: "nro$1Str".} =
|
||||
## Converts a string to a rope.
|
||||
if s.len == 0:
|
||||
result = nil
|
||||
@@ -242,10 +243,13 @@ proc write*(f: File, r: Rope) {.rtl, extern: "nro$1".} =
|
||||
## writes a rope to a file.
|
||||
for s in leaves(r): write(f, s)
|
||||
|
||||
proc write*(s: Stream, r: Rope) {.rtl, extern: "nroWriteStream".} =
|
||||
## writes a rope to a stream.
|
||||
for rs in leaves(r): write(s, rs)
|
||||
|
||||
proc `$`*(r: Rope): string {.rtl, extern: "nroToString".}=
|
||||
## converts a rope back to a string.
|
||||
result = newString(r.len)
|
||||
setLen(result, 0)
|
||||
result = newStringOfCap(r.len)
|
||||
for s in leaves(r): add(result, s)
|
||||
|
||||
when false:
|
||||
|
||||
@@ -578,15 +578,46 @@ iterator split*(s: string, seps: set[char] = Whitespace,
|
||||
else:
|
||||
splitCommon(s, seps, maxsplit, 1)
|
||||
|
||||
iterator splitWhitespace*(s: string): string =
|
||||
## Splits at whitespace.
|
||||
oldSplit(s, Whitespace, -1)
|
||||
iterator splitWhitespace*(s: string, maxsplit: int = -1): string =
|
||||
## Splits the string ``s`` at whitespace stripping leading and trailing
|
||||
## whitespace if necessary. If ``maxsplit`` is specified and is positive,
|
||||
## no more than ``maxsplit`` splits is made.
|
||||
##
|
||||
## The following code:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## let s = " foo \t bar baz "
|
||||
## for ms in [-1, 1, 2, 3]:
|
||||
## echo "------ maxsplit = ", ms, ":"
|
||||
## for item in s.splitWhitespace(maxsplit=ms):
|
||||
## echo '"', item, '"'
|
||||
##
|
||||
## ...results in:
|
||||
##
|
||||
## .. code-block::
|
||||
## ------ maxsplit = -1:
|
||||
## "foo"
|
||||
## "bar"
|
||||
## "baz"
|
||||
## ------ maxsplit = 1:
|
||||
## "foo"
|
||||
## "bar baz "
|
||||
## ------ maxsplit = 2:
|
||||
## "foo"
|
||||
## "bar"
|
||||
## "baz "
|
||||
## ------ maxsplit = 3:
|
||||
## "foo"
|
||||
## "bar"
|
||||
## "baz"
|
||||
##
|
||||
oldSplit(s, Whitespace, maxsplit)
|
||||
|
||||
proc splitWhitespace*(s: string): seq[string] {.noSideEffect,
|
||||
proc splitWhitespace*(s: string, maxsplit: int = -1): seq[string] {.noSideEffect,
|
||||
rtl, extern: "nsuSplitWhitespace".} =
|
||||
## The same as the `splitWhitespace <#splitWhitespace.i,string>`_
|
||||
## The same as the `splitWhitespace <#splitWhitespace.i,string,int>`_
|
||||
## iterator, but is a proc that returns a sequence of substrings.
|
||||
accumulateResult(splitWhitespace(s))
|
||||
accumulateResult(splitWhitespace(s, maxsplit))
|
||||
|
||||
iterator split*(s: string, sep: char, maxsplit: int = -1): string =
|
||||
## Splits the string `s` into substrings using a single separator.
|
||||
@@ -671,7 +702,7 @@ iterator rsplit*(s: string, seps: set[char] = Whitespace,
|
||||
maxsplit: int = -1): string =
|
||||
## Splits the string `s` into substrings from the right using a
|
||||
## string separator. Works exactly the same as `split iterator
|
||||
## <#split.i,string,char>`_ except in reverse order.
|
||||
## <#split.i,string,char,int>`_ except in reverse order.
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## for piece in "foo bar".rsplit(WhiteSpace):
|
||||
@@ -691,7 +722,7 @@ iterator rsplit*(s: string, sep: char,
|
||||
maxsplit: int = -1): string =
|
||||
## Splits the string `s` into substrings from the right using a
|
||||
## string separator. Works exactly the same as `split iterator
|
||||
## <#split.i,string,char>`_ except in reverse order.
|
||||
## <#split.i,string,char,int>`_ except in reverse order.
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## for piece in "foo:bar".rsplit(':'):
|
||||
@@ -710,7 +741,7 @@ iterator rsplit*(s: string, sep: string, maxsplit: int = -1,
|
||||
keepSeparators: bool = false): string =
|
||||
## Splits the string `s` into substrings from the right using a
|
||||
## string separator. Works exactly the same as `split iterator
|
||||
## <#split.i,string,string>`_ except in reverse order.
|
||||
## <#split.i,string,string,int>`_ except in reverse order.
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## for piece in "foothebar".rsplit("the"):
|
||||
@@ -791,13 +822,13 @@ proc countLines*(s: string): int {.noSideEffect,
|
||||
|
||||
proc split*(s: string, seps: set[char] = Whitespace, maxsplit: int = -1): seq[string] {.
|
||||
noSideEffect, rtl, extern: "nsuSplitCharSet".} =
|
||||
## The same as the `split iterator <#split.i,string,set[char]>`_, but is a
|
||||
## The same as the `split iterator <#split.i,string,set[char],int>`_, but is a
|
||||
## proc that returns a sequence of substrings.
|
||||
accumulateResult(split(s, seps, maxsplit))
|
||||
|
||||
proc split*(s: string, sep: char, maxsplit: int = -1): seq[string] {.noSideEffect,
|
||||
rtl, extern: "nsuSplitChar".} =
|
||||
## The same as the `split iterator <#split.i,string,char>`_, but is a proc
|
||||
## The same as the `split iterator <#split.i,string,char,int>`_, but is a proc
|
||||
## that returns a sequence of substrings.
|
||||
accumulateResult(split(s, sep, maxsplit))
|
||||
|
||||
@@ -806,7 +837,7 @@ proc split*(s: string, sep: string, maxsplit: int = -1): seq[string] {.noSideEff
|
||||
## Splits the string `s` into substrings using a string separator.
|
||||
##
|
||||
## Substrings are separated by the string `sep`. This is a wrapper around the
|
||||
## `split iterator <#split.i,string,string>`_.
|
||||
## `split iterator <#split.i,string,string,int>`_.
|
||||
doAssert(sep.len > 0)
|
||||
|
||||
accumulateResult(split(s, sep, maxsplit))
|
||||
@@ -814,7 +845,7 @@ proc split*(s: string, sep: string, maxsplit: int = -1): seq[string] {.noSideEff
|
||||
proc rsplit*(s: string, seps: set[char] = Whitespace,
|
||||
maxsplit: int = -1): seq[string]
|
||||
{.noSideEffect, rtl, extern: "nsuRSplitCharSet".} =
|
||||
## The same as the `rsplit iterator <#rsplit.i,string,set[char]>`_, but is a
|
||||
## The same as the `rsplit iterator <#rsplit.i,string,set[char],int>`_, but is a
|
||||
## proc that returns a sequence of substrings.
|
||||
##
|
||||
## A possible common use case for `rsplit` is path manipulation,
|
||||
@@ -836,7 +867,7 @@ proc rsplit*(s: string, seps: set[char] = Whitespace,
|
||||
|
||||
proc rsplit*(s: string, sep: char, maxsplit: int = -1): seq[string]
|
||||
{.noSideEffect, rtl, extern: "nsuRSplitChar".} =
|
||||
## The same as the `split iterator <#rsplit.i,string,char>`_, but is a proc
|
||||
## The same as the `rsplit iterator <#rsplit.i,string,char,int>`_, but is a proc
|
||||
## that returns a sequence of substrings.
|
||||
##
|
||||
## A possible common use case for `rsplit` is path manipulation,
|
||||
@@ -858,7 +889,7 @@ proc rsplit*(s: string, sep: char, maxsplit: int = -1): seq[string]
|
||||
|
||||
proc rsplit*(s: string, sep: string, maxsplit: int = -1): seq[string]
|
||||
{.noSideEffect, rtl, extern: "nsuRSplitString".} =
|
||||
## The same as the `split iterator <#rsplit.i,string,string>`_, but is a proc
|
||||
## The same as the `rsplit iterator <#rsplit.i,string,string,int>`_, but is a proc
|
||||
## that returns a sequence of substrings.
|
||||
##
|
||||
## A possible common use case for `rsplit` is path manipulation,
|
||||
@@ -2599,6 +2630,12 @@ bar
|
||||
doAssert s.split(' ', maxsplit=1) == @["", "this is an example "]
|
||||
doAssert s.split(" ", maxsplit=4) == @["", "this", "is", "an", "example "]
|
||||
|
||||
doAssert s.splitWhitespace() == @["this", "is", "an", "example"]
|
||||
doAssert s.splitWhitespace(maxsplit=1) == @["this", "is an example "]
|
||||
doAssert s.splitWhitespace(maxsplit=2) == @["this", "is", "an example "]
|
||||
doAssert s.splitWhitespace(maxsplit=3) == @["this", "is", "an", "example "]
|
||||
doAssert s.splitWhitespace(maxsplit=4) == @["this", "is", "an", "example"]
|
||||
|
||||
block: # formatEng tests
|
||||
doAssert formatEng(0, 2, trim=false) == "0.00"
|
||||
doAssert formatEng(0, 2) == "0"
|
||||
|
||||
@@ -3531,14 +3531,14 @@ proc `[]`*[Idx, T, U, V](a: array[Idx, T], x: HSlice[U, V]): seq[T] =
|
||||
let xa = a ^^ x.a
|
||||
let L = (a ^^ x.b) - xa + 1
|
||||
result = newSeq[T](L)
|
||||
for i in 0..<L: result[i] = a[Idx(i + xa + int low(a))]
|
||||
for i in 0..<L: result[i] = a[Idx(i + xa)]
|
||||
|
||||
proc `[]=`*[Idx, T, U, V](a: var array[Idx, T], x: HSlice[U, V], b: openArray[T]) =
|
||||
## slice assignment for arrays.
|
||||
let xa = a ^^ x.a
|
||||
let L = (a ^^ x.b) - xa + 1
|
||||
if L == b.len:
|
||||
for i in 0..<L: a[Idx(i + xa + int low(a))] = b[i]
|
||||
for i in 0..<L: a[Idx(i + xa)] = b[i]
|
||||
else:
|
||||
sysFatal(RangeError, "different lengths for slice assignment")
|
||||
|
||||
@@ -3565,18 +3565,20 @@ proc `[]=`*[T, U, V](s: var seq[T], x: HSlice[U, V], b: openArray[T]) =
|
||||
else:
|
||||
spliceImpl(s, a, L, b)
|
||||
|
||||
proc `[]`*[T](s: openArray[T]; i: BackwardsIndex): T {.inline.} = s[s.len - int(i)]
|
||||
proc `[]`*[T](s: openArray[T]; i: BackwardsIndex): T {.inline.} =
|
||||
system.`[]`(s, s.len - int(i))
|
||||
|
||||
proc `[]`*[Idx, T](a: array[Idx, T]; i: BackwardsIndex): T {.inline.} =
|
||||
a[Idx(a.len - int(i) + int low(a))]
|
||||
proc `[]`*(s: string; i: BackwardsIndex): char {.inline.} = s[s.len - int(i)]
|
||||
|
||||
proc `[]`*[T](s: var openArray[T]; i: BackwardsIndex): var T {.inline.} =
|
||||
s[s.len - int(i)]
|
||||
system.`[]`(s, s.len - int(i))
|
||||
proc `[]`*[Idx, T](a: var array[Idx, T]; i: BackwardsIndex): var T {.inline.} =
|
||||
a[Idx(a.len - int(i) + int low(a))]
|
||||
|
||||
proc `[]=`*[T](s: var openArray[T]; i: BackwardsIndex; x: T) {.inline.} =
|
||||
s[s.len - int(i)] = x
|
||||
system.`[]=`(s, s.len - int(i), x)
|
||||
proc `[]=`*[Idx, T](a: var array[Idx, T]; i: BackwardsIndex; x: T) {.inline.} =
|
||||
a[Idx(a.len - int(i) + int low(a))] = x
|
||||
proc `[]=`*(s: var string; i: BackwardsIndex; x: char) {.inline.} =
|
||||
|
||||
@@ -509,7 +509,7 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
|
||||
|
||||
# insert exponent
|
||||
t[ti] = 'E'; inc(ti)
|
||||
t[ti] = if exp_negative: '-' else: '+'; inc(ti)
|
||||
t[ti] = (if exp_negative: '-' else: '+'); inc(ti)
|
||||
inc(ti, 3)
|
||||
|
||||
# insert adjusted exponent
|
||||
|
||||
@@ -127,6 +127,7 @@ However, if you are short on time, you can just run the tests specific to your
|
||||
changes by only running the corresponding categories of tests. Travis CI verifies
|
||||
that all tests pass before allowing the pull request to be accepted, so only
|
||||
running specific tests should be harmless.
|
||||
Integration tests should go in ``tests/untestable``.
|
||||
|
||||
If you're looking for ways to contribute, please look at our [issue tracker][nim-issues].
|
||||
There are always plenty of issues labelled [``Easy``][nim-issues-easy]; these should
|
||||
|
||||
@@ -4,7 +4,8 @@ discard """
|
||||
3
|
||||
@[(Field0: 1, Field1: 2), (Field0: 3, Field1: 5)]
|
||||
2
|
||||
@[a, new one, c]'''
|
||||
@[a, new one, c]
|
||||
@[1, 2, 3]'''
|
||||
"""
|
||||
|
||||
proc foo[T](x, y: T): T = x
|
||||
@@ -35,3 +36,8 @@ useOpenarray([1, 2, 3])
|
||||
var z = @["a", "b", "c"]
|
||||
mutOpenarray(z)
|
||||
echo z
|
||||
|
||||
# bug #6675
|
||||
var y: array[1..5, int] = [1,2,3,4,5]
|
||||
y[3..5] = [1, 2, 3]
|
||||
echo y[3..5]
|
||||
|
||||
46
tests/array/troofregression.nim
Normal file
46
tests/array/troofregression.nim
Normal file
@@ -0,0 +1,46 @@
|
||||
###############################
|
||||
#### part from Arraymancer
|
||||
|
||||
type
|
||||
MetadataArray* = object
|
||||
data*: array[8, int]
|
||||
len*: int
|
||||
|
||||
# Commenting the converter removes the error "lib/system.nim(3536, 3) Error: for a 'var' type a variable needs to be passed"
|
||||
converter toMetadataArray*(se: varargs[int]): MetadataArray {.inline.} =
|
||||
result.len = se.len
|
||||
for i in 0..<se.len:
|
||||
result.data[i] = se[i]
|
||||
|
||||
|
||||
when NimVersion >= "0.17.3":
|
||||
type Index = int or BackwardsIndex
|
||||
template `^^`(s, i: untyped): untyped =
|
||||
when i is BackwardsIndex:
|
||||
s.len - int(i)
|
||||
else: i
|
||||
else:
|
||||
type Index = int
|
||||
template `^^`(s, i: untyped): untyped =
|
||||
i
|
||||
|
||||
## With Nim devel from the start of the week (~Oct30) I managed to trigger "lib/system.nim(3536, 4) Error: expression has no address"
|
||||
## but I can't anymore after updating Nim (Nov5)
|
||||
## Now commenting this plain compiles and removes the error "lib/system.nim(3536, 3) Error: for a 'var' type a variable needs to be passed"
|
||||
proc `[]`*(a: var MetadataArray, idx: Index): var int {.inline.} =
|
||||
a.data[a ^^ idx]
|
||||
|
||||
|
||||
##############################
|
||||
### Completely unrelated lib that triggers the issue
|
||||
|
||||
type
|
||||
MySeq[T] = ref object
|
||||
data: seq[T]
|
||||
|
||||
proc test[T](sx: MySeq[T]) =
|
||||
# Removing the backward index removes the error "lib/system.nim(3536, 3) Error: for a 'var' type a variable needs to be passed"
|
||||
echo sx.data[^1] # error here
|
||||
|
||||
let s = MySeq[int](data: @[1, 2, 3])
|
||||
s.test()
|
||||
@@ -4,6 +4,7 @@ discard """
|
||||
OK AF_INET
|
||||
OK AF_INET6
|
||||
'''
|
||||
disabled: "travis"
|
||||
"""
|
||||
|
||||
import
|
||||
|
||||
12
tests/closure/tinvalidclosure3.nim
Normal file
12
tests/closure/tinvalidclosure3.nim
Normal file
@@ -0,0 +1,12 @@
|
||||
discard """
|
||||
line: 9
|
||||
errormsg: "illegal capture 'x'"
|
||||
"""
|
||||
|
||||
proc outer(arg: string) =
|
||||
var x = 0
|
||||
proc inner {.inline.} =
|
||||
echo "inner", x
|
||||
inner()
|
||||
|
||||
outer("abc")
|
||||
13
tests/concepts/tinfrecursion.nim
Normal file
13
tests/concepts/tinfrecursion.nim
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
# bug #6691
|
||||
type
|
||||
ConceptA = concept c
|
||||
|
||||
ConceptB = concept c
|
||||
c.myProc(ConceptA)
|
||||
|
||||
Obj = object
|
||||
|
||||
proc myProc(obj: Obj, x: ConceptA) = discard
|
||||
|
||||
echo Obj is ConceptB
|
||||
44
tests/js/tarrayboundscheck.nim
Executable file
44
tests/js/tarrayboundscheck.nim
Executable file
@@ -0,0 +1,44 @@
|
||||
discard """
|
||||
output: '''idx out of bounds: -1
|
||||
month out of bounds: 0
|
||||
Jan
|
||||
Feb
|
||||
Mar
|
||||
Apr
|
||||
May
|
||||
Jun
|
||||
Jul
|
||||
Aug
|
||||
Sep
|
||||
Oct
|
||||
Nov
|
||||
Dec
|
||||
month out of bounds: 13
|
||||
idx out of bounds: 14
|
||||
'''
|
||||
"""
|
||||
|
||||
{.push boundChecks:on.}
|
||||
|
||||
# see issue #6532:
|
||||
# js backend 0.17.3: array bounds check for non zero based arrays is buggy
|
||||
|
||||
proc test_arrayboundscheck() =
|
||||
var months: array[1..12, string] =
|
||||
["Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
|
||||
|
||||
var indices = [0,1,2,3,4,5,6,7,8,9,10,11,12,13]
|
||||
|
||||
for i in -1 .. 14:
|
||||
try:
|
||||
let idx = indices[i]
|
||||
try:
|
||||
echo months[idx]
|
||||
except:
|
||||
echo "month out of bounds: ", idx
|
||||
except:
|
||||
echo "idx out of bounds: ", i
|
||||
|
||||
test_arrayboundscheck()
|
||||
{.pop.}
|
||||
@@ -1,6 +1,6 @@
|
||||
discard """
|
||||
line: 24
|
||||
errormsg: "expression expected, but found 'keyword else'"
|
||||
errormsg: "invalid indentation"
|
||||
"""
|
||||
|
||||
import macros
|
||||
@@ -11,7 +11,7 @@ var x = if 4 != 5:
|
||||
else:
|
||||
"no"
|
||||
|
||||
macro mymacro(n): untyped {.immediate.} =
|
||||
macro mymacro(n, b): untyped =
|
||||
discard
|
||||
|
||||
mymacro:
|
||||
|
||||
@@ -32,3 +32,21 @@ let other = x:
|
||||
echo "no"
|
||||
let outer = y(5):
|
||||
echo "yes"
|
||||
|
||||
|
||||
# bug #6609
|
||||
type
|
||||
TextureInternalFormat = enum RED, RGB, RGBA
|
||||
|
||||
const channels = 4
|
||||
|
||||
let format =
|
||||
if channels == 1:
|
||||
TextureInternalFormat.RED
|
||||
elif channels == 3:
|
||||
TextureInternalFormat.RGB
|
||||
elif channels == 4:
|
||||
TextureInternalFormat.RGBA
|
||||
else:
|
||||
echo "Texture Format Unknown, assuming RGB" #This echo causes an error
|
||||
TextureInternalFormat.RGB
|
||||
|
||||
@@ -2,6 +2,7 @@ discard """
|
||||
cmd: "nim c --threads:on -d:ssl $file"
|
||||
exitcode: 0
|
||||
output: "OK"
|
||||
disabled: "travis"
|
||||
"""
|
||||
|
||||
import strutils
|
||||
|
||||
@@ -2,6 +2,7 @@ discard """
|
||||
cmd: "nim c --threads:on $file"
|
||||
exitcode: 0
|
||||
output: "OK"
|
||||
disabled: "travis"
|
||||
"""
|
||||
|
||||
import os, net, nativesockets, asyncdispatch
|
||||
|
||||
@@ -418,8 +418,9 @@ proc `&?.`(a, b: string): string =
|
||||
|
||||
proc processSingleTest(r: var TResults, cat: Category, options, test: string) =
|
||||
let test = "tests" & DirSep &.? cat.string / test
|
||||
let target = if cat.string.normalize == "js": targetJS else: targetC
|
||||
|
||||
if existsFile(test): testSpec r, makeTest(test, options, cat)
|
||||
if existsFile(test): testSpec r, makeTest(test, options, cat, target = target)
|
||||
else: echo "[Warning] - ", test, " test does not exist"
|
||||
|
||||
proc processCategory(r: var TResults, cat: Category, options: string) =
|
||||
|
||||
@@ -12,6 +12,8 @@ import parseutils, strutils, os, osproc, streams, parsecfg
|
||||
|
||||
var compilerPrefix* = "compiler" / "nim "
|
||||
|
||||
let isTravis = existsEnv("TRAVIS")
|
||||
|
||||
proc cmdTemplate*(): string =
|
||||
compilerPrefix & "$target --lib:lib --hints:on -d:testing $options $file"
|
||||
|
||||
@@ -174,6 +176,8 @@ proc parseSpec*(filename: string): TSpec =
|
||||
when defined(unix): result.err = reIgnored
|
||||
of "posix":
|
||||
when defined(posix): result.err = reIgnored
|
||||
of "travis":
|
||||
if isTravis: result.err = reIgnored
|
||||
else:
|
||||
raise newException(ValueError, "cannot interpret as a bool: " & e.value)
|
||||
of "cmd":
|
||||
|
||||
@@ -439,6 +439,8 @@ proc main() =
|
||||
var optPrintResults = false
|
||||
var optFailing = false
|
||||
|
||||
var targetsStr = ""
|
||||
|
||||
var p = initOptParser()
|
||||
p.next()
|
||||
while p.kind == cmdLongoption:
|
||||
@@ -446,7 +448,9 @@ proc main() =
|
||||
of "print", "verbose": optPrintResults = true
|
||||
of "failing": optFailing = true
|
||||
of "pedantic": discard "now always enabled"
|
||||
of "targets": targets = parseTargets(p.val.string)
|
||||
of "targets":
|
||||
targetsStr = p.val.string
|
||||
targets = parseTargets(targetsStr)
|
||||
of "nim": compilerPrefix = p.val.string
|
||||
else: quit Usage
|
||||
p.next()
|
||||
@@ -457,7 +461,9 @@ proc main() =
|
||||
case action
|
||||
of "all":
|
||||
let testsDir = "tests" & DirSep
|
||||
let myself = quoteShell(findExe("tests" / "testament" / "tester"))
|
||||
var myself = quoteShell(findExe("tests" / "testament" / "tester"))
|
||||
if targetsStr.len > 0:
|
||||
myself &= " '--targets:" & targetsStr & "'"
|
||||
var cmds: seq[string] = @[]
|
||||
let rest = if p.cmdLineRest.string.len > 0: " " & p.cmdLineRest.string else: ""
|
||||
for kind, dir in walkDir(testsDir):
|
||||
|
||||
@@ -1,2 +1,9 @@
|
||||
This directory contains tests which are not automatically executed
|
||||
for various reasons. Mainly due to dependencies on external services.
|
||||
This directory contains integration tests which are not automatically executed
|
||||
for various reasons:
|
||||
- dependency on external services
|
||||
- dependency on files / configuration / state of the local host
|
||||
- tests that are extremely slow or require large amounts of memory or storage
|
||||
- tests that spawn local daemons
|
||||
|
||||
Integration tests can become stale very quickly. Automated ./koch tests are
|
||||
strongly recommended.
|
||||
|
||||
Reference in New Issue
Block a user