mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-18 21:40:32 +00:00
Merge branch 'devel' of https://github.com/Araq/Nim into devel
This commit is contained in:
@@ -399,6 +399,7 @@ const
|
||||
tyPureObject* = tyTuple
|
||||
GcTypeKinds* = {tyRef, tySequence, tyString}
|
||||
tyError* = tyProxy # as an errornous node should match everything
|
||||
tyUnknown* = tyFromExpr
|
||||
|
||||
tyUnknownTypes* = {tyError, tyFromExpr}
|
||||
|
||||
|
||||
@@ -277,16 +277,14 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
|
||||
styleCheckUse(n.sons[0].info, finalCallee)
|
||||
if finalCallee.ast == nil:
|
||||
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:
|
||||
# a generic proc!
|
||||
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
|
||||
finalCallee = generateInstance(c, x.calleeSym, x.bindings, n.info)
|
||||
result = x.call
|
||||
instGenericConvertersSons(c, result, x)
|
||||
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 =
|
||||
# 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 =
|
||||
t.n[1][0][1].typ
|
||||
|
||||
@@ -229,7 +229,7 @@ proc semConv(c: PContext, n: PNode): PNode =
|
||||
return n
|
||||
|
||||
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)
|
||||
result.addSon copyTree(n.sons[0])
|
||||
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)
|
||||
elif t != nil and t.kind == tyTypeDesc:
|
||||
if n.len == 1: return semObjConstr(c, n, flags)
|
||||
let destType = t.skipTypes({tyTypeDesc, tyGenericInst})
|
||||
return semConv(c, n)
|
||||
else:
|
||||
result = overloadedCallOpr(c, n)
|
||||
@@ -928,7 +927,6 @@ proc readTypeParameter(c: PContext, typ: PType,
|
||||
let ty = if typ.kind == tyGenericInst: typ.skipGenericAlias
|
||||
else: (internalAssert(typ.kind == tyCompositeTypeClass);
|
||||
typ.sons[1].skipGenericAlias)
|
||||
#debug ty
|
||||
let tbody = ty.sons[0]
|
||||
for s in countup(0, tbody.len-2):
|
||||
let tParam = tbody.sons[s]
|
||||
|
||||
@@ -1262,10 +1262,14 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
return
|
||||
else:
|
||||
n.sons[i] = semExpr(c, n.sons[i])
|
||||
if c.inTypeClass > 0 and n[i].typ != nil and n[i].typ.kind == tyBool:
|
||||
let verdict = semConstExpr(c, n[i])
|
||||
if verdict.intVal == 0:
|
||||
localError(result.info, "type class predicate failed")
|
||||
if c.inTypeClass > 0 and n[i].typ != nil:
|
||||
case n[i].typ.kind
|
||||
of tyBool:
|
||||
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]):
|
||||
voidContext = true
|
||||
n.typ = enforceVoidContext
|
||||
|
||||
@@ -225,11 +225,10 @@ proc semArrayIndex(c: PContext, n: PNode): PType =
|
||||
elif e.kind == nkSym and e.typ.kind == tyStatic:
|
||||
if e.sym.ast != nil:
|
||||
return semArrayIndex(c, e.sym.ast)
|
||||
internalAssert c.inGenericContext > 0
|
||||
if not isOrdinalType(e.typ.lastSon):
|
||||
localError(n[1].info, errOrdinalTypeExpected)
|
||||
result = makeRangeWithStaticExpr(c, e)
|
||||
result.flags.incl tfUnresolved
|
||||
if c.inGenericContext >0: result.flags.incl tfUnresolved
|
||||
elif e.kind in nkCallKinds and hasGenericArguments(e):
|
||||
if not isOrdinalType(e.typ):
|
||||
localError(n[1].info, errOrdinalTypeExpected)
|
||||
@@ -782,10 +781,12 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||
of tyGenericBody:
|
||||
result = newTypeS(tyGenericInvokation, c)
|
||||
result.rawAddSon(paramType)
|
||||
|
||||
for i in 0 .. paramType.sonsLen - 2:
|
||||
result.rawAddSon newTypeS(tyAnything, c)
|
||||
# result.rawAddSon(copyType(paramType.sons[i], getCurrOwner(), true))
|
||||
|
||||
let dummyType = if paramType.sons[i].kind == tyStatic: tyUnknown
|
||||
else: tyAnything
|
||||
result.rawAddSon newTypeS(dummyType, c)
|
||||
|
||||
if paramType.lastSon.kind == tyUserTypeClass:
|
||||
result.kind = tyUserTypeClassInst
|
||||
result.rawAddSon paramType.lastSon
|
||||
|
||||
@@ -39,7 +39,9 @@ type
|
||||
bindings*: TIdTable # maps types to types
|
||||
baseTypeMatch: bool # needed for conversions from T to openarray[T]
|
||||
# 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
|
||||
# be instantiated
|
||||
coerceDistincts*: bool # this is an explicit coercion that can strip away
|
||||
@@ -66,6 +68,8 @@ const
|
||||
|
||||
proc markUsed*(info: TLineInfo, s: PSym)
|
||||
|
||||
template hasFauxMatch*(c: TCandidate): bool = c.fauxMatch != tyNone
|
||||
|
||||
proc initCandidateAux(ctx: PContext,
|
||||
c: var TCandidate, callee: PType) {.inline.} =
|
||||
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):
|
||||
var formalTypeParam = typeParams.sons[i-1].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})
|
||||
assert bound != nil
|
||||
put(c.bindings, formalTypeParam, bound)
|
||||
|
||||
proc newCandidate*(ctx: PContext, callee: PSym,
|
||||
@@ -462,9 +469,23 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||
var
|
||||
typeParamName = ff.base.sons[i-1].sym.name
|
||||
typ = ff.sons[i]
|
||||
param = newSym(skType, typeParamName, body.sym, body.sym.info)
|
||||
|
||||
param.typ = makeTypeDesc(c, typ)
|
||||
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)
|
||||
|
||||
addDecl(c, param)
|
||||
|
||||
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
|
||||
of tyRange:
|
||||
if a.kind == f.kind:
|
||||
if f.base.kind == tyNone: return isGeneric
|
||||
result = typeRel(c, base(f), base(a))
|
||||
# bugfix: accept integer conversions here
|
||||
#if result < isGeneric: result = isNone
|
||||
@@ -672,22 +694,27 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
else:
|
||||
fRange = prev
|
||||
result = typeRel(c, f.sons[1], a.sons[1])
|
||||
if result < isGeneric:
|
||||
result = isNone
|
||||
elif tfUnresolved in fRange.flags and
|
||||
rangeHasStaticIf(fRange):
|
||||
# This is a range from an array instantiated with a generic
|
||||
# static param. We must extract the static param here and bind
|
||||
# it to the size of the currently supplied array.
|
||||
var
|
||||
rangeStaticT = fRange.getStaticTypeFromRange
|
||||
replacementT = newTypeWithSons(c.c, tyStatic, @[tyInt.getSysType])
|
||||
inputUpperBound = a.sons[0].n[1].intVal
|
||||
# we must correct for the off-by-one discrepancy between
|
||||
# ranges and static params:
|
||||
replacementT.n = newIntNode(nkIntLit, inputUpperBound + 1)
|
||||
put(c.bindings, rangeStaticT, replacementT)
|
||||
result = isGeneric
|
||||
if result < isGeneric: return isNone
|
||||
if rangeHasStaticIf(fRange):
|
||||
if tfUnresolved in fRange.flags:
|
||||
# This is a range from an array instantiated with a generic
|
||||
# static param. We must extract the static param here and bind
|
||||
# it to the size of the currently supplied array.
|
||||
var
|
||||
rangeStaticT = fRange.getStaticTypeFromRange
|
||||
replacementT = newTypeWithSons(c.c, tyStatic, @[tyInt.getSysType])
|
||||
inputUpperBound = a.sons[0].n[1].intVal
|
||||
# we must correct for the off-by-one discrepancy between
|
||||
# ranges and static params:
|
||||
replacementT.n = newIntNode(nkIntLit, inputUpperBound + 1)
|
||||
put(c.bindings, rangeStaticT, replacementT)
|
||||
return 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):
|
||||
result = isNone
|
||||
else: discard
|
||||
@@ -945,7 +972,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
else:
|
||||
internalAssert a.sons != nil and a.sons.len > 0
|
||||
c.typedescMatched = true
|
||||
result = typeRel(c, f.base, a.base)
|
||||
result = typeRel(c, f.base, a.skipTypes({tyGenericParam, tyTypeDesc}))
|
||||
else:
|
||||
result = isNone
|
||||
else:
|
||||
@@ -980,7 +1007,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
if aOrig.kind == tyStatic:
|
||||
result = typeRel(c, f.lastSon, a)
|
||||
if result != isNone and f.n != nil:
|
||||
if not exprStructuralEquivalent(f.n, a.n):
|
||||
if not exprStructuralEquivalent(f.n, aOrig.n):
|
||||
result = isNone
|
||||
if result != isNone: put(c.bindings, f, aOrig)
|
||||
else:
|
||||
@@ -1045,10 +1072,10 @@ proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation =
|
||||
initCandidate(c, m, f)
|
||||
result = typeRel(m, f, a)
|
||||
|
||||
proc getInstantiatedType(c: PContext, arg: PNode, m: TCandidate,
|
||||
f: PType): PType =
|
||||
proc getInstantiatedType(c: PContext, arg: PNode, m: TCandidate,
|
||||
f: PType): PType =
|
||||
result = PType(idTableGet(m.bindings, f))
|
||||
if result == nil:
|
||||
if result == nil:
|
||||
result = generateTypeInstance(c, m.bindings, arg, f)
|
||||
if result == nil:
|
||||
internalError(arg.info, "getInstantiatedType")
|
||||
@@ -1058,7 +1085,7 @@ proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
|
||||
c: PContext): PNode =
|
||||
result = newNodeI(kind, arg.info)
|
||||
if containsGenericType(f):
|
||||
if not m.proxyMatch:
|
||||
if not m.hasFauxMatch:
|
||||
result.typ = getInstantiatedType(c, arg, m, f)
|
||||
else:
|
||||
result.typ = errorType(c)
|
||||
@@ -1130,7 +1157,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||
arg = argSemantized
|
||||
argType = argType
|
||||
c = m.c
|
||||
|
||||
|
||||
if tfHasStatic in fMaybeStatic.flags:
|
||||
# XXX: When implicit statics are the default
|
||||
# this will be done earlier - we just have to
|
||||
@@ -1144,7 +1171,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||
return argSemantized
|
||||
|
||||
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.typ = makeTypeFromExpr(c, arg)
|
||||
return
|
||||
@@ -1237,9 +1264,9 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||
of isNone:
|
||||
# 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)
|
||||
m.proxyMatch = true
|
||||
m.fauxMatch = a.kind
|
||||
return copyTree(arg)
|
||||
result = userConvMatch(c, m, f, a, arg)
|
||||
# check for a base type match, which supports varargs[T] without []
|
||||
|
||||
@@ -37,4 +37,4 @@ Options:
|
||||
--advanced show advanced command line switches
|
||||
-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
|
||||
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
|
||||
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
|
||||
type/signature info provided by idetools and concentrate on the
|
||||
|
||||
@@ -40,7 +40,7 @@ These integer types are pre-defined:
|
||||
|
||||
``int``
|
||||
the generic signed integer type; its size is platform dependent and has the
|
||||
same size as a pointer. This type should be used in general. An integer
|
||||
same size as a pointer. This type should be used in general. An integer
|
||||
literal that has no type suffix is of this type.
|
||||
|
||||
intXX
|
||||
@@ -51,7 +51,7 @@ intXX
|
||||
|
||||
``uint``
|
||||
the generic `unsigned integer`:idx: type; its size is platform dependent and
|
||||
has the same size as a pointer. An integer literal with the type
|
||||
has the same size as a pointer. An integer literal with the type
|
||||
suffix ``'u`` is of this type.
|
||||
|
||||
uintXX
|
||||
@@ -59,15 +59,15 @@ uintXX
|
||||
(example: uint16 is a 16 bit wide unsigned integer).
|
||||
The current implementation supports ``uint8``, ``uint16``, ``uint32``,
|
||||
``uint64``. Literals of these types have the suffix 'uXX.
|
||||
Unsigned operations all wrap around; they cannot lead to over- or
|
||||
Unsigned operations all wrap around; they cannot lead to over- or
|
||||
underflow errors.
|
||||
|
||||
|
||||
In addition to the usual arithmetic operators for signed and unsigned integers
|
||||
(``+ - *`` etc.) there are also operators that formally work on *signed*
|
||||
integers but treat their arguments as *unsigned*: They are mostly provided
|
||||
for backwards compatibility with older versions of the language that lacked
|
||||
unsigned integer types. These unsigned operations for signed integers use
|
||||
(``+ - *`` etc.) there are also operators that formally work on *signed*
|
||||
integers but treat their arguments as *unsigned*: They are mostly provided
|
||||
for backwards compatibility with older versions of the language that lacked
|
||||
unsigned integer types. These unsigned operations for signed integers use
|
||||
the ``%`` suffix as convention:
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ operation meaning
|
||||
kinds of integer types are used: the smaller type is converted to the larger.
|
||||
|
||||
A `narrowing type conversion`:idx: converts a larger to a smaller type (for
|
||||
example ``int32 -> int16``. A `widening type conversion`:idx: converts a
|
||||
example ``int32 -> int16``. A `widening type conversion`:idx: converts a
|
||||
smaller type to a larger type (for example ``int16 -> int32``). In Nim only
|
||||
widening type conversions are *implicit*:
|
||||
|
||||
@@ -111,7 +111,7 @@ widening type conversions are *implicit*:
|
||||
|
||||
However, ``int`` literals are implicitly convertible to a smaller integer type
|
||||
if the literal's value fits this smaller type and such a conversion is less
|
||||
expensive than other implicit conversions, so ``myInt16 + 34`` produces
|
||||
expensive than other implicit conversions, so ``myInt16 + 34`` produces
|
||||
an ``int16`` result.
|
||||
|
||||
For further details, see `Convertible relation`_.
|
||||
@@ -137,12 +137,12 @@ determined). Assignments from the base type to one of its subrange types
|
||||
A subrange type has the same size as its base type (``int`` in the example).
|
||||
|
||||
Nim requires `interval arithmetic`:idx: for subrange types over a set
|
||||
of built-in operators that involve constants: ``x %% 3`` is of
|
||||
type ``range[0..2]``. The following built-in operators for integers are
|
||||
of built-in operators that involve constants: ``x %% 3`` is of
|
||||
type ``range[0..2]``. The following built-in operators for integers are
|
||||
affected by this rule: ``-``, ``+``, ``*``, ``min``, ``max``, ``succ``,
|
||||
``pred``, ``mod``, ``div``, ``%%``, ``and`` (bitwise ``and``).
|
||||
|
||||
Bitwise ``and`` only produces a ``range`` if one of its operands is a
|
||||
Bitwise ``and`` only produces a ``range`` if one of its operands is a
|
||||
constant *x* so that (x+1) is a number of two.
|
||||
(Bitwise ``and`` is then a ``%%`` operation.)
|
||||
|
||||
@@ -155,7 +155,7 @@ This means that the following code is accepted:
|
||||
of 9: echo "C"
|
||||
of 10: echo "D"
|
||||
# note: no ``else`` required as (x and 3) + 7 has the type: range[7..10]
|
||||
|
||||
|
||||
|
||||
Pre-defined floating point types
|
||||
--------------------------------
|
||||
@@ -186,17 +186,17 @@ The IEEE standard defines five types of floating-point exceptions:
|
||||
for example 0.0/0.0, sqrt(-1.0), and log(-37.8).
|
||||
* Division by zero: divisor is zero and dividend is a finite nonzero number,
|
||||
for example 1.0/0.0.
|
||||
* Overflow: operation produces a result that exceeds the range of the exponent,
|
||||
* Overflow: operation produces a result that exceeds the range of the exponent,
|
||||
for example MAXDOUBLE+0.0000000000001e308.
|
||||
* Underflow: operation produces a result that is too small to be represented
|
||||
* Underflow: operation produces a result that is too small to be represented
|
||||
as a normal number, for example, MINDOUBLE * MINDOUBLE.
|
||||
* Inexact: operation produces a result that cannot be represented with infinite
|
||||
* Inexact: operation produces a result that cannot be represented with infinite
|
||||
precision, for example, 2.0 / 3.0, log(1.1) and 0.1 in input.
|
||||
|
||||
The IEEE exceptions are either ignored at runtime or mapped to the
|
||||
The IEEE exceptions are either ignored at runtime or mapped to the
|
||||
Nim exceptions: `FloatInvalidOpError`:idx:, `FloatDivByZeroError`:idx:,
|
||||
`FloatOverflowError`:idx:, `FloatUnderflowError`:idx:,
|
||||
and `FloatInexactError`:idx:.
|
||||
and `FloatInexactError`:idx:.
|
||||
These exceptions inherit from the `FloatingPointError`:idx: base class.
|
||||
|
||||
Nim provides the pragmas `NaNChecks`:idx: and `InfChecks`:idx: to control
|
||||
@@ -212,7 +212,7 @@ whether the IEEE exceptions are ignored or trap a Nim exception:
|
||||
In the current implementation ``FloatDivByZeroError`` and ``FloatInexactError``
|
||||
are never raised. ``FloatOverflowError`` is raised instead of
|
||||
``FloatDivByZeroError``.
|
||||
There is also a `floatChecks`:idx: pragma that is a short-cut for the
|
||||
There is also a `floatChecks`:idx: pragma that is a short-cut for the
|
||||
combination of ``NaNChecks`` and ``InfChecks`` pragmas. ``floatChecks`` are
|
||||
turned off as default.
|
||||
|
||||
@@ -303,7 +303,7 @@ and ``pred`` are not available for them either.
|
||||
|
||||
|
||||
The compiler supports the built-in stringify operator ``$`` for enumerations.
|
||||
The stringify's result can be controlled by explicitly giving the string
|
||||
The stringify's result can be controlled by explicitly giving the string
|
||||
values to use:
|
||||
|
||||
.. code-block:: nim
|
||||
@@ -315,12 +315,12 @@ values to use:
|
||||
valueC = 2,
|
||||
valueD = (3, "abc")
|
||||
|
||||
As can be seen from the example, it is possible to both specify a field's
|
||||
As can be seen from the example, it is possible to both specify a field's
|
||||
ordinal value and its string value by using a tuple. It is also
|
||||
possible to only specify one of them.
|
||||
|
||||
An enum can be marked with the ``pure`` pragma so that it's fields are not
|
||||
added to the current scope, so they always need to be accessed
|
||||
added to the current scope, so they always need to be accessed
|
||||
via ``MyEnum.value``:
|
||||
|
||||
.. code-block:: nim
|
||||
@@ -328,7 +328,7 @@ via ``MyEnum.value``:
|
||||
type
|
||||
MyEnum {.pure.} = enum
|
||||
valueA, valueB, valueC, valueD
|
||||
|
||||
|
||||
echo valueA # error: Unknown identifier
|
||||
echo MyEnum.valueA # works
|
||||
|
||||
@@ -364,22 +364,22 @@ cstring type
|
||||
------------
|
||||
The ``cstring`` type represents a pointer to a zero-terminated char array
|
||||
compatible to the type ``char*`` in Ansi C. Its primary purpose lies in easy
|
||||
interfacing with C. The index operation ``s[i]`` means the i-th *char* of
|
||||
interfacing with C. The index operation ``s[i]`` means the i-th *char* of
|
||||
``s``; however no bounds checking for ``cstring`` is performed making the
|
||||
index operation unsafe.
|
||||
|
||||
A Nim ``string`` is implicitly convertible
|
||||
A Nim ``string`` is implicitly convertible
|
||||
to ``cstring`` for convenience. If a Nim string is passed to a C-style
|
||||
variadic proc, it is implicitly converted to ``cstring`` too:
|
||||
|
||||
.. code-block:: nim
|
||||
proc printf(formatstr: cstring) {.importc: "printf", varargs,
|
||||
proc printf(formatstr: cstring) {.importc: "printf", varargs,
|
||||
header: "<stdio.h>".}
|
||||
|
||||
|
||||
printf("This works %s", "as expected")
|
||||
|
||||
Even though the conversion is implicit, it is not *safe*: The garbage collector
|
||||
does not consider a ``cstring`` to be a root and may collect the underlying
|
||||
does not consider a ``cstring`` to be a root and may collect the underlying
|
||||
memory. However in practice this almost never happens as the GC considers
|
||||
stack roots conservatively. One can use the builtin procs ``GC_ref`` and
|
||||
``GC_unref`` to keep the string data alive for the rare cases where it does
|
||||
@@ -390,7 +390,7 @@ string from a cstring:
|
||||
|
||||
.. code-block:: nim
|
||||
var str: string = "Hello!"
|
||||
var cstr: cstring = s
|
||||
var cstr: cstring = str
|
||||
var newstr: string = $cstr
|
||||
|
||||
|
||||
@@ -410,9 +410,9 @@ integers from 0 to ``len(A)-1``. An array expression may be constructed by the
|
||||
array constructor ``[]``.
|
||||
|
||||
Sequences are similar to arrays but of dynamic length which may change
|
||||
during runtime (like strings). Sequences are implemented as growable arrays,
|
||||
during runtime (like strings). Sequences are implemented as growable arrays,
|
||||
allocating pieces of memory as items are added. A sequence ``S`` is always
|
||||
indexed by integers from 0 to ``len(S)-1`` and its bounds are checked.
|
||||
indexed by integers from 0 to ``len(S)-1`` and its bounds are checked.
|
||||
Sequences can be constructed by the array constructor ``[]`` in conjunction
|
||||
with the array to sequence operator ``@``. Another way to allocate space for a
|
||||
sequence is to call the built-in ``newSeq`` procedure.
|
||||
@@ -452,11 +452,11 @@ Open arrays
|
||||
|
||||
Often fixed size arrays turn out to be too inflexible; procedures should
|
||||
be able to deal with arrays of different sizes. The `openarray`:idx: type
|
||||
allows this; it can only be used for parameters. Openarrays are always
|
||||
indexed with an ``int`` starting at position 0. The ``len``, ``low``
|
||||
and ``high`` operations are available for open arrays too. Any array with
|
||||
a compatible base type can be passed to an openarray parameter, the index
|
||||
type does not matter. In addition to arrays sequences can also be passed
|
||||
allows this; it can only be used for parameters. Openarrays are always
|
||||
indexed with an ``int`` starting at position 0. The ``len``, ``low``
|
||||
and ``high`` operations are available for open arrays too. Any array with
|
||||
a compatible base type can be passed to an openarray parameter, the index
|
||||
type does not matter. In addition to arrays sequences can also be passed
|
||||
to an open array parameter.
|
||||
|
||||
The openarray type cannot be nested: multidimensional openarrays are not
|
||||
@@ -467,7 +467,7 @@ Varargs
|
||||
-------
|
||||
|
||||
A ``varargs`` parameter is an openarray parameter that additionally
|
||||
allows to pass a variable number of arguments to a procedure. The compiler
|
||||
allows to pass a variable number of arguments to a procedure. The compiler
|
||||
converts the list of arguments to an array implicitly:
|
||||
|
||||
.. code-block:: nim
|
||||
@@ -494,7 +494,7 @@ type conversions in this context:
|
||||
# is transformed to:
|
||||
myWriteln(stdout, [$123, $"def", $4.0])
|
||||
|
||||
In this example ``$`` is applied to any argument that is passed to the
|
||||
In this example ``$`` is applied to any argument that is passed to the
|
||||
parameter ``a``. (Note that ``$`` applied to strings is a nop.)
|
||||
|
||||
|
||||
@@ -531,7 +531,7 @@ in future versions of the compiler.
|
||||
person = (creditCard: "Peter", id: 20)
|
||||
|
||||
The implementation aligns the fields for best access performance. The alignment
|
||||
is compatible with the way the C compiler does it.
|
||||
is compatible with the way the C compiler does it.
|
||||
|
||||
For consistency with ``object`` declarations, tuples in a ``type`` section
|
||||
can also be defined with indentation instead of ``[]``:
|
||||
@@ -571,7 +571,7 @@ Object construction
|
||||
-------------------
|
||||
|
||||
Objects can also be created with an `object construction expression`:idx: that
|
||||
has the syntax ``T(fieldA: valueA, fieldB: valueB, ...)`` where ``T`` is
|
||||
has the syntax ``T(fieldA: valueA, fieldB: valueB, ...)`` where ``T`` is
|
||||
an ``object`` type or a ``ref object`` type:
|
||||
|
||||
.. code-block:: nim
|
||||
@@ -617,10 +617,10 @@ An example:
|
||||
# the following statement raises an `EInvalidField` exception, because
|
||||
# n.kind's value does not fit and the ``nkString`` branch is not active:
|
||||
n.strVal = ""
|
||||
|
||||
|
||||
# invalid: would change the active object branch:
|
||||
n.kind = nkInt
|
||||
|
||||
|
||||
var x = PNode(kind: nkAdd, leftOp: PNode(kind: nkInt, intVal: 4),
|
||||
rightOp: PNode(kind: nkInt, intVal: 2))
|
||||
# valid: does not change the active object branch:
|
||||
@@ -660,8 +660,8 @@ untraced references are *unsafe*. However for certain low-level operations
|
||||
Traced references are declared with the **ref** keyword, untraced references
|
||||
are declared with the **ptr** keyword.
|
||||
|
||||
An empty subscript ``[]`` notation can be used to derefer a reference,
|
||||
the ``addr`` procedure returns the address of an item. An address is always
|
||||
An empty subscript ``[]`` notation can be used to derefer a reference,
|
||||
the ``addr`` procedure returns the address of an item. An address is always
|
||||
an untraced reference.
|
||||
Thus the usage of ``addr`` is an *unsafe* feature.
|
||||
|
||||
@@ -680,7 +680,7 @@ dereferencing operations for reference types:
|
||||
var
|
||||
n: PNode
|
||||
new(n)
|
||||
n.data = 9
|
||||
n.data = 9
|
||||
# no need to write n[].data; in fact n[].data is highly discouraged!
|
||||
|
||||
In order to simplify structural type checking, recursive tuples are not valid:
|
||||
@@ -751,20 +751,20 @@ details like this when mixing garbage collected data with unmanaged memory.
|
||||
Not nil annotation
|
||||
------------------
|
||||
|
||||
All types for that ``nil`` is a valid value can be annotated to
|
||||
All types for that ``nil`` is a valid value can be annotated to
|
||||
exclude ``nil`` as a valid value with the ``not nil`` annotation:
|
||||
|
||||
.. code-block:: nim
|
||||
type
|
||||
PObject = ref TObj not nil
|
||||
TProc = (proc (x, y: int)) not nil
|
||||
|
||||
|
||||
proc p(x: PObject) =
|
||||
echo "not nil"
|
||||
|
||||
|
||||
# compiler catches this:
|
||||
p(nil)
|
||||
|
||||
|
||||
# and also this:
|
||||
var x: PObject
|
||||
p(x)
|
||||
@@ -851,22 +851,22 @@ Examples:
|
||||
|
||||
forEach(printItem) # this will NOT compile because calling conventions differ
|
||||
|
||||
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
type
|
||||
TOnMouseMove = proc (x, y: int) {.closure.}
|
||||
|
||||
|
||||
proc onMouseMove(mouseX, mouseY: int) =
|
||||
# has default calling convention
|
||||
echo "x: ", mouseX, " y: ", mouseY
|
||||
|
||||
|
||||
proc setOnMouseMove(mouseMoveEvent: TOnMouseMove) = discard
|
||||
|
||||
|
||||
# ok, 'onMouseMove' has the default calling convention, which is compatible
|
||||
# to 'closure':
|
||||
setOnMouseMove(onMouseMove)
|
||||
|
||||
|
||||
|
||||
A subtle issue with procedural types is that the calling convention of the
|
||||
procedure influences the type compatibility: procedural types are only
|
||||
@@ -932,7 +932,7 @@ of the following conditions hold:
|
||||
3) The procedure has a calling convention that differs from ``nimcall``.
|
||||
4) The procedure is anonymous.
|
||||
|
||||
The rules' purpose is to prevent the case that extending a non-``procvar``
|
||||
The rules' purpose is to prevent the case that extending a non-``procvar``
|
||||
procedure with default parameters breaks client code.
|
||||
|
||||
The default calling convention is ``nimcall``, unless it is an inner proc (a
|
||||
@@ -964,7 +964,7 @@ types are a perfect tool to model different currencies:
|
||||
type
|
||||
TDollar = distinct int
|
||||
TEuro = distinct int
|
||||
|
||||
|
||||
var
|
||||
d: TDollar
|
||||
e: TEuro
|
||||
@@ -989,7 +989,7 @@ number without unit; and the same holds for division:
|
||||
|
||||
proc `*` (x: int, y: TDollar): TDollar =
|
||||
result = TDollar(x * int(y))
|
||||
|
||||
|
||||
proc `div` ...
|
||||
|
||||
This quickly gets tedious. The implementations are trivial and the compiler
|
||||
@@ -1014,7 +1014,7 @@ currency. This can be solved with templates_.
|
||||
template additive(typ: typedesc): stmt =
|
||||
proc `+` *(x, y: typ): typ {.borrow.}
|
||||
proc `-` *(x, y: typ): typ {.borrow.}
|
||||
|
||||
|
||||
# unary operators:
|
||||
proc `+` *(x: typ): typ {.borrow.}
|
||||
proc `-` *(x: typ): typ {.borrow.}
|
||||
@@ -1036,7 +1036,7 @@ currency. This can be solved with templates_.
|
||||
additive(typ)
|
||||
multiplicative(typ, base)
|
||||
comparable(typ)
|
||||
|
||||
|
||||
defineCurrency(TDollar, int)
|
||||
defineCurrency(TEuro, int)
|
||||
|
||||
@@ -1127,21 +1127,21 @@ modules like `db_sqlite <db_sqlite.html>`_.
|
||||
Void type
|
||||
---------
|
||||
|
||||
The ``void`` type denotes the absense of any type. Parameters of
|
||||
The ``void`` type denotes the absense of any type. Parameters of
|
||||
type ``void`` are treated as non-existent, ``void`` as a return type means that
|
||||
the procedure does not return a value:
|
||||
|
||||
.. code-block:: nim
|
||||
proc nothing(x, y: void): void =
|
||||
echo "ha"
|
||||
|
||||
|
||||
nothing() # writes "ha" to stdout
|
||||
|
||||
The ``void`` type is particularly useful for generic code:
|
||||
|
||||
.. code-block:: nim
|
||||
proc callProc[T](p: proc (x: T), x: T) =
|
||||
when T is void:
|
||||
when T is void:
|
||||
p()
|
||||
else:
|
||||
p(x)
|
||||
@@ -1151,13 +1151,13 @@ The ``void`` type is particularly useful for generic code:
|
||||
|
||||
callProc[int](intProc, 12)
|
||||
callProc[void](emptyProc)
|
||||
|
||||
|
||||
However, a ``void`` type cannot be inferred in generic code:
|
||||
|
||||
.. code-block:: nim
|
||||
callProc(emptyProc)
|
||||
callProc(emptyProc)
|
||||
# Error: type mismatch: got (proc ())
|
||||
# but expected one of:
|
||||
# but expected one of:
|
||||
# callProc(p: proc (T), x: T)
|
||||
|
||||
The ``void`` type is only valid for parameters and return types; other symbols
|
||||
|
||||
@@ -139,7 +139,7 @@ Numbers
|
||||
Numerical literals are written as in most other languages. As a special twist,
|
||||
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:
|
||||
``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
|
||||
alone does not produce an octal.
|
||||
|
||||
@@ -1070,7 +1070,7 @@ Operation Comment
|
||||
``dec(x, n)`` decrements `x` by `n`; `n` is an integer
|
||||
``succ(x)`` returns the 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`
|
||||
----------------- --------------------------------------------------------
|
||||
|
||||
@@ -1323,7 +1323,7 @@ define operators which accept TSlice objects to define ranges.
|
||||
a = "Nim is a progamming language"
|
||||
b = "Slices are useless."
|
||||
|
||||
echo a[10..15] # --> 'a prog'
|
||||
echo a[7..12] # --> 'a prog'
|
||||
b[11.. -2] = "useful"
|
||||
echo b # --> 'Slices are useful.'
|
||||
|
||||
|
||||
54
doc/tut2.txt
54
doc/tut2.txt
@@ -35,7 +35,7 @@ Object Oriented Programming
|
||||
===========================
|
||||
|
||||
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
|
||||
and more efficient code. In particular, prefering composition over inheritance
|
||||
is often the better design.
|
||||
@@ -56,7 +56,7 @@ Objects have access to their type at runtime. There is an
|
||||
|
||||
.. code-block:: nim
|
||||
type
|
||||
TPerson = object of TObject
|
||||
TPerson = object of RootObj
|
||||
name*: string # the * means that `name` is accessible 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.
|
||||
|
||||
Inheritance is done with the ``object of`` syntax. Multiple inheritance is
|
||||
currently not supported. If an object type has no suitable ancestor, ``TObject``
|
||||
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
|
||||
to introduce new object roots apart from ``system.TObject``. (This is used
|
||||
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
|
||||
no ancestor are implicitly ``final``. You can use the ``inheritable`` pragma
|
||||
to introduce new object roots apart from ``system.RootObj``. (This is used
|
||||
in the GTK wrapper for instance.)
|
||||
|
||||
|
||||
@@ -199,7 +199,7 @@ This method call syntax is not restricted to objects, it can be used
|
||||
for any type:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
|
||||
echo("abc".len) # is the same as echo(len("abc"))
|
||||
echo("abc".toUpper())
|
||||
echo({'a', 'b', 'c'}.card)
|
||||
@@ -212,7 +212,7 @@ So "pure object oriented" code is easy to write:
|
||||
|
||||
.. code-block:: nim
|
||||
import strutils
|
||||
|
||||
|
||||
stdout.writeln("Give a list of numbers (separated by spaces): ")
|
||||
stdout.write(stdin.readLine.split.map(parseInt).max.`$`)
|
||||
stdout.writeln(" is the maximum!")
|
||||
@@ -226,9 +226,9 @@ the same. But setting a value is different; for this a special setter syntax
|
||||
is needed:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
|
||||
type
|
||||
TSocket* = object of TObject
|
||||
TSocket* = object of RootObj
|
||||
FHost: int # cannot be accessed from the outside of the module
|
||||
# the `F` prefix is a convention to avoid clashes since
|
||||
# the accessors are named `host`
|
||||
@@ -236,7 +236,7 @@ is needed:
|
||||
proc `host=`*(s: var TSocket, value: int) {.inline.} =
|
||||
## setter of hostAddr
|
||||
s.FHost = value
|
||||
|
||||
|
||||
proc host*(s: TSocket): int {.inline.} =
|
||||
## getter of hostAddr
|
||||
s.FHost
|
||||
@@ -284,7 +284,7 @@ Procedures always use static dispatch. For dynamic dispatch replace the
|
||||
|
||||
.. code-block:: nim
|
||||
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
|
||||
x: int
|
||||
PPlusExpr = ref object of PExpr
|
||||
@@ -294,15 +294,15 @@ Procedures always use static dispatch. For dynamic dispatch replace the
|
||||
method eval(e: PExpr): int =
|
||||
# override this base method
|
||||
quit "to override!"
|
||||
|
||||
|
||||
method eval(e: PLiteral): int = e.x
|
||||
method eval(e: PPlusExpr): int = eval(e.a) + eval(e.b)
|
||||
|
||||
|
||||
proc newLit(x: int): PLiteral = PLiteral(x: x)
|
||||
proc newPlus(a, b: PExpr): PPlusExpr = PPlusExpr(a: a, b: b)
|
||||
|
||||
|
||||
echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4)))
|
||||
|
||||
|
||||
Note that in the example the constructors ``newLit`` and ``newPlus`` are procs
|
||||
because they should use static binding, but ``eval`` is a method because it
|
||||
requires dynamic binding.
|
||||
@@ -313,19 +313,19 @@ dispatching:
|
||||
.. code-block:: nim
|
||||
|
||||
type
|
||||
TThing = object of TObject
|
||||
TThing = object of RootObj
|
||||
TUnit = object of TThing
|
||||
x: int
|
||||
|
||||
|
||||
method collide(a, b: TThing) {.inline.} =
|
||||
quit "to override!"
|
||||
|
||||
|
||||
method collide(a: TThing, b: TUnit) {.inline.} =
|
||||
echo "1"
|
||||
|
||||
|
||||
method collide(a: TUnit, b: TThing) {.inline.} =
|
||||
echo "2"
|
||||
|
||||
|
||||
var
|
||||
a, b: TUnit
|
||||
collide(a, b) # output: 2
|
||||
@@ -526,7 +526,7 @@ containers:
|
||||
yield n.data
|
||||
add(stack, n.ri) # push right subtree onto the stack
|
||||
n = n.le # and follow the left pointer
|
||||
|
||||
|
||||
var
|
||||
root: PBinaryTree[string] # instantiate a PBinaryTree with ``string``
|
||||
add(root, newNode("hello")) # instantiates ``newNode`` and ``add``
|
||||
@@ -578,7 +578,7 @@ simple proc for logging:
|
||||
|
||||
proc log(msg: string) {.inline.} =
|
||||
if debug: stdout.writeln(msg)
|
||||
|
||||
|
||||
var
|
||||
x = 4
|
||||
log("x has the value: " & $x)
|
||||
@@ -595,7 +595,7 @@ Turning the ``log`` proc into a template solves this problem:
|
||||
|
||||
template log(msg: string) =
|
||||
if debug: stdout.writeln(msg)
|
||||
|
||||
|
||||
var
|
||||
x = 4
|
||||
log("x has the value: " & $x)
|
||||
@@ -622,11 +622,11 @@ via a special ``:`` syntax:
|
||||
close(f)
|
||||
else:
|
||||
quit("cannot open: " & fn)
|
||||
|
||||
|
||||
withFile(txt, "ttempl3.txt", fmWrite):
|
||||
txt.writeln("line 1")
|
||||
txt.writeln("line 2")
|
||||
|
||||
|
||||
In the example the two ``writeln`` statements are bound to the ``body``
|
||||
parameter. The ``withFile`` template contains boilerplate code and helps to
|
||||
avoid a common bug: to forget to close the file. Note how the
|
||||
@@ -739,7 +739,7 @@ Term rewriting macros
|
||||
---------------------
|
||||
|
||||
Term rewriting macros can be used to enhance the compilation process
|
||||
with user defined optimizations; see this `document <trmacros.html>`_ for
|
||||
with user defined optimizations; see this `document <trmacros.html>`_ for
|
||||
further information.
|
||||
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
## as the response body.
|
||||
##
|
||||
## .. code-block::nim
|
||||
## import asynchttpserver, asyncdispatch
|
||||
##
|
||||
## var server = newAsyncHttpServer()
|
||||
## proc cb(req: Request) {.async.} =
|
||||
## 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 headers = substr($httpMethod, len("http"))
|
||||
if proxy == nil:
|
||||
headers.add(" /" & r.path & r.query)
|
||||
headers.add(" " & r.path)
|
||||
if r.query.len > 0:
|
||||
headers.add("?" & r.query)
|
||||
else:
|
||||
headers.add(" " & url)
|
||||
|
||||
@@ -442,7 +444,9 @@ proc generateHeaders(r: Uri, httpMethod: HttpMethod,
|
||||
headers: StringTableRef): string =
|
||||
result = substr($httpMethod, len("http"))
|
||||
# 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")
|
||||
|
||||
add(result, "Host: " & r.hostname & "\c\L")
|
||||
|
||||
270
lib/pure/md5.nim
270
lib/pure/md5.nim
@@ -9,18 +9,20 @@
|
||||
|
||||
## Module for computing MD5 checksums.
|
||||
|
||||
type
|
||||
MD5State = array[0..3, int32]
|
||||
MD5Block = array[0..15, int32]
|
||||
MD5CBits = array[0..7, int8]
|
||||
MD5Digest* = array[0..15, int8]
|
||||
MD5Buffer = array[0..63, int8]
|
||||
MD5Context* {.final.} = object
|
||||
import unsigned
|
||||
|
||||
type
|
||||
MD5State = array[0..3, uint32]
|
||||
MD5Block = array[0..15, uint32]
|
||||
MD5CBits = array[0..7, uint8]
|
||||
MD5Digest* = array[0..15, uint8]
|
||||
MD5Buffer = array[0..63, uint8]
|
||||
MD5Context* {.final.} = object
|
||||
state: MD5State
|
||||
count: array[0..1, int32]
|
||||
count: array[0..1, uint32]
|
||||
buffer: MD5Buffer
|
||||
|
||||
const
|
||||
const
|
||||
padding: cstring = "\x80\0\0\0" &
|
||||
"\0\0\0\0\0\0\0\0" &
|
||||
"\0\0\0\0\0\0\0\0" &
|
||||
@@ -31,60 +33,60 @@ const
|
||||
"\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)
|
||||
|
||||
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))
|
||||
|
||||
proc H(x, y, z: int32): int32 {.inline.} =
|
||||
proc H(x, y, z: uint32): uint32 {.inline.} =
|
||||
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))
|
||||
|
||||
proc rot(x: var int32, n: int8) {.inline.} =
|
||||
x = toU32(x shl ze(n)) or (x shr toU32(32 -% ze(n)))
|
||||
proc rot(x: var uint32, n: uint8) {.inline.} =
|
||||
x = (x shl n) or (x shr (32'u32 - n))
|
||||
|
||||
proc FF(a: var int32, b, c, d, x: int32, s: int8, ac: int32) =
|
||||
a = a +% F(b, c, d) +% x +% ac
|
||||
proc FF(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
|
||||
a = a + F(b, c, d) + x + ac
|
||||
rot(a, s)
|
||||
a = a +% b
|
||||
a = a + b
|
||||
|
||||
proc GG(a: var int32, b, c, d, x: int32, s: int8, ac: int32) =
|
||||
a = a +% G(b, c, d) +% x +% ac
|
||||
proc GG(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
|
||||
a = a + G(b, c, d) + x + ac
|
||||
rot(a, s)
|
||||
a = a +% b
|
||||
a = a + b
|
||||
|
||||
proc HH(a: var int32, b, c, d, x: int32, s: int8, ac: int32) =
|
||||
a = a +% H(b, c, d) +% x +% ac
|
||||
proc HH(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
|
||||
a = a + H(b, c, d) + x + ac
|
||||
rot(a, s)
|
||||
a = a +% b
|
||||
a = a + b
|
||||
|
||||
proc II(a: var int32, b, c, d, x: int32, s: int8, ac: int32) =
|
||||
a = a +% I(b, c, d) +% x +% ac
|
||||
proc II(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
|
||||
a = a + I(b, c, d) + x + ac
|
||||
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
|
||||
for i in 0..high(dest):
|
||||
dest[i] = toU32(ord(src[j]) or
|
||||
ord(src[j+1]) shl 8 or
|
||||
ord(src[j+2]) shl 16 or
|
||||
ord(src[j+3]) shl 24)
|
||||
dest[i] = uint32(ord(src[j])) or
|
||||
uint32(ord(src[j+1])) shl 8 or
|
||||
uint32(ord(src[j+2])) shl 16 or
|
||||
uint32(ord(src[j+3])) shl 24
|
||||
inc(j, 4)
|
||||
|
||||
proc decode(dest: var openArray[int8], src: openArray[int32]) =
|
||||
proc decode(dest: var openArray[uint8], src: openArray[uint32]) =
|
||||
var i = 0
|
||||
for j in 0..high(src):
|
||||
dest[i] = toU8(src[j] and 0xff'i32)
|
||||
dest[i+1] = toU8(src[j] shr 8'i32 and 0xff'i32)
|
||||
dest[i+2] = toU8(src[j] shr 16'i32 and 0xff'i32)
|
||||
dest[i+3] = toU8(src[j] shr 24'i32 and 0xff'i32)
|
||||
dest[i] = src[j] and 0xff'u32
|
||||
dest[i+1] = src[j] shr 8 and 0xff'u32
|
||||
dest[i+2] = src[j] shr 16 and 0xff'u32
|
||||
dest[i+3] = src[j] shr 24 and 0xff'u32
|
||||
inc(i, 4)
|
||||
|
||||
proc transform(buffer: pointer, state: var MD5State) =
|
||||
proc transform(buffer: pointer, state: var MD5State) =
|
||||
var
|
||||
myBlock: MD5Block
|
||||
encode(myBlock, cast[cstring](buffer))
|
||||
@@ -92,111 +94,111 @@ proc transform(buffer: pointer, state: var MD5State) =
|
||||
var b = state[1]
|
||||
var c = state[2]
|
||||
var d = state[3]
|
||||
FF(a, b, c, d, myBlock[0], 7'i8, 0xD76AA478'i32)
|
||||
FF(d, a, b, c, myBlock[1], 12'i8, 0xE8C7B756'i32)
|
||||
FF(c, d, a, b, myBlock[2], 17'i8, 0x242070DB'i32)
|
||||
FF(b, c, d, a, myBlock[3], 22'i8, 0xC1BDCEEE'i32)
|
||||
FF(a, b, c, d, myBlock[4], 7'i8, 0xF57C0FAF'i32)
|
||||
FF(d, a, b, c, myBlock[5], 12'i8, 0x4787C62A'i32)
|
||||
FF(c, d, a, b, myBlock[6], 17'i8, 0xA8304613'i32)
|
||||
FF(b, c, d, a, myBlock[7], 22'i8, 0xFD469501'i32)
|
||||
FF(a, b, c, d, myBlock[8], 7'i8, 0x698098D8'i32)
|
||||
FF(d, a, b, c, myBlock[9], 12'i8, 0x8B44F7AF'i32)
|
||||
FF(c, d, a, b, myBlock[10], 17'i8, 0xFFFF5BB1'i32)
|
||||
FF(b, c, d, a, myBlock[11], 22'i8, 0x895CD7BE'i32)
|
||||
FF(a, b, c, d, myBlock[12], 7'i8, 0x6B901122'i32)
|
||||
FF(d, a, b, c, myBlock[13], 12'i8, 0xFD987193'i32)
|
||||
FF(c, d, a, b, myBlock[14], 17'i8, 0xA679438E'i32)
|
||||
FF(b, c, d, a, myBlock[15], 22'i8, 0x49B40821'i32)
|
||||
GG(a, b, c, d, myBlock[1], 5'i8, 0xF61E2562'i32)
|
||||
GG(d, a, b, c, myBlock[6], 9'i8, 0xC040B340'i32)
|
||||
GG(c, d, a, b, myBlock[11], 14'i8, 0x265E5A51'i32)
|
||||
GG(b, c, d, a, myBlock[0], 20'i8, 0xE9B6C7AA'i32)
|
||||
GG(a, b, c, d, myBlock[5], 5'i8, 0xD62F105D'i32)
|
||||
GG(d, a, b, c, myBlock[10], 9'i8, 0x02441453'i32)
|
||||
GG(c, d, a, b, myBlock[15], 14'i8, 0xD8A1E681'i32)
|
||||
GG(b, c, d, a, myBlock[4], 20'i8, 0xE7D3FBC8'i32)
|
||||
GG(a, b, c, d, myBlock[9], 5'i8, 0x21E1CDE6'i32)
|
||||
GG(d, a, b, c, myBlock[14], 9'i8, 0xC33707D6'i32)
|
||||
GG(c, d, a, b, myBlock[3], 14'i8, 0xF4D50D87'i32)
|
||||
GG(b, c, d, a, myBlock[8], 20'i8, 0x455A14ED'i32)
|
||||
GG(a, b, c, d, myBlock[13], 5'i8, 0xA9E3E905'i32)
|
||||
GG(d, a, b, c, myBlock[2], 9'i8, 0xFCEFA3F8'i32)
|
||||
GG(c, d, a, b, myBlock[7], 14'i8, 0x676F02D9'i32)
|
||||
GG(b, c, d, a, myBlock[12], 20'i8, 0x8D2A4C8A'i32)
|
||||
HH(a, b, c, d, myBlock[5], 4'i8, 0xFFFA3942'i32)
|
||||
HH(d, a, b, c, myBlock[8], 11'i8, 0x8771F681'i32)
|
||||
HH(c, d, a, b, myBlock[11], 16'i8, 0x6D9D6122'i32)
|
||||
HH(b, c, d, a, myBlock[14], 23'i8, 0xFDE5380C'i32)
|
||||
HH(a, b, c, d, myBlock[1], 4'i8, 0xA4BEEA44'i32)
|
||||
HH(d, a, b, c, myBlock[4], 11'i8, 0x4BDECFA9'i32)
|
||||
HH(c, d, a, b, myBlock[7], 16'i8, 0xF6BB4B60'i32)
|
||||
HH(b, c, d, a, myBlock[10], 23'i8, 0xBEBFBC70'i32)
|
||||
HH(a, b, c, d, myBlock[13], 4'i8, 0x289B7EC6'i32)
|
||||
HH(d, a, b, c, myBlock[0], 11'i8, 0xEAA127FA'i32)
|
||||
HH(c, d, a, b, myBlock[3], 16'i8, 0xD4EF3085'i32)
|
||||
HH(b, c, d, a, myBlock[6], 23'i8, 0x04881D05'i32)
|
||||
HH(a, b, c, d, myBlock[9], 4'i8, 0xD9D4D039'i32)
|
||||
HH(d, a, b, c, myBlock[12], 11'i8, 0xE6DB99E5'i32)
|
||||
HH(c, d, a, b, myBlock[15], 16'i8, 0x1FA27CF8'i32)
|
||||
HH(b, c, d, a, myBlock[2], 23'i8, 0xC4AC5665'i32)
|
||||
II(a, b, c, d, myBlock[0], 6'i8, 0xF4292244'i32)
|
||||
II(d, a, b, c, myBlock[7], 10'i8, 0x432AFF97'i32)
|
||||
II(c, d, a, b, myBlock[14], 15'i8, 0xAB9423A7'i32)
|
||||
II(b, c, d, a, myBlock[5], 21'i8, 0xFC93A039'i32)
|
||||
II(a, b, c, d, myBlock[12], 6'i8, 0x655B59C3'i32)
|
||||
II(d, a, b, c, myBlock[3], 10'i8, 0x8F0CCC92'i32)
|
||||
II(c, d, a, b, myBlock[10], 15'i8, 0xFFEFF47D'i32)
|
||||
II(b, c, d, a, myBlock[1], 21'i8, 0x85845DD1'i32)
|
||||
II(a, b, c, d, myBlock[8], 6'i8, 0x6FA87E4F'i32)
|
||||
II(d, a, b, c, myBlock[15], 10'i8, 0xFE2CE6E0'i32)
|
||||
II(c, d, a, b, myBlock[6], 15'i8, 0xA3014314'i32)
|
||||
II(b, c, d, a, myBlock[13], 21'i8, 0x4E0811A1'i32)
|
||||
II(a, b, c, d, myBlock[4], 6'i8, 0xF7537E82'i32)
|
||||
II(d, a, b, c, myBlock[11], 10'i8, 0xBD3AF235'i32)
|
||||
II(c, d, a, b, myBlock[2], 15'i8, 0x2AD7D2BB'i32)
|
||||
II(b, c, d, a, myBlock[9], 21'i8, 0xEB86D391'i32)
|
||||
state[0] = state[0] +% a
|
||||
state[1] = state[1] +% b
|
||||
state[2] = state[2] +% c
|
||||
state[3] = state[3] +% d
|
||||
|
||||
proc md5Init*(c: var MD5Context) =
|
||||
## initializes a MD5Context
|
||||
c.state[0] = 0x67452301'i32
|
||||
c.state[1] = 0xEFCDAB89'i32
|
||||
c.state[2] = 0x98BADCFE'i32
|
||||
c.state[3] = 0x10325476'i32
|
||||
c.count[0] = 0'i32
|
||||
c.count[1] = 0'i32
|
||||
FF(a, b, c, d, myBlock[0], 7'u8, 0xD76AA478'u32)
|
||||
FF(d, a, b, c, myBlock[1], 12'u8, 0xE8C7B756'u32)
|
||||
FF(c, d, a, b, myBlock[2], 17'u8, 0x242070DB'u32)
|
||||
FF(b, c, d, a, myBlock[3], 22'u8, 0xC1BDCEEE'u32)
|
||||
FF(a, b, c, d, myBlock[4], 7'u8, 0xF57C0FAF'u32)
|
||||
FF(d, a, b, c, myBlock[5], 12'u8, 0x4787C62A'u32)
|
||||
FF(c, d, a, b, myBlock[6], 17'u8, 0xA8304613'u32)
|
||||
FF(b, c, d, a, myBlock[7], 22'u8, 0xFD469501'u32)
|
||||
FF(a, b, c, d, myBlock[8], 7'u8, 0x698098D8'u32)
|
||||
FF(d, a, b, c, myBlock[9], 12'u8, 0x8B44F7AF'u32)
|
||||
FF(c, d, a, b, myBlock[10], 17'u8, 0xFFFF5BB1'u32)
|
||||
FF(b, c, d, a, myBlock[11], 22'u8, 0x895CD7BE'u32)
|
||||
FF(a, b, c, d, myBlock[12], 7'u8, 0x6B901122'u32)
|
||||
FF(d, a, b, c, myBlock[13], 12'u8, 0xFD987193'u32)
|
||||
FF(c, d, a, b, myBlock[14], 17'u8, 0xA679438E'u32)
|
||||
FF(b, c, d, a, myBlock[15], 22'u8, 0x49B40821'u32)
|
||||
GG(a, b, c, d, myBlock[1], 5'u8, 0xF61E2562'u32)
|
||||
GG(d, a, b, c, myBlock[6], 9'u8, 0xC040B340'u32)
|
||||
GG(c, d, a, b, myBlock[11], 14'u8, 0x265E5A51'u32)
|
||||
GG(b, c, d, a, myBlock[0], 20'u8, 0xE9B6C7AA'u32)
|
||||
GG(a, b, c, d, myBlock[5], 5'u8, 0xD62F105D'u32)
|
||||
GG(d, a, b, c, myBlock[10], 9'u8, 0x02441453'u32)
|
||||
GG(c, d, a, b, myBlock[15], 14'u8, 0xD8A1E681'u32)
|
||||
GG(b, c, d, a, myBlock[4], 20'u8, 0xE7D3FBC8'u32)
|
||||
GG(a, b, c, d, myBlock[9], 5'u8, 0x21E1CDE6'u32)
|
||||
GG(d, a, b, c, myBlock[14], 9'u8, 0xC33707D6'u32)
|
||||
GG(c, d, a, b, myBlock[3], 14'u8, 0xF4D50D87'u32)
|
||||
GG(b, c, d, a, myBlock[8], 20'u8, 0x455A14ED'u32)
|
||||
GG(a, b, c, d, myBlock[13], 5'u8, 0xA9E3E905'u32)
|
||||
GG(d, a, b, c, myBlock[2], 9'u8, 0xFCEFA3F8'u32)
|
||||
GG(c, d, a, b, myBlock[7], 14'u8, 0x676F02D9'u32)
|
||||
GG(b, c, d, a, myBlock[12], 20'u8, 0x8D2A4C8A'u32)
|
||||
HH(a, b, c, d, myBlock[5], 4'u8, 0xFFFA3942'u32)
|
||||
HH(d, a, b, c, myBlock[8], 11'u8, 0x8771F681'u32)
|
||||
HH(c, d, a, b, myBlock[11], 16'u8, 0x6D9D6122'u32)
|
||||
HH(b, c, d, a, myBlock[14], 23'u8, 0xFDE5380C'u32)
|
||||
HH(a, b, c, d, myBlock[1], 4'u8, 0xA4BEEA44'u32)
|
||||
HH(d, a, b, c, myBlock[4], 11'u8, 0x4BDECFA9'u32)
|
||||
HH(c, d, a, b, myBlock[7], 16'u8, 0xF6BB4B60'u32)
|
||||
HH(b, c, d, a, myBlock[10], 23'u8, 0xBEBFBC70'u32)
|
||||
HH(a, b, c, d, myBlock[13], 4'u8, 0x289B7EC6'u32)
|
||||
HH(d, a, b, c, myBlock[0], 11'u8, 0xEAA127FA'u32)
|
||||
HH(c, d, a, b, myBlock[3], 16'u8, 0xD4EF3085'u32)
|
||||
HH(b, c, d, a, myBlock[6], 23'u8, 0x04881D05'u32)
|
||||
HH(a, b, c, d, myBlock[9], 4'u8, 0xD9D4D039'u32)
|
||||
HH(d, a, b, c, myBlock[12], 11'u8, 0xE6DB99E5'u32)
|
||||
HH(c, d, a, b, myBlock[15], 16'u8, 0x1FA27CF8'u32)
|
||||
HH(b, c, d, a, myBlock[2], 23'u8, 0xC4AC5665'u32)
|
||||
II(a, b, c, d, myBlock[0], 6'u8, 0xF4292244'u32)
|
||||
II(d, a, b, c, myBlock[7], 10'u8, 0x432AFF97'u32)
|
||||
II(c, d, a, b, myBlock[14], 15'u8, 0xAB9423A7'u32)
|
||||
II(b, c, d, a, myBlock[5], 21'u8, 0xFC93A039'u32)
|
||||
II(a, b, c, d, myBlock[12], 6'u8, 0x655B59C3'u32)
|
||||
II(d, a, b, c, myBlock[3], 10'u8, 0x8F0CCC92'u32)
|
||||
II(c, d, a, b, myBlock[10], 15'u8, 0xFFEFF47D'u32)
|
||||
II(b, c, d, a, myBlock[1], 21'u8, 0x85845DD1'u32)
|
||||
II(a, b, c, d, myBlock[8], 6'u8, 0x6FA87E4F'u32)
|
||||
II(d, a, b, c, myBlock[15], 10'u8, 0xFE2CE6E0'u32)
|
||||
II(c, d, a, b, myBlock[6], 15'u8, 0xA3014314'u32)
|
||||
II(b, c, d, a, myBlock[13], 21'u8, 0x4E0811A1'u32)
|
||||
II(a, b, c, d, myBlock[4], 6'u8, 0xF7537E82'u32)
|
||||
II(d, a, b, c, myBlock[11], 10'u8, 0xBD3AF235'u32)
|
||||
II(c, d, a, b, myBlock[2], 15'u8, 0x2AD7D2BB'u32)
|
||||
II(b, c, d, a, myBlock[9], 21'u8, 0xEB86D391'u32)
|
||||
state[0] = state[0] + a
|
||||
state[1] = state[1] + b
|
||||
state[2] = state[2] + c
|
||||
state[3] = state[3] + d
|
||||
|
||||
proc md5Init*(c: var MD5Context) =
|
||||
## initializes a MD5Context
|
||||
c.state[0] = 0x67452301'u32
|
||||
c.state[1] = 0xEFCDAB89'u32
|
||||
c.state[2] = 0x98BADCFE'u32
|
||||
c.state[3] = 0x10325476'u32
|
||||
c.count[0] = 0'u32
|
||||
c.count[1] = 0'u32
|
||||
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`
|
||||
var input = input
|
||||
var Index = (c.count[0] shr 3) and 0x3F
|
||||
c.count[0] = c.count[0] +% toU32(len shl 3)
|
||||
if c.count[0] < (len shl 3): c.count[1] = c.count[1] +% 1'i32
|
||||
c.count[1] = c.count[1] +% toU32(len shr 29)
|
||||
var Index = int((c.count[0] shr 3) and 0x3F)
|
||||
c.count[0] = c.count[0] + (uint32(len) shl 3)
|
||||
if c.count[0] < (uint32(len) shl 3): c.count[1] = c.count[1] + 1'u32
|
||||
c.count[1] = c.count[1] + (uint32(len) shr 29)
|
||||
var PartLen = 64 - Index
|
||||
if len >= PartLen:
|
||||
if len >= PartLen:
|
||||
copyMem(addr(c.buffer[Index]), input, PartLen)
|
||||
transform(addr(c.buffer), c.state)
|
||||
var i = PartLen
|
||||
while i + 63 < len:
|
||||
while i + 63 < len:
|
||||
transform(addr(input[i]), c.state)
|
||||
inc(i, 64)
|
||||
copyMem(addr(c.buffer[0]), addr(input[i]), len-i)
|
||||
else:
|
||||
copyMem(addr(c.buffer[Index]), addr(input[0]), len)
|
||||
|
||||
proc md5Final*(c: var MD5Context, digest: var MD5Digest) =
|
||||
proc md5Final*(c: var MD5Context, digest: var MD5Digest) =
|
||||
## finishes the MD5Context and stores the result in `digest`
|
||||
var
|
||||
Bits: MD5CBits
|
||||
PadLen: int
|
||||
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
|
||||
else: PadLen = 120 - Index
|
||||
md5Update(c, padding, PadLen)
|
||||
@@ -204,34 +206,34 @@ proc md5Final*(c: var MD5Context, digest: var MD5Digest) =
|
||||
decode(digest, c.state)
|
||||
zeroMem(addr(c), sizeof(MD5Context))
|
||||
|
||||
proc toMD5*(s: string): MD5Digest =
|
||||
proc toMD5*(s: string): MD5Digest =
|
||||
## computes the MD5Digest value for a string `s`
|
||||
var c: MD5Context
|
||||
md5Init(c)
|
||||
md5Update(c, cstring(s), len(s))
|
||||
md5Final(c, result)
|
||||
|
||||
proc `$`*(D: MD5Digest): string =
|
||||
|
||||
proc `$`*(D: MD5Digest): string =
|
||||
## converts a MD5Digest value into its string representation
|
||||
const digits = "0123456789abcdef"
|
||||
result = ""
|
||||
for i in 0..15:
|
||||
for i in 0..15:
|
||||
add(result, digits[(D[i] shr 4) and 0xF])
|
||||
add(result, digits[D[i] and 0xF])
|
||||
|
||||
proc getMD5*(s: string): string =
|
||||
proc getMD5*(s: string): string =
|
||||
## computes an MD5 value of `s` and returns its string representation
|
||||
var
|
||||
var
|
||||
c: MD5Context
|
||||
d: MD5Digest
|
||||
md5Init(c)
|
||||
md5Update(c, cstring(s), len(s))
|
||||
md5Final(c, d)
|
||||
result = $d
|
||||
|
||||
proc `==`*(D1, D2: MD5Digest): bool =
|
||||
|
||||
proc `==`*(D1, D2: MD5Digest): bool =
|
||||
## checks if two MD5Digest values are identical
|
||||
for i in 0..15:
|
||||
for i in 0..15:
|
||||
if D1[i] != D2[i]: return false
|
||||
return true
|
||||
|
||||
@@ -241,5 +243,3 @@ when isMainModule:
|
||||
assert(getMD5("Frank jagt im komplett verwahrlosten Taxi quer durch Bayern") ==
|
||||
"7e716d0e702df0505fc72e2b89467910")
|
||||
assert($toMD5("") == "d41d8cd98f00b204e9800998ecf8427e")
|
||||
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ type
|
||||
Uri* = object
|
||||
scheme*, username*, password*: string
|
||||
hostname*, port*, path*, query*, anchor*: string
|
||||
opaque*: bool
|
||||
|
||||
{.deprecated: [TUrl: Url, TUri: Uri].}
|
||||
|
||||
@@ -115,6 +116,8 @@ proc parseUri*(uri: string): Uri =
|
||||
if authority == "":
|
||||
raise newException(ValueError, "Expected authority got nothing.")
|
||||
parseAuthority(authority, result)
|
||||
else:
|
||||
result.opaque = true
|
||||
|
||||
# Path
|
||||
parsePath(uri, i, result)
|
||||
@@ -256,7 +259,10 @@ proc `$`*(u: Uri): string =
|
||||
result = ""
|
||||
if u.scheme.len > 0:
|
||||
result.add(u.scheme)
|
||||
result.add("://")
|
||||
if u.opaque:
|
||||
result.add(":")
|
||||
else:
|
||||
result.add("://")
|
||||
if u.username.len > 0:
|
||||
result.add(u.username)
|
||||
if u.password.len > 0:
|
||||
@@ -268,22 +274,28 @@ proc `$`*(u: Uri): string =
|
||||
result.add(":")
|
||||
result.add(u.port)
|
||||
if u.path.len > 0:
|
||||
if u.path[0] != '/': result.add("/")
|
||||
result.add(u.path)
|
||||
result.add(u.query)
|
||||
result.add(u.anchor)
|
||||
if u.query.len > 0:
|
||||
result.add("?")
|
||||
result.add(u.query)
|
||||
if u.anchor.len > 0:
|
||||
result.add("#")
|
||||
result.add(u.anchor)
|
||||
|
||||
when isMainModule:
|
||||
block:
|
||||
let test = parseUri("http://localhost:8080/test")
|
||||
let str = "http://localhost:8080/test"
|
||||
let test = parseUri(str)
|
||||
doAssert test.scheme == "http"
|
||||
doAssert test.port == "8080"
|
||||
doAssert test.path == "/test"
|
||||
doAssert test.hostname == "localhost"
|
||||
doAssert($test == str)
|
||||
|
||||
block:
|
||||
let test = parseUri("foo://username:password@example.com:8042/over/there" &
|
||||
"/index.dtb?type=animal&name=narwhal#nose")
|
||||
let str = "foo://username:password@example.com:8042/over/there" &
|
||||
"/index.dtb?type=animal&name=narwhal#nose"
|
||||
let test = parseUri(str)
|
||||
doAssert test.scheme == "foo"
|
||||
doAssert test.username == "username"
|
||||
doAssert test.password == "password"
|
||||
@@ -292,34 +304,45 @@ when isMainModule:
|
||||
doAssert test.path == "/over/there/index.dtb"
|
||||
doAssert test.query == "type=animal&name=narwhal"
|
||||
doAssert test.anchor == "nose"
|
||||
doAssert($test == str)
|
||||
|
||||
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.path == "example:animal:ferret:nose"
|
||||
doAssert($test == str)
|
||||
|
||||
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.username == "username"
|
||||
doAssert test.hostname == "example.com"
|
||||
doAssert test.query == "subject=Topic"
|
||||
doAssert($test == str)
|
||||
|
||||
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.query == "xt=urn:sha1:72hsga62ba515sbd62&dn=foobar"
|
||||
doAssert($test == str)
|
||||
|
||||
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.path == "/test/foo/bar"
|
||||
doAssert test.query == "q=2"
|
||||
doAssert test.anchor == "asdf"
|
||||
doAssert($test == str)
|
||||
|
||||
block:
|
||||
let test = parseUri("test/no/slash")
|
||||
let str = "test/no/slash"
|
||||
let test = parseUri(str)
|
||||
doAssert test.path == "test/no/slash"
|
||||
doAssert($test == str)
|
||||
|
||||
# Remove dot segments tests
|
||||
block:
|
||||
@@ -371,5 +394,3 @@ when isMainModule:
|
||||
block:
|
||||
let test = parseUri("http://example.com/foo/") / "/bar/asd"
|
||||
doAssert test.path == "/foo/bar/asd"
|
||||
|
||||
|
||||
|
||||
@@ -232,9 +232,10 @@ proc tryRecv*[TMsg](c: var TChannel[TMsg]): tuple[dataAvailable: bool,
|
||||
## it returns ``(false, default(msg))``.
|
||||
var q = cast[PRawChannel](addr(c))
|
||||
if q.mask != ChannelDeadMask:
|
||||
if tryAcquireSys(q.lock):
|
||||
llRecv(q, addr(result.msg), cast[PNimType](getTypeInfo(result.msg)))
|
||||
result.dataAvailable = true
|
||||
if tryAcquireSys(q.lock):
|
||||
if q.count > 0:
|
||||
llRecv(q, addr(result.msg), cast[PNimType](getTypeInfo(result.msg)))
|
||||
result.dataAvailable = true
|
||||
releaseSys(q.lock)
|
||||
|
||||
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 """
|
||||
msg: "static 10\ndynamic\nstatic 20\n"
|
||||
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]) =
|
||||
when isStatic(x):
|
||||
static: echo "static ", x
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
discard """
|
||||
file: "tstaticparams.nim"
|
||||
output: "abracadabra\ntest\n3\n15\n4\n2"
|
||||
output: "abracadabra\ntest\n3\n15\n4\n2\nfloat\n3\nfloat\nyin\nyang"
|
||||
"""
|
||||
|
||||
type
|
||||
@@ -56,3 +56,66 @@ type TTestSub[N: static[int]] = TTest[1, N]
|
||||
|
||||
var z: TTestSub[2]
|
||||
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 """
|
||||
output: "Sortable\nSortable\nContainer"
|
||||
output: '''Sortable
|
||||
Sortable
|
||||
Container
|
||||
true
|
||||
true
|
||||
false
|
||||
false
|
||||
false
|
||||
'''
|
||||
"""
|
||||
|
||||
import typetraits
|
||||
@@ -41,3 +49,20 @@ proc y(x: TObj): int = 10
|
||||
proc testFoo(x: TFoo) = discard
|
||||
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]
|
||||
|
||||
|
||||
@@ -1,67 +1,67 @@
|
||||
# Test various aspects
|
||||
# Test various aspects
|
||||
|
||||
# bug #572
|
||||
var a=12345678901'u64
|
||||
|
||||
|
||||
var x = (x: 42, y: (a: 8, z: 10))
|
||||
echo x.y
|
||||
|
||||
import
|
||||
mvarious
|
||||
|
||||
type
|
||||
PA = ref TA
|
||||
PB = ref TB
|
||||
|
||||
TB = object
|
||||
a: PA
|
||||
|
||||
TA = object
|
||||
b: TB
|
||||
x: int
|
||||
|
||||
proc getPA(): PA =
|
||||
var
|
||||
b: bool
|
||||
b = not false
|
||||
return nil
|
||||
|
||||
import
|
||||
mvarious
|
||||
|
||||
type
|
||||
PA = ref TA
|
||||
PB = ref TB
|
||||
|
||||
TB = object
|
||||
a: PA
|
||||
|
||||
TA = object
|
||||
b: TB
|
||||
x: int
|
||||
|
||||
proc getPA(): PA =
|
||||
var
|
||||
b: bool
|
||||
b = not false
|
||||
return nil
|
||||
|
||||
# bug #501
|
||||
proc f(): int = 54
|
||||
|
||||
var
|
||||
global: int
|
||||
|
||||
var
|
||||
s: string
|
||||
i: int
|
||||
r: TA
|
||||
|
||||
r.b.a.x = 0
|
||||
global = global + 1
|
||||
exportme()
|
||||
write(stdout, "Hallo wie heißt du? ")
|
||||
write(stdout, getPA().x)
|
||||
s = readLine(stdin)
|
||||
i = 0
|
||||
while i < s.len:
|
||||
if s[i] == 'c': write(stdout, "'c' in deinem Namen gefunden\n")
|
||||
i = i + 1
|
||||
|
||||
write(stdout, "Du heißt " & s)
|
||||
|
||||
var
|
||||
global: int
|
||||
|
||||
var
|
||||
s: string
|
||||
i: int
|
||||
r: TA
|
||||
|
||||
r.b.a.x = 0
|
||||
global = global + 1
|
||||
exportme()
|
||||
write(stdout, "Hallo wie heißt du? ")
|
||||
write(stdout, getPA().x)
|
||||
s = readLine(stdin)
|
||||
i = 0
|
||||
while i < s.len:
|
||||
if s[i] == 'c': write(stdout, "'c' in deinem Namen gefunden\n")
|
||||
i = i + 1
|
||||
|
||||
write(stdout, "Du heißt " & s)
|
||||
|
||||
# bug #544
|
||||
when false:
|
||||
# yay, fails again
|
||||
type Bar [T; I:range] = array[I, T]
|
||||
proc foo*[T; I:range](a, b: Bar[T, I]): Bar[T, I] =
|
||||
when len(a) != 3:
|
||||
# Error: constant expression expected
|
||||
{.fatal:"Dimensions have to be 3".}
|
||||
#...
|
||||
block:
|
||||
var a, b: Bar[int, 0..2]
|
||||
discard foo(a, b)
|
||||
|
||||
# yay, fails again
|
||||
type Bar [T; I:range] = array[I, T]
|
||||
proc foo*[T; I:range](a, b: Bar[T, I]): Bar[T, I] =
|
||||
when len(a) != 3:
|
||||
# Error: constant expression expected
|
||||
{.fatal:"Dimensions have to be 3".}
|
||||
#...
|
||||
block:
|
||||
var a, b: Bar[int, range[0..2]]
|
||||
discard foo(a, b)
|
||||
|
||||
# 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>
|
||||
|
||||
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>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
@@ -5,16 +5,16 @@ Home
|
||||
Welcome to Nim
|
||||
--------------
|
||||
|
||||
**Nim** (formerly known as "Nimrod") is a statically typed, imperative
|
||||
programming language that tries to give the programmer ultimate power without
|
||||
**Nim** (formerly known as "Nimrod") is a statically typed, imperative
|
||||
programming language that tries to give the programmer ultimate power without
|
||||
compromises on runtime efficiency. This means it focuses on compile-time
|
||||
mechanisms in all their various forms.
|
||||
|
||||
Beneath a nice infix/indentation based syntax with a
|
||||
powerful (AST based, hygienic) macro system lies a semantic model that supports
|
||||
a soft realtime GC on thread local heaps. Asynchronous message passing is used
|
||||
between threads, so no "stop the world" mechanism is necessary. An unsafe
|
||||
shared memory heap is also provided for the increased efficiency that results
|
||||
Beneath a nice infix/indentation based syntax with a
|
||||
powerful (AST based, hygienic) macro system lies a semantic model that supports
|
||||
a soft realtime GC on thread local heaps. Asynchronous message passing is used
|
||||
between threads, so no "stop the world" mechanism is necessary. An unsafe
|
||||
shared memory heap is also provided for the increased efficiency that results
|
||||
from that model.
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ Nim is efficient
|
||||
* Native code generation (currently via compilation to C), not dependent on a
|
||||
virtual machine: **Nim produces small executables without dependencies
|
||||
for easy redistribution.**
|
||||
* A fast **non-tracing** garbage collector that supports soft
|
||||
* A fast **non-tracing** garbage collector that supports soft
|
||||
real-time systems (like games).
|
||||
* System programming features: Ability to manage your own memory and access the
|
||||
hardware directly. Pointers to garbage collected memory are distinguished
|
||||
@@ -33,22 +33,22 @@ Nim is efficient
|
||||
* Cross-module inlining.
|
||||
* Dynamic method binding with inlining and without virtual method table.
|
||||
* Compile time evaluation of user-defined functions.
|
||||
* Whole program dead code elimination: Only *used functions* are included in
|
||||
* Whole program dead code elimination: Only *used functions* are included in
|
||||
the executable.
|
||||
* Value-based datatypes: For instance, objects and arrays can be allocated on
|
||||
* Value-based datatypes: For instance, objects and arrays can be allocated on
|
||||
the stack.
|
||||
|
||||
|
||||
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.**
|
||||
* 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,
|
||||
generics, etc.
|
||||
* User-defineable operators; code with new operators is often easier to read
|
||||
than code which overloads built-in operators. For example, a
|
||||
than code which overloads built-in operators. For example, a
|
||||
``=~`` operator is defined in the ``re`` module.
|
||||
* Macros can modify the abstract syntax tree at compile time.
|
||||
|
||||
@@ -58,7 +58,7 @@ Nim is elegant
|
||||
|
||||
* Macros can use the imperative paradigm to construct parse trees. Nim
|
||||
does not require a different coding style for meta programming.
|
||||
* Macros cannot change Nim's syntax because there is no need for it.
|
||||
* Macros cannot change Nim's syntax because there is no need for it.
|
||||
Nim's syntax is flexible enough.
|
||||
* Statements are grouped by indentation but can span multiple lines.
|
||||
Indentation must not contain tabulators so the compiler always sees
|
||||
@@ -72,12 +72,12 @@ Nim plays nice with others
|
||||
Porting to other platforms is easy.
|
||||
* **The Nim Compiler can also generate C++ or Objective C for easier
|
||||
interfacing.**
|
||||
* There are lots of bindings: for example, bindings to GTK2, the Windows API,
|
||||
the POSIX API, OpenGL, SDL, Cairo, Python, Lua, TCL, X11, libzip, PCRE,
|
||||
* There are lots of bindings: for example, bindings to GTK2, the Windows API,
|
||||
the POSIX API, OpenGL, SDL, Cairo, Python, Lua, TCL, X11, libzip, PCRE,
|
||||
libcurl, mySQL and SQLite are included in the standard distribution or
|
||||
can easily be obtained via the
|
||||
`Nimble package manager <https://github.com/nim-lang/nimble>`_.
|
||||
* A C to Nim conversion utility: New bindings to C libraries are easily
|
||||
* A C to Nim conversion utility: New bindings to C libraries are easily
|
||||
generated by ``c2nim``.
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user