Merge branch 'devel' of github.com:nim-lang/Nim into devel
This commit is contained in:
commit
c3d544221b
20 changed files with 222 additions and 165 deletions
|
|
@ -241,9 +241,6 @@ styledEcho "Red on Green.", resetStyle
|
||||||
and it no longer raises an OS error but returns an ``osInvalidSocket`` when
|
and it no longer raises an OS error but returns an ``osInvalidSocket`` when
|
||||||
creation fails.
|
creation fails.
|
||||||
- ``newNativeSocket`` is now named ``createNativeSocket``.
|
- ``newNativeSocket`` is now named ``createNativeSocket``.
|
||||||
- Type inference for generic type parameters involving numeric types is now symetric. See
|
|
||||||
[Generic type inference for numeric types](https://nim-lang.org/docs/manual.html#generics-generic-type-inference-fornumeric-types)
|
|
||||||
for more information.
|
|
||||||
- The ``deprecated`` pragma now supports a user-definable warning message for procs.
|
- The ``deprecated`` pragma now supports a user-definable warning message for procs.
|
||||||
|
|
||||||
```nim
|
```nim
|
||||||
|
|
|
||||||
|
|
@ -788,30 +788,13 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||||
# myDiv(4, 9);
|
# myDiv(4, 9);
|
||||||
# } catch (NimExceptionType1&) {
|
# } catch (NimExceptionType1&) {
|
||||||
# body
|
# body
|
||||||
# goto LA_END;
|
|
||||||
# } catch (NimExceptionType2&) {
|
# } catch (NimExceptionType2&) {
|
||||||
# finallyPart()
|
# finallyPart()
|
||||||
# raise;
|
# raise;
|
||||||
# goto LA_END;
|
# }
|
||||||
# } catch (NimExceptionType3&) {goto LA1;}
|
|
||||||
# } catch (NimExceptionType4&) {goto LA1;}
|
|
||||||
# } catch (NimExceptionType5&) {goto LA2;}
|
|
||||||
# } catch (NimExceptionType6&) {goto LA2;}
|
|
||||||
# catch(...) {
|
# catch(...) {
|
||||||
# // general handler
|
# general_handler_body
|
||||||
# goto LA_END;
|
|
||||||
# }
|
# }
|
||||||
# {LA1:
|
|
||||||
# labeled_branch_body_LA1
|
|
||||||
# goto LA_END;
|
|
||||||
# }
|
|
||||||
# {LA2:
|
|
||||||
# labeled_branch_body_LA2
|
|
||||||
# finallyPart()
|
|
||||||
# raise;
|
|
||||||
# goto LA_END;
|
|
||||||
# }
|
|
||||||
# LA_END:
|
|
||||||
# finallyPart();
|
# finallyPart();
|
||||||
|
|
||||||
template genExceptBranchBody(body: PNode) {.dirty.} =
|
template genExceptBranchBody(body: PNode) {.dirty.} =
|
||||||
|
|
@ -819,22 +802,19 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||||
linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR_);$n")
|
linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR_);$n")
|
||||||
expr(p, body, d)
|
expr(p, body, d)
|
||||||
linefmt(p, cpsStmts, "#popCurrentException();$n")
|
linefmt(p, cpsStmts, "#popCurrentException();$n")
|
||||||
linefmt(p, cpsStmts, "goto $1;$n", end_label)
|
|
||||||
|
|
||||||
|
|
||||||
if not isEmptyType(t.typ) and d.k == locNone:
|
if not isEmptyType(t.typ) and d.k == locNone:
|
||||||
getTemp(p, t.typ, d)
|
getTemp(p, t.typ, d)
|
||||||
genLineDir(p, t)
|
genLineDir(p, t)
|
||||||
|
|
||||||
|
let end_label = getLabel(p)
|
||||||
discard cgsym(p.module, "Exception")
|
discard cgsym(p.module, "Exception")
|
||||||
add(p.nestedTryStmts, t)
|
add(p.nestedTryStmts, t)
|
||||||
startBlock(p, "try {$n")
|
startBlock(p, "try {$n")
|
||||||
expr(p, t[0], d)
|
expr(p, t[0], d)
|
||||||
endBlock(p, ropecg(p.module, "}"))
|
endBlock(p)
|
||||||
|
|
||||||
let end_label = getLabel(p)
|
|
||||||
var catchAllPresent = false
|
var catchAllPresent = false
|
||||||
var labeled_branches: seq[tuple[label: Rope, body: PNode]] = @[] # generated after labels discovered
|
|
||||||
|
|
||||||
inc p.inExceptBlock
|
inc p.inExceptBlock
|
||||||
for i in 1..<t.len:
|
for i in 1..<t.len:
|
||||||
|
|
@ -849,20 +829,12 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||||
startBlock(p, "catch (...) {$n")
|
startBlock(p, "catch (...) {$n")
|
||||||
genExceptBranchBody(t[i][0])
|
genExceptBranchBody(t[i][0])
|
||||||
endBlock(p)
|
endBlock(p)
|
||||||
|
|
||||||
elif t[i].len == 2:
|
|
||||||
startBlock(p, "catch ($1*) {$n", getTypeDesc(p.module, t[i][0].typ))
|
|
||||||
genExceptBranchBody(t[i][^1])
|
|
||||||
endBlock(p)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# cpp can't catch multiple types in one statement so we need a label and goto
|
|
||||||
let label = getLabel(p)
|
|
||||||
labeled_branches.add((label, t[i][^1]))
|
|
||||||
for j in 0..t[i].len-2:
|
for j in 0..t[i].len-2:
|
||||||
assert(t[i][j].kind == nkType)
|
assert(t[i][j].kind == nkType)
|
||||||
linefmt(p, cpsStmts, "catch ($1*) {goto $2;}$n",
|
startBlock(p, "catch ($1*) {$n", getTypeDesc(p.module, t[i][j].typ))
|
||||||
[getTypeDesc(p.module, t[i][j].typ), label])
|
genExceptBranchBody(t[i][^1]) # exception handler body will duplicated for every type
|
||||||
|
endBlock(p)
|
||||||
|
|
||||||
if not catchAllPresent and t[^1].kind == nkFinally:
|
if not catchAllPresent and t[^1].kind == nkFinally:
|
||||||
# finally requires catch all presence
|
# finally requires catch all presence
|
||||||
|
|
@ -871,14 +843,6 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||||
line(p, cpsStmts, ~"throw;$n")
|
line(p, cpsStmts, ~"throw;$n")
|
||||||
endBlock(p)
|
endBlock(p)
|
||||||
|
|
||||||
# generate labeled branches bodies
|
|
||||||
for label, body in labeled_branches.items():
|
|
||||||
startBlock(p)
|
|
||||||
fixLabel(p, label)
|
|
||||||
genExceptBranchBody(body)
|
|
||||||
endBlock(p)
|
|
||||||
fixLabel(p, end_label)
|
|
||||||
|
|
||||||
dec p.inExceptBlock
|
dec p.inExceptBlock
|
||||||
discard pop(p.nestedTryStmts)
|
discard pop(p.nestedTryStmts)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -151,6 +151,11 @@ proc complement*(a: PNode): PNode =
|
||||||
for i in countup(0, high(x)): x[i] = not x[i]
|
for i in countup(0, high(x)): x[i] = not x[i]
|
||||||
result = toTreeSet(x, a.typ, a.info)
|
result = toTreeSet(x, a.typ, a.info)
|
||||||
|
|
||||||
|
proc deduplicate*(a: PNode): PNode =
|
||||||
|
var x: TBitSet
|
||||||
|
toBitSet(a, x)
|
||||||
|
result = toTreeSet(x, a.typ, a.info)
|
||||||
|
|
||||||
proc cardSet(s: PNode): BiggestInt =
|
proc cardSet(s: PNode): BiggestInt =
|
||||||
# here we can do better than converting it into a compact set
|
# here we can do better than converting it into a compact set
|
||||||
# we just count the elements directly
|
# we just count the elements directly
|
||||||
|
|
|
||||||
|
|
@ -169,21 +169,24 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
|
||||||
else:
|
else:
|
||||||
add(candidates, err.sym.getProcHeader(prefer))
|
add(candidates, err.sym.getProcHeader(prefer))
|
||||||
add(candidates, "\n")
|
add(candidates, "\n")
|
||||||
if err.firstMismatch != 0 and n.len > 2:
|
if err.firstMismatch != 0 and n.len > 1:
|
||||||
add(candidates, " first type mismatch at position: " & $err.firstMismatch &
|
let cond = n.len > 2
|
||||||
"\n required type: ")
|
if cond:
|
||||||
|
candidates.add(" first type mismatch at position: " & $err.firstMismatch &
|
||||||
|
"\n required type: ")
|
||||||
var wanted, got: PType = nil
|
var wanted, got: PType = nil
|
||||||
if err.firstMismatch < err.sym.typ.len:
|
if err.firstMismatch < err.sym.typ.len:
|
||||||
wanted = err.sym.typ.sons[err.firstMismatch]
|
wanted = err.sym.typ.sons[err.firstMismatch]
|
||||||
candidates.add typeToString(wanted)
|
if cond: candidates.add typeToString(wanted)
|
||||||
else:
|
else:
|
||||||
candidates.add "none"
|
if cond: candidates.add "none"
|
||||||
if err.firstMismatch < n.len:
|
if err.firstMismatch < n.len:
|
||||||
candidates.add "\n but expression '"
|
if cond:
|
||||||
candidates.add renderTree(n[err.firstMismatch])
|
candidates.add "\n but expression '"
|
||||||
candidates.add "' is of type: "
|
candidates.add renderTree(n[err.firstMismatch])
|
||||||
|
candidates.add "' is of type: "
|
||||||
got = n[err.firstMismatch].typ
|
got = n[err.firstMismatch].typ
|
||||||
candidates.add typeToString(got)
|
if cond: candidates.add typeToString(got)
|
||||||
if wanted != nil and got != nil:
|
if wanted != nil and got != nil:
|
||||||
effectProblem(wanted, got, candidates)
|
effectProblem(wanted, got, candidates)
|
||||||
candidates.add "\n"
|
candidates.add "\n"
|
||||||
|
|
|
||||||
|
|
@ -692,6 +692,12 @@ proc implicitIterator(c: PContext, it: string, arg: PNode): PNode =
|
||||||
result.add arg
|
result.add arg
|
||||||
result = semExprNoDeref(c, result, {efWantIterator})
|
result = semExprNoDeref(c, result, {efWantIterator})
|
||||||
|
|
||||||
|
proc isTrivalStmtExpr(n: PNode): bool =
|
||||||
|
for i in 0 .. n.len-2:
|
||||||
|
if n[i].kind notin {nkEmpty, nkCommentStmt}:
|
||||||
|
return false
|
||||||
|
result = true
|
||||||
|
|
||||||
proc semFor(c: PContext, n: PNode): PNode =
|
proc semFor(c: PContext, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
checkMinSonsLen(n, 3)
|
checkMinSonsLen(n, 3)
|
||||||
|
|
@ -699,6 +705,9 @@ proc semFor(c: PContext, n: PNode): PNode =
|
||||||
openScope(c)
|
openScope(c)
|
||||||
n.sons[length-2] = semExprNoDeref(c, n.sons[length-2], {efWantIterator})
|
n.sons[length-2] = semExprNoDeref(c, n.sons[length-2], {efWantIterator})
|
||||||
var call = n.sons[length-2]
|
var call = n.sons[length-2]
|
||||||
|
if call.kind == nkStmtListExpr and isTrivalStmtExpr(call):
|
||||||
|
call = call.lastSon
|
||||||
|
n.sons[length-2] = call
|
||||||
let isCallExpr = call.kind in nkCallKinds
|
let isCallExpr = call.kind in nkCallKinds
|
||||||
if isCallExpr and call[0].kind == nkSym and
|
if isCallExpr and call[0].kind == nkSym and
|
||||||
call[0].sym.magic in {mFields, mFieldPairs, mOmpParFor}:
|
call[0].sym.magic in {mFields, mFieldPairs, mOmpParFor}:
|
||||||
|
|
|
||||||
|
|
@ -497,8 +497,8 @@ proc semCaseBranchSetElem(c: PContext, t, b: PNode,
|
||||||
|
|
||||||
proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
|
proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
|
||||||
covered: var BiggestInt) =
|
covered: var BiggestInt) =
|
||||||
|
let lastIndex = sonsLen(branch) - 2
|
||||||
for i in countup(0, sonsLen(branch) - 2):
|
for i in 0..lastIndex:
|
||||||
var b = branch.sons[i]
|
var b = branch.sons[i]
|
||||||
if b.kind == nkRange:
|
if b.kind == nkRange:
|
||||||
branch.sons[i] = b
|
branch.sons[i] = b
|
||||||
|
|
@ -516,14 +516,21 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
|
||||||
branch.sons[i] = skipConv(fitNode(c, t.sons[0].typ, r, r.info))
|
branch.sons[i] = skipConv(fitNode(c, t.sons[0].typ, r, r.info))
|
||||||
inc(covered)
|
inc(covered)
|
||||||
else:
|
else:
|
||||||
|
if r.kind == nkCurly:
|
||||||
|
r = r.deduplicate
|
||||||
|
|
||||||
# first element is special and will overwrite: branch.sons[i]:
|
# first element is special and will overwrite: branch.sons[i]:
|
||||||
branch.sons[i] = semCaseBranchSetElem(c, t, r[0], covered)
|
branch.sons[i] = semCaseBranchSetElem(c, t, r[0], covered)
|
||||||
|
|
||||||
# other elements have to be added to ``branch``
|
# other elements have to be added to ``branch``
|
||||||
for j in 1 ..< r.len:
|
for j in 1 ..< r.len:
|
||||||
branch.add(semCaseBranchSetElem(c, t, r[j], covered))
|
branch.add(semCaseBranchSetElem(c, t, r[j], covered))
|
||||||
# caution! last son of branch must be the actions to execute:
|
# caution! last son of branch must be the actions to execute:
|
||||||
var L = branch.len
|
swap(branch.sons[^2], branch.sons[^1])
|
||||||
swap(branch.sons[L-2], branch.sons[L-1])
|
checkForOverlap(c, t, i, branchIndex)
|
||||||
|
|
||||||
|
# Elements added above needs to be checked for overlaps.
|
||||||
|
for i in lastIndex.succ..(sonsLen(branch) - 2):
|
||||||
checkForOverlap(c, t, i, branchIndex)
|
checkForOverlap(c, t, i, branchIndex)
|
||||||
|
|
||||||
proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||||
|
|
|
||||||
|
|
@ -915,24 +915,25 @@ proc isCovariantPtr(c: var TCandidate, f, a: PType): bool =
|
||||||
else:
|
else:
|
||||||
return false
|
return false
|
||||||
|
|
||||||
proc maxNumericType(prev, candidate: PType): PType =
|
when false:
|
||||||
let c = candidate.skipTypes({tyRange})
|
proc maxNumericType(prev, candidate: PType): PType =
|
||||||
template greater(s) =
|
let c = candidate.skipTypes({tyRange})
|
||||||
if c.kind in s: result = c
|
template greater(s) =
|
||||||
case prev.kind
|
if c.kind in s: result = c
|
||||||
of tyInt: greater({tyInt64})
|
case prev.kind
|
||||||
of tyInt8: greater({tyInt, tyInt16, tyInt32, tyInt64})
|
of tyInt: greater({tyInt64})
|
||||||
of tyInt16: greater({tyInt, tyInt32, tyInt64})
|
of tyInt8: greater({tyInt, tyInt16, tyInt32, tyInt64})
|
||||||
of tyInt32: greater({tyInt64})
|
of tyInt16: greater({tyInt, tyInt32, tyInt64})
|
||||||
|
of tyInt32: greater({tyInt64})
|
||||||
|
|
||||||
of tyUInt: greater({tyUInt64})
|
of tyUInt: greater({tyUInt64})
|
||||||
of tyUInt8: greater({tyUInt, tyUInt16, tyUInt32, tyUInt64})
|
of tyUInt8: greater({tyUInt, tyUInt16, tyUInt32, tyUInt64})
|
||||||
of tyUInt16: greater({tyUInt, tyUInt32, tyUInt64})
|
of tyUInt16: greater({tyUInt, tyUInt32, tyUInt64})
|
||||||
of tyUInt32: greater({tyUInt64})
|
of tyUInt32: greater({tyUInt64})
|
||||||
|
|
||||||
of tyFloat32: greater({tyFloat64, tyFloat128})
|
of tyFloat32: greater({tyFloat64, tyFloat128})
|
||||||
of tyFloat64: greater({tyFloat128})
|
of tyFloat64: greater({tyFloat128})
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
|
proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
|
||||||
flags: TTypeRelFlags = {}): TTypeRelation =
|
flags: TTypeRelFlags = {}): TTypeRelation =
|
||||||
|
|
@ -1631,13 +1632,15 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
|
||||||
# Special type binding rule for numeric types.
|
# Special type binding rule for numeric types.
|
||||||
# See section "Generic type inference for numeric types" of the
|
# See section "Generic type inference for numeric types" of the
|
||||||
# manual for further details:
|
# manual for further details:
|
||||||
let rebinding = maxNumericType(x.skipTypes({tyRange}), a)
|
when false:
|
||||||
if rebinding != nil:
|
let rebinding = maxNumericType(x.skipTypes({tyRange}), a)
|
||||||
put(c, f, rebinding)
|
if rebinding != nil:
|
||||||
result = isGeneric
|
put(c, f, rebinding)
|
||||||
else:
|
result = isGeneric
|
||||||
result = typeRel(c, x, a) # check if it fits
|
else:
|
||||||
if result > isGeneric: result = isGeneric
|
discard
|
||||||
|
result = typeRel(c, x, a) # check if it fits
|
||||||
|
if result > isGeneric: result = isGeneric
|
||||||
of tyStatic:
|
of tyStatic:
|
||||||
let prev = PType(idTableGet(c.bindings, f))
|
let prev = PType(idTableGet(c.bindings, f))
|
||||||
if prev == nil:
|
if prev == nil:
|
||||||
|
|
|
||||||
|
|
@ -713,29 +713,3 @@ definition):
|
||||||
But a ``bind`` is rarely useful because symbol binding from the definition
|
But a ``bind`` is rarely useful because symbol binding from the definition
|
||||||
scope is the default.
|
scope is the default.
|
||||||
|
|
||||||
|
|
||||||
Generic type inference for numeric types
|
|
||||||
----------------------------------------
|
|
||||||
|
|
||||||
A `numeric`:idx: type is any signed, unsigned integer type, floating point
|
|
||||||
type or a subrange thereof. Let ``maxNumericType(T1, T2)`` be the "greater"
|
|
||||||
type of ``T1`` and ``T2``, that is the type that uses more bits. For
|
|
||||||
example ``maxNumericType(int32, int64) == int64``. ``maxNumericType`` is only
|
|
||||||
defined for numeric types of the same class (signed, unsigned, floating point).
|
|
||||||
``maxNumericType`` strips away subranges,
|
|
||||||
``maxNumericType(subrangeof(int16), int8)`` produces ``int16`` not its
|
|
||||||
subrange. The definition ``maxNumericType`` is extended to take a variable
|
|
||||||
number of arguments in the obvious way;
|
|
||||||
``maxNumericType(x, y, z) == maxNumericType(maxNumericType(x, y), z)``.
|
|
||||||
|
|
||||||
A generic type parameter ``T`` that is bound to multiple numeric types ``N1``,
|
|
||||||
``N2``, ``N3``, ... during type checking is inferred to
|
|
||||||
be ``maxNumericType(N1, N2, N3, ...)``. This special type inference rule ensures
|
|
||||||
that the builtin arithmetic operators can be written in an intuitive way:
|
|
||||||
|
|
||||||
.. code-block:: nim
|
|
||||||
proc `@`[T: int|int16|int32](x, y: T): T
|
|
||||||
|
|
||||||
4'i32 @ 6'i64 # inferred to be of type ``int64``
|
|
||||||
|
|
||||||
4'i64 @ 6'i32 # inferred to be of type ``int64``
|
|
||||||
|
|
|
||||||
|
|
@ -955,6 +955,17 @@ proc `[]=`*[A](t: var CountTable[A], key: A, val: int) =
|
||||||
#t.data[h].key = key
|
#t.data[h].key = key
|
||||||
#t.data[h].val = val
|
#t.data[h].val = val
|
||||||
|
|
||||||
|
proc inc*[A](t: var CountTable[A], key: A, val = 1) =
|
||||||
|
## increments `t[key]` by `val`.
|
||||||
|
var index = rawGet(t, key)
|
||||||
|
if index >= 0:
|
||||||
|
inc(t.data[index].val, val)
|
||||||
|
if t.data[index].val == 0: dec(t.counter)
|
||||||
|
else:
|
||||||
|
if mustRehash(len(t.data), t.counter): enlarge(t)
|
||||||
|
rawInsert(t, t.data, key, val)
|
||||||
|
inc(t.counter)
|
||||||
|
|
||||||
proc initCountTable*[A](initialSize=64): CountTable[A] =
|
proc initCountTable*[A](initialSize=64): CountTable[A] =
|
||||||
## creates a new count table that is empty.
|
## creates a new count table that is empty.
|
||||||
##
|
##
|
||||||
|
|
@ -969,7 +980,7 @@ proc toCountTable*[A](keys: openArray[A]): CountTable[A] =
|
||||||
## creates a new count table with every key in `keys` having a count
|
## creates a new count table with every key in `keys` having a count
|
||||||
## of how many times it occurs in `keys`.
|
## of how many times it occurs in `keys`.
|
||||||
result = initCountTable[A](rightSize(keys.len))
|
result = initCountTable[A](rightSize(keys.len))
|
||||||
for key in items(keys): result.inc key
|
for key in items(keys): result.inc(key)
|
||||||
|
|
||||||
proc `$`*[A](t: CountTable[A]): string =
|
proc `$`*[A](t: CountTable[A]): string =
|
||||||
## The `$` operator for count tables.
|
## The `$` operator for count tables.
|
||||||
|
|
@ -980,17 +991,6 @@ proc `==`*[A](s, t: CountTable[A]): bool =
|
||||||
## contain the same keys with the same count. Insert order does not matter.
|
## contain the same keys with the same count. Insert order does not matter.
|
||||||
equalsImpl(s, t)
|
equalsImpl(s, t)
|
||||||
|
|
||||||
proc inc*[A](t: var CountTable[A], key: A, val = 1) =
|
|
||||||
## increments `t[key]` by `val`.
|
|
||||||
var index = rawGet(t, key)
|
|
||||||
if index >= 0:
|
|
||||||
inc(t.data[index].val, val)
|
|
||||||
if t.data[index].val == 0: dec(t.counter)
|
|
||||||
else:
|
|
||||||
if mustRehash(len(t.data), t.counter): enlarge(t)
|
|
||||||
rawInsert(t, t.data, key, val)
|
|
||||||
inc(t.counter)
|
|
||||||
|
|
||||||
proc smallest*[A](t: CountTable[A]): tuple[key: A, val: int] =
|
proc smallest*[A](t: CountTable[A]): tuple[key: A, val: int] =
|
||||||
## returns the (key,val)-pair with the smallest `val`. Efficiency: O(n)
|
## returns the (key,val)-pair with the smallest `val`. Efficiency: O(n)
|
||||||
assert t.len > 0
|
assert t.len > 0
|
||||||
|
|
@ -1088,6 +1088,10 @@ proc `[]=`*[A](t: CountTableRef[A], key: A, val: int) =
|
||||||
assert val > 0
|
assert val > 0
|
||||||
t[][key] = val
|
t[][key] = val
|
||||||
|
|
||||||
|
proc inc*[A](t: CountTableRef[A], key: A, val = 1) =
|
||||||
|
## increments `t[key]` by `val`.
|
||||||
|
t[].inc(key, val)
|
||||||
|
|
||||||
proc newCountTable*[A](initialSize=64): CountTableRef[A] =
|
proc newCountTable*[A](initialSize=64): CountTableRef[A] =
|
||||||
## creates a new count table that is empty.
|
## creates a new count table that is empty.
|
||||||
##
|
##
|
||||||
|
|
@ -1098,9 +1102,10 @@ proc newCountTable*[A](initialSize=64): CountTableRef[A] =
|
||||||
result[] = initCountTable[A](initialSize)
|
result[] = initCountTable[A](initialSize)
|
||||||
|
|
||||||
proc newCountTable*[A](keys: openArray[A]): CountTableRef[A] =
|
proc newCountTable*[A](keys: openArray[A]): CountTableRef[A] =
|
||||||
## creates a new count table with every key in `keys` having a count of 1.
|
## creates a new count table with every key in `keys` having a count
|
||||||
|
## of how many times it occurs in `keys`.
|
||||||
result = newCountTable[A](rightSize(keys.len))
|
result = newCountTable[A](rightSize(keys.len))
|
||||||
for key in items(keys): result[key] = 1
|
for key in items(keys): result.inc(key)
|
||||||
|
|
||||||
proc `$`*[A](t: CountTableRef[A]): string =
|
proc `$`*[A](t: CountTableRef[A]): string =
|
||||||
## The `$` operator for count tables.
|
## The `$` operator for count tables.
|
||||||
|
|
@ -1114,10 +1119,6 @@ proc `==`*[A](s, t: CountTableRef[A]): bool =
|
||||||
elif isNil(t): result = false
|
elif isNil(t): result = false
|
||||||
else: result = s[] == t[]
|
else: result = s[] == t[]
|
||||||
|
|
||||||
proc inc*[A](t: CountTableRef[A], key: A, val = 1) =
|
|
||||||
## increments `t[key]` by `val`.
|
|
||||||
t[].inc(key, val)
|
|
||||||
|
|
||||||
proc smallest*[A](t: CountTableRef[A]): (A, int) =
|
proc smallest*[A](t: CountTableRef[A]): (A, int) =
|
||||||
## returns the (key,val)-pair with the smallest `val`. Efficiency: O(n)
|
## returns the (key,val)-pair with the smallest `val`. Efficiency: O(n)
|
||||||
t[].smallest
|
t[].smallest
|
||||||
|
|
@ -1316,7 +1317,6 @@ when isMainModule:
|
||||||
assert a == b
|
assert a == b
|
||||||
assert a == c
|
assert a == c
|
||||||
|
|
||||||
|
|
||||||
block: #6250
|
block: #6250
|
||||||
let
|
let
|
||||||
a = {3: 1}.toOrderedTable
|
a = {3: 1}.toOrderedTable
|
||||||
|
|
@ -1332,6 +1332,5 @@ when isMainModule:
|
||||||
assert((b == a) == true)
|
assert((b == a) == true)
|
||||||
|
|
||||||
block: # CountTable.smallest
|
block: # CountTable.smallest
|
||||||
var t = initCountTable[int]()
|
let t = toCountTable([0, 0, 5, 5, 5])
|
||||||
for v in items([0, 0, 5, 5, 5]): t.inc(v)
|
|
||||||
doAssert t.smallest == (0, 2)
|
doAssert t.smallest == (0, 2)
|
||||||
|
|
|
||||||
|
|
@ -507,7 +507,7 @@ proc request*(url: string, httpMethod: string, extraHeaders = "",
|
||||||
port = net.Port(443)
|
port = net.Port(443)
|
||||||
else:
|
else:
|
||||||
raise newException(HttpRequestError,
|
raise newException(HttpRequestError,
|
||||||
"SSL support is not available. Cannot connect over SSL.")
|
"SSL support is not available. Cannot connect over SSL. Compile with -d:ssl to enable.")
|
||||||
if r.port != "":
|
if r.port != "":
|
||||||
port = net.Port(r.port.parseInt)
|
port = net.Port(r.port.parseInt)
|
||||||
|
|
||||||
|
|
@ -540,7 +540,8 @@ proc request*(url: string, httpMethod: string, extraHeaders = "",
|
||||||
"so a secure connection could not be established.")
|
"so a secure connection could not be established.")
|
||||||
sslContext.wrapConnectedSocket(s, handshakeAsClient, hostUrl.hostname)
|
sslContext.wrapConnectedSocket(s, handshakeAsClient, hostUrl.hostname)
|
||||||
else:
|
else:
|
||||||
raise newException(HttpRequestError, "SSL support not available. Cannot connect via proxy over SSL")
|
raise newException(HttpRequestError, "SSL support not available. Cannot " &
|
||||||
|
"connect via proxy over SSL. Compile with -d:ssl to enable.")
|
||||||
else:
|
else:
|
||||||
if timeout == -1:
|
if timeout == -1:
|
||||||
s.connect(r.hostname, port)
|
s.connect(r.hostname, port)
|
||||||
|
|
@ -1087,7 +1088,7 @@ proc newConnection(client: HttpClient | AsyncHttpClient,
|
||||||
|
|
||||||
if isSsl and not defined(ssl):
|
if isSsl and not defined(ssl):
|
||||||
raise newException(HttpRequestError,
|
raise newException(HttpRequestError,
|
||||||
"SSL support is not available. Cannot connect over SSL.")
|
"SSL support is not available. Cannot connect over SSL. Compile with -d:ssl to enable.")
|
||||||
|
|
||||||
if client.connected:
|
if client.connected:
|
||||||
client.close()
|
client.close()
|
||||||
|
|
@ -1137,7 +1138,7 @@ proc newConnection(client: HttpClient | AsyncHttpClient,
|
||||||
client.socket, handshakeAsClient, url.hostname)
|
client.socket, handshakeAsClient, url.hostname)
|
||||||
else:
|
else:
|
||||||
raise newException(HttpRequestError,
|
raise newException(HttpRequestError,
|
||||||
"SSL support is not available. Cannot connect over SSL.")
|
"SSL support is not available. Cannot connect over SSL. Compile with -d:ssl to enable.")
|
||||||
|
|
||||||
# May be connected through proxy but remember actual URL being accessed
|
# May be connected through proxy but remember actual URL being accessed
|
||||||
client.currentURL = url
|
client.currentURL = url
|
||||||
|
|
|
||||||
|
|
@ -430,8 +430,14 @@ when defineSsl:
|
||||||
raise newException(SSLError, "No error reported.")
|
raise newException(SSLError, "No error reported.")
|
||||||
if err == -1:
|
if err == -1:
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
var errStr = ErrErrorString(err, nil)
|
var errStr = $ErrErrorString(err, nil)
|
||||||
raise newException(SSLError, $errStr)
|
case err
|
||||||
|
of 336032814, 336032784:
|
||||||
|
errStr = "Please upgrade your OpenSSL library, it does not support the " &
|
||||||
|
"necessary protocols. OpenSSL error is: " & errStr
|
||||||
|
else:
|
||||||
|
discard
|
||||||
|
raise newException(SSLError, errStr)
|
||||||
|
|
||||||
proc getExtraData*(ctx: SSLContext, index: int): RootRef =
|
proc getExtraData*(ctx: SSLContext, index: int): RootRef =
|
||||||
## Retrieves arbitrary data stored inside SSLContext.
|
## Retrieves arbitrary data stored inside SSLContext.
|
||||||
|
|
|
||||||
|
|
@ -306,7 +306,7 @@ proc execProcesses*(cmds: openArray[string],
|
||||||
raiseOSError(err)
|
raiseOSError(err)
|
||||||
|
|
||||||
if rexit >= 0:
|
if rexit >= 0:
|
||||||
result = max(result, q[rexit].peekExitCode())
|
result = max(result, abs(q[rexit].peekExitCode()))
|
||||||
if afterRunEvent != nil: afterRunEvent(rexit, q[rexit])
|
if afterRunEvent != nil: afterRunEvent(rexit, q[rexit])
|
||||||
close(q[rexit])
|
close(q[rexit])
|
||||||
if i < len(cmds):
|
if i < len(cmds):
|
||||||
|
|
@ -331,7 +331,7 @@ proc execProcesses*(cmds: openArray[string],
|
||||||
if beforeRunEvent != nil:
|
if beforeRunEvent != nil:
|
||||||
beforeRunEvent(i)
|
beforeRunEvent(i)
|
||||||
var p = startProcess(cmds[i], options=options + {poEvalCommand})
|
var p = startProcess(cmds[i], options=options + {poEvalCommand})
|
||||||
result = max(waitForExit(p), result)
|
result = max(abs(waitForExit(p)), result)
|
||||||
if afterRunEvent != nil: afterRunEvent(i, p)
|
if afterRunEvent != nil: afterRunEvent(i, p)
|
||||||
close(p)
|
close(p)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@
|
||||||
## import parsecsv
|
## import parsecsv
|
||||||
## import os
|
## import os
|
||||||
## # Prepare a file
|
## # Prepare a file
|
||||||
## var content = """One,Two,Three,Four
|
## let content = """One,Two,Three,Four
|
||||||
## 1,2,3,4
|
## 1,2,3,4
|
||||||
## 10,20,30,40
|
## 10,20,30,40
|
||||||
## 100,200,300,400
|
## 100,200,300,400
|
||||||
|
|
@ -123,7 +123,7 @@ proc parseField(my: var CsvParser, a: var string) =
|
||||||
if buf[pos] == my.quote and my.quote != '\0':
|
if buf[pos] == my.quote and my.quote != '\0':
|
||||||
inc(pos)
|
inc(pos)
|
||||||
while true:
|
while true:
|
||||||
var c = buf[pos]
|
let c = buf[pos]
|
||||||
if c == '\0':
|
if c == '\0':
|
||||||
my.bufpos = pos # can continue after exception?
|
my.bufpos = pos # can continue after exception?
|
||||||
error(my, pos, my.quote & " expected")
|
error(my, pos, my.quote & " expected")
|
||||||
|
|
@ -153,7 +153,7 @@ proc parseField(my: var CsvParser, a: var string) =
|
||||||
inc(pos)
|
inc(pos)
|
||||||
else:
|
else:
|
||||||
while true:
|
while true:
|
||||||
var c = buf[pos]
|
let c = buf[pos]
|
||||||
if c == my.sep: break
|
if c == my.sep: break
|
||||||
if c in {'\c', '\l', '\0'}: break
|
if c in {'\c', '\l', '\0'}: break
|
||||||
add(a, c)
|
add(a, c)
|
||||||
|
|
@ -171,9 +171,9 @@ proc readRow*(my: var CsvParser, columns = 0): bool =
|
||||||
##
|
##
|
||||||
## Blank lines are skipped.
|
## Blank lines are skipped.
|
||||||
var col = 0 # current column
|
var col = 0 # current column
|
||||||
var oldpos = my.bufpos
|
let oldpos = my.bufpos
|
||||||
while my.buf[my.bufpos] != '\0':
|
while my.buf[my.bufpos] != '\0':
|
||||||
var oldlen = my.row.len
|
let oldlen = my.row.len
|
||||||
if oldlen < col+1:
|
if oldlen < col+1:
|
||||||
setLen(my.row, col+1)
|
setLen(my.row, col+1)
|
||||||
my.row[col] = ""
|
my.row[col] = ""
|
||||||
|
|
@ -208,16 +208,16 @@ proc close*(my: var CsvParser) {.inline.} =
|
||||||
proc readHeaderRow*(my: var CsvParser) =
|
proc readHeaderRow*(my: var CsvParser) =
|
||||||
## Reads the first row and creates a look-up table for column numbers
|
## Reads the first row and creates a look-up table for column numbers
|
||||||
## See also `rowEntry <#rowEntry.CsvParser.string>`_.
|
## See also `rowEntry <#rowEntry.CsvParser.string>`_.
|
||||||
var present = my.readRow()
|
let present = my.readRow()
|
||||||
if present:
|
if present:
|
||||||
my.headers = my.row
|
my.headers = my.row
|
||||||
|
|
||||||
proc rowEntry*(my: var CsvParser, entry: string): string =
|
proc rowEntry*(my: var CsvParser, entry: string): var string =
|
||||||
## Reads a specified `entry` from the current row.
|
## Acceses a specified `entry` from the current row.
|
||||||
##
|
##
|
||||||
## Assumes that `readHeaderRow <#readHeaderRow.CsvParser>`_ has already been
|
## Assumes that `readHeaderRow <#readHeaderRow.CsvParser>`_ has already been
|
||||||
## called.
|
## called.
|
||||||
var index = my.headers.find(entry)
|
let index = my.headers.find(entry)
|
||||||
if index >= 0:
|
if index >= 0:
|
||||||
result = my.row[index]
|
result = my.row[index]
|
||||||
|
|
||||||
|
|
@ -237,14 +237,14 @@ when isMainModule:
|
||||||
import os
|
import os
|
||||||
import strutils
|
import strutils
|
||||||
block: # Tests for reading the header row
|
block: # Tests for reading the header row
|
||||||
var content = "One,Two,Three,Four\n1,2,3,4\n10,20,30,40,\n100,200,300,400\n"
|
let content = "One,Two,Three,Four\n1,2,3,4\n10,20,30,40,\n100,200,300,400\n"
|
||||||
writeFile("temp.csv", content)
|
writeFile("temp.csv", content)
|
||||||
|
|
||||||
var p: CsvParser
|
var p: CsvParser
|
||||||
p.open("temp.csv")
|
p.open("temp.csv")
|
||||||
p.readHeaderRow()
|
p.readHeaderRow()
|
||||||
while p.readRow():
|
while p.readRow():
|
||||||
var zeros = repeat('0', p.currRow-2)
|
let zeros = repeat('0', p.currRow-2)
|
||||||
doAssert p.rowEntry("One") == "1" & zeros
|
doAssert p.rowEntry("One") == "1" & zeros
|
||||||
doAssert p.rowEntry("Two") == "2" & zeros
|
doAssert p.rowEntry("Two") == "2" & zeros
|
||||||
doAssert p.rowEntry("Three") == "3" & zeros
|
doAssert p.rowEntry("Three") == "3" & zeros
|
||||||
|
|
|
||||||
|
|
@ -372,7 +372,7 @@ proc cursorForward*(f: File, count=1) =
|
||||||
inc(p.x, count)
|
inc(p.x, count)
|
||||||
setCursorPos(h, p.x, p.y)
|
setCursorPos(h, p.x, p.y)
|
||||||
else:
|
else:
|
||||||
f.write("{stylePrefix}{count}C")
|
f.write(fmt"{stylePrefix}{count}C")
|
||||||
|
|
||||||
proc cursorBackward*(f: File, count=1) =
|
proc cursorBackward*(f: File, count=1) =
|
||||||
## Moves the cursor backward by `count` columns.
|
## Moves the cursor backward by `count` columns.
|
||||||
|
|
@ -382,7 +382,7 @@ proc cursorBackward*(f: File, count=1) =
|
||||||
dec(p.x, count)
|
dec(p.x, count)
|
||||||
setCursorPos(h, p.x, p.y)
|
setCursorPos(h, p.x, p.y)
|
||||||
else:
|
else:
|
||||||
f.write("{stylePrefix}{count}D")
|
f.write(fmt"{stylePrefix}{count}D")
|
||||||
|
|
||||||
when true:
|
when true:
|
||||||
discard
|
discard
|
||||||
|
|
|
||||||
|
|
@ -1917,7 +1917,7 @@ proc `$` *(x: float): string {.magic: "FloatToStr", noSideEffect.}
|
||||||
proc `$` *(x: bool): string {.magic: "BoolToStr", noSideEffect.}
|
proc `$` *(x: bool): string {.magic: "BoolToStr", noSideEffect.}
|
||||||
## The stringify operator for a boolean argument. Returns `x`
|
## The stringify operator for a boolean argument. Returns `x`
|
||||||
## converted to the string "false" or "true".
|
## converted to the string "false" or "true".
|
||||||
#
|
|
||||||
proc `$` *(x: char): string {.magic: "CharToStr", noSideEffect.}
|
proc `$` *(x: char): string {.magic: "CharToStr", noSideEffect.}
|
||||||
## The stringify operator for a character argument. Returns `x`
|
## The stringify operator for a character argument. Returns `x`
|
||||||
## converted to a string.
|
## converted to a string.
|
||||||
|
|
|
||||||
50
tests/casestmt/tduplicates.nim
Normal file
50
tests/casestmt/tduplicates.nim
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
discard """
|
||||||
|
output: '''
|
||||||
|
OK
|
||||||
|
OK
|
||||||
|
OK
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
type Kind = enum A, B
|
||||||
|
var k = A
|
||||||
|
|
||||||
|
template reject(b) =
|
||||||
|
static: doAssert(not compiles(b))
|
||||||
|
|
||||||
|
reject:
|
||||||
|
var i = 2
|
||||||
|
case i
|
||||||
|
of [1, 1]: discard
|
||||||
|
else: discard
|
||||||
|
|
||||||
|
reject:
|
||||||
|
var i = 2
|
||||||
|
case i
|
||||||
|
of 1, { 1..2 }: discard
|
||||||
|
else: discard
|
||||||
|
|
||||||
|
reject:
|
||||||
|
var i = 2
|
||||||
|
case i
|
||||||
|
of { 1, 1 }: discard
|
||||||
|
of { 1, 1 }: discard
|
||||||
|
else: discard
|
||||||
|
|
||||||
|
reject:
|
||||||
|
case k
|
||||||
|
of [A, A]: discard
|
||||||
|
|
||||||
|
var i = 2
|
||||||
|
case i
|
||||||
|
of { 1, 1 }: discard
|
||||||
|
of { 2, 2 }: echo "OK"
|
||||||
|
else: discard
|
||||||
|
|
||||||
|
case i
|
||||||
|
of { 10..30, 15..25, 5..15, 25..35 }: discard
|
||||||
|
else: echo "OK"
|
||||||
|
|
||||||
|
case k
|
||||||
|
of {A, A..A}: echo "OK"
|
||||||
|
of B: discard
|
||||||
|
|
@ -3,7 +3,9 @@ discard """
|
||||||
output: '''foo
|
output: '''foo
|
||||||
bar
|
bar
|
||||||
Need odd and >= 3 digits##
|
Need odd and >= 3 digits##
|
||||||
baz'''
|
baz
|
||||||
|
caught
|
||||||
|
'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# bug #1888
|
# bug #1888
|
||||||
|
|
@ -15,3 +17,21 @@ try:
|
||||||
except ValueError:
|
except ValueError:
|
||||||
echo getCurrentExceptionMsg(), "##"
|
echo getCurrentExceptionMsg(), "##"
|
||||||
echo "baz"
|
echo "baz"
|
||||||
|
|
||||||
|
|
||||||
|
# bug 7232
|
||||||
|
try:
|
||||||
|
discard
|
||||||
|
except KeyError, ValueError:
|
||||||
|
echo "except handler" # should not be invoked
|
||||||
|
|
||||||
|
|
||||||
|
#bug 7239
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
raise newException(ValueError, "asdf")
|
||||||
|
except KeyError, ValueError:
|
||||||
|
raise
|
||||||
|
except:
|
||||||
|
echo "caught"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,21 @@
|
||||||
discard """
|
discard """
|
||||||
output: '''int64
|
output: '''false'''
|
||||||
int64'''
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import typetraits
|
when false:
|
||||||
|
import typetraits
|
||||||
|
|
||||||
proc `@`[T: SomeInteger](x, y: T): T = x
|
proc `@`[T: SomeInteger](x, y: T): T = x
|
||||||
|
|
||||||
echo(type(5'i64 @ 6'i32))
|
echo(type(5'i64 @ 6'i32))
|
||||||
|
|
||||||
echo(type(5'i32 @ 6'i64))
|
echo(type(5'i32 @ 6'i64))
|
||||||
|
|
||||||
|
import sets
|
||||||
|
# bug #7247
|
||||||
|
type
|
||||||
|
n8 = range[0'i8..127'i8]
|
||||||
|
|
||||||
|
var tab = initSet[n8]()
|
||||||
|
|
||||||
|
echo tab.contains(8)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,12 @@ discard """
|
||||||
output: '''true
|
output: '''true
|
||||||
3
|
3
|
||||||
4
|
4
|
||||||
5'''
|
5
|
||||||
|
0
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4'''
|
||||||
cmd: "nim $target --gc:none --hints:on --warnings:off $options $file"
|
cmd: "nim $target --gc:none --hints:on --warnings:off $options $file"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -55,3 +60,7 @@ echo "true"
|
||||||
# bug #1560
|
# bug #1560
|
||||||
for i in @[3, 4, 5]:
|
for i in @[3, 4, 5]:
|
||||||
echo($i)
|
echo($i)
|
||||||
|
|
||||||
|
# bug #6992
|
||||||
|
for i in 0 ..< 5u32:
|
||||||
|
echo i
|
||||||
|
|
|
||||||
|
|
@ -294,7 +294,6 @@ proc compilerOutputTests(test: TTest, target: TTarget, given: var TSpec,
|
||||||
proc testSpec(r: var TResults, test: TTest, target = targetC) =
|
proc testSpec(r: var TResults, test: TTest, target = targetC) =
|
||||||
let tname = test.name.addFileExt(".nim")
|
let tname = test.name.addFileExt(".nim")
|
||||||
#echo "TESTING ", tname
|
#echo "TESTING ", tname
|
||||||
inc(r.total)
|
|
||||||
var expected: TSpec
|
var expected: TSpec
|
||||||
if test.action != actionRunNoSpec:
|
if test.action != actionRunNoSpec:
|
||||||
expected = parseSpec(tname)
|
expected = parseSpec(tname)
|
||||||
|
|
@ -305,12 +304,14 @@ proc testSpec(r: var TResults, test: TTest, target = targetC) =
|
||||||
if expected.err == reIgnored:
|
if expected.err == reIgnored:
|
||||||
r.addResult(test, target, "", "", reIgnored)
|
r.addResult(test, target, "", "", reIgnored)
|
||||||
inc(r.skipped)
|
inc(r.skipped)
|
||||||
|
inc(r.total)
|
||||||
return
|
return
|
||||||
|
|
||||||
if expected.targets == {}:
|
if expected.targets == {}:
|
||||||
expected.targets.incl(target)
|
expected.targets.incl(target)
|
||||||
|
|
||||||
for target in expected.targets:
|
for target in expected.targets:
|
||||||
|
inc(r.total)
|
||||||
if target notin targets:
|
if target notin targets:
|
||||||
r.addResult(test, target, "", "", reIgnored)
|
r.addResult(test, target, "", "", reIgnored)
|
||||||
inc(r.skipped)
|
inc(r.skipped)
|
||||||
|
|
@ -490,7 +491,7 @@ proc main() =
|
||||||
else: echo r, r.data
|
else: echo r, r.data
|
||||||
backend.close()
|
backend.close()
|
||||||
var failed = r.total - r.passed - r.skipped
|
var failed = r.total - r.passed - r.skipped
|
||||||
if failed > 0:
|
if failed != 0:
|
||||||
echo "FAILURE! total: ", r.total, " passed: ", r.passed, " skipped: ", r.skipped
|
echo "FAILURE! total: ", r.total, " passed: ", r.passed, " skipped: ", r.skipped
|
||||||
quit(QuitFailure)
|
quit(QuitFailure)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue