Merge branch 'devel' into araq-devel
This commit is contained in:
commit
e455023902
18 changed files with 175 additions and 64 deletions
|
|
@ -1587,20 +1587,24 @@ proc genInOp(p: BProc, e: PNode, d: var TLoc) =
|
||||||
e.sons[2]
|
e.sons[2]
|
||||||
initLocExpr(p, ea, a)
|
initLocExpr(p, ea, a)
|
||||||
initLoc(b, locExpr, e, OnUnknown)
|
initLoc(b, locExpr, e, OnUnknown)
|
||||||
b.r = rope("(")
|
|
||||||
var length = sonsLen(e.sons[1])
|
var length = sonsLen(e.sons[1])
|
||||||
for i in countup(0, length - 1):
|
if length > 0:
|
||||||
let it = e.sons[1].sons[i]
|
b.r = rope("(")
|
||||||
if it.kind == nkRange:
|
for i in countup(0, length - 1):
|
||||||
initLocExpr(p, it.sons[0], x)
|
let it = e.sons[1].sons[i]
|
||||||
initLocExpr(p, it.sons[1], y)
|
if it.kind == nkRange:
|
||||||
addf(b.r, "$1 >= $2 && $1 <= $3",
|
initLocExpr(p, it.sons[0], x)
|
||||||
[rdCharLoc(a), rdCharLoc(x), rdCharLoc(y)])
|
initLocExpr(p, it.sons[1], y)
|
||||||
else:
|
addf(b.r, "$1 >= $2 && $1 <= $3",
|
||||||
initLocExpr(p, it, x)
|
[rdCharLoc(a), rdCharLoc(x), rdCharLoc(y)])
|
||||||
addf(b.r, "$1 == $2", [rdCharLoc(a), rdCharLoc(x)])
|
else:
|
||||||
if i < length - 1: add(b.r, " || ")
|
initLocExpr(p, it, x)
|
||||||
add(b.r, ")")
|
addf(b.r, "$1 == $2", [rdCharLoc(a), rdCharLoc(x)])
|
||||||
|
if i < length - 1: add(b.r, " || ")
|
||||||
|
add(b.r, ")")
|
||||||
|
else:
|
||||||
|
# handle the case of an empty set
|
||||||
|
b.r = rope("0")
|
||||||
putIntoDest(p, d, e, b.r)
|
putIntoDest(p, d, e, b.r)
|
||||||
else:
|
else:
|
||||||
assert(e.sons[1].typ != nil)
|
assert(e.sons[1].typ != nil)
|
||||||
|
|
|
||||||
|
|
@ -344,7 +344,8 @@ proc getNumber(L: var TLexer, result: var TToken) =
|
||||||
if buf[pos] == '_':
|
if buf[pos] == '_':
|
||||||
if buf[pos+1] notin chars:
|
if buf[pos+1] notin chars:
|
||||||
lexMessage(L, errGenerated,
|
lexMessage(L, errGenerated,
|
||||||
"only single underscores may occur in a token: '__' is invalid")
|
"only single underscores may occur in a token and token may not " &
|
||||||
|
"end with an underscore: e.g. '1__1' and '1_' are invalid")
|
||||||
break
|
break
|
||||||
add(tok.literal, '_')
|
add(tok.literal, '_')
|
||||||
inc(pos)
|
inc(pos)
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ template semIdeForTemplateOrGeneric(c: PContext; n: PNode;
|
||||||
proc fitNodePostMatch(c: PContext, formal: PType, arg: PNode): PNode =
|
proc fitNodePostMatch(c: PContext, formal: PType, arg: PNode): PNode =
|
||||||
result = arg
|
result = arg
|
||||||
let x = result.skipConv
|
let x = result.skipConv
|
||||||
if x.kind in {nkPar, nkTupleConstr} and formal.kind != tyExpr:
|
if x.kind in {nkPar, nkTupleConstr, nkCurly} and formal.kind != tyExpr:
|
||||||
changeType(c, x, formal, check=true)
|
changeType(c, x, formal, check=true)
|
||||||
else:
|
else:
|
||||||
result = skipHiddenSubConv(result)
|
result = skipHiddenSubConv(result)
|
||||||
|
|
|
||||||
|
|
@ -393,6 +393,8 @@ proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
# When the right-hand side is an explicit type, we must
|
# When the right-hand side is an explicit type, we must
|
||||||
# not allow regular values to be matched against the type:
|
# not allow regular values to be matched against the type:
|
||||||
liftLhs = false
|
liftLhs = false
|
||||||
|
else:
|
||||||
|
n.sons[2] = semExpr(c, n[2])
|
||||||
|
|
||||||
var lhsType = n[1].typ
|
var lhsType = n[1].typ
|
||||||
if lhsType.kind != tyTypeDesc:
|
if lhsType.kind != tyTypeDesc:
|
||||||
|
|
@ -906,19 +908,6 @@ proc buildEchoStmt(c: PContext, n: PNode): PNode =
|
||||||
|
|
||||||
proc semExprNoType(c: PContext, n: PNode): PNode =
|
proc semExprNoType(c: PContext, n: PNode): PNode =
|
||||||
result = semExpr(c, n, {efWantStmt})
|
result = semExpr(c, n, {efWantStmt})
|
||||||
# make an 'if' expression an 'if' statement again for backwards
|
|
||||||
# compatibility (.discardable was a bad idea!); bug #6980
|
|
||||||
var isStmt = false
|
|
||||||
if result.kind == nkIfExpr:
|
|
||||||
isStmt = true
|
|
||||||
for condActionPair in result:
|
|
||||||
let action = condActionPair.lastSon
|
|
||||||
if not implicitlyDiscardable(action) and not
|
|
||||||
endsInNoReturn(action):
|
|
||||||
isStmt = false
|
|
||||||
if isStmt:
|
|
||||||
result.kind = nkIfStmt
|
|
||||||
result.typ = nil
|
|
||||||
discardCheck(c, result)
|
discardCheck(c, result)
|
||||||
|
|
||||||
proc isTypeExpr(n: PNode): bool =
|
proc isTypeExpr(n: PNode): bool =
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,8 @@ template macroToExpand(s): untyped =
|
||||||
s.kind in {skMacro, skTemplate} and (s.typ.len == 1 or sfAllUntyped in s.flags)
|
s.kind in {skMacro, skTemplate} and (s.typ.len == 1 or sfAllUntyped in s.flags)
|
||||||
|
|
||||||
template macroToExpandSym(s): untyped =
|
template macroToExpandSym(s): untyped =
|
||||||
s.kind in {skMacro, skTemplate} and (s.typ.len == 1) and not fromDotExpr
|
sfCustomPragma notin s.flags and s.kind in {skMacro, skTemplate} and
|
||||||
|
(s.typ.len == 1) and not fromDotExpr
|
||||||
|
|
||||||
template isMixedIn(sym): bool =
|
template isMixedIn(sym): bool =
|
||||||
let s = sym
|
let s = sym
|
||||||
|
|
|
||||||
|
|
@ -111,13 +111,15 @@ proc semExprBranchScope(c: PContext, n: PNode): PNode =
|
||||||
const
|
const
|
||||||
skipForDiscardable = {nkIfStmt, nkIfExpr, nkCaseStmt, nkOfBranch,
|
skipForDiscardable = {nkIfStmt, nkIfExpr, nkCaseStmt, nkOfBranch,
|
||||||
nkElse, nkStmtListExpr, nkTryStmt, nkFinally, nkExceptBranch,
|
nkElse, nkStmtListExpr, nkTryStmt, nkFinally, nkExceptBranch,
|
||||||
nkElifBranch, nkElifExpr, nkElseExpr, nkBlockStmt, nkBlockExpr}
|
nkElifBranch, nkElifExpr, nkElseExpr, nkBlockStmt, nkBlockExpr,
|
||||||
|
nkHiddenStdConv}
|
||||||
|
|
||||||
proc implicitlyDiscardable(n: PNode): bool =
|
proc implicitlyDiscardable(n: PNode): bool =
|
||||||
var n = n
|
var n = n
|
||||||
while n.kind in skipForDiscardable: n = n.lastSon
|
while n.kind in skipForDiscardable: n = n.lastSon
|
||||||
result = isCallExpr(n) and n.sons[0].kind == nkSym and
|
result = n.kind == nkRaiseStmt or
|
||||||
sfDiscardable in n.sons[0].sym.flags
|
(isCallExpr(n) and n.sons[0].kind == nkSym and
|
||||||
|
sfDiscardable in n.sons[0].sym.flags)
|
||||||
|
|
||||||
proc fixNilType(c: PContext; n: PNode) =
|
proc fixNilType(c: PContext; n: PNode) =
|
||||||
if isAtom(n):
|
if isAtom(n):
|
||||||
|
|
@ -132,11 +134,8 @@ proc discardCheck(c: PContext, result: PNode) =
|
||||||
if c.matchedConcept != nil: return
|
if c.matchedConcept != nil: return
|
||||||
if result.typ != nil and result.typ.kind notin {tyStmt, tyVoid}:
|
if result.typ != nil and result.typ.kind notin {tyStmt, tyVoid}:
|
||||||
if implicitlyDiscardable(result):
|
if implicitlyDiscardable(result):
|
||||||
var n = result
|
var n = newNodeI(nkDiscardStmt, result.info, 1)
|
||||||
result.typ = nil
|
n[0] = result
|
||||||
while n.kind in skipForDiscardable:
|
|
||||||
n = n.lastSon
|
|
||||||
n.typ = nil
|
|
||||||
elif result.typ.kind != tyError and c.config.cmd != cmdInteractive:
|
elif result.typ.kind != tyError and c.config.cmd != cmdInteractive:
|
||||||
var n = result
|
var n = result
|
||||||
while n.kind in skipForDiscardable: n = n.lastSon
|
while n.kind in skipForDiscardable: n = n.lastSon
|
||||||
|
|
|
||||||
|
|
@ -623,7 +623,7 @@ proc firstOrd*(conf: ConfigRef; t: PType): BiggestInt =
|
||||||
assert(t.n.sons[0].kind == nkSym)
|
assert(t.n.sons[0].kind == nkSym)
|
||||||
result = t.n.sons[0].sym.position
|
result = t.n.sons[0].sym.position
|
||||||
of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink,
|
of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink,
|
||||||
tyStatic, tyInferred, tyUserTypeClassInst:
|
tyStatic, tyInferred, tyUserTypeClasses:
|
||||||
result = firstOrd(conf, lastSon(t))
|
result = firstOrd(conf, lastSon(t))
|
||||||
of tyOrdinal:
|
of tyOrdinal:
|
||||||
if t.len > 0: result = firstOrd(conf, lastSon(t))
|
if t.len > 0: result = firstOrd(conf, lastSon(t))
|
||||||
|
|
@ -642,7 +642,7 @@ proc firstFloat*(t: PType): BiggestFloat =
|
||||||
getFloatValue(t.n.sons[0])
|
getFloatValue(t.n.sons[0])
|
||||||
of tyVar: firstFloat(t.sons[0])
|
of tyVar: firstFloat(t.sons[0])
|
||||||
of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink,
|
of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink,
|
||||||
tyStatic, tyInferred:
|
tyStatic, tyInferred, tyUserTypeClasses:
|
||||||
firstFloat(lastSon(t))
|
firstFloat(lastSon(t))
|
||||||
else:
|
else:
|
||||||
internalError(newPartialConfigRef(), "invalid kind for firstFloat(" & $t.kind & ')')
|
internalError(newPartialConfigRef(), "invalid kind for firstFloat(" & $t.kind & ')')
|
||||||
|
|
@ -679,7 +679,7 @@ proc lastOrd*(conf: ConfigRef; t: PType; fixedUnsigned = false): BiggestInt =
|
||||||
assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym)
|
assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym)
|
||||||
result = t.n.sons[sonsLen(t.n) - 1].sym.position
|
result = t.n.sons[sonsLen(t.n) - 1].sym.position
|
||||||
of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink,
|
of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink,
|
||||||
tyStatic, tyInferred:
|
tyStatic, tyInferred, tyUserTypeClasses:
|
||||||
result = lastOrd(conf, lastSon(t))
|
result = lastOrd(conf, lastSon(t))
|
||||||
of tyProxy: result = 0
|
of tyProxy: result = 0
|
||||||
of tyOrdinal:
|
of tyOrdinal:
|
||||||
|
|
@ -699,7 +699,7 @@ proc lastFloat*(t: PType): BiggestFloat =
|
||||||
assert(t.n.kind == nkRange)
|
assert(t.n.kind == nkRange)
|
||||||
getFloatValue(t.n.sons[1])
|
getFloatValue(t.n.sons[1])
|
||||||
of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink,
|
of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink,
|
||||||
tyStatic, tyInferred:
|
tyStatic, tyInferred, tyUserTypeClasses:
|
||||||
lastFloat(lastSon(t))
|
lastFloat(lastSon(t))
|
||||||
else:
|
else:
|
||||||
internalError(newPartialConfigRef(), "invalid kind for lastFloat(" & $t.kind & ')')
|
internalError(newPartialConfigRef(), "invalid kind for lastFloat(" & $t.kind & ')')
|
||||||
|
|
@ -707,7 +707,7 @@ proc lastFloat*(t: PType): BiggestFloat =
|
||||||
|
|
||||||
|
|
||||||
proc lengthOrd*(conf: ConfigRef; t: PType): BiggestInt =
|
proc lengthOrd*(conf: ConfigRef; t: PType): BiggestInt =
|
||||||
case t.kind
|
case t.skipTypes(tyUserTypeClasses).kind
|
||||||
of tyInt64, tyInt32, tyInt: result = lastOrd(conf, t)
|
of tyInt64, tyInt32, tyInt: result = lastOrd(conf, t)
|
||||||
of tyDistinct: result = lengthOrd(conf, t.sons[0])
|
of tyDistinct: result = lengthOrd(conf, t.sons[0])
|
||||||
else:
|
else:
|
||||||
|
|
@ -717,7 +717,7 @@ proc lengthOrd*(conf: ConfigRef; t: PType): BiggestInt =
|
||||||
if last == high(BiggestInt) and first <= 0:
|
if last == high(BiggestInt) and first <= 0:
|
||||||
result = last
|
result = last
|
||||||
else:
|
else:
|
||||||
result = lastOrd(conf, t) - firstOrd(conf, t) + 1
|
result = last - first + 1
|
||||||
|
|
||||||
# -------------- type equality -----------------------------------------------
|
# -------------- type equality -----------------------------------------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -209,7 +209,7 @@ proc writeField(n: var PNode, x: TFullReg) =
|
||||||
of rkNone: discard
|
of rkNone: discard
|
||||||
of rkInt: n.intVal = x.intVal
|
of rkInt: n.intVal = x.intVal
|
||||||
of rkFloat: n.floatVal = x.floatVal
|
of rkFloat: n.floatVal = x.floatVal
|
||||||
of rkNode: n = x.node
|
of rkNode: n = copyValue(x.node)
|
||||||
of rkRegisterAddr: writeField(n, x.regAddr[])
|
of rkRegisterAddr: writeField(n, x.regAddr[])
|
||||||
of rkNodeAddr: n = x.nodeAddr[]
|
of rkNodeAddr: n = x.nodeAddr[]
|
||||||
|
|
||||||
|
|
@ -622,6 +622,13 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
stackTrace(c, tos, pc, errNilAccess)
|
stackTrace(c, tos, pc, errNilAccess)
|
||||||
regs[ra].nodeAddr[][] = n[]
|
regs[ra].nodeAddr[][] = n[]
|
||||||
regs[ra].nodeAddr[].flags.incl nfIsRef
|
regs[ra].nodeAddr[].flags.incl nfIsRef
|
||||||
|
# `var object` parameters are sent as rkNodeAddr. When they are mutated
|
||||||
|
# vmgen generates opcWrDeref, which means that we must dereference
|
||||||
|
# twice.
|
||||||
|
# TODO: This should likely be handled differently in vmgen.
|
||||||
|
elif (nfIsRef notin regs[ra].nodeAddr[].flags and
|
||||||
|
nfIsRef notin n.flags):
|
||||||
|
regs[ra].nodeAddr[][] = n[]
|
||||||
else:
|
else:
|
||||||
regs[ra].nodeAddr[] = n
|
regs[ra].nodeAddr[] = n
|
||||||
of rkRegisterAddr: regs[ra].regAddr[] = regs[rc]
|
of rkRegisterAddr: regs[ra].regAddr[] = regs[rc]
|
||||||
|
|
@ -912,6 +919,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
if a.kind == nkSym:
|
if a.kind == nkSym:
|
||||||
regs[ra].node = if a.sym.ast.isNil: newNode(nkNilLit)
|
regs[ra].node = if a.sym.ast.isNil: newNode(nkNilLit)
|
||||||
else: copyTree(a.sym.ast)
|
else: copyTree(a.sym.ast)
|
||||||
|
regs[ra].node.flags.incl nfIsRef
|
||||||
else:
|
else:
|
||||||
stackTrace(c, tos, pc, "node is not a symbol")
|
stackTrace(c, tos, pc, "node is not a symbol")
|
||||||
of opcEcho:
|
of opcEcho:
|
||||||
|
|
@ -1210,8 +1218,14 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
of opcIsNil:
|
of opcIsNil:
|
||||||
decodeB(rkInt)
|
decodeB(rkInt)
|
||||||
let node = regs[rb].node
|
let node = regs[rb].node
|
||||||
regs[ra].intVal = ord(node.kind == nkNilLit or
|
regs[ra].intVal = ord(
|
||||||
(node.kind in {nkStrLit..nkTripleStrLit} and node.strVal.isNil))
|
# Note that `nfIsRef` + `nkNilLit` represents an allocated
|
||||||
|
# reference with the value `nil`, so `isNil` should be false!
|
||||||
|
(node.kind == nkNilLit and nfIsRef notin node.flags) or
|
||||||
|
(node.kind in {nkStrLit..nkTripleStrLit} and node.strVal.isNil) or
|
||||||
|
(not node.typ.isNil and node.typ.kind == tyProc and
|
||||||
|
node.typ.callConv == ccClosure and node.sons[0].kind == nkNilLit and
|
||||||
|
node.sons[1].kind == nkNilLit))
|
||||||
of opcNBindSym:
|
of opcNBindSym:
|
||||||
decodeBx(rkNode)
|
decodeBx(rkNode)
|
||||||
regs[ra].node = copyTree(c.constants.sons[rbx])
|
regs[ra].node = copyTree(c.constants.sons[rbx])
|
||||||
|
|
@ -1462,6 +1476,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
else:
|
else:
|
||||||
regs[ra].node = newNodeI(nkIdent, c.debug[pc])
|
regs[ra].node = newNodeI(nkIdent, c.debug[pc])
|
||||||
regs[ra].node.ident = getIdent(c.cache, regs[rb].node.strVal)
|
regs[ra].node.ident = getIdent(c.cache, regs[rb].node.strVal)
|
||||||
|
regs[ra].node.flags.incl nfIsRef
|
||||||
of opcSetType:
|
of opcSetType:
|
||||||
if regs[ra].kind != rkNode:
|
if regs[ra].kind != rkNode:
|
||||||
internalError(c.config, c.debug[pc], "cannot set type")
|
internalError(c.config, c.debug[pc], "cannot set type")
|
||||||
|
|
|
||||||
|
|
@ -654,17 +654,17 @@ template replaceImpl(str: string, pattern: Regex,
|
||||||
|
|
||||||
proc replace*(str: string, pattern: Regex,
|
proc replace*(str: string, pattern: Regex,
|
||||||
subproc: proc (match: RegexMatch): string): string =
|
subproc: proc (match: RegexMatch): string): string =
|
||||||
## Replaces each match of Regex in the string with ``sub``, which should
|
## Replaces each match of Regex in the string with ``subproc``, which should
|
||||||
## never be or return ``nil``.
|
## never be or return ``nil``.
|
||||||
##
|
##
|
||||||
## If ``sub`` is a ``proc (RegexMatch): string``, then it is executed with
|
## If ``subproc`` is a ``proc (RegexMatch): string``, then it is executed with
|
||||||
## each match and the return value is the replacement value.
|
## each match and the return value is the replacement value.
|
||||||
##
|
##
|
||||||
## If ``sub`` is a ``proc (string): string``, then it is executed with the
|
## If ``subproc`` is a ``proc (string): string``, then it is executed with the
|
||||||
## full text of the match and and the return value is the replacement
|
## full text of the match and and the return value is the replacement
|
||||||
## value.
|
## value.
|
||||||
##
|
##
|
||||||
## If ``sub`` is a string, the syntax is as follows:
|
## If ``subproc`` is a string, the syntax is as follows:
|
||||||
##
|
##
|
||||||
## - ``$$`` - literal ``$``
|
## - ``$$`` - literal ``$``
|
||||||
## - ``$123`` - capture number ``123``
|
## - ``$123`` - capture number ``123``
|
||||||
|
|
|
||||||
|
|
@ -884,11 +884,9 @@ elif not defined(useNimRtl):
|
||||||
chck posix_spawn_file_actions_adddup2(fops, data.pStdin[readIdx], readIdx)
|
chck posix_spawn_file_actions_adddup2(fops, data.pStdin[readIdx], readIdx)
|
||||||
chck posix_spawn_file_actions_addclose(fops, data.pStdout[readIdx])
|
chck posix_spawn_file_actions_addclose(fops, data.pStdout[readIdx])
|
||||||
chck posix_spawn_file_actions_adddup2(fops, data.pStdout[writeIdx], writeIdx)
|
chck posix_spawn_file_actions_adddup2(fops, data.pStdout[writeIdx], writeIdx)
|
||||||
chck posix_spawn_file_actions_addclose(fops, data.pStderr[readIdx])
|
|
||||||
if (poStdErrToStdOut in data.options):
|
if (poStdErrToStdOut in data.options):
|
||||||
|
chck posix_spawn_file_actions_addclose(fops, data.pStderr[readIdx])
|
||||||
chck posix_spawn_file_actions_adddup2(fops, data.pStdout[writeIdx], 2)
|
chck posix_spawn_file_actions_adddup2(fops, data.pStdout[writeIdx], 2)
|
||||||
else:
|
|
||||||
chck posix_spawn_file_actions_adddup2(fops, data.pStderr[writeIdx], 2)
|
|
||||||
|
|
||||||
var res: cint
|
var res: cint
|
||||||
if data.workingDir.len > 0:
|
if data.workingDir.len > 0:
|
||||||
|
|
|
||||||
|
|
@ -258,7 +258,9 @@ template callFormat(res, arg) {.dirty.} =
|
||||||
# workaround in order to circumvent 'strutils.format' which matches
|
# workaround in order to circumvent 'strutils.format' which matches
|
||||||
# too but doesn't adhere to our protocol.
|
# too but doesn't adhere to our protocol.
|
||||||
res.add arg
|
res.add arg
|
||||||
elif compiles(format(arg, res)):
|
elif compiles(format(arg, res)) and
|
||||||
|
# Check if format returns void
|
||||||
|
not (compiles do: discard format(arg, res)):
|
||||||
format(arg, res)
|
format(arg, res)
|
||||||
elif compiles(format(arg)):
|
elif compiles(format(arg)):
|
||||||
res.add format(arg)
|
res.add format(arg)
|
||||||
|
|
@ -684,6 +686,9 @@ when isMainModule:
|
||||||
var nullTime: DateTime
|
var nullTime: DateTime
|
||||||
check &"{nullTime:yyyy-mm-dd}", "0000-00-00"
|
check &"{nullTime:yyyy-mm-dd}", "0000-00-00"
|
||||||
|
|
||||||
|
var tm = fromUnix(0)
|
||||||
|
discard &"{tm}"
|
||||||
|
|
||||||
# Unicode string tests
|
# Unicode string tests
|
||||||
check &"""{"αβγ"}""", "αβγ"
|
check &"""{"αβγ"}""", "αβγ"
|
||||||
check &"""{"αβγ":>5}""", " αβγ"
|
check &"""{"αβγ":>5}""", " αβγ"
|
||||||
|
|
|
||||||
|
|
@ -489,18 +489,16 @@ proc toParts*(dur: Duration): DurationParts =
|
||||||
|
|
||||||
result[unit] = quantity
|
result[unit] = quantity
|
||||||
|
|
||||||
proc stringifyUnit*(value: int | int64, unit: string): string =
|
proc stringifyUnit(value: int | int64, unit: TimeUnit): string =
|
||||||
## Stringify time unit with it's name, lowercased
|
## Stringify time unit with it's name, lowercased
|
||||||
runnableExamples:
|
let strUnit = $unit
|
||||||
doAssert stringifyUnit(2, "Seconds") == "2 seconds"
|
|
||||||
doAssert stringifyUnit(1, "Years") == "1 year"
|
|
||||||
result = ""
|
result = ""
|
||||||
result.add($value)
|
result.add($value)
|
||||||
result.add(" ")
|
result.add(" ")
|
||||||
if abs(value) != 1:
|
if abs(value) != 1:
|
||||||
result.add(unit.toLowerAscii())
|
result.add(strUnit.toLowerAscii())
|
||||||
else:
|
else:
|
||||||
result.add(unit[0..^2].toLowerAscii())
|
result.add(strUnit[0..^2].toLowerAscii())
|
||||||
|
|
||||||
proc humanizeParts(parts: seq[string]): string =
|
proc humanizeParts(parts: seq[string]): string =
|
||||||
## Make date string parts human-readable
|
## Make date string parts human-readable
|
||||||
|
|
@ -530,7 +528,7 @@ proc `$`*(dur: Duration): string =
|
||||||
for unit in countdown(Weeks, Nanoseconds):
|
for unit in countdown(Weeks, Nanoseconds):
|
||||||
let quantity = numParts[unit]
|
let quantity = numParts[unit]
|
||||||
if quantity != 0.int64:
|
if quantity != 0.int64:
|
||||||
parts.add(stringifyUnit(quantity, $unit))
|
parts.add(stringifyUnit(quantity, unit))
|
||||||
|
|
||||||
result = humanizeParts(parts)
|
result = humanizeParts(parts)
|
||||||
|
|
||||||
|
|
@ -1024,7 +1022,7 @@ proc `$`*(ti: TimeInterval): string =
|
||||||
var tiParts = toParts(ti)
|
var tiParts = toParts(ti)
|
||||||
for unit in countdown(Years, Nanoseconds):
|
for unit in countdown(Years, Nanoseconds):
|
||||||
if tiParts[unit] != 0:
|
if tiParts[unit] != 0:
|
||||||
parts.add(stringifyUnit(tiParts[unit], $unit))
|
parts.add(stringifyUnit(tiParts[unit], unit))
|
||||||
|
|
||||||
result = humanizeParts(parts)
|
result = humanizeParts(parts)
|
||||||
|
|
||||||
|
|
|
||||||
12
tests/concepts/t7952.nim
Normal file
12
tests/concepts/t7952.nim
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
discard """
|
||||||
|
output: 5
|
||||||
|
"""
|
||||||
|
|
||||||
|
type
|
||||||
|
HasLen = concept iter
|
||||||
|
len(iter) is int
|
||||||
|
|
||||||
|
proc echoLen(x: HasLen) =
|
||||||
|
echo len(x)
|
||||||
|
|
||||||
|
echoLen([1, 2, 3, 4, 5])
|
||||||
|
|
@ -151,3 +151,13 @@ if true:
|
||||||
fooBool()
|
fooBool()
|
||||||
else:
|
else:
|
||||||
raise newException(ValueError, "argh")
|
raise newException(ValueError, "argh")
|
||||||
|
|
||||||
|
# bug #5374
|
||||||
|
|
||||||
|
proc test1(): int64 {.discardable.} = discard
|
||||||
|
proc test2(): int {.discardable.} = discard
|
||||||
|
|
||||||
|
if true:
|
||||||
|
test1()
|
||||||
|
else:
|
||||||
|
test2()
|
||||||
|
|
|
||||||
7
tests/iter/t8041.nim
Normal file
7
tests/iter/t8041.nim
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
iterator xy[T](a: T, b: set[T]): T =
|
||||||
|
if a in b:
|
||||||
|
yield a
|
||||||
|
|
||||||
|
for a in xy(1'i8, {}):
|
||||||
|
for b in xy(a, {}):
|
||||||
|
echo a
|
||||||
|
|
@ -137,4 +137,12 @@ block:
|
||||||
static:
|
static:
|
||||||
assert hasIntSerKey
|
assert hasIntSerKey
|
||||||
assert strSerKey == "string"
|
assert strSerKey == "string"
|
||||||
assert nestedItemDefVal == "Nimmers of the world, unite!"
|
assert nestedItemDefVal == "Nimmers of the world, unite!"
|
||||||
|
|
||||||
|
block:
|
||||||
|
template simpleAttr {.pragma.}
|
||||||
|
|
||||||
|
type Annotated {.simpleAttr.} = object
|
||||||
|
|
||||||
|
proc generic_proc[T]() =
|
||||||
|
assert Annotated.hasCustomPragma(simpleAttr)
|
||||||
6
tests/sets/t2669.nim
Normal file
6
tests/sets/t2669.nim
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
discard """
|
||||||
|
line: 6
|
||||||
|
errormsg: "cannot convert 6 to range 1..5(int8)"
|
||||||
|
"""
|
||||||
|
|
||||||
|
var c: set[range[1i8..5i8]] = {1i8, 2i8, 6i8}
|
||||||
|
|
@ -89,4 +89,62 @@ block:
|
||||||
proc f(size: int): int =
|
proc f(size: int): int =
|
||||||
var some = newStringOfCap(size)
|
var some = newStringOfCap(size)
|
||||||
result = size
|
result = size
|
||||||
doAssert f(4) == 4
|
doAssert f(4) == 4
|
||||||
|
|
||||||
|
# #6689
|
||||||
|
block:
|
||||||
|
static:
|
||||||
|
proc foo(): int = 0
|
||||||
|
var f: proc(): int
|
||||||
|
doAssert f.isNil
|
||||||
|
f = foo
|
||||||
|
doAssert(not f.isNil)
|
||||||
|
|
||||||
|
block:
|
||||||
|
static:
|
||||||
|
var x: ref ref int
|
||||||
|
new(x)
|
||||||
|
doAssert(not x.isNil)
|
||||||
|
|
||||||
|
# #7871
|
||||||
|
static:
|
||||||
|
type Obj = object
|
||||||
|
field: int
|
||||||
|
var s = newSeq[Obj](1)
|
||||||
|
var o = Obj()
|
||||||
|
s[0] = o
|
||||||
|
o.field = 2
|
||||||
|
doAssert s[0].field == 0
|
||||||
|
|
||||||
|
# #8125
|
||||||
|
static:
|
||||||
|
let def_iter_var = ident("it")
|
||||||
|
|
||||||
|
# #8142
|
||||||
|
static:
|
||||||
|
type Obj = object
|
||||||
|
names: string
|
||||||
|
|
||||||
|
proc pushName(o: var Obj) =
|
||||||
|
var s = ""
|
||||||
|
s.add("FOOBAR")
|
||||||
|
o.names.add(s)
|
||||||
|
|
||||||
|
var o = Obj()
|
||||||
|
o.names = ""
|
||||||
|
o.pushName()
|
||||||
|
o.pushName()
|
||||||
|
doAssert o.names == "FOOBARFOOBAR"
|
||||||
|
|
||||||
|
# #8154
|
||||||
|
import parseutils
|
||||||
|
|
||||||
|
static:
|
||||||
|
type Obj = object
|
||||||
|
i: int
|
||||||
|
|
||||||
|
proc foo(): Obj =
|
||||||
|
discard parseInt("1", result.i, 0)
|
||||||
|
|
||||||
|
static:
|
||||||
|
doAssert foo().i == 1
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue