Merge branch 'devel' of https://github.com/Araq/Nim into devel
This commit is contained in:
commit
4316fdddf3
25 changed files with 582 additions and 380 deletions
|
|
@ -399,6 +399,7 @@ const
|
||||||
tyPureObject* = tyTuple
|
tyPureObject* = tyTuple
|
||||||
GcTypeKinds* = {tyRef, tySequence, tyString}
|
GcTypeKinds* = {tyRef, tySequence, tyString}
|
||||||
tyError* = tyProxy # as an errornous node should match everything
|
tyError* = tyProxy # as an errornous node should match everything
|
||||||
|
tyUnknown* = tyFromExpr
|
||||||
|
|
||||||
tyUnknownTypes* = {tyError, tyFromExpr}
|
tyUnknownTypes* = {tyError, tyFromExpr}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -277,16 +277,14 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
|
||||||
styleCheckUse(n.sons[0].info, finalCallee)
|
styleCheckUse(n.sons[0].info, finalCallee)
|
||||||
if finalCallee.ast == nil:
|
if finalCallee.ast == nil:
|
||||||
internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check!
|
internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check!
|
||||||
|
if x.hasFauxMatch:
|
||||||
|
result = x.call
|
||||||
|
result.sons[0] = newSymNode(finalCallee, result.sons[0].info)
|
||||||
|
if containsGenericType(result.typ) or x.fauxMatch == tyUnknown:
|
||||||
|
result.typ = newTypeS(x.fauxMatch, c)
|
||||||
|
return
|
||||||
if finalCallee.ast.sons[genericParamsPos].kind != nkEmpty:
|
if finalCallee.ast.sons[genericParamsPos].kind != nkEmpty:
|
||||||
# a generic proc!
|
finalCallee = generateInstance(c, x.calleeSym, x.bindings, n.info)
|
||||||
if not x.proxyMatch:
|
|
||||||
finalCallee = generateInstance(c, x.calleeSym, x.bindings, n.info)
|
|
||||||
else:
|
|
||||||
result = x.call
|
|
||||||
result.sons[0] = newSymNode(finalCallee, result.sons[0].info)
|
|
||||||
result.typ = finalCallee.typ.sons[0]
|
|
||||||
if containsGenericType(result.typ): result.typ = errorType(c)
|
|
||||||
return
|
|
||||||
result = x.call
|
result = x.call
|
||||||
instGenericConvertersSons(c, result, x)
|
instGenericConvertersSons(c, result, x)
|
||||||
result.sons[0] = newSymNode(finalCallee, result.sons[0].info)
|
result.sons[0] = newSymNode(finalCallee, result.sons[0].info)
|
||||||
|
|
|
||||||
|
|
@ -268,7 +268,7 @@ proc makeRangeWithStaticExpr*(c: PContext, n: PNode): PType =
|
||||||
|
|
||||||
template rangeHasStaticIf*(t: PType): bool =
|
template rangeHasStaticIf*(t: PType): bool =
|
||||||
# this accepts the ranges's node
|
# this accepts the ranges's node
|
||||||
t.n[1].kind == nkStaticExpr
|
t.n != nil and t.n.len > 1 and t.n[1].kind == nkStaticExpr
|
||||||
|
|
||||||
template getStaticTypeFromRange*(t: PType): PType =
|
template getStaticTypeFromRange*(t: PType): PType =
|
||||||
t.n[1][0][1].typ
|
t.n[1][0][1].typ
|
||||||
|
|
|
||||||
|
|
@ -229,7 +229,7 @@ proc semConv(c: PContext, n: PNode): PNode =
|
||||||
return n
|
return n
|
||||||
|
|
||||||
result = newNodeI(nkConv, n.info)
|
result = newNodeI(nkConv, n.info)
|
||||||
var targetType = semTypeNode(c, n.sons[0], nil)
|
var targetType = semTypeNode(c, n.sons[0], nil).skipTypes({tyTypeDesc})
|
||||||
maybeLiftType(targetType, c, n[0].info)
|
maybeLiftType(targetType, c, n[0].info)
|
||||||
result.addSon copyTree(n.sons[0])
|
result.addSon copyTree(n.sons[0])
|
||||||
var op = semExprWithType(c, n.sons[1])
|
var op = semExprWithType(c, n.sons[1])
|
||||||
|
|
@ -780,7 +780,6 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
if tfNoSideEffect notin t.flags: incl(c.p.owner.flags, sfSideEffect)
|
if tfNoSideEffect notin t.flags: incl(c.p.owner.flags, sfSideEffect)
|
||||||
elif t != nil and t.kind == tyTypeDesc:
|
elif t != nil and t.kind == tyTypeDesc:
|
||||||
if n.len == 1: return semObjConstr(c, n, flags)
|
if n.len == 1: return semObjConstr(c, n, flags)
|
||||||
let destType = t.skipTypes({tyTypeDesc, tyGenericInst})
|
|
||||||
return semConv(c, n)
|
return semConv(c, n)
|
||||||
else:
|
else:
|
||||||
result = overloadedCallOpr(c, n)
|
result = overloadedCallOpr(c, n)
|
||||||
|
|
@ -928,7 +927,6 @@ proc readTypeParameter(c: PContext, typ: PType,
|
||||||
let ty = if typ.kind == tyGenericInst: typ.skipGenericAlias
|
let ty = if typ.kind == tyGenericInst: typ.skipGenericAlias
|
||||||
else: (internalAssert(typ.kind == tyCompositeTypeClass);
|
else: (internalAssert(typ.kind == tyCompositeTypeClass);
|
||||||
typ.sons[1].skipGenericAlias)
|
typ.sons[1].skipGenericAlias)
|
||||||
#debug ty
|
|
||||||
let tbody = ty.sons[0]
|
let tbody = ty.sons[0]
|
||||||
for s in countup(0, tbody.len-2):
|
for s in countup(0, tbody.len-2):
|
||||||
let tParam = tbody.sons[s]
|
let tParam = tbody.sons[s]
|
||||||
|
|
|
||||||
|
|
@ -1262,10 +1262,14 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
n.sons[i] = semExpr(c, n.sons[i])
|
n.sons[i] = semExpr(c, n.sons[i])
|
||||||
if c.inTypeClass > 0 and n[i].typ != nil and n[i].typ.kind == tyBool:
|
if c.inTypeClass > 0 and n[i].typ != nil:
|
||||||
let verdict = semConstExpr(c, n[i])
|
case n[i].typ.kind
|
||||||
if verdict.intVal == 0:
|
of tyBool:
|
||||||
localError(result.info, "type class predicate failed")
|
let verdict = semConstExpr(c, n[i])
|
||||||
|
if verdict.intVal == 0:
|
||||||
|
localError(result.info, "type class predicate failed")
|
||||||
|
of tyUnknown: continue
|
||||||
|
else: discard
|
||||||
if n.sons[i].typ == enforceVoidContext or usesResult(n.sons[i]):
|
if n.sons[i].typ == enforceVoidContext or usesResult(n.sons[i]):
|
||||||
voidContext = true
|
voidContext = true
|
||||||
n.typ = enforceVoidContext
|
n.typ = enforceVoidContext
|
||||||
|
|
|
||||||
|
|
@ -225,11 +225,10 @@ proc semArrayIndex(c: PContext, n: PNode): PType =
|
||||||
elif e.kind == nkSym and e.typ.kind == tyStatic:
|
elif e.kind == nkSym and e.typ.kind == tyStatic:
|
||||||
if e.sym.ast != nil:
|
if e.sym.ast != nil:
|
||||||
return semArrayIndex(c, e.sym.ast)
|
return semArrayIndex(c, e.sym.ast)
|
||||||
internalAssert c.inGenericContext > 0
|
|
||||||
if not isOrdinalType(e.typ.lastSon):
|
if not isOrdinalType(e.typ.lastSon):
|
||||||
localError(n[1].info, errOrdinalTypeExpected)
|
localError(n[1].info, errOrdinalTypeExpected)
|
||||||
result = makeRangeWithStaticExpr(c, e)
|
result = makeRangeWithStaticExpr(c, e)
|
||||||
result.flags.incl tfUnresolved
|
if c.inGenericContext >0: result.flags.incl tfUnresolved
|
||||||
elif e.kind in nkCallKinds and hasGenericArguments(e):
|
elif e.kind in nkCallKinds and hasGenericArguments(e):
|
||||||
if not isOrdinalType(e.typ):
|
if not isOrdinalType(e.typ):
|
||||||
localError(n[1].info, errOrdinalTypeExpected)
|
localError(n[1].info, errOrdinalTypeExpected)
|
||||||
|
|
@ -782,9 +781,11 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||||
of tyGenericBody:
|
of tyGenericBody:
|
||||||
result = newTypeS(tyGenericInvokation, c)
|
result = newTypeS(tyGenericInvokation, c)
|
||||||
result.rawAddSon(paramType)
|
result.rawAddSon(paramType)
|
||||||
|
|
||||||
for i in 0 .. paramType.sonsLen - 2:
|
for i in 0 .. paramType.sonsLen - 2:
|
||||||
result.rawAddSon newTypeS(tyAnything, c)
|
let dummyType = if paramType.sons[i].kind == tyStatic: tyUnknown
|
||||||
# result.rawAddSon(copyType(paramType.sons[i], getCurrOwner(), true))
|
else: tyAnything
|
||||||
|
result.rawAddSon newTypeS(dummyType, c)
|
||||||
|
|
||||||
if paramType.lastSon.kind == tyUserTypeClass:
|
if paramType.lastSon.kind == tyUserTypeClass:
|
||||||
result.kind = tyUserTypeClassInst
|
result.kind = tyUserTypeClassInst
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,9 @@ type
|
||||||
bindings*: TIdTable # maps types to types
|
bindings*: TIdTable # maps types to types
|
||||||
baseTypeMatch: bool # needed for conversions from T to openarray[T]
|
baseTypeMatch: bool # needed for conversions from T to openarray[T]
|
||||||
# for example
|
# for example
|
||||||
proxyMatch*: bool # to prevent instantiations
|
fauxMatch*: TTypeKind # the match was successful only due to the use
|
||||||
|
# of error or wildcard (unknown) types.
|
||||||
|
# this is used to prevent instantiations.
|
||||||
genericConverter*: bool # true if a generic converter needs to
|
genericConverter*: bool # true if a generic converter needs to
|
||||||
# be instantiated
|
# be instantiated
|
||||||
coerceDistincts*: bool # this is an explicit coercion that can strip away
|
coerceDistincts*: bool # this is an explicit coercion that can strip away
|
||||||
|
|
@ -66,6 +68,8 @@ const
|
||||||
|
|
||||||
proc markUsed*(info: TLineInfo, s: PSym)
|
proc markUsed*(info: TLineInfo, s: PSym)
|
||||||
|
|
||||||
|
template hasFauxMatch*(c: TCandidate): bool = c.fauxMatch != tyNone
|
||||||
|
|
||||||
proc initCandidateAux(ctx: PContext,
|
proc initCandidateAux(ctx: PContext,
|
||||||
c: var TCandidate, callee: PType) {.inline.} =
|
c: var TCandidate, callee: PType) {.inline.} =
|
||||||
c.c = ctx
|
c.c = ctx
|
||||||
|
|
@ -109,9 +113,12 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
|
||||||
for i in 1..min(sonsLen(typeParams), sonsLen(binding)-1):
|
for i in 1..min(sonsLen(typeParams), sonsLen(binding)-1):
|
||||||
var formalTypeParam = typeParams.sons[i-1].typ
|
var formalTypeParam = typeParams.sons[i-1].typ
|
||||||
var bound = binding[i].typ
|
var bound = binding[i].typ
|
||||||
if bound != nil and formalTypeParam.kind != tyTypeDesc:
|
internalAssert bound != nil
|
||||||
|
if formalTypeParam.kind == tyTypeDesc:
|
||||||
|
if bound.kind != tyTypeDesc:
|
||||||
|
bound = makeTypeDesc(ctx, bound)
|
||||||
|
else:
|
||||||
bound = bound.skipTypes({tyTypeDesc})
|
bound = bound.skipTypes({tyTypeDesc})
|
||||||
assert bound != nil
|
|
||||||
put(c.bindings, formalTypeParam, bound)
|
put(c.bindings, formalTypeParam, bound)
|
||||||
|
|
||||||
proc newCandidate*(ctx: PContext, callee: PSym,
|
proc newCandidate*(ctx: PContext, callee: PSym,
|
||||||
|
|
@ -462,9 +469,23 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||||
var
|
var
|
||||||
typeParamName = ff.base.sons[i-1].sym.name
|
typeParamName = ff.base.sons[i-1].sym.name
|
||||||
typ = ff.sons[i]
|
typ = ff.sons[i]
|
||||||
param = newSym(skType, typeParamName, body.sym, body.sym.info)
|
param: PSym
|
||||||
|
|
||||||
|
template paramSym(kind): expr =
|
||||||
|
newSym(kind, typeParamName, body.sym, body.sym.info)
|
||||||
|
|
||||||
|
case typ.kind
|
||||||
|
of tyStatic:
|
||||||
|
param = paramSym skConst
|
||||||
|
param.typ = typ.base
|
||||||
|
param.ast = typ.n
|
||||||
|
of tyUnknown:
|
||||||
|
param = paramSym skVar
|
||||||
|
param.typ = typ
|
||||||
|
else:
|
||||||
|
param = paramSym skType
|
||||||
|
param.typ = makeTypeDesc(c, typ)
|
||||||
|
|
||||||
param.typ = makeTypeDesc(c, typ)
|
|
||||||
addDecl(c, param)
|
addDecl(c, param)
|
||||||
|
|
||||||
for param in body.n[0]:
|
for param in body.n[0]:
|
||||||
|
|
@ -626,6 +647,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
elif skipTypes(a, {tyRange}).kind == f.kind: result = isSubtype
|
elif skipTypes(a, {tyRange}).kind == f.kind: result = isSubtype
|
||||||
of tyRange:
|
of tyRange:
|
||||||
if a.kind == f.kind:
|
if a.kind == f.kind:
|
||||||
|
if f.base.kind == tyNone: return isGeneric
|
||||||
result = typeRel(c, base(f), base(a))
|
result = typeRel(c, base(f), base(a))
|
||||||
# bugfix: accept integer conversions here
|
# bugfix: accept integer conversions here
|
||||||
#if result < isGeneric: result = isNone
|
#if result < isGeneric: result = isNone
|
||||||
|
|
@ -672,22 +694,27 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
else:
|
else:
|
||||||
fRange = prev
|
fRange = prev
|
||||||
result = typeRel(c, f.sons[1], a.sons[1])
|
result = typeRel(c, f.sons[1], a.sons[1])
|
||||||
if result < isGeneric:
|
if result < isGeneric: return isNone
|
||||||
result = isNone
|
if rangeHasStaticIf(fRange):
|
||||||
elif tfUnresolved in fRange.flags and
|
if tfUnresolved in fRange.flags:
|
||||||
rangeHasStaticIf(fRange):
|
# This is a range from an array instantiated with a generic
|
||||||
# This is a range from an array instantiated with a generic
|
# static param. We must extract the static param here and bind
|
||||||
# static param. We must extract the static param here and bind
|
# it to the size of the currently supplied array.
|
||||||
# it to the size of the currently supplied array.
|
var
|
||||||
var
|
rangeStaticT = fRange.getStaticTypeFromRange
|
||||||
rangeStaticT = fRange.getStaticTypeFromRange
|
replacementT = newTypeWithSons(c.c, tyStatic, @[tyInt.getSysType])
|
||||||
replacementT = newTypeWithSons(c.c, tyStatic, @[tyInt.getSysType])
|
inputUpperBound = a.sons[0].n[1].intVal
|
||||||
inputUpperBound = a.sons[0].n[1].intVal
|
# we must correct for the off-by-one discrepancy between
|
||||||
# we must correct for the off-by-one discrepancy between
|
# ranges and static params:
|
||||||
# ranges and static params:
|
replacementT.n = newIntNode(nkIntLit, inputUpperBound + 1)
|
||||||
replacementT.n = newIntNode(nkIntLit, inputUpperBound + 1)
|
put(c.bindings, rangeStaticT, replacementT)
|
||||||
put(c.bindings, rangeStaticT, replacementT)
|
return isGeneric
|
||||||
result = isGeneric
|
|
||||||
|
let len = tryResolvingStaticExpr(c, fRange.n[1])
|
||||||
|
if len.kind == nkIntLit and len.intVal+1 == lengthOrd(a):
|
||||||
|
return # if we get this far, the result is already good
|
||||||
|
else:
|
||||||
|
return isNone
|
||||||
elif lengthOrd(fRange) != lengthOrd(a):
|
elif lengthOrd(fRange) != lengthOrd(a):
|
||||||
result = isNone
|
result = isNone
|
||||||
else: discard
|
else: discard
|
||||||
|
|
@ -945,7 +972,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
else:
|
else:
|
||||||
internalAssert a.sons != nil and a.sons.len > 0
|
internalAssert a.sons != nil and a.sons.len > 0
|
||||||
c.typedescMatched = true
|
c.typedescMatched = true
|
||||||
result = typeRel(c, f.base, a.base)
|
result = typeRel(c, f.base, a.skipTypes({tyGenericParam, tyTypeDesc}))
|
||||||
else:
|
else:
|
||||||
result = isNone
|
result = isNone
|
||||||
else:
|
else:
|
||||||
|
|
@ -980,7 +1007,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
if aOrig.kind == tyStatic:
|
if aOrig.kind == tyStatic:
|
||||||
result = typeRel(c, f.lastSon, a)
|
result = typeRel(c, f.lastSon, a)
|
||||||
if result != isNone and f.n != nil:
|
if result != isNone and f.n != nil:
|
||||||
if not exprStructuralEquivalent(f.n, a.n):
|
if not exprStructuralEquivalent(f.n, aOrig.n):
|
||||||
result = isNone
|
result = isNone
|
||||||
if result != isNone: put(c.bindings, f, aOrig)
|
if result != isNone: put(c.bindings, f, aOrig)
|
||||||
else:
|
else:
|
||||||
|
|
@ -1058,7 +1085,7 @@ proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
|
||||||
c: PContext): PNode =
|
c: PContext): PNode =
|
||||||
result = newNodeI(kind, arg.info)
|
result = newNodeI(kind, arg.info)
|
||||||
if containsGenericType(f):
|
if containsGenericType(f):
|
||||||
if not m.proxyMatch:
|
if not m.hasFauxMatch:
|
||||||
result.typ = getInstantiatedType(c, arg, m, f)
|
result.typ = getInstantiatedType(c, arg, m, f)
|
||||||
else:
|
else:
|
||||||
result.typ = errorType(c)
|
result.typ = errorType(c)
|
||||||
|
|
@ -1144,7 +1171,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||||
return argSemantized
|
return argSemantized
|
||||||
|
|
||||||
if argType.kind == tyStatic:
|
if argType.kind == tyStatic:
|
||||||
if m.callee.kind == tyGenericBody:
|
if m.callee.kind == tyGenericBody and tfGenericTypeParam notin argType.flags:
|
||||||
result = newNodeI(nkType, argOrig.info)
|
result = newNodeI(nkType, argOrig.info)
|
||||||
result.typ = makeTypeFromExpr(c, arg)
|
result.typ = makeTypeFromExpr(c, arg)
|
||||||
return
|
return
|
||||||
|
|
@ -1237,9 +1264,9 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||||
of isNone:
|
of isNone:
|
||||||
# do not do this in ``typeRel`` as it then can't infere T in ``ref T``:
|
# do not do this in ``typeRel`` as it then can't infere T in ``ref T``:
|
||||||
if a.kind == tyProxy:
|
if a.kind in {tyProxy, tyUnknown}:
|
||||||
inc(m.genericMatches)
|
inc(m.genericMatches)
|
||||||
m.proxyMatch = true
|
m.fauxMatch = a.kind
|
||||||
return copyTree(arg)
|
return copyTree(arg)
|
||||||
result = userConvMatch(c, m, f, a, arg)
|
result = userConvMatch(c, m, f, a, arg)
|
||||||
# check for a base type match, which supports varargs[T] without []
|
# check for a base type match, which supports varargs[T] without []
|
||||||
|
|
|
||||||
|
|
@ -37,4 +37,4 @@ Options:
|
||||||
--advanced show advanced command line switches
|
--advanced show advanced command line switches
|
||||||
-h, --help show this help
|
-h, --help show this help
|
||||||
|
|
||||||
Note: Even single letter options require the colon: -p:PATH.
|
Note, single letter options that take an argument require a colon. E.g. -p:PATH.
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ The ``--usages`` idetools switch lists all usages of the symbol at
|
||||||
a position. IDEs can use this to find all the places in the file
|
a position. IDEs can use this to find all the places in the file
|
||||||
where the symbol is used and offer the user to rename it in all
|
where the symbol is used and offer the user to rename it in all
|
||||||
places at the same time. Again, a pure string based search and
|
places at the same time. Again, a pure string based search and
|
||||||
replace may catch symbols out of the scope of a funcion/loop.
|
replace may catch symbols out of the scope of a function/loop.
|
||||||
|
|
||||||
For this kind of query the IDE will most likely ignore all the
|
For this kind of query the IDE will most likely ignore all the
|
||||||
type/signature info provided by idetools and concentrate on the
|
type/signature info provided by idetools and concentrate on the
|
||||||
|
|
|
||||||
|
|
@ -390,7 +390,7 @@ string from a cstring:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
var str: string = "Hello!"
|
var str: string = "Hello!"
|
||||||
var cstr: cstring = s
|
var cstr: cstring = str
|
||||||
var newstr: string = $cstr
|
var newstr: string = $cstr
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,7 @@ Numbers
|
||||||
Numerical literals are written as in most other languages. As a special twist,
|
Numerical literals are written as in most other languages. As a special twist,
|
||||||
underscores are allowed for better readability: ``1_000_000`` (one million).
|
underscores are allowed for better readability: ``1_000_000`` (one million).
|
||||||
A number that contains a dot (or 'e' or 'E') is a floating point literal:
|
A number that contains a dot (or 'e' or 'E') is a floating point literal:
|
||||||
``1.0e9`` (one million). Hexadecimal literals are prefixed with ``0x``,
|
``1.0e9`` (one billion). Hexadecimal literals are prefixed with ``0x``,
|
||||||
binary literals with ``0b`` and octal literals with ``0o``. A leading zero
|
binary literals with ``0b`` and octal literals with ``0o``. A leading zero
|
||||||
alone does not produce an octal.
|
alone does not produce an octal.
|
||||||
|
|
||||||
|
|
@ -1070,7 +1070,7 @@ Operation Comment
|
||||||
``dec(x, n)`` decrements `x` by `n`; `n` is an integer
|
``dec(x, n)`` decrements `x` by `n`; `n` is an integer
|
||||||
``succ(x)`` returns the successor of `x`
|
``succ(x)`` returns the successor of `x`
|
||||||
``succ(x, n)`` returns the `n`'th successor of `x`
|
``succ(x, n)`` returns the `n`'th successor of `x`
|
||||||
``prec(x)`` returns the predecessor of `x`
|
``pred(x)`` returns the predecessor of `x`
|
||||||
``pred(x, n)`` returns the `n`'th predecessor of `x`
|
``pred(x, n)`` returns the `n`'th predecessor of `x`
|
||||||
----------------- --------------------------------------------------------
|
----------------- --------------------------------------------------------
|
||||||
|
|
||||||
|
|
@ -1323,7 +1323,7 @@ define operators which accept TSlice objects to define ranges.
|
||||||
a = "Nim is a progamming language"
|
a = "Nim is a progamming language"
|
||||||
b = "Slices are useless."
|
b = "Slices are useless."
|
||||||
|
|
||||||
echo a[10..15] # --> 'a prog'
|
echo a[7..12] # --> 'a prog'
|
||||||
b[11.. -2] = "useful"
|
b[11.. -2] = "useful"
|
||||||
echo b # --> 'Slices are useful.'
|
echo b # --> 'Slices are useful.'
|
||||||
|
|
||||||
|
|
|
||||||
14
doc/tut2.txt
14
doc/tut2.txt
|
|
@ -35,7 +35,7 @@ Object Oriented Programming
|
||||||
===========================
|
===========================
|
||||||
|
|
||||||
While Nim's support for object oriented programming (OOP) is minimalistic,
|
While Nim's support for object oriented programming (OOP) is minimalistic,
|
||||||
powerful OOP technics can be used. OOP is seen as *one* way to design a
|
powerful OOP techniques can be used. OOP is seen as *one* way to design a
|
||||||
program, not *the only* way. Often a procedural approach leads to simpler
|
program, not *the only* way. Often a procedural approach leads to simpler
|
||||||
and more efficient code. In particular, prefering composition over inheritance
|
and more efficient code. In particular, prefering composition over inheritance
|
||||||
is often the better design.
|
is often the better design.
|
||||||
|
|
@ -56,7 +56,7 @@ Objects have access to their type at runtime. There is an
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
type
|
type
|
||||||
TPerson = object of TObject
|
TPerson = object of RootObj
|
||||||
name*: string # the * means that `name` is accessible from other modules
|
name*: string # the * means that `name` is accessible from other modules
|
||||||
age: int # no * means that the field is hidden from other modules
|
age: int # no * means that the field is hidden from other modules
|
||||||
|
|
||||||
|
|
@ -76,10 +76,10 @@ never *equivalent*. New object types can only be defined within a type
|
||||||
section.
|
section.
|
||||||
|
|
||||||
Inheritance is done with the ``object of`` syntax. Multiple inheritance is
|
Inheritance is done with the ``object of`` syntax. Multiple inheritance is
|
||||||
currently not supported. If an object type has no suitable ancestor, ``TObject``
|
currently not supported. If an object type has no suitable ancestor, ``RootObj``
|
||||||
can be used as its ancestor, but this is only a convention. Objects that have
|
can be used as its ancestor, but this is only a convention. Objects that have
|
||||||
no ancestor are implicitly ``final``. You can use the ``inheritable`` pragma
|
no ancestor are implicitly ``final``. You can use the ``inheritable`` pragma
|
||||||
to introduce new object roots apart from ``system.TObject``. (This is used
|
to introduce new object roots apart from ``system.RootObj``. (This is used
|
||||||
in the GTK wrapper for instance.)
|
in the GTK wrapper for instance.)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -228,7 +228,7 @@ is needed:
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
|
|
||||||
type
|
type
|
||||||
TSocket* = object of TObject
|
TSocket* = object of RootObj
|
||||||
FHost: int # cannot be accessed from the outside of the module
|
FHost: int # cannot be accessed from the outside of the module
|
||||||
# the `F` prefix is a convention to avoid clashes since
|
# the `F` prefix is a convention to avoid clashes since
|
||||||
# the accessors are named `host`
|
# the accessors are named `host`
|
||||||
|
|
@ -284,7 +284,7 @@ Procedures always use static dispatch. For dynamic dispatch replace the
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
type
|
type
|
||||||
PExpr = ref object of TObject ## abstract base class for an expression
|
PExpr = ref object of RootObj ## abstract base class for an expression
|
||||||
PLiteral = ref object of PExpr
|
PLiteral = ref object of PExpr
|
||||||
x: int
|
x: int
|
||||||
PPlusExpr = ref object of PExpr
|
PPlusExpr = ref object of PExpr
|
||||||
|
|
@ -313,7 +313,7 @@ dispatching:
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
|
|
||||||
type
|
type
|
||||||
TThing = object of TObject
|
TThing = object of RootObj
|
||||||
TUnit = object of TThing
|
TUnit = object of TThing
|
||||||
x: int
|
x: int
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@
|
||||||
## as the response body.
|
## as the response body.
|
||||||
##
|
##
|
||||||
## .. code-block::nim
|
## .. code-block::nim
|
||||||
|
## import asynchttpserver, asyncdispatch
|
||||||
|
##
|
||||||
## var server = newAsyncHttpServer()
|
## var server = newAsyncHttpServer()
|
||||||
## proc cb(req: Request) {.async.} =
|
## proc cb(req: Request) {.async.} =
|
||||||
## await req.respond(Http200, "Hello World")
|
## await req.respond(Http200, "Hello World")
|
||||||
|
|
|
||||||
|
|
@ -294,7 +294,9 @@ proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
|
||||||
var r = if proxy == nil: parseUri(url) else: proxy.url
|
var r = if proxy == nil: parseUri(url) else: proxy.url
|
||||||
var headers = substr($httpMethod, len("http"))
|
var headers = substr($httpMethod, len("http"))
|
||||||
if proxy == nil:
|
if proxy == nil:
|
||||||
headers.add(" /" & r.path & r.query)
|
headers.add(" " & r.path)
|
||||||
|
if r.query.len > 0:
|
||||||
|
headers.add("?" & r.query)
|
||||||
else:
|
else:
|
||||||
headers.add(" " & url)
|
headers.add(" " & url)
|
||||||
|
|
||||||
|
|
@ -442,7 +444,9 @@ proc generateHeaders(r: Uri, httpMethod: HttpMethod,
|
||||||
headers: StringTableRef): string =
|
headers: StringTableRef): string =
|
||||||
result = substr($httpMethod, len("http"))
|
result = substr($httpMethod, len("http"))
|
||||||
# TODO: Proxies
|
# TODO: Proxies
|
||||||
result.add(" /" & r.path & r.query)
|
result.add(" " & r.path)
|
||||||
|
if r.query.len > 0:
|
||||||
|
result.add("?" & r.query)
|
||||||
result.add(" HTTP/1.1\c\L")
|
result.add(" HTTP/1.1\c\L")
|
||||||
|
|
||||||
add(result, "Host: " & r.hostname & "\c\L")
|
add(result, "Host: " & r.hostname & "\c\L")
|
||||||
|
|
|
||||||
228
lib/pure/md5.nim
228
lib/pure/md5.nim
|
|
@ -9,15 +9,17 @@
|
||||||
|
|
||||||
## Module for computing MD5 checksums.
|
## Module for computing MD5 checksums.
|
||||||
|
|
||||||
|
import unsigned
|
||||||
|
|
||||||
type
|
type
|
||||||
MD5State = array[0..3, int32]
|
MD5State = array[0..3, uint32]
|
||||||
MD5Block = array[0..15, int32]
|
MD5Block = array[0..15, uint32]
|
||||||
MD5CBits = array[0..7, int8]
|
MD5CBits = array[0..7, uint8]
|
||||||
MD5Digest* = array[0..15, int8]
|
MD5Digest* = array[0..15, uint8]
|
||||||
MD5Buffer = array[0..63, int8]
|
MD5Buffer = array[0..63, uint8]
|
||||||
MD5Context* {.final.} = object
|
MD5Context* {.final.} = object
|
||||||
state: MD5State
|
state: MD5State
|
||||||
count: array[0..1, int32]
|
count: array[0..1, uint32]
|
||||||
buffer: MD5Buffer
|
buffer: MD5Buffer
|
||||||
|
|
||||||
const
|
const
|
||||||
|
|
@ -31,57 +33,57 @@ const
|
||||||
"\0\0\0\0\0\0\0\0" &
|
"\0\0\0\0\0\0\0\0" &
|
||||||
"\0\0\0\0"
|
"\0\0\0\0"
|
||||||
|
|
||||||
proc F(x, y, z: int32): int32 {.inline.} =
|
proc F(x, y, z: uint32): uint32 {.inline.} =
|
||||||
result = (x and y) or ((not x) and z)
|
result = (x and y) or ((not x) and z)
|
||||||
|
|
||||||
proc G(x, y, z: int32): int32 {.inline.} =
|
proc G(x, y, z: uint32): uint32 {.inline.} =
|
||||||
result = (x and z) or (y and (not z))
|
result = (x and z) or (y and (not z))
|
||||||
|
|
||||||
proc H(x, y, z: int32): int32 {.inline.} =
|
proc H(x, y, z: uint32): uint32 {.inline.} =
|
||||||
result = x xor y xor z
|
result = x xor y xor z
|
||||||
|
|
||||||
proc I(x, y, z: int32): int32 {.inline.} =
|
proc I(x, y, z: uint32): uint32 {.inline.} =
|
||||||
result = y xor (x or (not z))
|
result = y xor (x or (not z))
|
||||||
|
|
||||||
proc rot(x: var int32, n: int8) {.inline.} =
|
proc rot(x: var uint32, n: uint8) {.inline.} =
|
||||||
x = toU32(x shl ze(n)) or (x shr toU32(32 -% ze(n)))
|
x = (x shl n) or (x shr (32'u32 - n))
|
||||||
|
|
||||||
proc FF(a: var int32, b, c, d, x: int32, s: int8, ac: int32) =
|
proc FF(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
|
||||||
a = a +% F(b, c, d) +% x +% ac
|
a = a + F(b, c, d) + x + ac
|
||||||
rot(a, s)
|
rot(a, s)
|
||||||
a = a +% b
|
a = a + b
|
||||||
|
|
||||||
proc GG(a: var int32, b, c, d, x: int32, s: int8, ac: int32) =
|
proc GG(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
|
||||||
a = a +% G(b, c, d) +% x +% ac
|
a = a + G(b, c, d) + x + ac
|
||||||
rot(a, s)
|
rot(a, s)
|
||||||
a = a +% b
|
a = a + b
|
||||||
|
|
||||||
proc HH(a: var int32, b, c, d, x: int32, s: int8, ac: int32) =
|
proc HH(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
|
||||||
a = a +% H(b, c, d) +% x +% ac
|
a = a + H(b, c, d) + x + ac
|
||||||
rot(a, s)
|
rot(a, s)
|
||||||
a = a +% b
|
a = a + b
|
||||||
|
|
||||||
proc II(a: var int32, b, c, d, x: int32, s: int8, ac: int32) =
|
proc II(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
|
||||||
a = a +% I(b, c, d) +% x +% ac
|
a = a + I(b, c, d) + x + ac
|
||||||
rot(a, s)
|
rot(a, s)
|
||||||
a = a +% b
|
a = a + b
|
||||||
|
|
||||||
proc encode(dest: var MD5Block, src: cstring) =
|
proc encode(dest: var MD5Block, src: cstring) =
|
||||||
var j = 0
|
var j = 0
|
||||||
for i in 0..high(dest):
|
for i in 0..high(dest):
|
||||||
dest[i] = toU32(ord(src[j]) or
|
dest[i] = uint32(ord(src[j])) or
|
||||||
ord(src[j+1]) shl 8 or
|
uint32(ord(src[j+1])) shl 8 or
|
||||||
ord(src[j+2]) shl 16 or
|
uint32(ord(src[j+2])) shl 16 or
|
||||||
ord(src[j+3]) shl 24)
|
uint32(ord(src[j+3])) shl 24
|
||||||
inc(j, 4)
|
inc(j, 4)
|
||||||
|
|
||||||
proc decode(dest: var openArray[int8], src: openArray[int32]) =
|
proc decode(dest: var openArray[uint8], src: openArray[uint32]) =
|
||||||
var i = 0
|
var i = 0
|
||||||
for j in 0..high(src):
|
for j in 0..high(src):
|
||||||
dest[i] = toU8(src[j] and 0xff'i32)
|
dest[i] = src[j] and 0xff'u32
|
||||||
dest[i+1] = toU8(src[j] shr 8'i32 and 0xff'i32)
|
dest[i+1] = src[j] shr 8 and 0xff'u32
|
||||||
dest[i+2] = toU8(src[j] shr 16'i32 and 0xff'i32)
|
dest[i+2] = src[j] shr 16 and 0xff'u32
|
||||||
dest[i+3] = toU8(src[j] shr 24'i32 and 0xff'i32)
|
dest[i+3] = src[j] shr 24 and 0xff'u32
|
||||||
inc(i, 4)
|
inc(i, 4)
|
||||||
|
|
||||||
proc transform(buffer: pointer, state: var MD5State) =
|
proc transform(buffer: pointer, state: var MD5State) =
|
||||||
|
|
@ -92,92 +94,92 @@ proc transform(buffer: pointer, state: var MD5State) =
|
||||||
var b = state[1]
|
var b = state[1]
|
||||||
var c = state[2]
|
var c = state[2]
|
||||||
var d = state[3]
|
var d = state[3]
|
||||||
FF(a, b, c, d, myBlock[0], 7'i8, 0xD76AA478'i32)
|
FF(a, b, c, d, myBlock[0], 7'u8, 0xD76AA478'u32)
|
||||||
FF(d, a, b, c, myBlock[1], 12'i8, 0xE8C7B756'i32)
|
FF(d, a, b, c, myBlock[1], 12'u8, 0xE8C7B756'u32)
|
||||||
FF(c, d, a, b, myBlock[2], 17'i8, 0x242070DB'i32)
|
FF(c, d, a, b, myBlock[2], 17'u8, 0x242070DB'u32)
|
||||||
FF(b, c, d, a, myBlock[3], 22'i8, 0xC1BDCEEE'i32)
|
FF(b, c, d, a, myBlock[3], 22'u8, 0xC1BDCEEE'u32)
|
||||||
FF(a, b, c, d, myBlock[4], 7'i8, 0xF57C0FAF'i32)
|
FF(a, b, c, d, myBlock[4], 7'u8, 0xF57C0FAF'u32)
|
||||||
FF(d, a, b, c, myBlock[5], 12'i8, 0x4787C62A'i32)
|
FF(d, a, b, c, myBlock[5], 12'u8, 0x4787C62A'u32)
|
||||||
FF(c, d, a, b, myBlock[6], 17'i8, 0xA8304613'i32)
|
FF(c, d, a, b, myBlock[6], 17'u8, 0xA8304613'u32)
|
||||||
FF(b, c, d, a, myBlock[7], 22'i8, 0xFD469501'i32)
|
FF(b, c, d, a, myBlock[7], 22'u8, 0xFD469501'u32)
|
||||||
FF(a, b, c, d, myBlock[8], 7'i8, 0x698098D8'i32)
|
FF(a, b, c, d, myBlock[8], 7'u8, 0x698098D8'u32)
|
||||||
FF(d, a, b, c, myBlock[9], 12'i8, 0x8B44F7AF'i32)
|
FF(d, a, b, c, myBlock[9], 12'u8, 0x8B44F7AF'u32)
|
||||||
FF(c, d, a, b, myBlock[10], 17'i8, 0xFFFF5BB1'i32)
|
FF(c, d, a, b, myBlock[10], 17'u8, 0xFFFF5BB1'u32)
|
||||||
FF(b, c, d, a, myBlock[11], 22'i8, 0x895CD7BE'i32)
|
FF(b, c, d, a, myBlock[11], 22'u8, 0x895CD7BE'u32)
|
||||||
FF(a, b, c, d, myBlock[12], 7'i8, 0x6B901122'i32)
|
FF(a, b, c, d, myBlock[12], 7'u8, 0x6B901122'u32)
|
||||||
FF(d, a, b, c, myBlock[13], 12'i8, 0xFD987193'i32)
|
FF(d, a, b, c, myBlock[13], 12'u8, 0xFD987193'u32)
|
||||||
FF(c, d, a, b, myBlock[14], 17'i8, 0xA679438E'i32)
|
FF(c, d, a, b, myBlock[14], 17'u8, 0xA679438E'u32)
|
||||||
FF(b, c, d, a, myBlock[15], 22'i8, 0x49B40821'i32)
|
FF(b, c, d, a, myBlock[15], 22'u8, 0x49B40821'u32)
|
||||||
GG(a, b, c, d, myBlock[1], 5'i8, 0xF61E2562'i32)
|
GG(a, b, c, d, myBlock[1], 5'u8, 0xF61E2562'u32)
|
||||||
GG(d, a, b, c, myBlock[6], 9'i8, 0xC040B340'i32)
|
GG(d, a, b, c, myBlock[6], 9'u8, 0xC040B340'u32)
|
||||||
GG(c, d, a, b, myBlock[11], 14'i8, 0x265E5A51'i32)
|
GG(c, d, a, b, myBlock[11], 14'u8, 0x265E5A51'u32)
|
||||||
GG(b, c, d, a, myBlock[0], 20'i8, 0xE9B6C7AA'i32)
|
GG(b, c, d, a, myBlock[0], 20'u8, 0xE9B6C7AA'u32)
|
||||||
GG(a, b, c, d, myBlock[5], 5'i8, 0xD62F105D'i32)
|
GG(a, b, c, d, myBlock[5], 5'u8, 0xD62F105D'u32)
|
||||||
GG(d, a, b, c, myBlock[10], 9'i8, 0x02441453'i32)
|
GG(d, a, b, c, myBlock[10], 9'u8, 0x02441453'u32)
|
||||||
GG(c, d, a, b, myBlock[15], 14'i8, 0xD8A1E681'i32)
|
GG(c, d, a, b, myBlock[15], 14'u8, 0xD8A1E681'u32)
|
||||||
GG(b, c, d, a, myBlock[4], 20'i8, 0xE7D3FBC8'i32)
|
GG(b, c, d, a, myBlock[4], 20'u8, 0xE7D3FBC8'u32)
|
||||||
GG(a, b, c, d, myBlock[9], 5'i8, 0x21E1CDE6'i32)
|
GG(a, b, c, d, myBlock[9], 5'u8, 0x21E1CDE6'u32)
|
||||||
GG(d, a, b, c, myBlock[14], 9'i8, 0xC33707D6'i32)
|
GG(d, a, b, c, myBlock[14], 9'u8, 0xC33707D6'u32)
|
||||||
GG(c, d, a, b, myBlock[3], 14'i8, 0xF4D50D87'i32)
|
GG(c, d, a, b, myBlock[3], 14'u8, 0xF4D50D87'u32)
|
||||||
GG(b, c, d, a, myBlock[8], 20'i8, 0x455A14ED'i32)
|
GG(b, c, d, a, myBlock[8], 20'u8, 0x455A14ED'u32)
|
||||||
GG(a, b, c, d, myBlock[13], 5'i8, 0xA9E3E905'i32)
|
GG(a, b, c, d, myBlock[13], 5'u8, 0xA9E3E905'u32)
|
||||||
GG(d, a, b, c, myBlock[2], 9'i8, 0xFCEFA3F8'i32)
|
GG(d, a, b, c, myBlock[2], 9'u8, 0xFCEFA3F8'u32)
|
||||||
GG(c, d, a, b, myBlock[7], 14'i8, 0x676F02D9'i32)
|
GG(c, d, a, b, myBlock[7], 14'u8, 0x676F02D9'u32)
|
||||||
GG(b, c, d, a, myBlock[12], 20'i8, 0x8D2A4C8A'i32)
|
GG(b, c, d, a, myBlock[12], 20'u8, 0x8D2A4C8A'u32)
|
||||||
HH(a, b, c, d, myBlock[5], 4'i8, 0xFFFA3942'i32)
|
HH(a, b, c, d, myBlock[5], 4'u8, 0xFFFA3942'u32)
|
||||||
HH(d, a, b, c, myBlock[8], 11'i8, 0x8771F681'i32)
|
HH(d, a, b, c, myBlock[8], 11'u8, 0x8771F681'u32)
|
||||||
HH(c, d, a, b, myBlock[11], 16'i8, 0x6D9D6122'i32)
|
HH(c, d, a, b, myBlock[11], 16'u8, 0x6D9D6122'u32)
|
||||||
HH(b, c, d, a, myBlock[14], 23'i8, 0xFDE5380C'i32)
|
HH(b, c, d, a, myBlock[14], 23'u8, 0xFDE5380C'u32)
|
||||||
HH(a, b, c, d, myBlock[1], 4'i8, 0xA4BEEA44'i32)
|
HH(a, b, c, d, myBlock[1], 4'u8, 0xA4BEEA44'u32)
|
||||||
HH(d, a, b, c, myBlock[4], 11'i8, 0x4BDECFA9'i32)
|
HH(d, a, b, c, myBlock[4], 11'u8, 0x4BDECFA9'u32)
|
||||||
HH(c, d, a, b, myBlock[7], 16'i8, 0xF6BB4B60'i32)
|
HH(c, d, a, b, myBlock[7], 16'u8, 0xF6BB4B60'u32)
|
||||||
HH(b, c, d, a, myBlock[10], 23'i8, 0xBEBFBC70'i32)
|
HH(b, c, d, a, myBlock[10], 23'u8, 0xBEBFBC70'u32)
|
||||||
HH(a, b, c, d, myBlock[13], 4'i8, 0x289B7EC6'i32)
|
HH(a, b, c, d, myBlock[13], 4'u8, 0x289B7EC6'u32)
|
||||||
HH(d, a, b, c, myBlock[0], 11'i8, 0xEAA127FA'i32)
|
HH(d, a, b, c, myBlock[0], 11'u8, 0xEAA127FA'u32)
|
||||||
HH(c, d, a, b, myBlock[3], 16'i8, 0xD4EF3085'i32)
|
HH(c, d, a, b, myBlock[3], 16'u8, 0xD4EF3085'u32)
|
||||||
HH(b, c, d, a, myBlock[6], 23'i8, 0x04881D05'i32)
|
HH(b, c, d, a, myBlock[6], 23'u8, 0x04881D05'u32)
|
||||||
HH(a, b, c, d, myBlock[9], 4'i8, 0xD9D4D039'i32)
|
HH(a, b, c, d, myBlock[9], 4'u8, 0xD9D4D039'u32)
|
||||||
HH(d, a, b, c, myBlock[12], 11'i8, 0xE6DB99E5'i32)
|
HH(d, a, b, c, myBlock[12], 11'u8, 0xE6DB99E5'u32)
|
||||||
HH(c, d, a, b, myBlock[15], 16'i8, 0x1FA27CF8'i32)
|
HH(c, d, a, b, myBlock[15], 16'u8, 0x1FA27CF8'u32)
|
||||||
HH(b, c, d, a, myBlock[2], 23'i8, 0xC4AC5665'i32)
|
HH(b, c, d, a, myBlock[2], 23'u8, 0xC4AC5665'u32)
|
||||||
II(a, b, c, d, myBlock[0], 6'i8, 0xF4292244'i32)
|
II(a, b, c, d, myBlock[0], 6'u8, 0xF4292244'u32)
|
||||||
II(d, a, b, c, myBlock[7], 10'i8, 0x432AFF97'i32)
|
II(d, a, b, c, myBlock[7], 10'u8, 0x432AFF97'u32)
|
||||||
II(c, d, a, b, myBlock[14], 15'i8, 0xAB9423A7'i32)
|
II(c, d, a, b, myBlock[14], 15'u8, 0xAB9423A7'u32)
|
||||||
II(b, c, d, a, myBlock[5], 21'i8, 0xFC93A039'i32)
|
II(b, c, d, a, myBlock[5], 21'u8, 0xFC93A039'u32)
|
||||||
II(a, b, c, d, myBlock[12], 6'i8, 0x655B59C3'i32)
|
II(a, b, c, d, myBlock[12], 6'u8, 0x655B59C3'u32)
|
||||||
II(d, a, b, c, myBlock[3], 10'i8, 0x8F0CCC92'i32)
|
II(d, a, b, c, myBlock[3], 10'u8, 0x8F0CCC92'u32)
|
||||||
II(c, d, a, b, myBlock[10], 15'i8, 0xFFEFF47D'i32)
|
II(c, d, a, b, myBlock[10], 15'u8, 0xFFEFF47D'u32)
|
||||||
II(b, c, d, a, myBlock[1], 21'i8, 0x85845DD1'i32)
|
II(b, c, d, a, myBlock[1], 21'u8, 0x85845DD1'u32)
|
||||||
II(a, b, c, d, myBlock[8], 6'i8, 0x6FA87E4F'i32)
|
II(a, b, c, d, myBlock[8], 6'u8, 0x6FA87E4F'u32)
|
||||||
II(d, a, b, c, myBlock[15], 10'i8, 0xFE2CE6E0'i32)
|
II(d, a, b, c, myBlock[15], 10'u8, 0xFE2CE6E0'u32)
|
||||||
II(c, d, a, b, myBlock[6], 15'i8, 0xA3014314'i32)
|
II(c, d, a, b, myBlock[6], 15'u8, 0xA3014314'u32)
|
||||||
II(b, c, d, a, myBlock[13], 21'i8, 0x4E0811A1'i32)
|
II(b, c, d, a, myBlock[13], 21'u8, 0x4E0811A1'u32)
|
||||||
II(a, b, c, d, myBlock[4], 6'i8, 0xF7537E82'i32)
|
II(a, b, c, d, myBlock[4], 6'u8, 0xF7537E82'u32)
|
||||||
II(d, a, b, c, myBlock[11], 10'i8, 0xBD3AF235'i32)
|
II(d, a, b, c, myBlock[11], 10'u8, 0xBD3AF235'u32)
|
||||||
II(c, d, a, b, myBlock[2], 15'i8, 0x2AD7D2BB'i32)
|
II(c, d, a, b, myBlock[2], 15'u8, 0x2AD7D2BB'u32)
|
||||||
II(b, c, d, a, myBlock[9], 21'i8, 0xEB86D391'i32)
|
II(b, c, d, a, myBlock[9], 21'u8, 0xEB86D391'u32)
|
||||||
state[0] = state[0] +% a
|
state[0] = state[0] + a
|
||||||
state[1] = state[1] +% b
|
state[1] = state[1] + b
|
||||||
state[2] = state[2] +% c
|
state[2] = state[2] + c
|
||||||
state[3] = state[3] +% d
|
state[3] = state[3] + d
|
||||||
|
|
||||||
proc md5Init*(c: var MD5Context) =
|
proc md5Init*(c: var MD5Context) =
|
||||||
## initializes a MD5Context
|
## initializes a MD5Context
|
||||||
c.state[0] = 0x67452301'i32
|
c.state[0] = 0x67452301'u32
|
||||||
c.state[1] = 0xEFCDAB89'i32
|
c.state[1] = 0xEFCDAB89'u32
|
||||||
c.state[2] = 0x98BADCFE'i32
|
c.state[2] = 0x98BADCFE'u32
|
||||||
c.state[3] = 0x10325476'i32
|
c.state[3] = 0x10325476'u32
|
||||||
c.count[0] = 0'i32
|
c.count[0] = 0'u32
|
||||||
c.count[1] = 0'i32
|
c.count[1] = 0'u32
|
||||||
zeroMem(addr(c.buffer), sizeof(MD5buffer))
|
zeroMem(addr(c.buffer), sizeof(MD5buffer))
|
||||||
|
|
||||||
proc md5Update*(c: var MD5Context, input: cstring, len: int) =
|
proc md5Update*(c: var MD5Context, input: cstring, len: int) =
|
||||||
## updates the MD5Context with the `input` data of length `len`
|
## updates the MD5Context with the `input` data of length `len`
|
||||||
var input = input
|
var input = input
|
||||||
var Index = (c.count[0] shr 3) and 0x3F
|
var Index = int((c.count[0] shr 3) and 0x3F)
|
||||||
c.count[0] = c.count[0] +% toU32(len shl 3)
|
c.count[0] = c.count[0] + (uint32(len) shl 3)
|
||||||
if c.count[0] < (len shl 3): c.count[1] = c.count[1] +% 1'i32
|
if c.count[0] < (uint32(len) shl 3): c.count[1] = c.count[1] + 1'u32
|
||||||
c.count[1] = c.count[1] +% toU32(len shr 29)
|
c.count[1] = c.count[1] + (uint32(len) shr 29)
|
||||||
var PartLen = 64 - Index
|
var PartLen = 64 - Index
|
||||||
if len >= PartLen:
|
if len >= PartLen:
|
||||||
copyMem(addr(c.buffer[Index]), input, PartLen)
|
copyMem(addr(c.buffer[Index]), input, PartLen)
|
||||||
|
|
@ -196,7 +198,7 @@ proc md5Final*(c: var MD5Context, digest: var MD5Digest) =
|
||||||
Bits: MD5CBits
|
Bits: MD5CBits
|
||||||
PadLen: int
|
PadLen: int
|
||||||
decode(Bits, c.count)
|
decode(Bits, c.count)
|
||||||
var Index = (c.count[0] shr 3) and 0x3F
|
var Index = int((c.count[0] shr 3) and 0x3F)
|
||||||
if Index < 56: PadLen = 56 - Index
|
if Index < 56: PadLen = 56 - Index
|
||||||
else: PadLen = 120 - Index
|
else: PadLen = 120 - Index
|
||||||
md5Update(c, padding, PadLen)
|
md5Update(c, padding, PadLen)
|
||||||
|
|
@ -241,5 +243,3 @@ when isMainModule:
|
||||||
assert(getMD5("Frank jagt im komplett verwahrlosten Taxi quer durch Bayern") ==
|
assert(getMD5("Frank jagt im komplett verwahrlosten Taxi quer durch Bayern") ==
|
||||||
"7e716d0e702df0505fc72e2b89467910")
|
"7e716d0e702df0505fc72e2b89467910")
|
||||||
assert($toMD5("") == "d41d8cd98f00b204e9800998ecf8427e")
|
assert($toMD5("") == "d41d8cd98f00b204e9800998ecf8427e")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ type
|
||||||
Uri* = object
|
Uri* = object
|
||||||
scheme*, username*, password*: string
|
scheme*, username*, password*: string
|
||||||
hostname*, port*, path*, query*, anchor*: string
|
hostname*, port*, path*, query*, anchor*: string
|
||||||
|
opaque*: bool
|
||||||
|
|
||||||
{.deprecated: [TUrl: Url, TUri: Uri].}
|
{.deprecated: [TUrl: Url, TUri: Uri].}
|
||||||
|
|
||||||
|
|
@ -115,6 +116,8 @@ proc parseUri*(uri: string): Uri =
|
||||||
if authority == "":
|
if authority == "":
|
||||||
raise newException(ValueError, "Expected authority got nothing.")
|
raise newException(ValueError, "Expected authority got nothing.")
|
||||||
parseAuthority(authority, result)
|
parseAuthority(authority, result)
|
||||||
|
else:
|
||||||
|
result.opaque = true
|
||||||
|
|
||||||
# Path
|
# Path
|
||||||
parsePath(uri, i, result)
|
parsePath(uri, i, result)
|
||||||
|
|
@ -256,7 +259,10 @@ proc `$`*(u: Uri): string =
|
||||||
result = ""
|
result = ""
|
||||||
if u.scheme.len > 0:
|
if u.scheme.len > 0:
|
||||||
result.add(u.scheme)
|
result.add(u.scheme)
|
||||||
result.add("://")
|
if u.opaque:
|
||||||
|
result.add(":")
|
||||||
|
else:
|
||||||
|
result.add("://")
|
||||||
if u.username.len > 0:
|
if u.username.len > 0:
|
||||||
result.add(u.username)
|
result.add(u.username)
|
||||||
if u.password.len > 0:
|
if u.password.len > 0:
|
||||||
|
|
@ -268,22 +274,28 @@ proc `$`*(u: Uri): string =
|
||||||
result.add(":")
|
result.add(":")
|
||||||
result.add(u.port)
|
result.add(u.port)
|
||||||
if u.path.len > 0:
|
if u.path.len > 0:
|
||||||
if u.path[0] != '/': result.add("/")
|
|
||||||
result.add(u.path)
|
result.add(u.path)
|
||||||
result.add(u.query)
|
if u.query.len > 0:
|
||||||
result.add(u.anchor)
|
result.add("?")
|
||||||
|
result.add(u.query)
|
||||||
|
if u.anchor.len > 0:
|
||||||
|
result.add("#")
|
||||||
|
result.add(u.anchor)
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
block:
|
block:
|
||||||
let test = parseUri("http://localhost:8080/test")
|
let str = "http://localhost:8080/test"
|
||||||
|
let test = parseUri(str)
|
||||||
doAssert test.scheme == "http"
|
doAssert test.scheme == "http"
|
||||||
doAssert test.port == "8080"
|
doAssert test.port == "8080"
|
||||||
doAssert test.path == "/test"
|
doAssert test.path == "/test"
|
||||||
doAssert test.hostname == "localhost"
|
doAssert test.hostname == "localhost"
|
||||||
|
doAssert($test == str)
|
||||||
|
|
||||||
block:
|
block:
|
||||||
let test = parseUri("foo://username:password@example.com:8042/over/there" &
|
let str = "foo://username:password@example.com:8042/over/there" &
|
||||||
"/index.dtb?type=animal&name=narwhal#nose")
|
"/index.dtb?type=animal&name=narwhal#nose"
|
||||||
|
let test = parseUri(str)
|
||||||
doAssert test.scheme == "foo"
|
doAssert test.scheme == "foo"
|
||||||
doAssert test.username == "username"
|
doAssert test.username == "username"
|
||||||
doAssert test.password == "password"
|
doAssert test.password == "password"
|
||||||
|
|
@ -292,34 +304,45 @@ when isMainModule:
|
||||||
doAssert test.path == "/over/there/index.dtb"
|
doAssert test.path == "/over/there/index.dtb"
|
||||||
doAssert test.query == "type=animal&name=narwhal"
|
doAssert test.query == "type=animal&name=narwhal"
|
||||||
doAssert test.anchor == "nose"
|
doAssert test.anchor == "nose"
|
||||||
|
doAssert($test == str)
|
||||||
|
|
||||||
block:
|
block:
|
||||||
let test = parseUri("urn:example:animal:ferret:nose")
|
let str = "urn:example:animal:ferret:nose"
|
||||||
|
let test = parseUri(str)
|
||||||
doAssert test.scheme == "urn"
|
doAssert test.scheme == "urn"
|
||||||
doAssert test.path == "example:animal:ferret:nose"
|
doAssert test.path == "example:animal:ferret:nose"
|
||||||
|
doAssert($test == str)
|
||||||
|
|
||||||
block:
|
block:
|
||||||
let test = parseUri("mailto:username@example.com?subject=Topic")
|
let str = "mailto:username@example.com?subject=Topic"
|
||||||
|
let test = parseUri(str)
|
||||||
doAssert test.scheme == "mailto"
|
doAssert test.scheme == "mailto"
|
||||||
doAssert test.username == "username"
|
doAssert test.username == "username"
|
||||||
doAssert test.hostname == "example.com"
|
doAssert test.hostname == "example.com"
|
||||||
doAssert test.query == "subject=Topic"
|
doAssert test.query == "subject=Topic"
|
||||||
|
doAssert($test == str)
|
||||||
|
|
||||||
block:
|
block:
|
||||||
let test = parseUri("magnet:?xt=urn:sha1:72hsga62ba515sbd62&dn=foobar")
|
let str = "magnet:?xt=urn:sha1:72hsga62ba515sbd62&dn=foobar"
|
||||||
|
let test = parseUri(str)
|
||||||
doAssert test.scheme == "magnet"
|
doAssert test.scheme == "magnet"
|
||||||
doAssert test.query == "xt=urn:sha1:72hsga62ba515sbd62&dn=foobar"
|
doAssert test.query == "xt=urn:sha1:72hsga62ba515sbd62&dn=foobar"
|
||||||
|
doAssert($test == str)
|
||||||
|
|
||||||
block:
|
block:
|
||||||
let test = parseUri("/test/foo/bar?q=2#asdf")
|
let str = "/test/foo/bar?q=2#asdf"
|
||||||
|
let test = parseUri(str)
|
||||||
doAssert test.scheme == ""
|
doAssert test.scheme == ""
|
||||||
doAssert test.path == "/test/foo/bar"
|
doAssert test.path == "/test/foo/bar"
|
||||||
doAssert test.query == "q=2"
|
doAssert test.query == "q=2"
|
||||||
doAssert test.anchor == "asdf"
|
doAssert test.anchor == "asdf"
|
||||||
|
doAssert($test == str)
|
||||||
|
|
||||||
block:
|
block:
|
||||||
let test = parseUri("test/no/slash")
|
let str = "test/no/slash"
|
||||||
|
let test = parseUri(str)
|
||||||
doAssert test.path == "test/no/slash"
|
doAssert test.path == "test/no/slash"
|
||||||
|
doAssert($test == str)
|
||||||
|
|
||||||
# Remove dot segments tests
|
# Remove dot segments tests
|
||||||
block:
|
block:
|
||||||
|
|
@ -371,5 +394,3 @@ when isMainModule:
|
||||||
block:
|
block:
|
||||||
let test = parseUri("http://example.com/foo/") / "/bar/asd"
|
let test = parseUri("http://example.com/foo/") / "/bar/asd"
|
||||||
doAssert test.path == "/foo/bar/asd"
|
doAssert test.path == "/foo/bar/asd"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -233,8 +233,9 @@ proc tryRecv*[TMsg](c: var TChannel[TMsg]): tuple[dataAvailable: bool,
|
||||||
var q = cast[PRawChannel](addr(c))
|
var q = cast[PRawChannel](addr(c))
|
||||||
if q.mask != ChannelDeadMask:
|
if q.mask != ChannelDeadMask:
|
||||||
if tryAcquireSys(q.lock):
|
if tryAcquireSys(q.lock):
|
||||||
llRecv(q, addr(result.msg), cast[PNimType](getTypeInfo(result.msg)))
|
if q.count > 0:
|
||||||
result.dataAvailable = true
|
llRecv(q, addr(result.msg), cast[PNimType](getTypeInfo(result.msg)))
|
||||||
|
result.dataAvailable = true
|
||||||
releaseSys(q.lock)
|
releaseSys(q.lock)
|
||||||
|
|
||||||
proc peek*[TMsg](c: var TChannel[TMsg]): int =
|
proc peek*[TMsg](c: var TChannel[TMsg]): int =
|
||||||
|
|
|
||||||
16
tests/generics/t1050.nim
Normal file
16
tests/generics/t1050.nim
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
discard """
|
||||||
|
msg: "int"
|
||||||
|
output: "4"
|
||||||
|
"""
|
||||||
|
|
||||||
|
import typetraits
|
||||||
|
|
||||||
|
type ArrayType[T] = distinct T
|
||||||
|
|
||||||
|
proc arrayItem(a: ArrayType): auto =
|
||||||
|
static: echo(name(type(a).T))
|
||||||
|
result = (type(a).T)(4)
|
||||||
|
|
||||||
|
var arr: ArrayType[int]
|
||||||
|
echo arrayItem(arr)
|
||||||
|
|
||||||
|
|
@ -1,9 +1,15 @@
|
||||||
discard """
|
discard """
|
||||||
msg: "static 10\ndynamic\nstatic 20\n"
|
msg: "static 10\ndynamic\nstatic 20\n"
|
||||||
output: "s\nd\nd\ns"
|
output: "s\nd\nd\ns"
|
||||||
disabled: "true"
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
type
|
||||||
|
semistatic[T] =
|
||||||
|
static[T] or T
|
||||||
|
|
||||||
|
template isStatic*(x): expr =
|
||||||
|
compiles(static(x))
|
||||||
|
|
||||||
proc foo(x: semistatic[int]) =
|
proc foo(x: semistatic[int]) =
|
||||||
when isStatic(x):
|
when isStatic(x):
|
||||||
static: echo "static ", x
|
static: echo "static ", x
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
discard """
|
discard """
|
||||||
file: "tstaticparams.nim"
|
file: "tstaticparams.nim"
|
||||||
output: "abracadabra\ntest\n3\n15\n4\n2"
|
output: "abracadabra\ntest\n3\n15\n4\n2\nfloat\n3\nfloat\nyin\nyang"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
@ -56,3 +56,66 @@ type TTestSub[N: static[int]] = TTest[1, N]
|
||||||
|
|
||||||
var z: TTestSub[2]
|
var z: TTestSub[2]
|
||||||
echo z.high
|
echo z.high
|
||||||
|
|
||||||
|
# issue 1049
|
||||||
|
proc matrix_1*[M, N, T](mat: Matrix[M,N,T], a: array[N, int]) = discard
|
||||||
|
proc matrix_2*[M, N, T](mat: Matrix[M,N,T], a: array[N+1, int]) = discard
|
||||||
|
|
||||||
|
proc matrix_3*[M, N: static[int]; T](mat: Matrix[M,N,T], a: array[N, int]) = discard
|
||||||
|
proc matrix_4*[M, N: static[int]; T](mat: Matrix[M,N,T], a: array[N+1, int]) = discard
|
||||||
|
|
||||||
|
var
|
||||||
|
tmat: Matrix[4,4,int]
|
||||||
|
ar1: array[4, int]
|
||||||
|
ar2: array[5, int]
|
||||||
|
|
||||||
|
matrix_1(tmat, ar1)
|
||||||
|
matrix_2(tmat, ar2)
|
||||||
|
matrix_3(tmat, ar1)
|
||||||
|
matrix_4(tmat, ar2)
|
||||||
|
|
||||||
|
template reject(x): stmt =
|
||||||
|
static: assert(not compiles(x))
|
||||||
|
|
||||||
|
# test with arrays of wrong size
|
||||||
|
reject matrix_1(tmat, ar2)
|
||||||
|
reject matrix_2(tmat, ar1)
|
||||||
|
reject matrix_3(tmat, ar2)
|
||||||
|
reject matrix_4(tmat, ar1)
|
||||||
|
|
||||||
|
# bug 1820
|
||||||
|
|
||||||
|
type
|
||||||
|
T1820_1[T; Y: static[int]] = object
|
||||||
|
bar: T
|
||||||
|
|
||||||
|
proc intOrFloat*[Y](f: T1820_1[int, Y]) = echo "int"
|
||||||
|
proc intOrFloat*[Y](f: T1820_1[float, Y]) = echo "float"
|
||||||
|
proc threeOrFour*[T](f: T1820_1[T, 3]) = echo "3"
|
||||||
|
proc threeOrFour*[T](f: T1820_1[T, 4]) = echo "4"
|
||||||
|
|
||||||
|
var foo_1: T1820_1[float, 3]
|
||||||
|
|
||||||
|
foo_1.intOrFloat
|
||||||
|
foo_1.threeOrFour
|
||||||
|
|
||||||
|
type
|
||||||
|
YinAndYang = enum
|
||||||
|
Yin,
|
||||||
|
Yang
|
||||||
|
|
||||||
|
T1820_2[T; Y: static[YinAndYang]] = object
|
||||||
|
bar: T
|
||||||
|
|
||||||
|
proc intOrFloat*[Y](f: T1820_2[int, Y]) = echo "int"
|
||||||
|
proc intOrFloat*[Y](f: T1820_2[float, Y]) = echo "float"
|
||||||
|
proc yinOrYang*[T](f: T1820_2[T, YinAndYang.Yin]) = echo "yin"
|
||||||
|
proc yinOrYang*[T](f: T1820_2[T, Yang]) = echo "yang"
|
||||||
|
|
||||||
|
var foo_2: T1820_2[float, Yin]
|
||||||
|
var foo_3: T1820_2[float, YinAndYang.Yang]
|
||||||
|
|
||||||
|
foo_2.intOrFloat
|
||||||
|
foo_2.yinOrYang
|
||||||
|
foo_3.yinOrYang
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,13 @@
|
||||||
discard """
|
discard """
|
||||||
output: "Sortable\nSortable\nContainer"
|
output: '''Sortable
|
||||||
|
Sortable
|
||||||
|
Container
|
||||||
|
true
|
||||||
|
true
|
||||||
|
false
|
||||||
|
false
|
||||||
|
false
|
||||||
|
'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import typetraits
|
import typetraits
|
||||||
|
|
@ -41,3 +49,20 @@ proc y(x: TObj): int = 10
|
||||||
proc testFoo(x: TFoo) = discard
|
proc testFoo(x: TFoo) = discard
|
||||||
testFoo(TObj(x: 10))
|
testFoo(TObj(x: 10))
|
||||||
|
|
||||||
|
type
|
||||||
|
Matrix[Rows, Cols: static[int]; T] = generic M
|
||||||
|
M.M == Rows
|
||||||
|
M.N == Cols
|
||||||
|
M.T is T
|
||||||
|
|
||||||
|
MyMatrix[M, N: static[int]; T] = object
|
||||||
|
data: array[M*N, T]
|
||||||
|
|
||||||
|
var x: MyMatrix[3, 3, int]
|
||||||
|
|
||||||
|
echo x is Matrix
|
||||||
|
echo x is Matrix[3, 3, int]
|
||||||
|
echo x is Matrix[3, 3, float]
|
||||||
|
echo x is Matrix[4, 3, int]
|
||||||
|
echo x is Matrix[3, 4, int]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,17 +51,17 @@ while i < s.len:
|
||||||
write(stdout, "Du heißt " & s)
|
write(stdout, "Du heißt " & s)
|
||||||
|
|
||||||
# bug #544
|
# bug #544
|
||||||
when false:
|
|
||||||
# yay, fails again
|
# yay, fails again
|
||||||
type Bar [T; I:range] = array[I, T]
|
type Bar [T; I:range] = array[I, T]
|
||||||
proc foo*[T; I:range](a, b: Bar[T, I]): Bar[T, I] =
|
proc foo*[T; I:range](a, b: Bar[T, I]): Bar[T, I] =
|
||||||
when len(a) != 3:
|
when len(a) != 3:
|
||||||
# Error: constant expression expected
|
# Error: constant expression expected
|
||||||
{.fatal:"Dimensions have to be 3".}
|
{.fatal:"Dimensions have to be 3".}
|
||||||
#...
|
#...
|
||||||
block:
|
block:
|
||||||
var a, b: Bar[int, 0..2]
|
var a, b: Bar[int, range[0..2]]
|
||||||
discard foo(a, b)
|
discard foo(a, b)
|
||||||
|
|
||||||
# bug #1788
|
# bug #1788
|
||||||
|
|
||||||
|
|
|
||||||
35
tests/threads/ttryrecv.nim
Normal file
35
tests/threads/ttryrecv.nim
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
discard """
|
||||||
|
outputsub: "channel is empty"
|
||||||
|
"""
|
||||||
|
|
||||||
|
# bug #1816
|
||||||
|
|
||||||
|
from math import random
|
||||||
|
from os import sleep
|
||||||
|
|
||||||
|
type PComm = ptr TChannel[int]
|
||||||
|
|
||||||
|
proc doAction(outC: PComm) {.thread.} =
|
||||||
|
for i in 0.. <5:
|
||||||
|
sleep(random(100))
|
||||||
|
send(outC[], i)
|
||||||
|
|
||||||
|
var
|
||||||
|
thr: TThread[PComm]
|
||||||
|
chan: TChannel[int]
|
||||||
|
|
||||||
|
open(chan)
|
||||||
|
createThread[PComm](thr, doAction, addr(chan))
|
||||||
|
|
||||||
|
while true:
|
||||||
|
let (flag, x) = tryRecv(chan)
|
||||||
|
if flag:
|
||||||
|
echo("received from chan: " & $x)
|
||||||
|
else:
|
||||||
|
echo "channel is empty"
|
||||||
|
break
|
||||||
|
|
||||||
|
echo "Finished listening"
|
||||||
|
|
||||||
|
joinThread(thr)
|
||||||
|
close(chan)
|
||||||
|
|
@ -63,7 +63,7 @@
|
||||||
<span class="tab end"> </span>count += <span class="val">1</span>
|
<span class="tab end"> </span>count += <span class="val">1</span>
|
||||||
|
|
||||||
echo(<span class="val">"Average line length: "</span>,
|
echo(<span class="val">"Average line length: "</span>,
|
||||||
<span class="kwd">if</span> count: sum / count <span class="kwd">else</span>: <span class="val">0</span>)
|
<span class="kwd">if</span> count > <span class="val">0</span>: sum / count <span class="kwd">else</span>: <span class="val">0</span>)
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ Nim is efficient
|
||||||
Nim is expressive
|
Nim is expressive
|
||||||
=================
|
=================
|
||||||
|
|
||||||
* **The Nim compiler and all of the standard library are implemented in
|
* **The Nim compiler and all of the standard libraries are implemented in
|
||||||
Nim.**
|
Nim.**
|
||||||
* Built-in high level datatypes: strings, sets, sequences, etc.
|
* Built-in high level datatypes: strings, sets, sequences, etc.
|
||||||
* Modern type system with local type inference, tuples, variants,
|
* Modern type system with local type inference, tuples, variants,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue