Merge branch 'devel' of https://github.com/Araq/Nim into devel
Conflicts: compiler/semexprs.nim
This commit is contained in:
commit
65310266d8
46 changed files with 991 additions and 490 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -41,3 +41,4 @@ xcuserdata/
|
|||
/testresults.html
|
||||
/testresults.json
|
||||
testament.db
|
||||
/csources/
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
||||
|
|
@ -1340,6 +1341,10 @@ proc skipTypes*(t: PType, kinds: TTypeKinds): PType =
|
|||
result = t
|
||||
while result.kind in kinds: result = lastSon(result)
|
||||
|
||||
proc safeSkipTypes*(t: PType, kinds: TTypeKinds): PType =
|
||||
result = if t != nil: t.skipTypes(kinds)
|
||||
else: nil
|
||||
|
||||
proc isGCedMem*(t: PType): bool {.inline.} =
|
||||
result = t.kind in {tyString, tyRef, tySequence} or
|
||||
t.kind == tyProc and t.callConv == ccClosure
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ type
|
|||
id: int # for generating IDs
|
||||
toc, section: TSections
|
||||
indexValFilename: string
|
||||
analytics: string # Google Analytics javascript, "" if doesn't exist
|
||||
seenSymbols: StringTableRef # avoids duplicate symbol generation for HTML.
|
||||
|
||||
PDoc* = ref TDocumentor ## Alias to type less.
|
||||
|
|
@ -61,6 +62,23 @@ proc newDocumentor*(filename: string, config: StringTableRef): PDoc =
|
|||
initRstGenerator(result[], (if gCmd != cmdRst2tex: outHtml else: outLatex),
|
||||
options.gConfigVars, filename, {roSupportRawDirective},
|
||||
docgenFindFile, compilerMsgHandler)
|
||||
|
||||
if config.hasKey("doc.googleAnalytics"):
|
||||
result.analytics = """
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', '$1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
""" % [config["doc.googleAnalytics"]]
|
||||
else:
|
||||
result.analytics = ""
|
||||
|
||||
result.seenSymbols = newStringTable(modeCaseInsensitive)
|
||||
result.id = 100
|
||||
|
||||
|
|
@ -562,10 +580,10 @@ proc genOutFile(d: PDoc): PRope =
|
|||
# XXX what is this hack doing here? 'optCompileOnly' means raw output!?
|
||||
code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",
|
||||
"tableofcontents", "moduledesc", "date", "time",
|
||||
"content", "author", "version"],
|
||||
"content", "author", "version", "analytics"],
|
||||
[title.toRope, toc, d.modDesc, toRope(getDateStr()),
|
||||
toRope(getClockStr()), content, d.meta[metaAuthor].toRope,
|
||||
d.meta[metaVersion].toRope])
|
||||
d.meta[metaVersion].toRope, d.analytics.toRope])
|
||||
else:
|
||||
code = content
|
||||
result = code
|
||||
|
|
@ -630,7 +648,8 @@ proc commandBuildIndex*() =
|
|||
|
||||
let code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",
|
||||
"tableofcontents", "moduledesc", "date", "time",
|
||||
"content", "author", "version"],
|
||||
"content", "author", "version", "analytics"],
|
||||
["Index".toRope, nil, nil, toRope(getDateStr()),
|
||||
toRope(getClockStr()), content, nil, nil])
|
||||
toRope(getClockStr()), content, nil, nil, nil])
|
||||
# no analytics because context is not available
|
||||
writeRope(code, getOutFile("theindex", HtmlExt))
|
||||
|
|
|
|||
|
|
@ -25,16 +25,22 @@ proc copyNode(ctx: TemplCtx, a, b: PNode): PNode =
|
|||
if ctx.instLines: result.info = b.info
|
||||
|
||||
proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
|
||||
template handleParam(param) =
|
||||
let x = param
|
||||
if x.kind == nkArgList:
|
||||
for y in items(x): result.add(y)
|
||||
else:
|
||||
result.add copyTree(x)
|
||||
|
||||
case templ.kind
|
||||
of nkSym:
|
||||
var s = templ.sym
|
||||
if s.owner.id == c.owner.id:
|
||||
if s.kind == skParam:
|
||||
let x = actual.sons[s.position]
|
||||
if x.kind == nkArgList:
|
||||
for y in items(x): result.add(y)
|
||||
else:
|
||||
result.add copyTree(x)
|
||||
case s.kind
|
||||
of skParam:
|
||||
handleParam actual.sons[s.position]
|
||||
of skGenericParam:
|
||||
handleParam actual.sons[s.owner.typ.len + s.position - 1]
|
||||
else:
|
||||
internalAssert sfGenSym in s.flags
|
||||
var x = PSym(idTableGet(c.mapping, s))
|
||||
|
|
@ -56,20 +62,30 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
|
|||
proc evalTemplateArgs(n: PNode, s: PSym): PNode =
|
||||
# if the template has zero arguments, it can be called without ``()``
|
||||
# `n` is then a nkSym or something similar
|
||||
var a: int
|
||||
case n.kind
|
||||
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
|
||||
a = sonsLen(n)
|
||||
else: a = 0
|
||||
var f = s.typ.sonsLen
|
||||
if a > f: globalError(n.info, errWrongNumberOfArguments)
|
||||
var totalParams = case n.kind
|
||||
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: <n.len
|
||||
else: 0
|
||||
|
||||
var
|
||||
genericParams = s.ast[genericParamsPos].len
|
||||
expectedRegularParams = <s.typ.len
|
||||
givenRegularParams = totalParams - genericParams
|
||||
|
||||
if totalParams > expectedRegularParams + genericParams:
|
||||
globalError(n.info, errWrongNumberOfArguments)
|
||||
|
||||
result = newNodeI(nkArgList, n.info)
|
||||
for i in countup(1, f - 1):
|
||||
var arg = if i < a: n.sons[i] else: copyTree(s.typ.n.sons[i].sym.ast)
|
||||
if arg == nil or arg.kind == nkEmpty:
|
||||
for i in 1 .. givenRegularParams:
|
||||
result.addSon n.sons[i]
|
||||
|
||||
for i in givenRegularParams+1 .. expectedRegularParams:
|
||||
let default = s.typ.n.sons[i].sym.ast
|
||||
if default.kind == nkEmpty:
|
||||
localError(n.info, errWrongNumberOfArguments)
|
||||
addSon(result, arg)
|
||||
result.addSon default.copyTree
|
||||
|
||||
for i in 1 .. genericParams:
|
||||
result.addSon n.sons[givenRegularParams + i]
|
||||
|
||||
var evalTemplateCounter* = 0
|
||||
# to prevent endless recursion in templates instantiation
|
||||
|
|
|
|||
|
|
@ -277,16 +277,27 @@ 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 finalCallee.ast.sons[genericParamsPos].kind != nkEmpty:
|
||||
# a generic proc!
|
||||
if not x.proxyMatch:
|
||||
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
|
||||
let gp = finalCallee.ast.sons[genericParamsPos]
|
||||
if gp.kind != nkEmpty:
|
||||
if x.calleeSym.kind notin {skMacro, skTemplate}:
|
||||
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
|
||||
# For macros and templates, the resolved generic params
|
||||
# are added as normal params.
|
||||
for s in instantiateGenericParamList(c, gp, x.bindings):
|
||||
case s.kind
|
||||
of skConst:
|
||||
x.call.add s.ast
|
||||
of skType:
|
||||
x.call.add newSymNode(s, n.info)
|
||||
else:
|
||||
internalAssert false
|
||||
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)
|
||||
|
|
@ -926,8 +925,8 @@ const
|
|||
proc readTypeParameter(c: PContext, typ: PType,
|
||||
paramName: PIdent, info: TLineInfo): PNode =
|
||||
let ty = if typ.kind == tyGenericInst: typ.skipGenericAlias
|
||||
else: (internalAssert(typ.kind == tyCompositeTypeClass); typ.sons[1])
|
||||
#debug ty
|
||||
else: (internalAssert(typ.kind == tyCompositeTypeClass);
|
||||
typ.sons[1].skipGenericAlias)
|
||||
let tbody = ty.sons[0]
|
||||
for s in countup(0, tbody.len-2):
|
||||
let tParam = tbody.sons[s]
|
||||
|
|
|
|||
|
|
@ -10,14 +10,10 @@
|
|||
# This module implements the instantiation of generic procs.
|
||||
# included from sem.nim
|
||||
|
||||
proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
||||
entry: var TInstantiation) =
|
||||
if n.kind != nkGenericParams:
|
||||
internalError(n.info, "instantiateGenericParamList; no generic params")
|
||||
newSeq(entry.concreteTypes, n.len)
|
||||
iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym =
|
||||
internalAssert n.kind == nkGenericParams
|
||||
for i, a in n.pairs:
|
||||
if a.kind != nkSym:
|
||||
internalError(a.info, "instantiateGenericParamList; no symbol")
|
||||
internalAssert a.kind == nkSym
|
||||
var q = a.sym
|
||||
if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic, tyIter}+tyTypeClasses:
|
||||
continue
|
||||
|
|
@ -42,8 +38,7 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
|||
#t = ReplaceTypeVarsT(cl, t)
|
||||
s.typ = t
|
||||
if t.kind == tyStatic: s.ast = t.n
|
||||
addDecl(c, s)
|
||||
entry.concreteTypes[i] = t
|
||||
yield s
|
||||
|
||||
proc sameInstantiation(a, b: TInstantiation): bool =
|
||||
if a.concreteTypes.len == b.concreteTypes.len:
|
||||
|
|
@ -196,7 +191,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
|||
## The `pt` parameter is a type-unsafe mapping table used to link generic
|
||||
## parameters to their concrete types within the generic instance.
|
||||
# no need to instantiate generic templates/macros:
|
||||
if fn.kind in {skTemplate, skMacro}: return fn
|
||||
internalAssert fn.kind notin {skMacro, skTemplate}
|
||||
# generates an instantiated proc
|
||||
if c.instCounter > 1000: internalError(fn.ast.info, "nesting too deep")
|
||||
inc(c.instCounter)
|
||||
|
|
@ -213,12 +208,18 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
|||
result.ast = n
|
||||
pushOwner(result)
|
||||
openScope(c)
|
||||
internalAssert n.sons[genericParamsPos].kind != nkEmpty
|
||||
let gp = n.sons[genericParamsPos]
|
||||
internalAssert gp.kind != nkEmpty
|
||||
n.sons[namePos] = newSymNode(result)
|
||||
pushInfoContext(info)
|
||||
var entry = TInstantiation.new
|
||||
entry.sym = result
|
||||
instantiateGenericParamList(c, n.sons[genericParamsPos], pt, entry[])
|
||||
newSeq(entry.concreteTypes, gp.len)
|
||||
var i = 0
|
||||
for s in instantiateGenericParamList(c, gp, pt):
|
||||
addDecl(c, s)
|
||||
entry.concreteTypes[i] = s.typ
|
||||
inc i
|
||||
pushProcCon(c, result)
|
||||
instantiateProcType(c, pt, result, info)
|
||||
n.sons[genericParamsPos] = ast.emptyNode
|
||||
|
|
|
|||
|
|
@ -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,9 +781,11 @@ 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
|
||||
|
|
|
|||
|
|
@ -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: 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)
|
||||
|
||||
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:
|
||||
|
|
@ -977,14 +1004,18 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
result = typeRel(c, x, a) # check if it fits
|
||||
|
||||
of tyStatic:
|
||||
if aOrig.kind == tyStatic:
|
||||
result = typeRel(c, f.lastSon, a)
|
||||
if result != isNone and f.n != nil:
|
||||
if not exprStructuralEquivalent(f.n, a.n):
|
||||
result = isNone
|
||||
if result != isNone: put(c.bindings, f, aOrig)
|
||||
let prev = PType(idTableGet(c.bindings, f))
|
||||
if prev == nil:
|
||||
if aOrig.kind == tyStatic:
|
||||
result = typeRel(c, f.lastSon, a)
|
||||
if result != isNone and f.n != nil:
|
||||
if not exprStructuralEquivalent(f.n, aOrig.n):
|
||||
result = isNone
|
||||
if result != isNone: put(c.bindings, f, aOrig)
|
||||
else:
|
||||
result = isNone
|
||||
else:
|
||||
result = isNone
|
||||
result = typeRel(c, prev, aOrig)
|
||||
|
||||
of tyTypeDesc:
|
||||
var prev = PType(idTableGet(c.bindings, f))
|
||||
|
|
@ -1024,6 +1055,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
|
||||
of tyFromExpr:
|
||||
# fix the expression, so it contains the already instantiated types
|
||||
if f.n == nil: return isGeneric
|
||||
let reevaluated = tryResolvingStaticExpr(c, f.n)
|
||||
case reevaluated.typ.kind
|
||||
of tyTypeDesc:
|
||||
|
|
@ -1058,7 +1090,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)
|
||||
|
|
@ -1144,7 +1176,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 +1269,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 []
|
||||
|
|
|
|||
|
|
@ -1417,12 +1417,20 @@ proc evalStaticStmt*(module: PSym, e: PNode, prc: PSym) =
|
|||
proc setupCompileTimeVar*(module: PSym, n: PNode) =
|
||||
discard evalConstExprAux(module, nil, n, emStaticStmt)
|
||||
|
||||
proc setupMacroParam(x: PNode): PNode =
|
||||
result = x
|
||||
if result.kind in {nkHiddenSubConv, nkHiddenStdConv}: result = result.sons[1]
|
||||
result = canonValue(result)
|
||||
result.flags.incl nfIsRef
|
||||
result.typ = x.typ
|
||||
proc setupMacroParam(x: PNode, typ: PType): TFullReg =
|
||||
case typ.kind
|
||||
of tyStatic:
|
||||
putIntoReg(result, x)
|
||||
of tyTypeDesc:
|
||||
putIntoReg(result, x)
|
||||
else:
|
||||
result.kind = rkNode
|
||||
var n = x
|
||||
if n.kind in {nkHiddenSubConv, nkHiddenStdConv}: n = n.sons[1]
|
||||
n = n.canonValue
|
||||
n.flags.incl nfIsRef
|
||||
n.typ = x.typ
|
||||
result.node = n
|
||||
|
||||
var evalMacroCounter: int
|
||||
|
||||
|
|
@ -1442,6 +1450,7 @@ proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode =
|
|||
|
||||
c.callsite = nOrig
|
||||
let start = genProc(c, sym)
|
||||
# c.echoCode start
|
||||
|
||||
var tos = PStackFrame(prc: sym, comesFrom: 0, next: nil)
|
||||
let maxSlots = sym.offset
|
||||
|
|
@ -1457,9 +1466,14 @@ proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode =
|
|||
tos.slots[0].kind = rkNode
|
||||
tos.slots[0].node = newNodeIT(nkEmpty, n.info, sym.typ.sons[0])
|
||||
# setup parameters:
|
||||
for i in 1 .. < min(tos.slots.len, L):
|
||||
tos.slots[i].kind = rkNode
|
||||
tos.slots[i].node = setupMacroParam(n.sons[i])
|
||||
for i in 1.. <sym.typ.len:
|
||||
tos.slots[i] = setupMacroParam(n.sons[i], sym.typ.sons[i])
|
||||
|
||||
let gp = sym.ast[genericParamsPos]
|
||||
for i in 0 .. <gp.len:
|
||||
let idx = sym.typ.len + i
|
||||
tos.slots[idx] = setupMacroParam(n.sons[idx], gp[i].sym.typ)
|
||||
|
||||
# temporary storage:
|
||||
#for i in L .. <maxSlots: tos.slots[i] = newNode(nkEmpty)
|
||||
result = rawExecute(c, start, tos).regToNode
|
||||
|
|
|
|||
|
|
@ -164,7 +164,8 @@ proc getSlotKind(t: PType): TSlotKind =
|
|||
const
|
||||
HighRegisterPressure = 40
|
||||
|
||||
proc getTemp(c: PCtx; typ: PType): TRegister =
|
||||
proc getTemp(c: PCtx; tt: PType): TRegister =
|
||||
let typ = tt.safeSkipTypes({tyStatic})
|
||||
let c = c.prc
|
||||
# we prefer the same slot kind here for efficiency. Unfortunately for
|
||||
# discardable return types we may not know the desired type. This can happen
|
||||
|
|
@ -685,7 +686,7 @@ proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =
|
|||
if dest < 0: dest = c.getTemp(n.typ)
|
||||
c.gABC(n, opc, dest, tmp)
|
||||
c.gABx(n, opc, 0, genType(c, n.typ))
|
||||
c.gABx(n, opc, 0, genType(c, arg.typ))
|
||||
c.gABx(n, opc, 0, genType(c, arg.typ.skipTypes({tyStatic})))
|
||||
c.freeTemp(tmp)
|
||||
|
||||
proc genCard(c: PCtx; n: PNode; dest: var TDest) =
|
||||
|
|
@ -1085,7 +1086,8 @@ proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
|
|||
c.freeTemp(tmp)
|
||||
|
||||
proc whichAsgnOpc(n: PNode): TOpcode =
|
||||
case n.typ.skipTypes(abstractRange-{tyTypeDesc}).kind
|
||||
let toSkip = abstractRange-{tyTypeDesc}
|
||||
case n.typ.skipTypes(toSkip).kind
|
||||
of tyBool, tyChar, tyEnum, tyOrdinal, tyInt..tyInt64, tyUInt..tyUInt64:
|
||||
opcAsgnInt
|
||||
of tyString, tyCString:
|
||||
|
|
@ -1559,6 +1561,11 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
|
|||
c.gABx(n, opcLdConst, dest, lit)
|
||||
of skType:
|
||||
genTypeLit(c, s.typ, dest)
|
||||
of skGenericParam:
|
||||
if c.prc.sym.kind == skMacro:
|
||||
genRdVar(c, n, dest, flags)
|
||||
else:
|
||||
internalError(n.info, "cannot generate code for: " & s.name.s)
|
||||
else:
|
||||
internalError(n.info, "cannot generate code for: " & s.name.s)
|
||||
of nkCallKinds:
|
||||
|
|
@ -1690,6 +1697,14 @@ proc genParams(c: PCtx; params: PNode) =
|
|||
c.prc.slots[i] = (inUse: true, kind: slotFixedLet)
|
||||
c.prc.maxSlots = max(params.len, 1)
|
||||
|
||||
proc genGenericParams(c: PCtx; gp: PNode) =
|
||||
var base = c.prc.maxSlots
|
||||
for i in 0.. <gp.len:
|
||||
var param = gp.sons[i].sym
|
||||
param.position = base + i # XXX: fix this earlier; make it consistent with templates
|
||||
c.prc.slots[base + i] = (inUse: true, kind: slotFixedLet)
|
||||
c.prc.maxSlots = base + gp.len
|
||||
|
||||
proc finalJumpTarget(c: PCtx; pc, diff: int) =
|
||||
internalAssert(-0x7fff < diff and diff < 0x7fff)
|
||||
let oldInstr = c.code[pc]
|
||||
|
|
@ -1761,6 +1776,8 @@ proc genProc(c: PCtx; s: PSym): int =
|
|||
c.prc = p
|
||||
# iterate over the parameters and allocate space for them:
|
||||
genParams(c, s.typ.n)
|
||||
if s.kind == skMacro and s.ast[genericParamsPos].kind != nkEmpty:
|
||||
genGenericParams(c, s.ast[genericParamsPos])
|
||||
if tfCapturesEnv in s.typ.flags:
|
||||
#let env = s.ast.sons[paramsPos].lastSon.sym
|
||||
#assert env.position == 2
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ $moduledesc
|
|||
$content
|
||||
"""
|
||||
|
||||
# * $analytics: Google analytics location, includes <script> tags
|
||||
doc.file = """<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
|
|
@ -1243,6 +1244,7 @@ dt pre > span.Operator ~ span.Identifier, dt pre > span.Operator ~ span.Operator
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
$analytics
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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.'
|
||||
|
||||
|
|
|
|||
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,
|
||||
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``
|
||||
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.TObject``. (This is used
|
||||
to introduce new object roots apart from ``system.RootObj``. (This is used
|
||||
in the GTK wrapper for instance.)
|
||||
|
||||
|
||||
|
|
@ -228,7 +228,7 @@ 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`
|
||||
|
|
@ -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
|
||||
|
|
@ -313,7 +313,7 @@ dispatching:
|
|||
.. code-block:: nim
|
||||
|
||||
type
|
||||
TThing = object of TObject
|
||||
TThing = object of RootObj
|
||||
TUnit = object of TThing
|
||||
x: int
|
||||
|
||||
|
|
|
|||
|
|
@ -878,6 +878,10 @@ else:
|
|||
let data = PData(info.key.data)
|
||||
assert data.fd == info.key.fd.TAsyncFD
|
||||
#echo("In poll ", data.fd.cint)
|
||||
if EvError in info.events:
|
||||
closeSocket(data.fd)
|
||||
continue
|
||||
|
||||
if EvRead in info.events:
|
||||
# Callback may add items to ``data.readCBs`` which causes issues if
|
||||
# we are iterating over ``data.readCBs`` at the same time. We therefore
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -32,21 +32,12 @@
|
|||
## the server.
|
||||
##
|
||||
## .. code-block:: Nim
|
||||
## var headers: string = "Content-Type: multipart/form-data; boundary=xyz\c\L"
|
||||
## var body: string = "--xyz\c\L"
|
||||
## # soap 1.2 output
|
||||
## body.add("Content-Disposition: form-data; name=\"output\"\c\L")
|
||||
## body.add("\c\Lsoap12\c\L")
|
||||
## var data = newMultipartData()
|
||||
## data["output"] = "soap12"
|
||||
## data["uploaded_file"] = ("test.html", "text/html",
|
||||
## "<html><head></head><body><p>test</p></body></html>")
|
||||
##
|
||||
## # html
|
||||
## body.add("--xyz\c\L")
|
||||
## body.add("Content-Disposition: form-data; name=\"uploaded_file\";" &
|
||||
## " filename=\"test.html\"\c\L")
|
||||
## body.add("Content-Type: text/html\c\L")
|
||||
## body.add("\c\L<html><head></head><body><p>test</p></body></html>\c\L")
|
||||
## body.add("--xyz--")
|
||||
##
|
||||
## echo(postContent("http://validator.w3.org/check", headers, body))
|
||||
## echo postContent("http://validator.w3.org/check", multipart=data)
|
||||
##
|
||||
## Asynchronous HTTP requests
|
||||
## ==========================
|
||||
|
|
@ -88,7 +79,7 @@
|
|||
## constructor should be used for this purpose. However,
|
||||
## currently only basic authentication is supported.
|
||||
|
||||
import net, strutils, uri, parseutils, strtabs, base64, os
|
||||
import net, strutils, uri, parseutils, strtabs, base64, os, mimetypes, math
|
||||
import asyncnet, asyncdispatch
|
||||
import rawsockets
|
||||
|
||||
|
|
@ -103,6 +94,10 @@ type
|
|||
url*: Uri
|
||||
auth*: string
|
||||
|
||||
MultipartEntries* = openarray[tuple[name, content: string]]
|
||||
MultipartData* = ref object
|
||||
content: seq[string]
|
||||
|
||||
ProtocolError* = object of IOError ## exception that is raised when server
|
||||
## does not conform to the implemented
|
||||
## protocol
|
||||
|
|
@ -282,6 +277,109 @@ proc newProxy*(url: string, auth = ""): Proxy =
|
|||
## Constructs a new ``TProxy`` object.
|
||||
result = Proxy(url: parseUri(url), auth: auth)
|
||||
|
||||
proc newMultipartData*: MultipartData =
|
||||
## Constructs a new ``MultipartData`` object.
|
||||
MultipartData(content: @[])
|
||||
|
||||
proc add*(p: var MultipartData, name, content: string, filename: string = nil,
|
||||
contentType: string = nil) =
|
||||
## Add a value to the multipart data. Raises a `ValueError` exception if
|
||||
## `name`, `filename` or `contentType` contain newline characters.
|
||||
|
||||
if {'\c','\L'} in name:
|
||||
raise newException(ValueError, "name contains a newline character")
|
||||
if filename != nil and {'\c','\L'} in filename:
|
||||
raise newException(ValueError, "filename contains a newline character")
|
||||
if contentType != nil and {'\c','\L'} in contentType:
|
||||
raise newException(ValueError, "contentType contains a newline character")
|
||||
|
||||
var str = "Content-Disposition: form-data; name=\"" & name & "\""
|
||||
if filename != nil:
|
||||
str.add("; filename=\"" & filename & "\"")
|
||||
str.add("\c\L")
|
||||
if contentType != nil:
|
||||
str.add("Content-Type: " & contentType & "\c\L")
|
||||
str.add("\c\L" & content & "\c\L")
|
||||
|
||||
p.content.add(str)
|
||||
|
||||
proc add*(p: var MultipartData, xs: MultipartEntries): MultipartData
|
||||
{.discardable.} =
|
||||
## Add a list of multipart entries to the multipart data `p`. All values are
|
||||
## added without a filename and without a content type.
|
||||
##
|
||||
## .. code-block:: Nim
|
||||
## data.add({"action": "login", "format": "json"})
|
||||
for name, content in xs.items:
|
||||
p.add(name, content)
|
||||
result = p
|
||||
|
||||
proc newMultipartData*(xs: MultipartEntries): MultipartData =
|
||||
## Create a new multipart data object and fill it with the entries `xs`
|
||||
## directly.
|
||||
##
|
||||
## .. code-block:: Nim
|
||||
## var data = newMultipartData({"action": "login", "format": "json"})
|
||||
result = MultipartData(content: @[])
|
||||
result.add(xs)
|
||||
|
||||
proc addFiles*(p: var MultipartData, xs: openarray[tuple[name, file: string]]):
|
||||
MultipartData {.discardable.} =
|
||||
## Add files to a multipart data object. The file will be opened from your
|
||||
## disk, read and sent with the automatically determined MIME type. Raises an
|
||||
## `IOError` if the file cannot be opened or reading fails. To manually
|
||||
## specify file content, filename and MIME type, use `[]=` instead.
|
||||
##
|
||||
## .. code-block:: Nim
|
||||
## data.addFiles({"uploaded_file": "public/test.html"})
|
||||
var m = newMimetypes()
|
||||
for name, file in xs.items:
|
||||
var contentType: string
|
||||
let (dir, fName, ext) = splitFile(file)
|
||||
if ext.len > 0:
|
||||
contentType = m.getMimetype(ext[1..ext.high], nil)
|
||||
p.add(name, readFile(file), fName & ext, contentType)
|
||||
result = p
|
||||
|
||||
proc `[]=`*(p: var MultipartData, name, content: string) =
|
||||
## Add a multipart entry to the multipart data `p`. The value is added
|
||||
## without a filename and without a content type.
|
||||
##
|
||||
## .. code-block:: Nim
|
||||
## data["username"] = "NimUser"
|
||||
p.add(name, content)
|
||||
|
||||
proc `[]=`*(p: var MultipartData, name: string,
|
||||
file: tuple[name, contentType, content: string]) =
|
||||
## Add a file to the multipart data `p`, specifying filename, contentType and
|
||||
## content manually.
|
||||
##
|
||||
## .. code-block:: Nim
|
||||
## data["uploaded_file"] = ("test.html", "text/html",
|
||||
## "<html><head></head><body><p>test</p></body></html>")
|
||||
p.add(name, file.content, file.name, file.contentType)
|
||||
|
||||
proc format(p: MultipartData): tuple[header, body: string] =
|
||||
if p == nil or p.content == nil or p.content.len == 0:
|
||||
return ("", "")
|
||||
|
||||
# Create boundary that is not in the data to be formatted
|
||||
var bound: string
|
||||
while true:
|
||||
bound = $random(int.high)
|
||||
var found = false
|
||||
for s in p.content:
|
||||
if bound in s:
|
||||
found = true
|
||||
if not found:
|
||||
break
|
||||
|
||||
result.header = "Content-Type: multipart/form-data; boundary=" & bound & "\c\L"
|
||||
result.body = ""
|
||||
for s in p.content:
|
||||
result.body.add("--" & bound & "\c\L" & s)
|
||||
result.body.add("--" & bound & "--\c\L")
|
||||
|
||||
proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
|
||||
body = "",
|
||||
sslContext: SSLContext = defaultSSLContext,
|
||||
|
|
@ -294,7 +392,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)
|
||||
|
||||
|
|
@ -387,15 +487,30 @@ proc post*(url: string, extraHeaders = "", body = "",
|
|||
maxRedirects = 5,
|
||||
sslContext: SSLContext = defaultSSLContext,
|
||||
timeout = -1, userAgent = defUserAgent,
|
||||
proxy: Proxy = nil): Response =
|
||||
proxy: Proxy = nil,
|
||||
multipart: MultipartData = nil): Response =
|
||||
## | POSTs ``body`` to the ``url`` and returns a ``Response`` object.
|
||||
## | This proc adds the necessary Content-Length header.
|
||||
## | This proc also handles redirection.
|
||||
## | Extra headers can be specified and must be separated by ``\c\L``.
|
||||
## | An optional timeout can be specified in miliseconds, if reading from the
|
||||
## server takes longer than specified an ETimeout exception will be raised.
|
||||
var xh = extraHeaders & "Content-Length: " & $len(body) & "\c\L"
|
||||
result = request(url, httpPOST, xh, body, sslContext, timeout, userAgent,
|
||||
## | The optional ``multipart`` parameter can be used to create
|
||||
## ``multipart/form-data`` POSTs comfortably.
|
||||
let (mpHeaders, mpBody) = format(multipart)
|
||||
|
||||
template withNewLine(x): expr =
|
||||
if x.len > 0 and not x.endsWith("\c\L"):
|
||||
x & "\c\L"
|
||||
else:
|
||||
x
|
||||
|
||||
var xb = mpBody.withNewLine() & body.withNewLine()
|
||||
|
||||
var xh = extraHeaders.withNewLine() & mpHeaders.withNewLine() &
|
||||
withNewLine("Content-Length: " & $len(xb))
|
||||
|
||||
result = request(url, httpPOST, xh, xb, sslContext, timeout, userAgent,
|
||||
proxy)
|
||||
var lastUrl = ""
|
||||
for i in 1..maxRedirects:
|
||||
|
|
@ -410,14 +525,17 @@ proc postContent*(url: string, extraHeaders = "", body = "",
|
|||
maxRedirects = 5,
|
||||
sslContext: SSLContext = defaultSSLContext,
|
||||
timeout = -1, userAgent = defUserAgent,
|
||||
proxy: Proxy = nil): string =
|
||||
proxy: Proxy = nil,
|
||||
multipart: MultipartData = nil): string =
|
||||
## | POSTs ``body`` to ``url`` and returns the response's body as a string
|
||||
## | Raises exceptions for the status codes ``4xx`` and ``5xx``
|
||||
## | Extra headers can be specified and must be separated by ``\c\L``.
|
||||
## | An optional timeout can be specified in miliseconds, if reading from the
|
||||
## server takes longer than specified an ETimeout exception will be raised.
|
||||
## | The optional ``multipart`` parameter can be used to create
|
||||
## ``multipart/form-data`` POSTs comfortably.
|
||||
var r = post(url, extraHeaders, body, maxRedirects, sslContext, timeout,
|
||||
userAgent, proxy)
|
||||
userAgent, proxy, multipart)
|
||||
if r.status[0] in {'4','5'}:
|
||||
raise newException(HttpRequestError, r.status)
|
||||
else:
|
||||
|
|
@ -442,7 +560,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")
|
||||
|
|
@ -706,18 +826,9 @@ when isMainModule:
|
|||
#var r = get("http://validator.w3.org/check?uri=http%3A%2F%2Fgoogle.com&
|
||||
# charset=%28detect+automatically%29&doctype=Inline&group=0")
|
||||
|
||||
var headers: string = "Content-Type: multipart/form-data; boundary=xyz\c\L"
|
||||
var body: string = "--xyz\c\L"
|
||||
# soap 1.2 output
|
||||
body.add("Content-Disposition: form-data; name=\"output\"\c\L")
|
||||
body.add("\c\Lsoap12\c\L")
|
||||
var data = newMultipartData()
|
||||
data["output"] = "soap12"
|
||||
data["uploaded_file"] = ("test.html", "text/html",
|
||||
"<html><head></head><body><p>test</p></body></html>")
|
||||
|
||||
# html
|
||||
body.add("--xyz\c\L")
|
||||
body.add("Content-Disposition: form-data; name=\"uploaded_file\";" &
|
||||
" filename=\"test.html\"\c\L")
|
||||
body.add("Content-Type: text/html\c\L")
|
||||
body.add("\c\L<html><head></head><body><p>test</p></body></html>\c\L")
|
||||
body.add("--xyz--")
|
||||
|
||||
echo(postContent("http://validator.w3.org/check", headers, body))
|
||||
echo postContent("http://validator.w3.org/check", multipart=data)
|
||||
|
|
|
|||
228
lib/pure/md5.nim
228
lib/pure/md5.nim
|
|
@ -9,15 +9,17 @@
|
|||
|
||||
## Module for computing MD5 checksums.
|
||||
|
||||
import unsigned
|
||||
|
||||
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]
|
||||
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
|
||||
|
|
@ -31,57 +33,57 @@ 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) =
|
||||
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) =
|
||||
|
|
@ -92,92 +94,92 @@ 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
|
||||
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'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
|
||||
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) =
|
||||
## 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:
|
||||
copyMem(addr(c.buffer[Index]), input, PartLen)
|
||||
|
|
@ -196,7 +198,7 @@ proc md5Final*(c: var MD5Context, digest: var MD5Digest) =
|
|||
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)
|
||||
|
|
@ -241,5 +243,3 @@ when isMainModule:
|
|||
assert(getMD5("Frank jagt im komplett verwahrlosten Taxi quer durch Bayern") ==
|
||||
"7e716d0e702df0505fc72e2b89467910")
|
||||
assert($toMD5("") == "d41d8cd98f00b204e9800998ecf8427e")
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ proc `$`*(x: SocketHandle): string {.borrow.}
|
|||
|
||||
type
|
||||
Event* = enum
|
||||
EvRead, EvWrite
|
||||
EvRead, EvWrite, EvError
|
||||
|
||||
SelectorKey* = ref object
|
||||
fd*: SocketHandle
|
||||
|
|
@ -146,12 +146,19 @@ elif defined(linux):
|
|||
## on the ``fd``.
|
||||
result = @[]
|
||||
let evNum = epoll_wait(s.epollFD, addr s.events[0], 64.cint, timeout.cint)
|
||||
if evNum < 0: raiseOSError(osLastError())
|
||||
if evNum < 0:
|
||||
let err = osLastError()
|
||||
if err.cint == EINTR:
|
||||
return @[]
|
||||
raiseOSError(osLastError())
|
||||
if evNum == 0: return @[]
|
||||
for i in 0 .. <evNum:
|
||||
let fd = s.events[i].data.fd.SocketHandle
|
||||
|
||||
var evSet: set[Event] = {}
|
||||
if (s.events[i].events and EPOLLERR) != 0: evSet = evSet + {EvError}
|
||||
if (s.events[i].events and EPOLLHUP) != 0: evSet = evSet + {EvError}
|
||||
if (s.events[i].events and EPOLLRDHUP) != 0: evSet = evSet + {EvError}
|
||||
if (s.events[i].events and EPOLLIN) != 0: evSet = evSet + {EvRead}
|
||||
if (s.events[i].events and EPOLLOUT) != 0: evSet = evSet + {EvWrite}
|
||||
let selectorKey = s.fds[fd]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# Nim's Runtime Library
|
||||
# (c) Copyright 2012 Nim Contributors
|
||||
# (c) Copyright 2015 Nim Contributors
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
@ -9,12 +9,27 @@
|
|||
|
||||
## :Author: Zahary Karadjov
|
||||
##
|
||||
## This module implements the standard unit testing facilities such as
|
||||
## suites, fixtures and test cases as well as facilities for combinatorial
|
||||
## and randomzied test case generation (not yet available)
|
||||
## and object mocking (not yet available)
|
||||
## This module implements boilerplate to make testing easy.
|
||||
##
|
||||
## It is loosely based on C++'s boost.test and Haskell's QuickTest
|
||||
## Example:
|
||||
##
|
||||
## .. code:: nim
|
||||
##
|
||||
## suite "description for this stuff":
|
||||
## test "essential truths":
|
||||
## # give up and stop if this fails
|
||||
## require(true)
|
||||
##
|
||||
## test "slightly less obvious stuff":
|
||||
## # print a nasty message and move on, skipping
|
||||
## # the remainder of this block
|
||||
## check(1 != 1)
|
||||
## check("asd"[2] == 'd')
|
||||
##
|
||||
## test "out of bounds error is thrown on bad access":
|
||||
## let v = @[1, 2, 3] # you can do initialization here
|
||||
## expect(IndexError):
|
||||
## discard v[4]
|
||||
|
||||
import
|
||||
macros
|
||||
|
|
@ -209,3 +224,5 @@ if envOutLvl.len > 0:
|
|||
if $opt == envOutLvl:
|
||||
outputLevel = opt
|
||||
break
|
||||
|
||||
system.addQuitProc(resetAttributes)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ type
|
|||
waMarkGlobal, # part of the backup/debug mark&sweep
|
||||
waMarkPrecise, # part of the backup/debug mark&sweep
|
||||
waZctDecRef, waPush, waCycleDecRef, waMarkGray, waScan, waScanBlack,
|
||||
waCollectWhite,
|
||||
waCollectWhite #, waDebug
|
||||
|
||||
TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
|
||||
# A ref type can have a finalizer that is called before the object's
|
||||
|
|
@ -597,7 +597,13 @@ proc scan(s: PCell) =
|
|||
forAllChildren(s, waScan)
|
||||
|
||||
proc collectWhite(s: PCell) =
|
||||
if s.color == rcWhite and s notin gch.cycleRoots:
|
||||
# This is a hacky way to deal with the following problem (bug #1796)
|
||||
# Consider this content in cycleRoots:
|
||||
# x -> a; y -> a where 'a' is an acyclic object so not included in
|
||||
# cycleRoots itself. Then 'collectWhite' used to free 'a' twice. The
|
||||
# 'isAllocatedPtr' check prevents this. This also means we do not need
|
||||
# to query 's notin gch.cycleRoots' at all.
|
||||
if isAllocatedPtr(gch.region, s) and s.color == rcWhite:
|
||||
s.setColor(rcBlack)
|
||||
forAllChildren(s, waCollectWhite)
|
||||
freeCyclicCell(gch, s)
|
||||
|
|
@ -648,6 +654,28 @@ when useMarkForDebug or useBackupGc:
|
|||
if objStart != nil:
|
||||
markS(gch, objStart)
|
||||
|
||||
when logGC:
|
||||
var
|
||||
cycleCheckA: array[100, PCell]
|
||||
cycleCheckALen = 0
|
||||
|
||||
proc alreadySeen(c: PCell): bool =
|
||||
for i in 0 .. <cycleCheckALen:
|
||||
if cycleCheckA[i] == c: return true
|
||||
if cycleCheckALen == len(cycleCheckA):
|
||||
gcAssert(false, "cycle detection overflow")
|
||||
quit 1
|
||||
cycleCheckA[cycleCheckALen] = c
|
||||
inc cycleCheckALen
|
||||
|
||||
proc debugGraph(s: PCell) =
|
||||
if alreadySeen(s):
|
||||
writeCell("child cell (already seen) ", s)
|
||||
else:
|
||||
writeCell("cell {", s)
|
||||
forAllChildren(s, waDebug)
|
||||
c_fprintf(c_stdout, "}\n")
|
||||
|
||||
proc doOperation(p: pointer, op: TWalkOp) =
|
||||
if p == nil: return
|
||||
var c: PCell = usrToCell(p)
|
||||
|
|
@ -690,6 +718,7 @@ proc doOperation(p: pointer, op: TWalkOp) =
|
|||
of waMarkPrecise:
|
||||
when useMarkForDebug or useBackupGc:
|
||||
add(gch.tempStack, c)
|
||||
#of waDebug: debugGraph(c)
|
||||
|
||||
proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} =
|
||||
doOperation(d, TWalkOp(op))
|
||||
|
|
@ -702,7 +731,6 @@ when useMarkForDebug or useBackupGc:
|
|||
|
||||
proc collectRoots(gch: var TGcHeap) =
|
||||
for s in elements(gch.cycleRoots):
|
||||
excl(gch.cycleRoots, s)
|
||||
collectWhite(s)
|
||||
|
||||
proc collectCycles(gch: var TGcHeap) =
|
||||
|
|
|
|||
|
|
@ -1344,7 +1344,7 @@ when not defined(useNimRtl):
|
|||
else:
|
||||
dec(gch.recGcLock)
|
||||
|
||||
proc GC_setStrategy(strategy: TGC_Strategy) =
|
||||
proc GC_setStrategy(strategy: GC_Strategy) =
|
||||
case strategy
|
||||
of gcThroughput: nil
|
||||
of gcResponsiveness: nil
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ when defined(boehmgc):
|
|||
proc GC_disable() = boehmGC_disable()
|
||||
proc GC_enable() = boehmGC_enable()
|
||||
proc GC_fullCollect() = boehmGCfullCollect()
|
||||
proc GC_setStrategy(strategy: TGC_Strategy) = discard
|
||||
proc GC_setStrategy(strategy: GC_Strategy) = discard
|
||||
proc GC_enableMarkAndSweep() = discard
|
||||
proc GC_disableMarkAndSweep() = discard
|
||||
proc GC_getStatistics(): string = return ""
|
||||
|
|
@ -221,7 +221,7 @@ elif defined(nogc) and defined(useMalloc):
|
|||
proc GC_disable() = discard
|
||||
proc GC_enable() = discard
|
||||
proc GC_fullCollect() = discard
|
||||
proc GC_setStrategy(strategy: TGC_Strategy) = discard
|
||||
proc GC_setStrategy(strategy: GC_Strategy) = discard
|
||||
proc GC_enableMarkAndSweep() = discard
|
||||
proc GC_disableMarkAndSweep() = discard
|
||||
proc GC_getStatistics(): string = return ""
|
||||
|
|
@ -281,7 +281,7 @@ elif defined(nogc):
|
|||
proc GC_disable() = discard
|
||||
proc GC_enable() = discard
|
||||
proc GC_fullCollect() = discard
|
||||
proc GC_setStrategy(strategy: TGC_Strategy) = discard
|
||||
proc GC_setStrategy(strategy: GC_Strategy) = discard
|
||||
proc GC_enableMarkAndSweep() = discard
|
||||
proc GC_disableMarkAndSweep() = discard
|
||||
proc GC_getStatistics(): string = return ""
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
when defined(Unix):
|
||||
const
|
||||
lib = "libmysqlclient.so.15"
|
||||
lib = "libmysqlclient.so.(15|16|17|18)"
|
||||
when defined(Windows):
|
||||
const
|
||||
lib = "libmysql.dll"
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ when useWinVersion:
|
|||
from winlean import SocketHandle
|
||||
else:
|
||||
const
|
||||
versions = "(|.1.0.0|.0.9.9|.0.9.8|.0.9.7|.0.9.6|.0.9.5|.0.9.4)"
|
||||
versions = "(.10|.1.0.1|.1.0.0|.0.9.9|.0.9.8|.0.9.7|.0.9.6|.0.9.5|.0.9.4)"
|
||||
when defined(macosx):
|
||||
const
|
||||
DLLSSLName = "libssl" & versions & ".dylib"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ from strutils import join
|
|||
type
|
||||
TFoo * = object
|
||||
id: int
|
||||
func: proc(){.closure.}
|
||||
fn: proc(){.closure.}
|
||||
var foo_counter = 0
|
||||
var alive_foos = newseq[int](0)
|
||||
|
||||
|
|
@ -26,7 +26,7 @@ for i in 0 .. <10:
|
|||
|
||||
for i in 0 .. <10:
|
||||
let f = newFoo()
|
||||
f.func = proc =
|
||||
f.fn = proc =
|
||||
echo f.id
|
||||
|
||||
GC_fullcollect()
|
||||
|
|
|
|||
21
tests/gc/cyclecollector.nim
Normal file
21
tests/gc/cyclecollector.nim
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
# Program to detect bug #1796 reliably
|
||||
|
||||
type
|
||||
Node = ref object
|
||||
a, b: Node
|
||||
leaf: string
|
||||
|
||||
proc createCycle(leaf: string): Node =
|
||||
new result
|
||||
result.a = result
|
||||
shallowCopy result.leaf, leaf
|
||||
|
||||
proc main =
|
||||
for i in 0 .. 100_000:
|
||||
var leaf = "this is the leaf. it allocates"
|
||||
let x = createCycle(leaf)
|
||||
let y = createCycle(leaf)
|
||||
echo "done ", getOccupiedMem()
|
||||
|
||||
main()
|
||||
|
|
@ -196,7 +196,8 @@ write(stdout, "starting main...\n")
|
|||
main()
|
||||
|
||||
GC_fullCollect()
|
||||
# the M&S GC fails with this call and it's unclear why. Definitely something
|
||||
# we need to fix!
|
||||
GC_fullCollect()
|
||||
writeln(stdout, GC_getStatistics())
|
||||
write(stdout, "finished\n")
|
||||
|
||||
|
|
|
|||
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,87 @@ 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
|
||||
|
||||
# bug 1859
|
||||
|
||||
type
|
||||
TypeWith2Params[N, M: static[int]] = object
|
||||
|
||||
proc bindBothParams[N](x: TypeWith2Params[N, N]) = discard
|
||||
proc dontBind1[N,M](x: TypeWith2Params[N, M]) = discard
|
||||
proc dontBind2(x: TypeWith2Params) = discard
|
||||
|
||||
var bb_1: TypeWith2Params[2, 2]
|
||||
var bb_2: TypeWith2Params[2, 3]
|
||||
|
||||
bindBothParams(bb_1)
|
||||
reject bindBothParams(bb_2)
|
||||
|
||||
dontBind1 bb_1
|
||||
dontBind1 bb_2
|
||||
|
||||
dontBind2 bb_1
|
||||
dontBind2 bb_2
|
||||
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
||||
|
|
|
|||
|
|
@ -51,17 +51,17 @@ while i < s.len:
|
|||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@ AST a
|
|||
AST b
|
||||
(e: [55, 66], f: [77, 88])
|
||||
55
|
||||
10
|
||||
20Test
|
||||
20
|
||||
'''
|
||||
"""
|
||||
|
||||
|
|
@ -50,3 +53,22 @@ macro mB(data: static[Tb]): stmt =
|
|||
mA(a)
|
||||
mB(b)
|
||||
|
||||
type
|
||||
Foo[N: static[int], Z: static[string]] = object
|
||||
|
||||
macro staticIntMacro(f: static[int]): stmt = echo f
|
||||
staticIntMacro 10
|
||||
|
||||
var
|
||||
x: Foo[20, "Test"]
|
||||
|
||||
macro genericMacro[N; Z: static[string]](f: Foo[N, Z], ll = 3, zz = 12): stmt =
|
||||
echo N, Z
|
||||
|
||||
genericMacro x
|
||||
|
||||
template genericTemplate[N, Z](f: Foo[N, Z], ll = 3, zz = 12): int = N
|
||||
|
||||
static:
|
||||
echo genericTemplate(x) # Error: internal error: (filename: compiler/evaltempl.nim, line: 39)
|
||||
|
||||
|
|
|
|||
|
|
@ -107,12 +107,15 @@ proc dllTests(r: var TResults, cat: Category, options: string) =
|
|||
# ------------------------------ GC tests -------------------------------------
|
||||
|
||||
proc gcTests(r: var TResults, cat: Category, options: string) =
|
||||
template test(filename: expr): stmt =
|
||||
template testWithoutMs(filename: expr): stmt =
|
||||
testSpec r, makeTest("tests/gc" / filename, options, cat, actionRun)
|
||||
testSpec r, makeTest("tests/gc" / filename, options &
|
||||
" -d:release", cat, actionRun)
|
||||
testSpec r, makeTest("tests/gc" / filename, options &
|
||||
" -d:release -d:useRealtimeGC", cat, actionRun)
|
||||
|
||||
template test(filename: expr): stmt =
|
||||
testWithoutMs filename
|
||||
testSpec r, makeTest("tests/gc" / filename, options &
|
||||
" --gc:markAndSweep", cat, actionRun)
|
||||
testSpec r, makeTest("tests/gc" / filename, options &
|
||||
|
|
@ -124,13 +127,15 @@ proc gcTests(r: var TResults, cat: Category, options: string) =
|
|||
test "gctest"
|
||||
test "gcleak3"
|
||||
test "gcleak4"
|
||||
test "gcleak5"
|
||||
# Disabled because it works and takes too long to run:
|
||||
#test "gcleak5"
|
||||
test "weakrefs"
|
||||
test "cycleleak"
|
||||
test "closureleak"
|
||||
test "refarrayleak"
|
||||
test "stackrefleak"
|
||||
testWithoutMs "refarrayleak"
|
||||
|
||||
test "stackrefleak"
|
||||
test "cyclecollector"
|
||||
|
||||
# ------------------------- threading tests -----------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@
|
|||
; Write application registry keys
|
||||
WriteRegStr HKCU "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR\bin\?{c.name}.exe"
|
||||
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)"
|
||||
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe"
|
||||
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninstaller.exe"
|
||||
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\bin\?{c.name}.exe"
|
||||
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
|
||||
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ type
|
|||
gitCommit: string
|
||||
quotations: Table[string, tuple[quote, author: string]]
|
||||
numProcessors: int # Set by parallelBuild:n, only works for values > 0.
|
||||
gaId: string # google analytics ID, nil means analytics are disabled
|
||||
TRssItem = object
|
||||
year, month, day, title: string
|
||||
TAction = enum
|
||||
|
|
@ -144,7 +145,12 @@ proc parseCmdLine(c: var TConfigData) =
|
|||
c.vars[substr(val, 0, idx-1)] = substr(val, idx+1)
|
||||
of "website": action = actOnlyWebsite
|
||||
of "pdf": action = actPdf
|
||||
else: quit(usage)
|
||||
of "googleanalytics":
|
||||
c.gaId = val
|
||||
c.nimArgs.add("--doc.googleAnalytics:" & val & " ")
|
||||
else:
|
||||
echo("Invalid argument $1" % [key])
|
||||
quit(usage)
|
||||
of cmdEnd: break
|
||||
if c.infile.len == 0: quit(usage)
|
||||
|
||||
|
|
|
|||
|
|
@ -192,13 +192,15 @@ View at: localhost:5000
|
|||
</footer>
|
||||
|
||||
<script>
|
||||
# if c.gaId != nil:
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-48159761-1', 'nim-lang.org');
|
||||
ga('create', '${c.gaId}', 'nim-lang.org');
|
||||
ga('send', 'pageview');
|
||||
# end if
|
||||
|
||||
var timer;
|
||||
var prevIndex = 0;
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ Nim is efficient
|
|||
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,
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@ General
|
|||
- Scite: Included
|
||||
- Gedit: The `Aporia .lang file <https://github.com/nimrod-code/Aporia/blob/master/share/gtksourceview-2.0/language-specs/nimrod.lang>`_
|
||||
- jEdit: https://github.com/exhu/nimrod-misc/tree/master/jedit
|
||||
- TextMate: Available in bundle installer (`Repository <https://github.com/textmate/nim.tmbundle>`_)
|
||||
|
||||
|
||||
.. container:: standout
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue