Merge branch 'devel' of https://github.com/Araq/Nim into devel

Conflicts:
	compiler/semexprs.nim
This commit is contained in:
Araq 2015-01-07 02:44:22 +01:00
commit 65310266d8
46 changed files with 991 additions and 490 deletions

1
.gitignore vendored
View file

@ -41,3 +41,4 @@ xcuserdata/
/testresults.html
/testresults.json
testament.db
/csources/

View file

@ -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

View file

@ -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))

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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]

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 []

View file

@ -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

View file

@ -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

View file

@ -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>
"""

View file

@ -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.

View file

@ -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

View file

@ -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

View file

@ -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.'

View file

@ -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

View file

@ -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

View file

@ -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")

View file

@ -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)

View file

@ -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")

View file

@ -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]

View file

@ -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)

View file

@ -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"

View file

@ -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) =

View file

@ -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

View file

@ -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 ""

View file

@ -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"

View file

@ -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"

View file

@ -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()

View 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()

View file

@ -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
View 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)

View file

@ -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

View file

@ -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

View file

@ -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]

View file

@ -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

View file

@ -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)

View file

@ -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 -----------------------------------

View file

@ -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}"

View file

@ -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)

View file

@ -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;

View file

@ -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,

View file

@ -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