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
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,21 +62,31 @@ 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:
localError(n.info, errWrongNumberOfArguments)
addSon(result, arg)
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)
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,10 +781,12 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
of tyGenericBody:
result = newTypeS(tyGenericInvokation, c)
result.rawAddSon(paramType)
for i in 0 .. paramType.sonsLen - 2:
result.rawAddSon newTypeS(tyAnything, c)
# result.rawAddSon(copyType(paramType.sons[i], getCurrOwner(), true))
let dummyType = if paramType.sons[i].kind == tyStatic: tyUnknown
else: tyAnything
result.rawAddSon newTypeS(dummyType, c)
if paramType.lastSon.kind == tyUserTypeClass:
result.kind = tyUserTypeClassInst
result.rawAddSon paramType.lastSon

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.typ = makeTypeDesc(c, typ)
param: PSym
template paramSym(kind): expr =
newSym(kind, typeParamName, body.sym, body.sym.info)
case typ.kind
of tyStatic:
param = paramSym skConst
param.typ = typ.base
param.ast = typ.n
of tyUnknown:
param = paramSym skVar
param.typ = typ
else:
param = paramSym skType
param.typ = makeTypeDesc(c, typ)
addDecl(c, param)
for param in body.n[0]:
@@ -626,6 +647,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
elif skipTypes(a, {tyRange}).kind == f.kind: result = isSubtype
of tyRange:
if a.kind == f.kind:
if f.base.kind == tyNone: return isGeneric
result = typeRel(c, base(f), base(a))
# bugfix: accept integer conversions here
#if result < isGeneric: result = isNone
@@ -672,22 +694,27 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
else:
fRange = prev
result = typeRel(c, f.sons[1], a.sons[1])
if result < isGeneric:
result = isNone
elif tfUnresolved in fRange.flags and
rangeHasStaticIf(fRange):
# This is a range from an array instantiated with a generic
# static param. We must extract the static param here and bind
# it to the size of the currently supplied array.
var
rangeStaticT = fRange.getStaticTypeFromRange
replacementT = newTypeWithSons(c.c, tyStatic, @[tyInt.getSysType])
inputUpperBound = a.sons[0].n[1].intVal
# we must correct for the off-by-one discrepancy between
# ranges and static params:
replacementT.n = newIntNode(nkIntLit, inputUpperBound + 1)
put(c.bindings, rangeStaticT, replacementT)
result = isGeneric
if result < isGeneric: return isNone
if rangeHasStaticIf(fRange):
if tfUnresolved in fRange.flags:
# This is a range from an array instantiated with a generic
# static param. We must extract the static param here and bind
# it to the size of the currently supplied array.
var
rangeStaticT = fRange.getStaticTypeFromRange
replacementT = newTypeWithSons(c.c, tyStatic, @[tyInt.getSysType])
inputUpperBound = a.sons[0].n[1].intVal
# we must correct for the off-by-one discrepancy between
# ranges and static params:
replacementT.n = newIntNode(nkIntLit, inputUpperBound + 1)
put(c.bindings, rangeStaticT, replacementT)
return isGeneric
let len = tryResolvingStaticExpr(c, fRange.n[1])
if len.kind == nkIntLit and len.intVal+1 == lengthOrd(a):
return # if we get this far, the result is already good
else:
return isNone
elif lengthOrd(fRange) != lengthOrd(a):
result = isNone
else: discard
@@ -945,7 +972,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
else:
internalAssert a.sons != nil and a.sons.len > 0
c.typedescMatched = true
result = typeRel(c, f.base, a.base)
result = typeRel(c, f.base, a.skipTypes({tyGenericParam, tyTypeDesc}))
else:
result = isNone
else:
@@ -977,15 +1004,19 @@ 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))
if prev == nil:
@@ -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:
@@ -1045,10 +1077,10 @@ proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation =
initCandidate(c, m, f)
result = typeRel(m, f, a)
proc getInstantiatedType(c: PContext, arg: PNode, m: TCandidate,
f: PType): PType =
proc getInstantiatedType(c: PContext, arg: PNode, m: TCandidate,
f: PType): PType =
result = PType(idTableGet(m.bindings, f))
if result == nil:
if result == nil:
result = generateTypeInstance(c, m.bindings, arg, f)
if result == nil:
internalError(arg.info, "getInstantiatedType")
@@ -1058,7 +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)
@@ -1130,7 +1162,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
arg = argSemantized
argType = argType
c = m.c
if tfHasStatic in fMaybeStatic.flags:
# XXX: When implicit statics are the default
# this will be done earlier - we just have to
@@ -1144,7 +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

@@ -40,7 +40,7 @@ These integer types are pre-defined:
``int``
the generic signed integer type; its size is platform dependent and has the
same size as a pointer. This type should be used in general. An integer
same size as a pointer. This type should be used in general. An integer
literal that has no type suffix is of this type.
intXX
@@ -51,7 +51,7 @@ intXX
``uint``
the generic `unsigned integer`:idx: type; its size is platform dependent and
has the same size as a pointer. An integer literal with the type
has the same size as a pointer. An integer literal with the type
suffix ``'u`` is of this type.
uintXX
@@ -59,15 +59,15 @@ uintXX
(example: uint16 is a 16 bit wide unsigned integer).
The current implementation supports ``uint8``, ``uint16``, ``uint32``,
``uint64``. Literals of these types have the suffix 'uXX.
Unsigned operations all wrap around; they cannot lead to over- or
Unsigned operations all wrap around; they cannot lead to over- or
underflow errors.
In addition to the usual arithmetic operators for signed and unsigned integers
(``+ - *`` etc.) there are also operators that formally work on *signed*
integers but treat their arguments as *unsigned*: They are mostly provided
for backwards compatibility with older versions of the language that lacked
unsigned integer types. These unsigned operations for signed integers use
(``+ - *`` etc.) there are also operators that formally work on *signed*
integers but treat their arguments as *unsigned*: They are mostly provided
for backwards compatibility with older versions of the language that lacked
unsigned integer types. These unsigned operations for signed integers use
the ``%`` suffix as convention:
@@ -98,7 +98,7 @@ operation meaning
kinds of integer types are used: the smaller type is converted to the larger.
A `narrowing type conversion`:idx: converts a larger to a smaller type (for
example ``int32 -> int16``. A `widening type conversion`:idx: converts a
example ``int32 -> int16``. A `widening type conversion`:idx: converts a
smaller type to a larger type (for example ``int16 -> int32``). In Nim only
widening type conversions are *implicit*:
@@ -111,7 +111,7 @@ widening type conversions are *implicit*:
However, ``int`` literals are implicitly convertible to a smaller integer type
if the literal's value fits this smaller type and such a conversion is less
expensive than other implicit conversions, so ``myInt16 + 34`` produces
expensive than other implicit conversions, so ``myInt16 + 34`` produces
an ``int16`` result.
For further details, see `Convertible relation`_.
@@ -137,12 +137,12 @@ determined). Assignments from the base type to one of its subrange types
A subrange type has the same size as its base type (``int`` in the example).
Nim requires `interval arithmetic`:idx: for subrange types over a set
of built-in operators that involve constants: ``x %% 3`` is of
type ``range[0..2]``. The following built-in operators for integers are
of built-in operators that involve constants: ``x %% 3`` is of
type ``range[0..2]``. The following built-in operators for integers are
affected by this rule: ``-``, ``+``, ``*``, ``min``, ``max``, ``succ``,
``pred``, ``mod``, ``div``, ``%%``, ``and`` (bitwise ``and``).
Bitwise ``and`` only produces a ``range`` if one of its operands is a
Bitwise ``and`` only produces a ``range`` if one of its operands is a
constant *x* so that (x+1) is a number of two.
(Bitwise ``and`` is then a ``%%`` operation.)
@@ -155,7 +155,7 @@ This means that the following code is accepted:
of 9: echo "C"
of 10: echo "D"
# note: no ``else`` required as (x and 3) + 7 has the type: range[7..10]
Pre-defined floating point types
--------------------------------
@@ -186,17 +186,17 @@ The IEEE standard defines five types of floating-point exceptions:
for example 0.0/0.0, sqrt(-1.0), and log(-37.8).
* Division by zero: divisor is zero and dividend is a finite nonzero number,
for example 1.0/0.0.
* Overflow: operation produces a result that exceeds the range of the exponent,
* Overflow: operation produces a result that exceeds the range of the exponent,
for example MAXDOUBLE+0.0000000000001e308.
* Underflow: operation produces a result that is too small to be represented
* Underflow: operation produces a result that is too small to be represented
as a normal number, for example, MINDOUBLE * MINDOUBLE.
* Inexact: operation produces a result that cannot be represented with infinite
* Inexact: operation produces a result that cannot be represented with infinite
precision, for example, 2.0 / 3.0, log(1.1) and 0.1 in input.
The IEEE exceptions are either ignored at runtime or mapped to the
The IEEE exceptions are either ignored at runtime or mapped to the
Nim exceptions: `FloatInvalidOpError`:idx:, `FloatDivByZeroError`:idx:,
`FloatOverflowError`:idx:, `FloatUnderflowError`:idx:,
and `FloatInexactError`:idx:.
and `FloatInexactError`:idx:.
These exceptions inherit from the `FloatingPointError`:idx: base class.
Nim provides the pragmas `NaNChecks`:idx: and `InfChecks`:idx: to control
@@ -212,7 +212,7 @@ whether the IEEE exceptions are ignored or trap a Nim exception:
In the current implementation ``FloatDivByZeroError`` and ``FloatInexactError``
are never raised. ``FloatOverflowError`` is raised instead of
``FloatDivByZeroError``.
There is also a `floatChecks`:idx: pragma that is a short-cut for the
There is also a `floatChecks`:idx: pragma that is a short-cut for the
combination of ``NaNChecks`` and ``InfChecks`` pragmas. ``floatChecks`` are
turned off as default.
@@ -303,7 +303,7 @@ and ``pred`` are not available for them either.
The compiler supports the built-in stringify operator ``$`` for enumerations.
The stringify's result can be controlled by explicitly giving the string
The stringify's result can be controlled by explicitly giving the string
values to use:
.. code-block:: nim
@@ -315,12 +315,12 @@ values to use:
valueC = 2,
valueD = (3, "abc")
As can be seen from the example, it is possible to both specify a field's
As can be seen from the example, it is possible to both specify a field's
ordinal value and its string value by using a tuple. It is also
possible to only specify one of them.
An enum can be marked with the ``pure`` pragma so that it's fields are not
added to the current scope, so they always need to be accessed
added to the current scope, so they always need to be accessed
via ``MyEnum.value``:
.. code-block:: nim
@@ -328,7 +328,7 @@ via ``MyEnum.value``:
type
MyEnum {.pure.} = enum
valueA, valueB, valueC, valueD
echo valueA # error: Unknown identifier
echo MyEnum.valueA # works
@@ -364,22 +364,22 @@ cstring type
------------
The ``cstring`` type represents a pointer to a zero-terminated char array
compatible to the type ``char*`` in Ansi C. Its primary purpose lies in easy
interfacing with C. The index operation ``s[i]`` means the i-th *char* of
interfacing with C. The index operation ``s[i]`` means the i-th *char* of
``s``; however no bounds checking for ``cstring`` is performed making the
index operation unsafe.
A Nim ``string`` is implicitly convertible
A Nim ``string`` is implicitly convertible
to ``cstring`` for convenience. If a Nim string is passed to a C-style
variadic proc, it is implicitly converted to ``cstring`` too:
.. code-block:: nim
proc printf(formatstr: cstring) {.importc: "printf", varargs,
proc printf(formatstr: cstring) {.importc: "printf", varargs,
header: "<stdio.h>".}
printf("This works %s", "as expected")
Even though the conversion is implicit, it is not *safe*: The garbage collector
does not consider a ``cstring`` to be a root and may collect the underlying
does not consider a ``cstring`` to be a root and may collect the underlying
memory. However in practice this almost never happens as the GC considers
stack roots conservatively. One can use the builtin procs ``GC_ref`` and
``GC_unref`` to keep the string data alive for the rare cases where it does
@@ -390,7 +390,7 @@ string from a cstring:
.. code-block:: nim
var str: string = "Hello!"
var cstr: cstring = s
var cstr: cstring = str
var newstr: string = $cstr
@@ -410,9 +410,9 @@ integers from 0 to ``len(A)-1``. An array expression may be constructed by the
array constructor ``[]``.
Sequences are similar to arrays but of dynamic length which may change
during runtime (like strings). Sequences are implemented as growable arrays,
during runtime (like strings). Sequences are implemented as growable arrays,
allocating pieces of memory as items are added. A sequence ``S`` is always
indexed by integers from 0 to ``len(S)-1`` and its bounds are checked.
indexed by integers from 0 to ``len(S)-1`` and its bounds are checked.
Sequences can be constructed by the array constructor ``[]`` in conjunction
with the array to sequence operator ``@``. Another way to allocate space for a
sequence is to call the built-in ``newSeq`` procedure.
@@ -452,11 +452,11 @@ Open arrays
Often fixed size arrays turn out to be too inflexible; procedures should
be able to deal with arrays of different sizes. The `openarray`:idx: type
allows this; it can only be used for parameters. Openarrays are always
indexed with an ``int`` starting at position 0. The ``len``, ``low``
and ``high`` operations are available for open arrays too. Any array with
a compatible base type can be passed to an openarray parameter, the index
type does not matter. In addition to arrays sequences can also be passed
allows this; it can only be used for parameters. Openarrays are always
indexed with an ``int`` starting at position 0. The ``len``, ``low``
and ``high`` operations are available for open arrays too. Any array with
a compatible base type can be passed to an openarray parameter, the index
type does not matter. In addition to arrays sequences can also be passed
to an open array parameter.
The openarray type cannot be nested: multidimensional openarrays are not
@@ -467,7 +467,7 @@ Varargs
-------
A ``varargs`` parameter is an openarray parameter that additionally
allows to pass a variable number of arguments to a procedure. The compiler
allows to pass a variable number of arguments to a procedure. The compiler
converts the list of arguments to an array implicitly:
.. code-block:: nim
@@ -494,7 +494,7 @@ type conversions in this context:
# is transformed to:
myWriteln(stdout, [$123, $"def", $4.0])
In this example ``$`` is applied to any argument that is passed to the
In this example ``$`` is applied to any argument that is passed to the
parameter ``a``. (Note that ``$`` applied to strings is a nop.)
@@ -531,7 +531,7 @@ in future versions of the compiler.
person = (creditCard: "Peter", id: 20)
The implementation aligns the fields for best access performance. The alignment
is compatible with the way the C compiler does it.
is compatible with the way the C compiler does it.
For consistency with ``object`` declarations, tuples in a ``type`` section
can also be defined with indentation instead of ``[]``:
@@ -571,7 +571,7 @@ Object construction
-------------------
Objects can also be created with an `object construction expression`:idx: that
has the syntax ``T(fieldA: valueA, fieldB: valueB, ...)`` where ``T`` is
has the syntax ``T(fieldA: valueA, fieldB: valueB, ...)`` where ``T`` is
an ``object`` type or a ``ref object`` type:
.. code-block:: nim
@@ -617,10 +617,10 @@ An example:
# the following statement raises an `EInvalidField` exception, because
# n.kind's value does not fit and the ``nkString`` branch is not active:
n.strVal = ""
# invalid: would change the active object branch:
n.kind = nkInt
var x = PNode(kind: nkAdd, leftOp: PNode(kind: nkInt, intVal: 4),
rightOp: PNode(kind: nkInt, intVal: 2))
# valid: does not change the active object branch:
@@ -660,8 +660,8 @@ untraced references are *unsafe*. However for certain low-level operations
Traced references are declared with the **ref** keyword, untraced references
are declared with the **ptr** keyword.
An empty subscript ``[]`` notation can be used to derefer a reference,
the ``addr`` procedure returns the address of an item. An address is always
An empty subscript ``[]`` notation can be used to derefer a reference,
the ``addr`` procedure returns the address of an item. An address is always
an untraced reference.
Thus the usage of ``addr`` is an *unsafe* feature.
@@ -680,7 +680,7 @@ dereferencing operations for reference types:
var
n: PNode
new(n)
n.data = 9
n.data = 9
# no need to write n[].data; in fact n[].data is highly discouraged!
In order to simplify structural type checking, recursive tuples are not valid:
@@ -751,20 +751,20 @@ details like this when mixing garbage collected data with unmanaged memory.
Not nil annotation
------------------
All types for that ``nil`` is a valid value can be annotated to
All types for that ``nil`` is a valid value can be annotated to
exclude ``nil`` as a valid value with the ``not nil`` annotation:
.. code-block:: nim
type
PObject = ref TObj not nil
TProc = (proc (x, y: int)) not nil
proc p(x: PObject) =
echo "not nil"
# compiler catches this:
p(nil)
# and also this:
var x: PObject
p(x)
@@ -851,22 +851,22 @@ Examples:
forEach(printItem) # this will NOT compile because calling conventions differ
.. code-block:: nim
type
TOnMouseMove = proc (x, y: int) {.closure.}
proc onMouseMove(mouseX, mouseY: int) =
# has default calling convention
echo "x: ", mouseX, " y: ", mouseY
proc setOnMouseMove(mouseMoveEvent: TOnMouseMove) = discard
# ok, 'onMouseMove' has the default calling convention, which is compatible
# to 'closure':
setOnMouseMove(onMouseMove)
A subtle issue with procedural types is that the calling convention of the
procedure influences the type compatibility: procedural types are only
@@ -932,7 +932,7 @@ of the following conditions hold:
3) The procedure has a calling convention that differs from ``nimcall``.
4) The procedure is anonymous.
The rules' purpose is to prevent the case that extending a non-``procvar``
The rules' purpose is to prevent the case that extending a non-``procvar``
procedure with default parameters breaks client code.
The default calling convention is ``nimcall``, unless it is an inner proc (a
@@ -964,7 +964,7 @@ types are a perfect tool to model different currencies:
type
TDollar = distinct int
TEuro = distinct int
var
d: TDollar
e: TEuro
@@ -989,7 +989,7 @@ number without unit; and the same holds for division:
proc `*` (x: int, y: TDollar): TDollar =
result = TDollar(x * int(y))
proc `div` ...
This quickly gets tedious. The implementations are trivial and the compiler
@@ -1014,7 +1014,7 @@ currency. This can be solved with templates_.
template additive(typ: typedesc): stmt =
proc `+` *(x, y: typ): typ {.borrow.}
proc `-` *(x, y: typ): typ {.borrow.}
# unary operators:
proc `+` *(x: typ): typ {.borrow.}
proc `-` *(x: typ): typ {.borrow.}
@@ -1036,7 +1036,7 @@ currency. This can be solved with templates_.
additive(typ)
multiplicative(typ, base)
comparable(typ)
defineCurrency(TDollar, int)
defineCurrency(TEuro, int)
@@ -1127,21 +1127,21 @@ modules like `db_sqlite <db_sqlite.html>`_.
Void type
---------
The ``void`` type denotes the absense of any type. Parameters of
The ``void`` type denotes the absense of any type. Parameters of
type ``void`` are treated as non-existent, ``void`` as a return type means that
the procedure does not return a value:
.. code-block:: nim
proc nothing(x, y: void): void =
echo "ha"
nothing() # writes "ha" to stdout
The ``void`` type is particularly useful for generic code:
.. code-block:: nim
proc callProc[T](p: proc (x: T), x: T) =
when T is void:
when T is void:
p()
else:
p(x)
@@ -1151,13 +1151,13 @@ The ``void`` type is particularly useful for generic code:
callProc[int](intProc, 12)
callProc[void](emptyProc)
However, a ``void`` type cannot be inferred in generic code:
.. code-block:: nim
callProc(emptyProc)
callProc(emptyProc)
# Error: type mismatch: got (proc ())
# but expected one of:
# but expected one of:
# callProc(p: proc (T), x: T)
The ``void`` type is only valid for parameters and return types; other symbols

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``
can be used as its ancestor, but this is only a convention. Objects that have
no ancestor are implicitly ``final``. You can use the ``inheritable`` pragma
to introduce new object roots apart from ``system.TObject``. (This is used
currently not supported. If an object type has no suitable ancestor, ``RootObj``
can be used as its ancestor, but this is only a convention. Objects that have
no ancestor are implicitly ``final``. You can use the ``inheritable`` pragma
to introduce new object roots apart from ``system.RootObj``. (This is used
in the GTK wrapper for instance.)
@@ -199,7 +199,7 @@ This method call syntax is not restricted to objects, it can be used
for any type:
.. code-block:: nim
echo("abc".len) # is the same as echo(len("abc"))
echo("abc".toUpper())
echo({'a', 'b', 'c'}.card)
@@ -212,7 +212,7 @@ So "pure object oriented" code is easy to write:
.. code-block:: nim
import strutils
stdout.writeln("Give a list of numbers (separated by spaces): ")
stdout.write(stdin.readLine.split.map(parseInt).max.`$`)
stdout.writeln(" is the maximum!")
@@ -226,9 +226,9 @@ the same. But setting a value is different; for this a special setter syntax
is needed:
.. code-block:: nim
type
TSocket* = object of TObject
TSocket* = object of RootObj
FHost: int # cannot be accessed from the outside of the module
# the `F` prefix is a convention to avoid clashes since
# the accessors are named `host`
@@ -236,7 +236,7 @@ is needed:
proc `host=`*(s: var TSocket, value: int) {.inline.} =
## setter of hostAddr
s.FHost = value
proc host*(s: TSocket): int {.inline.} =
## getter of hostAddr
s.FHost
@@ -284,7 +284,7 @@ Procedures always use static dispatch. For dynamic dispatch replace the
.. code-block:: nim
type
PExpr = ref object of TObject ## abstract base class for an expression
PExpr = ref object of RootObj ## abstract base class for an expression
PLiteral = ref object of PExpr
x: int
PPlusExpr = ref object of PExpr
@@ -294,15 +294,15 @@ Procedures always use static dispatch. For dynamic dispatch replace the
method eval(e: PExpr): int =
# override this base method
quit "to override!"
method eval(e: PLiteral): int = e.x
method eval(e: PPlusExpr): int = eval(e.a) + eval(e.b)
proc newLit(x: int): PLiteral = PLiteral(x: x)
proc newPlus(a, b: PExpr): PPlusExpr = PPlusExpr(a: a, b: b)
echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4)))
Note that in the example the constructors ``newLit`` and ``newPlus`` are procs
because they should use static binding, but ``eval`` is a method because it
requires dynamic binding.
@@ -313,19 +313,19 @@ dispatching:
.. code-block:: nim
type
TThing = object of TObject
TThing = object of RootObj
TUnit = object of TThing
x: int
method collide(a, b: TThing) {.inline.} =
quit "to override!"
method collide(a: TThing, b: TUnit) {.inline.} =
echo "1"
method collide(a: TUnit, b: TThing) {.inline.} =
echo "2"
var
a, b: TUnit
collide(a, b) # output: 2
@@ -526,7 +526,7 @@ containers:
yield n.data
add(stack, n.ri) # push right subtree onto the stack
n = n.le # and follow the left pointer
var
root: PBinaryTree[string] # instantiate a PBinaryTree with ``string``
add(root, newNode("hello")) # instantiates ``newNode`` and ``add``
@@ -578,7 +578,7 @@ simple proc for logging:
proc log(msg: string) {.inline.} =
if debug: stdout.writeln(msg)
var
x = 4
log("x has the value: " & $x)
@@ -595,7 +595,7 @@ Turning the ``log`` proc into a template solves this problem:
template log(msg: string) =
if debug: stdout.writeln(msg)
var
x = 4
log("x has the value: " & $x)
@@ -622,11 +622,11 @@ via a special ``:`` syntax:
close(f)
else:
quit("cannot open: " & fn)
withFile(txt, "ttempl3.txt", fmWrite):
txt.writeln("line 1")
txt.writeln("line 2")
In the example the two ``writeln`` statements are bound to the ``body``
parameter. The ``withFile`` template contains boilerplate code and helps to
avoid a common bug: to forget to close the file. Note how the
@@ -739,7 +739,7 @@ Term rewriting macros
---------------------
Term rewriting macros can be used to enhance the compilation process
with user defined optimizations; see this `document <trmacros.html>`_ for
with user defined optimizations; see this `document <trmacros.html>`_ for
further information.

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,18 +9,20 @@
## Module for computing MD5 checksums.
type
MD5State = array[0..3, int32]
MD5Block = array[0..15, int32]
MD5CBits = array[0..7, int8]
MD5Digest* = array[0..15, int8]
MD5Buffer = array[0..63, int8]
MD5Context* {.final.} = object
import unsigned
type
MD5State = array[0..3, uint32]
MD5Block = array[0..15, uint32]
MD5CBits = array[0..7, uint8]
MD5Digest* = array[0..15, uint8]
MD5Buffer = array[0..63, uint8]
MD5Context* {.final.} = object
state: MD5State
count: array[0..1, int32]
count: array[0..1, uint32]
buffer: MD5Buffer
const
const
padding: cstring = "\x80\0\0\0" &
"\0\0\0\0\0\0\0\0" &
"\0\0\0\0\0\0\0\0" &
@@ -31,60 +33,60 @@ const
"\0\0\0\0\0\0\0\0" &
"\0\0\0\0"
proc F(x, y, z: int32): int32 {.inline.} =
proc F(x, y, z: uint32): uint32 {.inline.} =
result = (x and y) or ((not x) and z)
proc G(x, y, z: int32): int32 {.inline.} =
proc G(x, y, z: uint32): uint32 {.inline.} =
result = (x and z) or (y and (not z))
proc H(x, y, z: int32): int32 {.inline.} =
proc H(x, y, z: uint32): uint32 {.inline.} =
result = x xor y xor z
proc I(x, y, z: int32): int32 {.inline.} =
proc I(x, y, z: uint32): uint32 {.inline.} =
result = y xor (x or (not z))
proc rot(x: var int32, n: int8) {.inline.} =
x = toU32(x shl ze(n)) or (x shr toU32(32 -% ze(n)))
proc rot(x: var uint32, n: uint8) {.inline.} =
x = (x shl n) or (x shr (32'u32 - n))
proc FF(a: var int32, b, c, d, x: int32, s: int8, ac: int32) =
a = a +% F(b, c, d) +% x +% ac
proc FF(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
a = a + F(b, c, d) + x + ac
rot(a, s)
a = a +% b
a = a + b
proc GG(a: var int32, b, c, d, x: int32, s: int8, ac: int32) =
a = a +% G(b, c, d) +% x +% ac
proc GG(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
a = a + G(b, c, d) + x + ac
rot(a, s)
a = a +% b
a = a + b
proc HH(a: var int32, b, c, d, x: int32, s: int8, ac: int32) =
a = a +% H(b, c, d) +% x +% ac
proc HH(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
a = a + H(b, c, d) + x + ac
rot(a, s)
a = a +% b
a = a + b
proc II(a: var int32, b, c, d, x: int32, s: int8, ac: int32) =
a = a +% I(b, c, d) +% x +% ac
proc II(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
a = a + I(b, c, d) + x + ac
rot(a, s)
a = a +% b
a = a + b
proc encode(dest: var MD5Block, src: cstring) =
proc encode(dest: var MD5Block, src: cstring) =
var j = 0
for i in 0..high(dest):
dest[i] = toU32(ord(src[j]) or
ord(src[j+1]) shl 8 or
ord(src[j+2]) shl 16 or
ord(src[j+3]) shl 24)
dest[i] = uint32(ord(src[j])) or
uint32(ord(src[j+1])) shl 8 or
uint32(ord(src[j+2])) shl 16 or
uint32(ord(src[j+3])) shl 24
inc(j, 4)
proc decode(dest: var openArray[int8], src: openArray[int32]) =
proc decode(dest: var openArray[uint8], src: openArray[uint32]) =
var i = 0
for j in 0..high(src):
dest[i] = toU8(src[j] and 0xff'i32)
dest[i+1] = toU8(src[j] shr 8'i32 and 0xff'i32)
dest[i+2] = toU8(src[j] shr 16'i32 and 0xff'i32)
dest[i+3] = toU8(src[j] shr 24'i32 and 0xff'i32)
dest[i] = src[j] and 0xff'u32
dest[i+1] = src[j] shr 8 and 0xff'u32
dest[i+2] = src[j] shr 16 and 0xff'u32
dest[i+3] = src[j] shr 24 and 0xff'u32
inc(i, 4)
proc transform(buffer: pointer, state: var MD5State) =
proc transform(buffer: pointer, state: var MD5State) =
var
myBlock: MD5Block
encode(myBlock, cast[cstring](buffer))
@@ -92,111 +94,111 @@ proc transform(buffer: pointer, state: var MD5State) =
var b = state[1]
var c = state[2]
var d = state[3]
FF(a, b, c, d, myBlock[0], 7'i8, 0xD76AA478'i32)
FF(d, a, b, c, myBlock[1], 12'i8, 0xE8C7B756'i32)
FF(c, d, a, b, myBlock[2], 17'i8, 0x242070DB'i32)
FF(b, c, d, a, myBlock[3], 22'i8, 0xC1BDCEEE'i32)
FF(a, b, c, d, myBlock[4], 7'i8, 0xF57C0FAF'i32)
FF(d, a, b, c, myBlock[5], 12'i8, 0x4787C62A'i32)
FF(c, d, a, b, myBlock[6], 17'i8, 0xA8304613'i32)
FF(b, c, d, a, myBlock[7], 22'i8, 0xFD469501'i32)
FF(a, b, c, d, myBlock[8], 7'i8, 0x698098D8'i32)
FF(d, a, b, c, myBlock[9], 12'i8, 0x8B44F7AF'i32)
FF(c, d, a, b, myBlock[10], 17'i8, 0xFFFF5BB1'i32)
FF(b, c, d, a, myBlock[11], 22'i8, 0x895CD7BE'i32)
FF(a, b, c, d, myBlock[12], 7'i8, 0x6B901122'i32)
FF(d, a, b, c, myBlock[13], 12'i8, 0xFD987193'i32)
FF(c, d, a, b, myBlock[14], 17'i8, 0xA679438E'i32)
FF(b, c, d, a, myBlock[15], 22'i8, 0x49B40821'i32)
GG(a, b, c, d, myBlock[1], 5'i8, 0xF61E2562'i32)
GG(d, a, b, c, myBlock[6], 9'i8, 0xC040B340'i32)
GG(c, d, a, b, myBlock[11], 14'i8, 0x265E5A51'i32)
GG(b, c, d, a, myBlock[0], 20'i8, 0xE9B6C7AA'i32)
GG(a, b, c, d, myBlock[5], 5'i8, 0xD62F105D'i32)
GG(d, a, b, c, myBlock[10], 9'i8, 0x02441453'i32)
GG(c, d, a, b, myBlock[15], 14'i8, 0xD8A1E681'i32)
GG(b, c, d, a, myBlock[4], 20'i8, 0xE7D3FBC8'i32)
GG(a, b, c, d, myBlock[9], 5'i8, 0x21E1CDE6'i32)
GG(d, a, b, c, myBlock[14], 9'i8, 0xC33707D6'i32)
GG(c, d, a, b, myBlock[3], 14'i8, 0xF4D50D87'i32)
GG(b, c, d, a, myBlock[8], 20'i8, 0x455A14ED'i32)
GG(a, b, c, d, myBlock[13], 5'i8, 0xA9E3E905'i32)
GG(d, a, b, c, myBlock[2], 9'i8, 0xFCEFA3F8'i32)
GG(c, d, a, b, myBlock[7], 14'i8, 0x676F02D9'i32)
GG(b, c, d, a, myBlock[12], 20'i8, 0x8D2A4C8A'i32)
HH(a, b, c, d, myBlock[5], 4'i8, 0xFFFA3942'i32)
HH(d, a, b, c, myBlock[8], 11'i8, 0x8771F681'i32)
HH(c, d, a, b, myBlock[11], 16'i8, 0x6D9D6122'i32)
HH(b, c, d, a, myBlock[14], 23'i8, 0xFDE5380C'i32)
HH(a, b, c, d, myBlock[1], 4'i8, 0xA4BEEA44'i32)
HH(d, a, b, c, myBlock[4], 11'i8, 0x4BDECFA9'i32)
HH(c, d, a, b, myBlock[7], 16'i8, 0xF6BB4B60'i32)
HH(b, c, d, a, myBlock[10], 23'i8, 0xBEBFBC70'i32)
HH(a, b, c, d, myBlock[13], 4'i8, 0x289B7EC6'i32)
HH(d, a, b, c, myBlock[0], 11'i8, 0xEAA127FA'i32)
HH(c, d, a, b, myBlock[3], 16'i8, 0xD4EF3085'i32)
HH(b, c, d, a, myBlock[6], 23'i8, 0x04881D05'i32)
HH(a, b, c, d, myBlock[9], 4'i8, 0xD9D4D039'i32)
HH(d, a, b, c, myBlock[12], 11'i8, 0xE6DB99E5'i32)
HH(c, d, a, b, myBlock[15], 16'i8, 0x1FA27CF8'i32)
HH(b, c, d, a, myBlock[2], 23'i8, 0xC4AC5665'i32)
II(a, b, c, d, myBlock[0], 6'i8, 0xF4292244'i32)
II(d, a, b, c, myBlock[7], 10'i8, 0x432AFF97'i32)
II(c, d, a, b, myBlock[14], 15'i8, 0xAB9423A7'i32)
II(b, c, d, a, myBlock[5], 21'i8, 0xFC93A039'i32)
II(a, b, c, d, myBlock[12], 6'i8, 0x655B59C3'i32)
II(d, a, b, c, myBlock[3], 10'i8, 0x8F0CCC92'i32)
II(c, d, a, b, myBlock[10], 15'i8, 0xFFEFF47D'i32)
II(b, c, d, a, myBlock[1], 21'i8, 0x85845DD1'i32)
II(a, b, c, d, myBlock[8], 6'i8, 0x6FA87E4F'i32)
II(d, a, b, c, myBlock[15], 10'i8, 0xFE2CE6E0'i32)
II(c, d, a, b, myBlock[6], 15'i8, 0xA3014314'i32)
II(b, c, d, a, myBlock[13], 21'i8, 0x4E0811A1'i32)
II(a, b, c, d, myBlock[4], 6'i8, 0xF7537E82'i32)
II(d, a, b, c, myBlock[11], 10'i8, 0xBD3AF235'i32)
II(c, d, a, b, myBlock[2], 15'i8, 0x2AD7D2BB'i32)
II(b, c, d, a, myBlock[9], 21'i8, 0xEB86D391'i32)
state[0] = state[0] +% a
state[1] = state[1] +% b
state[2] = state[2] +% c
state[3] = state[3] +% d
proc md5Init*(c: var MD5Context) =
## initializes a MD5Context
c.state[0] = 0x67452301'i32
c.state[1] = 0xEFCDAB89'i32
c.state[2] = 0x98BADCFE'i32
c.state[3] = 0x10325476'i32
c.count[0] = 0'i32
c.count[1] = 0'i32
FF(a, b, c, d, myBlock[0], 7'u8, 0xD76AA478'u32)
FF(d, a, b, c, myBlock[1], 12'u8, 0xE8C7B756'u32)
FF(c, d, a, b, myBlock[2], 17'u8, 0x242070DB'u32)
FF(b, c, d, a, myBlock[3], 22'u8, 0xC1BDCEEE'u32)
FF(a, b, c, d, myBlock[4], 7'u8, 0xF57C0FAF'u32)
FF(d, a, b, c, myBlock[5], 12'u8, 0x4787C62A'u32)
FF(c, d, a, b, myBlock[6], 17'u8, 0xA8304613'u32)
FF(b, c, d, a, myBlock[7], 22'u8, 0xFD469501'u32)
FF(a, b, c, d, myBlock[8], 7'u8, 0x698098D8'u32)
FF(d, a, b, c, myBlock[9], 12'u8, 0x8B44F7AF'u32)
FF(c, d, a, b, myBlock[10], 17'u8, 0xFFFF5BB1'u32)
FF(b, c, d, a, myBlock[11], 22'u8, 0x895CD7BE'u32)
FF(a, b, c, d, myBlock[12], 7'u8, 0x6B901122'u32)
FF(d, a, b, c, myBlock[13], 12'u8, 0xFD987193'u32)
FF(c, d, a, b, myBlock[14], 17'u8, 0xA679438E'u32)
FF(b, c, d, a, myBlock[15], 22'u8, 0x49B40821'u32)
GG(a, b, c, d, myBlock[1], 5'u8, 0xF61E2562'u32)
GG(d, a, b, c, myBlock[6], 9'u8, 0xC040B340'u32)
GG(c, d, a, b, myBlock[11], 14'u8, 0x265E5A51'u32)
GG(b, c, d, a, myBlock[0], 20'u8, 0xE9B6C7AA'u32)
GG(a, b, c, d, myBlock[5], 5'u8, 0xD62F105D'u32)
GG(d, a, b, c, myBlock[10], 9'u8, 0x02441453'u32)
GG(c, d, a, b, myBlock[15], 14'u8, 0xD8A1E681'u32)
GG(b, c, d, a, myBlock[4], 20'u8, 0xE7D3FBC8'u32)
GG(a, b, c, d, myBlock[9], 5'u8, 0x21E1CDE6'u32)
GG(d, a, b, c, myBlock[14], 9'u8, 0xC33707D6'u32)
GG(c, d, a, b, myBlock[3], 14'u8, 0xF4D50D87'u32)
GG(b, c, d, a, myBlock[8], 20'u8, 0x455A14ED'u32)
GG(a, b, c, d, myBlock[13], 5'u8, 0xA9E3E905'u32)
GG(d, a, b, c, myBlock[2], 9'u8, 0xFCEFA3F8'u32)
GG(c, d, a, b, myBlock[7], 14'u8, 0x676F02D9'u32)
GG(b, c, d, a, myBlock[12], 20'u8, 0x8D2A4C8A'u32)
HH(a, b, c, d, myBlock[5], 4'u8, 0xFFFA3942'u32)
HH(d, a, b, c, myBlock[8], 11'u8, 0x8771F681'u32)
HH(c, d, a, b, myBlock[11], 16'u8, 0x6D9D6122'u32)
HH(b, c, d, a, myBlock[14], 23'u8, 0xFDE5380C'u32)
HH(a, b, c, d, myBlock[1], 4'u8, 0xA4BEEA44'u32)
HH(d, a, b, c, myBlock[4], 11'u8, 0x4BDECFA9'u32)
HH(c, d, a, b, myBlock[7], 16'u8, 0xF6BB4B60'u32)
HH(b, c, d, a, myBlock[10], 23'u8, 0xBEBFBC70'u32)
HH(a, b, c, d, myBlock[13], 4'u8, 0x289B7EC6'u32)
HH(d, a, b, c, myBlock[0], 11'u8, 0xEAA127FA'u32)
HH(c, d, a, b, myBlock[3], 16'u8, 0xD4EF3085'u32)
HH(b, c, d, a, myBlock[6], 23'u8, 0x04881D05'u32)
HH(a, b, c, d, myBlock[9], 4'u8, 0xD9D4D039'u32)
HH(d, a, b, c, myBlock[12], 11'u8, 0xE6DB99E5'u32)
HH(c, d, a, b, myBlock[15], 16'u8, 0x1FA27CF8'u32)
HH(b, c, d, a, myBlock[2], 23'u8, 0xC4AC5665'u32)
II(a, b, c, d, myBlock[0], 6'u8, 0xF4292244'u32)
II(d, a, b, c, myBlock[7], 10'u8, 0x432AFF97'u32)
II(c, d, a, b, myBlock[14], 15'u8, 0xAB9423A7'u32)
II(b, c, d, a, myBlock[5], 21'u8, 0xFC93A039'u32)
II(a, b, c, d, myBlock[12], 6'u8, 0x655B59C3'u32)
II(d, a, b, c, myBlock[3], 10'u8, 0x8F0CCC92'u32)
II(c, d, a, b, myBlock[10], 15'u8, 0xFFEFF47D'u32)
II(b, c, d, a, myBlock[1], 21'u8, 0x85845DD1'u32)
II(a, b, c, d, myBlock[8], 6'u8, 0x6FA87E4F'u32)
II(d, a, b, c, myBlock[15], 10'u8, 0xFE2CE6E0'u32)
II(c, d, a, b, myBlock[6], 15'u8, 0xA3014314'u32)
II(b, c, d, a, myBlock[13], 21'u8, 0x4E0811A1'u32)
II(a, b, c, d, myBlock[4], 6'u8, 0xF7537E82'u32)
II(d, a, b, c, myBlock[11], 10'u8, 0xBD3AF235'u32)
II(c, d, a, b, myBlock[2], 15'u8, 0x2AD7D2BB'u32)
II(b, c, d, a, myBlock[9], 21'u8, 0xEB86D391'u32)
state[0] = state[0] + a
state[1] = state[1] + b
state[2] = state[2] + c
state[3] = state[3] + d
proc md5Init*(c: var MD5Context) =
## initializes a MD5Context
c.state[0] = 0x67452301'u32
c.state[1] = 0xEFCDAB89'u32
c.state[2] = 0x98BADCFE'u32
c.state[3] = 0x10325476'u32
c.count[0] = 0'u32
c.count[1] = 0'u32
zeroMem(addr(c.buffer), sizeof(MD5buffer))
proc md5Update*(c: var MD5Context, input: cstring, len: int) =
proc md5Update*(c: var MD5Context, input: cstring, len: int) =
## updates the MD5Context with the `input` data of length `len`
var input = input
var Index = (c.count[0] shr 3) and 0x3F
c.count[0] = c.count[0] +% toU32(len shl 3)
if c.count[0] < (len shl 3): c.count[1] = c.count[1] +% 1'i32
c.count[1] = c.count[1] +% toU32(len shr 29)
var Index = int((c.count[0] shr 3) and 0x3F)
c.count[0] = c.count[0] + (uint32(len) shl 3)
if c.count[0] < (uint32(len) shl 3): c.count[1] = c.count[1] + 1'u32
c.count[1] = c.count[1] + (uint32(len) shr 29)
var PartLen = 64 - Index
if len >= PartLen:
if len >= PartLen:
copyMem(addr(c.buffer[Index]), input, PartLen)
transform(addr(c.buffer), c.state)
var i = PartLen
while i + 63 < len:
while i + 63 < len:
transform(addr(input[i]), c.state)
inc(i, 64)
copyMem(addr(c.buffer[0]), addr(input[i]), len-i)
else:
copyMem(addr(c.buffer[Index]), addr(input[0]), len)
proc md5Final*(c: var MD5Context, digest: var MD5Digest) =
proc md5Final*(c: var MD5Context, digest: var MD5Digest) =
## finishes the MD5Context and stores the result in `digest`
var
Bits: MD5CBits
PadLen: int
decode(Bits, c.count)
var Index = (c.count[0] shr 3) and 0x3F
var Index = int((c.count[0] shr 3) and 0x3F)
if Index < 56: PadLen = 56 - Index
else: PadLen = 120 - Index
md5Update(c, padding, PadLen)
@@ -204,34 +206,34 @@ proc md5Final*(c: var MD5Context, digest: var MD5Digest) =
decode(digest, c.state)
zeroMem(addr(c), sizeof(MD5Context))
proc toMD5*(s: string): MD5Digest =
proc toMD5*(s: string): MD5Digest =
## computes the MD5Digest value for a string `s`
var c: MD5Context
md5Init(c)
md5Update(c, cstring(s), len(s))
md5Final(c, result)
proc `$`*(D: MD5Digest): string =
proc `$`*(D: MD5Digest): string =
## converts a MD5Digest value into its string representation
const digits = "0123456789abcdef"
result = ""
for i in 0..15:
for i in 0..15:
add(result, digits[(D[i] shr 4) and 0xF])
add(result, digits[D[i] and 0xF])
proc getMD5*(s: string): string =
proc getMD5*(s: string): string =
## computes an MD5 value of `s` and returns its string representation
var
var
c: MD5Context
d: MD5Digest
md5Init(c)
md5Update(c, cstring(s), len(s))
md5Final(c, d)
result = $d
proc `==`*(D1, D2: MD5Digest): bool =
proc `==`*(D1, D2: MD5Digest): bool =
## checks if two MD5Digest values are identical
for i in 0..15:
for i in 0..15:
if D1[i] != D2[i]: return false
return true
@@ -241,5 +243,3 @@ when isMainModule:
assert(getMD5("Frank jagt im komplett verwahrlosten Taxi quer durch Bayern") ==
"7e716d0e702df0505fc72e2b89467910")
assert($toMD5("") == "d41d8cd98f00b204e9800998ecf8427e")

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
@@ -595,9 +595,15 @@ proc scan(s: PCell) =
else:
s.setColor(rcWhite)
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

@@ -1,67 +1,67 @@
# Test various aspects
# Test various aspects
# bug #572
var a=12345678901'u64
var x = (x: 42, y: (a: 8, z: 10))
echo x.y
import
mvarious
type
PA = ref TA
PB = ref TB
TB = object
a: PA
TA = object
b: TB
x: int
proc getPA(): PA =
var
b: bool
b = not false
return nil
import
mvarious
type
PA = ref TA
PB = ref TB
TB = object
a: PA
TA = object
b: TB
x: int
proc getPA(): PA =
var
b: bool
b = not false
return nil
# bug #501
proc f(): int = 54
var
global: int
var
s: string
i: int
r: TA
r.b.a.x = 0
global = global + 1
exportme()
write(stdout, "Hallo wie heißt du? ")
write(stdout, getPA().x)
s = readLine(stdin)
i = 0
while i < s.len:
if s[i] == 'c': write(stdout, "'c' in deinem Namen gefunden\n")
i = i + 1
write(stdout, "Du heißt " & s)
var
global: int
var
s: string
i: int
r: TA
r.b.a.x = 0
global = global + 1
exportme()
write(stdout, "Hallo wie heißt du? ")
write(stdout, getPA().x)
s = readLine(stdin)
i = 0
while i < s.len:
if s[i] == 'c': write(stdout, "'c' in deinem Namen gefunden\n")
i = i + 1
write(stdout, "Du heißt " & s)
# bug #544
when false:
# yay, fails again
type Bar [T; I:range] = array[I, T]
proc foo*[T; I:range](a, b: Bar[T, I]): Bar[T, I] =
when len(a) != 3:
# Error: constant expression expected
{.fatal:"Dimensions have to be 3".}
#...
block:
var a, b: Bar[int, 0..2]
discard foo(a, b)
# yay, fails again
type Bar [T; I:range] = array[I, T]
proc foo*[T; I:range](a, b: Bar[T, I]): Bar[T, I] =
when len(a) != 3:
# Error: constant expression expected
{.fatal:"Dimensions have to be 3".}
#...
block:
var a, b: Bar[int, range[0..2]]
discard foo(a, b)
# bug #1788

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

@@ -5,16 +5,16 @@ Home
Welcome to Nim
--------------
**Nim** (formerly known as "Nimrod") is a statically typed, imperative
programming language that tries to give the programmer ultimate power without
**Nim** (formerly known as "Nimrod") is a statically typed, imperative
programming language that tries to give the programmer ultimate power without
compromises on runtime efficiency. This means it focuses on compile-time
mechanisms in all their various forms.
Beneath a nice infix/indentation based syntax with a
powerful (AST based, hygienic) macro system lies a semantic model that supports
a soft realtime GC on thread local heaps. Asynchronous message passing is used
between threads, so no "stop the world" mechanism is necessary. An unsafe
shared memory heap is also provided for the increased efficiency that results
Beneath a nice infix/indentation based syntax with a
powerful (AST based, hygienic) macro system lies a semantic model that supports
a soft realtime GC on thread local heaps. Asynchronous message passing is used
between threads, so no "stop the world" mechanism is necessary. An unsafe
shared memory heap is also provided for the increased efficiency that results
from that model.
@@ -24,7 +24,7 @@ Nim is efficient
* Native code generation (currently via compilation to C), not dependent on a
virtual machine: **Nim produces small executables without dependencies
for easy redistribution.**
* A fast **non-tracing** garbage collector that supports soft
* A fast **non-tracing** garbage collector that supports soft
real-time systems (like games).
* System programming features: Ability to manage your own memory and access the
hardware directly. Pointers to garbage collected memory are distinguished
@@ -33,22 +33,22 @@ Nim is efficient
* Cross-module inlining.
* Dynamic method binding with inlining and without virtual method table.
* Compile time evaluation of user-defined functions.
* Whole program dead code elimination: Only *used functions* are included in
* Whole program dead code elimination: Only *used functions* are included in
the executable.
* Value-based datatypes: For instance, objects and arrays can be allocated on
* Value-based datatypes: For instance, objects and arrays can be allocated on
the stack.
Nim is expressive
=================
* **The Nim compiler and all of the standard library are implemented in
* **The Nim compiler and all of the standard libraries are implemented in
Nim.**
* Built-in high level datatypes: strings, sets, sequences, etc.
* Modern type system with local type inference, tuples, variants,
* Modern type system with local type inference, tuples, variants,
generics, etc.
* User-defineable operators; code with new operators is often easier to read
than code which overloads built-in operators. For example, a
than code which overloads built-in operators. For example, a
``=~`` operator is defined in the ``re`` module.
* Macros can modify the abstract syntax tree at compile time.
@@ -58,7 +58,7 @@ Nim is elegant
* Macros can use the imperative paradigm to construct parse trees. Nim
does not require a different coding style for meta programming.
* Macros cannot change Nim's syntax because there is no need for it.
* Macros cannot change Nim's syntax because there is no need for it.
Nim's syntax is flexible enough.
* Statements are grouped by indentation but can span multiple lines.
Indentation must not contain tabulators so the compiler always sees
@@ -72,12 +72,12 @@ Nim plays nice with others
Porting to other platforms is easy.
* **The Nim Compiler can also generate C++ or Objective C for easier
interfacing.**
* There are lots of bindings: for example, bindings to GTK2, the Windows API,
the POSIX API, OpenGL, SDL, Cairo, Python, Lua, TCL, X11, libzip, PCRE,
* There are lots of bindings: for example, bindings to GTK2, the Windows API,
the POSIX API, OpenGL, SDL, Cairo, Python, Lua, TCL, X11, libzip, PCRE,
libcurl, mySQL and SQLite are included in the standard distribution or
can easily be obtained via the
`Nimble package manager <https://github.com/nim-lang/nimble>`_.
* A C to Nim conversion utility: New bindings to C libraries are easily
* A C to Nim conversion utility: New bindings to C libraries are easily
generated by ``c2nim``.

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