Merge remote-tracking branch 'upstream/devel' into devel
This commit is contained in:
commit
8c5a47ee2b
148 changed files with 750 additions and 584 deletions
|
|
@ -314,7 +314,7 @@ type
|
||||||
# XXX put this into an include file to avoid this issue!
|
# XXX put this into an include file to avoid this issue!
|
||||||
tyNone, tyBool, tyChar,
|
tyNone, tyBool, tyChar,
|
||||||
tyEmpty, tyArrayConstr, tyNil, tyExpr, tyStmt, tyTypeDesc,
|
tyEmpty, tyArrayConstr, tyNil, tyExpr, tyStmt, tyTypeDesc,
|
||||||
tyGenericInvokation, # ``T[a, b]`` for types to invoke
|
tyGenericInvocation, # ``T[a, b]`` for types to invoke
|
||||||
tyGenericBody, # ``T[a, b, body]`` last parameter is the body
|
tyGenericBody, # ``T[a, b, body]`` last parameter is the body
|
||||||
tyGenericInst, # ``T[a, b, realInstance]`` instantiated generic type
|
tyGenericInst, # ``T[a, b, realInstance]`` instantiated generic type
|
||||||
# realInstance will be a concrete type like tyObject
|
# realInstance will be a concrete type like tyObject
|
||||||
|
|
@ -859,7 +859,7 @@ const
|
||||||
OverloadableSyms* = {skProc, skMethod, skIterator, skClosureIterator,
|
OverloadableSyms* = {skProc, skMethod, skIterator, skClosureIterator,
|
||||||
skConverter, skModule, skTemplate, skMacro}
|
skConverter, skModule, skTemplate, skMacro}
|
||||||
|
|
||||||
GenericTypes*: TTypeKinds = {tyGenericInvokation, tyGenericBody,
|
GenericTypes*: TTypeKinds = {tyGenericInvocation, tyGenericBody,
|
||||||
tyGenericParam}
|
tyGenericParam}
|
||||||
|
|
||||||
StructuralEquivTypes*: TTypeKinds = {tyArrayConstr, tyNil, tyTuple, tyArray,
|
StructuralEquivTypes*: TTypeKinds = {tyArrayConstr, tyNil, tyTuple, tyArray,
|
||||||
|
|
@ -1298,6 +1298,12 @@ proc initIdTable(x: var TIdTable) =
|
||||||
x.counter = 0
|
x.counter = 0
|
||||||
newSeq(x.data, StartSize)
|
newSeq(x.data, StartSize)
|
||||||
|
|
||||||
|
proc resetIdTable*(x: var TIdTable) =
|
||||||
|
x.counter = 0
|
||||||
|
# clear and set to old initial size:
|
||||||
|
setLen(x.data, 0)
|
||||||
|
setLen(x.data, StartSize)
|
||||||
|
|
||||||
proc initObjectSet(x: var TObjectSet) =
|
proc initObjectSet(x: var TObjectSet) =
|
||||||
x.counter = 0
|
x.counter = 0
|
||||||
newSeq(x.data, StartSize)
|
newSeq(x.data, StartSize)
|
||||||
|
|
@ -1350,7 +1356,7 @@ proc propagateToOwner*(owner, elem: PType) =
|
||||||
const HaveTheirOwnEmpty = {tySequence, tySet}
|
const HaveTheirOwnEmpty = {tySequence, tySet}
|
||||||
owner.flags = owner.flags + (elem.flags * {tfHasMeta})
|
owner.flags = owner.flags + (elem.flags * {tfHasMeta})
|
||||||
if tfNotNil in elem.flags:
|
if tfNotNil in elem.flags:
|
||||||
if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvokation}:
|
if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvocation}:
|
||||||
owner.flags.incl tfNotNil
|
owner.flags.incl tfNotNil
|
||||||
elif owner.kind notin HaveTheirOwnEmpty:
|
elif owner.kind notin HaveTheirOwnEmpty:
|
||||||
owner.flags.incl tfNeedsInit
|
owner.flags.incl tfNeedsInit
|
||||||
|
|
|
||||||
|
|
@ -119,8 +119,8 @@ proc hashType(c: var MD5Context, t: PType) =
|
||||||
c.hashSym(t.sym)
|
c.hashSym(t.sym)
|
||||||
|
|
||||||
case t.kind
|
case t.kind
|
||||||
of tyGenericBody, tyGenericInst, tyGenericInvokation:
|
of tyGenericBody, tyGenericInst, tyGenericInvocation:
|
||||||
for i in countup(0, sonsLen(t) -1 -ord(t.kind != tyGenericInvokation)):
|
for i in countup(0, sonsLen(t) -1 -ord(t.kind != tyGenericInvocation)):
|
||||||
c.hashType t.sons[i]
|
c.hashType t.sons[i]
|
||||||
of tyUserTypeClass:
|
of tyUserTypeClass:
|
||||||
internalAssert t.sym != nil and t.sym.owner != nil
|
internalAssert t.sym != nil and t.sym.owner != nil
|
||||||
|
|
|
||||||
|
|
@ -1390,7 +1390,7 @@ proc genSwap(p: BProc, e: PNode, d: var TLoc) =
|
||||||
genAssignment(p, b, tmp, {})
|
genAssignment(p, b, tmp, {})
|
||||||
|
|
||||||
proc rdSetElemLoc(a: TLoc, setType: PType): PRope =
|
proc rdSetElemLoc(a: TLoc, setType: PType): PRope =
|
||||||
# read a location of an set element; it may need a substraction operation
|
# read a location of an set element; it may need a subtraction operation
|
||||||
# before the set operation
|
# before the set operation
|
||||||
result = rdCharLoc(a)
|
result = rdCharLoc(a)
|
||||||
assert(setType.kind == tySet)
|
assert(setType.kind == tySet)
|
||||||
|
|
|
||||||
|
|
@ -223,7 +223,7 @@ proc processMergeInfo(L: var TBaseLexer, m: BModule) =
|
||||||
of "typeInfo": readIntSet(L, m.typeInfoMarker)
|
of "typeInfo": readIntSet(L, m.typeInfoMarker)
|
||||||
of "labels": m.labels = decodeVInt(L.buf, L.bufpos)
|
of "labels": m.labels = decodeVInt(L.buf, L.bufpos)
|
||||||
of "hasframe": m.frameDeclared = decodeVInt(L.buf, L.bufpos) != 0
|
of "hasframe": m.frameDeclared = decodeVInt(L.buf, L.bufpos) != 0
|
||||||
else: internalError("ccgmerge: unkown key: " & k)
|
else: internalError("ccgmerge: unknown key: " & k)
|
||||||
|
|
||||||
when not defined(nimhygiene):
|
when not defined(nimhygiene):
|
||||||
{.pragma: inject.}
|
{.pragma: inject.}
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ proc getUniqueType*(key: PType): PType =
|
||||||
#if obj.sym != nil and obj.sym.name.s == "TOption":
|
#if obj.sym != nil and obj.sym.name.s == "TOption":
|
||||||
# echo "for ", typeToString(key), " I returned "
|
# echo "for ", typeToString(key), " I returned "
|
||||||
# debug result
|
# debug result
|
||||||
of tyArrayConstr, tyGenericInvokation, tyGenericBody,
|
of tyArrayConstr, tyGenericInvocation, tyGenericBody,
|
||||||
tyOpenArray, tyArray, tySet, tyRange, tyTuple,
|
tyOpenArray, tyArray, tySet, tyRange, tyTuple,
|
||||||
tyPtr, tyRef, tySequence, tyForward, tyVarargs, tyProxy, tyVar:
|
tyPtr, tyRef, tySequence, tyForward, tyVarargs, tyProxy, tyVar:
|
||||||
# tuples are quite horrible as C does not support them directly and
|
# tuples are quite horrible as C does not support them directly and
|
||||||
|
|
|
||||||
|
|
@ -395,7 +395,7 @@ proc localVarDecl(p: BProc; s: PSym): PRope =
|
||||||
|
|
||||||
proc assignLocalVar(p: BProc, s: PSym) =
|
proc assignLocalVar(p: BProc, s: PSym) =
|
||||||
#assert(s.loc.k == locNone) # not yet assigned
|
#assert(s.loc.k == locNone) # not yet assigned
|
||||||
# this need not be fullfilled for inline procs; they are regenerated
|
# this need not be fulfilled for inline procs; they are regenerated
|
||||||
# for each module that uses them!
|
# for each module that uses them!
|
||||||
let decl = localVarDecl(p, s).con(";" & tnl)
|
let decl = localVarDecl(p, s).con(";" & tnl)
|
||||||
line(p, cpsLocals, decl)
|
line(p, cpsLocals, decl)
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openArray[string],
|
||||||
if not (frmt[i] in {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}): break
|
if not (frmt[i] in {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}): break
|
||||||
var idx = getVarIdx(varnames, id)
|
var idx = getVarIdx(varnames, id)
|
||||||
if idx >= 0: app(result, varvalues[idx])
|
if idx >= 0: app(result, varvalues[idx])
|
||||||
else: rawMessage(errUnkownSubstitionVar, id)
|
else: rawMessage(errUnknownSubstitionVar, id)
|
||||||
of '{':
|
of '{':
|
||||||
var id = ""
|
var id = ""
|
||||||
inc(i)
|
inc(i)
|
||||||
|
|
@ -138,7 +138,7 @@ proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openArray[string],
|
||||||
# search for the variable:
|
# search for the variable:
|
||||||
var idx = getVarIdx(varnames, id)
|
var idx = getVarIdx(varnames, id)
|
||||||
if idx >= 0: app(result, varvalues[idx])
|
if idx >= 0: app(result, varvalues[idx])
|
||||||
else: rawMessage(errUnkownSubstitionVar, id)
|
else: rawMessage(errUnknownSubstitionVar, id)
|
||||||
else: internalError("ropeFormatNamedVars")
|
else: internalError("ropeFormatNamedVars")
|
||||||
var start = i
|
var start = i
|
||||||
while i < L:
|
while i < L:
|
||||||
|
|
@ -272,7 +272,7 @@ proc complexName(k: TSymKind, n: PNode, baseName: string): string =
|
||||||
## type)?(,param type)*``. The callable type part will be added only if the
|
## type)?(,param type)*``. The callable type part will be added only if the
|
||||||
## node is not a proc, as those are the common ones. The suffix will be a dot
|
## node is not a proc, as those are the common ones. The suffix will be a dot
|
||||||
## and a single letter representing the type of the callable. The parameter
|
## and a single letter representing the type of the callable. The parameter
|
||||||
## types will be added with a preceeding dash. Return types won't be added.
|
## types will be added with a preceding dash. Return types won't be added.
|
||||||
##
|
##
|
||||||
## If you modify the output of this proc, please update the anchor generation
|
## If you modify the output of this proc, please update the anchor generation
|
||||||
## section of ``doc/docgen.txt``.
|
## section of ``doc/docgen.txt``.
|
||||||
|
|
|
||||||
|
|
@ -630,13 +630,13 @@ proc callCCompiler*(projectfile: string) =
|
||||||
res = execWithEcho(cmds[i])
|
res = execWithEcho(cmds[i])
|
||||||
if res != 0: rawMessage(errExecutionOfProgramFailed, [])
|
if res != 0: rawMessage(errExecutionOfProgramFailed, [])
|
||||||
elif optListCmd in gGlobalOptions or gVerbosity > 1:
|
elif optListCmd in gGlobalOptions or gVerbosity > 1:
|
||||||
res = execProcesses(cmds, {poEchoCmd, poUseShell, poParentStreams},
|
res = execProcesses(cmds, {poEchoCmd, poUsePath, poParentStreams},
|
||||||
gNumberOfProcessors)
|
gNumberOfProcessors)
|
||||||
elif gVerbosity == 1:
|
elif gVerbosity == 1:
|
||||||
res = execProcesses(cmds, {poUseShell, poParentStreams},
|
res = execProcesses(cmds, {poUsePath, poParentStreams},
|
||||||
gNumberOfProcessors, prettyCb)
|
gNumberOfProcessors, prettyCb)
|
||||||
else:
|
else:
|
||||||
res = execProcesses(cmds, {poUseShell, poParentStreams},
|
res = execProcesses(cmds, {poUsePath, poParentStreams},
|
||||||
gNumberOfProcessors)
|
gNumberOfProcessors)
|
||||||
if res != 0:
|
if res != 0:
|
||||||
if gNumberOfProcessors <= 1:
|
if gNumberOfProcessors <= 1:
|
||||||
|
|
|
||||||
|
|
@ -148,7 +148,7 @@ proc mapType(typ: PType): TJSTypeKind =
|
||||||
tyVarargs:
|
tyVarargs:
|
||||||
result = etyObject
|
result = etyObject
|
||||||
of tyNil: result = etyNull
|
of tyNil: result = etyNull
|
||||||
of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvokation,
|
of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvocation,
|
||||||
tyNone, tyFromExpr, tyForward, tyEmpty, tyFieldAccessor,
|
tyNone, tyFromExpr, tyForward, tyEmpty, tyFieldAccessor,
|
||||||
tyExpr, tyStmt, tyStatic, tyTypeDesc, tyTypeClasses:
|
tyExpr, tyStmt, tyStatic, tyTypeDesc, tyTypeClasses:
|
||||||
result = etyNone
|
result = etyNone
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import
|
||||||
|
|
||||||
discard """
|
discard """
|
||||||
The basic approach is that captured vars need to be put on the heap and
|
The basic approach is that captured vars need to be put on the heap and
|
||||||
that the calling chain needs to be explicitely modelled. Things to consider:
|
that the calling chain needs to be explicitly modelled. Things to consider:
|
||||||
|
|
||||||
proc a =
|
proc a =
|
||||||
var v = 0
|
var v = 0
|
||||||
|
|
@ -583,7 +583,7 @@ proc searchForInnerProcs(o: POuterContext, n: PNode, env: PEnv) =
|
||||||
elif it.kind == nkIdentDefs:
|
elif it.kind == nkIdentDefs:
|
||||||
var L = sonsLen(it)
|
var L = sonsLen(it)
|
||||||
if it.sons[0].kind == nkSym:
|
if it.sons[0].kind == nkSym:
|
||||||
# this can be false for recursive invokations that already
|
# this can be false for recursive invocations that already
|
||||||
# transformed it into 'env.varName':
|
# transformed it into 'env.varName':
|
||||||
env.vars.incl(it.sons[0].sym.id)
|
env.vars.incl(it.sons[0].sym.id)
|
||||||
searchForInnerProcs(o, it.sons[L-1], env)
|
searchForInnerProcs(o, it.sons[L-1], env)
|
||||||
|
|
@ -999,7 +999,7 @@ proc liftForLoop*(body: PNode): PNode =
|
||||||
# proc invoke(iter: iterator(): int) =
|
# proc invoke(iter: iterator(): int) =
|
||||||
# for x in iter(): echo x
|
# for x in iter(): echo x
|
||||||
#
|
#
|
||||||
# --> When to create the closure? --> for the (count) occurence!
|
# --> When to create the closure? --> for the (count) occurrence!
|
||||||
discard """
|
discard """
|
||||||
for i in foo(): ...
|
for i in foo(): ...
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ type
|
||||||
TToken* = object # a Nim token
|
TToken* = object # a Nim token
|
||||||
tokType*: TTokType # the type of the token
|
tokType*: TTokType # the type of the token
|
||||||
indent*: int # the indentation; != -1 if the token has been
|
indent*: int # the indentation; != -1 if the token has been
|
||||||
# preceeded with indentation
|
# preceded with indentation
|
||||||
ident*: PIdent # the parsed identifier
|
ident*: PIdent # the parsed identifier
|
||||||
iNumber*: BiggestInt # the parsed integer literal
|
iNumber*: BiggestInt # the parsed integer literal
|
||||||
fNumber*: BiggestFloat # the parsed floating point literal
|
fNumber*: BiggestFloat # the parsed floating point literal
|
||||||
|
|
@ -679,7 +679,7 @@ proc getOperator(L: var TLexer, tok: var TToken) =
|
||||||
inc(pos)
|
inc(pos)
|
||||||
endOperator(L, tok, pos, h)
|
endOperator(L, tok, pos, h)
|
||||||
# advance pos but don't store it in L.bufpos so the next token (which might
|
# advance pos but don't store it in L.bufpos so the next token (which might
|
||||||
# be an operator too) gets the preceeding spaces:
|
# be an operator too) gets the preceding spaces:
|
||||||
tok.strongSpaceB = 0
|
tok.strongSpaceB = 0
|
||||||
while buf[pos] == ' ':
|
while buf[pos] == ' ':
|
||||||
inc pos
|
inc pos
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ type
|
||||||
errInvalidOrderInArrayConstructor,
|
errInvalidOrderInArrayConstructor,
|
||||||
errInvalidOrderInEnumX, errEnumXHasHoles, errExceptExpected, errInvalidTry,
|
errInvalidOrderInEnumX, errEnumXHasHoles, errExceptExpected, errInvalidTry,
|
||||||
errOptionExpected, errXisNoLabel, errNotAllCasesCovered,
|
errOptionExpected, errXisNoLabel, errNotAllCasesCovered,
|
||||||
errUnkownSubstitionVar, errComplexStmtRequiresInd, errXisNotCallable,
|
errUnknownSubstitionVar, errComplexStmtRequiresInd, errXisNotCallable,
|
||||||
errNoPragmasAllowedForX, errNoGenericParamsAllowedForX,
|
errNoPragmasAllowedForX, errNoGenericParamsAllowedForX,
|
||||||
errInvalidParamKindX, errDefaultArgumentInvalid, errNamedParamHasToBeIdent,
|
errInvalidParamKindX, errDefaultArgumentInvalid, errNamedParamHasToBeIdent,
|
||||||
errNoReturnTypeForX, errConvNeedsOneArg, errInvalidPragmaX,
|
errNoReturnTypeForX, errConvNeedsOneArg, errInvalidPragmaX,
|
||||||
|
|
@ -89,7 +89,7 @@ type
|
||||||
errTIsNotAConcreteType,
|
errTIsNotAConcreteType,
|
||||||
errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError,
|
errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError,
|
||||||
errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile,
|
errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile,
|
||||||
errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitely,
|
errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitly,
|
||||||
errOnlyACallOpCanBeDelegator, errUsingNoSymbol,
|
errOnlyACallOpCanBeDelegator, errUsingNoSymbol,
|
||||||
errMacroBodyDependsOnGenericTypes,
|
errMacroBodyDependsOnGenericTypes,
|
||||||
errDestructorNotGenericEnough,
|
errDestructorNotGenericEnough,
|
||||||
|
|
@ -279,7 +279,7 @@ const
|
||||||
errOptionExpected: "option expected, but found \'$1\'",
|
errOptionExpected: "option expected, but found \'$1\'",
|
||||||
errXisNoLabel: "\'$1\' is not a label",
|
errXisNoLabel: "\'$1\' is not a label",
|
||||||
errNotAllCasesCovered: "not all cases are covered",
|
errNotAllCasesCovered: "not all cases are covered",
|
||||||
errUnkownSubstitionVar: "unknown substitution variable: \'$1\'",
|
errUnknownSubstitionVar: "unknown substitution variable: \'$1\'",
|
||||||
errComplexStmtRequiresInd: "complex statement requires indentation",
|
errComplexStmtRequiresInd: "complex statement requires indentation",
|
||||||
errXisNotCallable: "\'$1\' is not callable",
|
errXisNotCallable: "\'$1\' is not callable",
|
||||||
errNoPragmasAllowedForX: "no pragmas allowed for $1",
|
errNoPragmasAllowedForX: "no pragmas allowed for $1",
|
||||||
|
|
@ -325,7 +325,7 @@ const
|
||||||
errXisNoValidIndexFile: "\'$1\' is no valid index file",
|
errXisNoValidIndexFile: "\'$1\' is no valid index file",
|
||||||
errCannotRenderX: "cannot render reStructuredText element \'$1\'",
|
errCannotRenderX: "cannot render reStructuredText element \'$1\'",
|
||||||
errVarVarTypeNotAllowed: "type \'var var\' is not allowed",
|
errVarVarTypeNotAllowed: "type \'var var\' is not allowed",
|
||||||
errInstantiateXExplicitely: "instantiate '$1' explicitely",
|
errInstantiateXExplicitly: "instantiate '$1' explicitly",
|
||||||
errOnlyACallOpCanBeDelegator: "only a call operator can be a delegator",
|
errOnlyACallOpCanBeDelegator: "only a call operator can be a delegator",
|
||||||
errUsingNoSymbol: "'$1' is not a variable, constant or a proc name",
|
errUsingNoSymbol: "'$1' is not a variable, constant or a proc name",
|
||||||
errMacroBodyDependsOnGenericTypes: "the macro body cannot be compiled, " &
|
errMacroBodyDependsOnGenericTypes: "the macro body cannot be compiled, " &
|
||||||
|
|
@ -359,7 +359,7 @@ const
|
||||||
errCannotInferReturnType: "cannot infer the return type of the proc",
|
errCannotInferReturnType: "cannot infer the return type of the proc",
|
||||||
errGenericLambdaNotAllowed: "A nested proc can have generic parameters only when " &
|
errGenericLambdaNotAllowed: "A nested proc can have generic parameters only when " &
|
||||||
"it is used as an operand to another routine and the types " &
|
"it is used as an operand to another routine and the types " &
|
||||||
"of the generic paramers can be infered from the expected signature.",
|
"of the generic paramers can be inferred from the expected signature.",
|
||||||
errCompilerDoesntSupportTarget: "The current compiler \'$1\' doesn't support the requested compilation target",
|
errCompilerDoesntSupportTarget: "The current compiler \'$1\' doesn't support the requested compilation target",
|
||||||
errUser: "$1",
|
errUser: "$1",
|
||||||
warnCannotOpenFile: "cannot open \'$1\' [CannotOpenFile]",
|
warnCannotOpenFile: "cannot open \'$1\' [CannotOpenFile]",
|
||||||
|
|
@ -723,7 +723,7 @@ proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
|
||||||
if stackTraceAvailable():
|
if stackTraceAvailable():
|
||||||
writeStackTrace()
|
writeStackTrace()
|
||||||
else:
|
else:
|
||||||
msgWriteln("No stack traceback available\nTo create a stacktrace, rerun compilation with ./koch temp c <file>")
|
msgWriteln("No stack traceback available\nTo create a stacktrace, rerun compilation with ./koch temp " & options.command & " <file>")
|
||||||
quit 1
|
quit 1
|
||||||
|
|
||||||
if msg >= fatalMin and msg <= fatalMax:
|
if msg >= fatalMin and msg <= fatalMax:
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ proc `<.`(a, b: string): bool =
|
||||||
while true:
|
while true:
|
||||||
let ii = parseInt(a, verA, i)
|
let ii = parseInt(a, verA, i)
|
||||||
let jj = parseInt(b, verB, j)
|
let jj = parseInt(b, verB, j)
|
||||||
# if A has no number left, but B has, B is prefered: 0.8 vs 0.8.3
|
# if A has no number left, but B has, B is preferred: 0.8 vs 0.8.3
|
||||||
if ii <= 0 or jj <= 0: return jj > 0
|
if ii <= 0 or jj <= 0: return jj > 0
|
||||||
if verA < verB: return true
|
if verA < verB: return true
|
||||||
elif verA > verB: return false
|
elif verA > verB: return false
|
||||||
|
|
|
||||||
|
|
@ -275,7 +275,7 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
|
||||||
if arg != rs and aliases.isPartOf(rs, arg) == arYes:
|
if arg != rs and aliases.isPartOf(rs, arg) == arYes:
|
||||||
ok = true
|
ok = true
|
||||||
break
|
break
|
||||||
# constraint not fullfilled:
|
# constraint not fulfilled:
|
||||||
if not ok: return nil
|
if not ok: return nil
|
||||||
of aqNoAlias:
|
of aqNoAlias:
|
||||||
# it MUST not alias with any other param:
|
# it MUST not alias with any other param:
|
||||||
|
|
@ -284,7 +284,7 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
|
||||||
if arg != rs and aliases.isPartOf(rs, arg) != arNo:
|
if arg != rs and aliases.isPartOf(rs, arg) != arNo:
|
||||||
ok = false
|
ok = false
|
||||||
break
|
break
|
||||||
# constraint not fullfilled:
|
# constraint not fulfilled:
|
||||||
if not ok: return nil
|
if not ok: return nil
|
||||||
|
|
||||||
markUsed(n.info, s)
|
markUsed(n.info, s)
|
||||||
|
|
|
||||||
|
|
@ -666,7 +666,7 @@ proc newRodReader(modfilename: string, crc: TCrc32,
|
||||||
r.readerIndex = readerIndex
|
r.readerIndex = readerIndex
|
||||||
r.filename = modfilename
|
r.filename = modfilename
|
||||||
initIdTable(r.syms)
|
initIdTable(r.syms)
|
||||||
# we terminate the file explicitely with ``\0``, so the cast to `cstring`
|
# we terminate the file explicitly with ``\0``, so the cast to `cstring`
|
||||||
# is safe:
|
# is safe:
|
||||||
r.s = cast[cstring](r.memfile.mem)
|
r.s = cast[cstring](r.memfile.mem)
|
||||||
if startsWith(r.s, "NIM:"):
|
if startsWith(r.s, "NIM:"):
|
||||||
|
|
|
||||||
|
|
@ -200,7 +200,7 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
|
||||||
return
|
return
|
||||||
# we need no surrounding [] here because the type is in a line of its own
|
# we need no surrounding [] here because the type is in a line of its own
|
||||||
if t.kind == tyForward: internalError("encodeType: tyForward")
|
if t.kind == tyForward: internalError("encodeType: tyForward")
|
||||||
# for the new rodfile viewer we use a preceeding [ so that the data section
|
# for the new rodfile viewer we use a preceding [ so that the data section
|
||||||
# can easily be disambiguated:
|
# can easily be disambiguated:
|
||||||
add(result, '[')
|
add(result, '[')
|
||||||
encodeVInt(ord(t.kind), result)
|
encodeVInt(ord(t.kind), result)
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@
|
||||||
# Note that the left and right pointers are not needed for leaves.
|
# Note that the left and right pointers are not needed for leaves.
|
||||||
# Leaves have relatively high memory overhead (~30 bytes on a 32
|
# Leaves have relatively high memory overhead (~30 bytes on a 32
|
||||||
# bit machines) and we produce many of them. This is why we cache and
|
# bit machines) and we produce many of them. This is why we cache and
|
||||||
# share leaves accross different rope trees.
|
# share leaves across different rope trees.
|
||||||
# To cache them they are inserted in a `cache` array.
|
# To cache them they are inserted in a `cache` array.
|
||||||
|
|
||||||
import
|
import
|
||||||
|
|
|
||||||
|
|
@ -184,7 +184,7 @@ proc liftBodyAux(c: TLiftCtx; t: PType; x, y: PNode) =
|
||||||
of tyFromExpr, tyIter, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
|
of tyFromExpr, tyIter, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
|
||||||
tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot, tyAnything,
|
tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot, tyAnything,
|
||||||
tyMutable, tyGenericParam, tyGenericBody, tyNil, tyExpr, tyStmt,
|
tyMutable, tyGenericParam, tyGenericBody, tyNil, tyExpr, tyStmt,
|
||||||
tyTypeDesc, tyGenericInvokation, tyBigNum, tyConst, tyForward:
|
tyTypeDesc, tyGenericInvocation, tyBigNum, tyConst, tyForward:
|
||||||
internalError(c.info, "assignment requested for type: " & typeToString(t))
|
internalError(c.info, "assignment requested for type: " & typeToString(t))
|
||||||
of tyDistinct, tyOrdinal, tyRange,
|
of tyDistinct, tyOrdinal, tyRange,
|
||||||
tyGenericInst, tyFieldAccessor, tyStatic, tyVar:
|
tyGenericInst, tyFieldAccessor, tyStatic, tyVar:
|
||||||
|
|
|
||||||
|
|
@ -264,7 +264,7 @@ proc inferWithMetatype(c: PContext, formal: PType,
|
||||||
instGenericConvertersArg(c, result, m)
|
instGenericConvertersArg(c, result, m)
|
||||||
if result != nil:
|
if result != nil:
|
||||||
# This almost exactly replicates the steps taken by the compiler during
|
# This almost exactly replicates the steps taken by the compiler during
|
||||||
# param matching. It performs an embarassing ammount of back-and-forth
|
# param matching. It performs an embarrassing amount of back-and-forth
|
||||||
# type jugling, but it's the price to pay for consistency and correctness
|
# type jugling, but it's the price to pay for consistency and correctness
|
||||||
result.typ = generateTypeInstance(c, m.bindings, arg.info,
|
result.typ = generateTypeInstance(c, m.bindings, arg.info,
|
||||||
formal.skipTypes({tyCompositeTypeClass}))
|
formal.skipTypes({tyCompositeTypeClass}))
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ proc instantiateDestructor(c: PContext, typ: PType): PType
|
||||||
|
|
||||||
proc doDestructorStuff(c: PContext, s: PSym, n: PNode) =
|
proc doDestructorStuff(c: PContext, s: PSym, n: PNode) =
|
||||||
var t = s.typ.sons[1].skipTypes({tyVar})
|
var t = s.typ.sons[1].skipTypes({tyVar})
|
||||||
if t.kind == tyGenericInvokation:
|
if t.kind == tyGenericInvocation:
|
||||||
for i in 1 .. <t.sonsLen:
|
for i in 1 .. <t.sonsLen:
|
||||||
if t.sons[i].kind != tyGenericParam:
|
if t.sons[i].kind != tyGenericParam:
|
||||||
localError(n.info, errDestructorNotGenericEnough)
|
localError(n.info, errDestructorNotGenericEnough)
|
||||||
|
|
|
||||||
|
|
@ -1637,7 +1637,7 @@ proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
result = semDirectOp(c, n, flags)
|
result = semDirectOp(c, n, flags)
|
||||||
|
|
||||||
proc createFlowVar(c: PContext; t: PType; info: TLineInfo): PType =
|
proc createFlowVar(c: PContext; t: PType; info: TLineInfo): PType =
|
||||||
result = newType(tyGenericInvokation, c.module)
|
result = newType(tyGenericInvocation, c.module)
|
||||||
addSonSkipIntLit(result, magicsys.getCompilerProc("FlowVar").typ)
|
addSonSkipIntLit(result, magicsys.getCompilerProc("FlowVar").typ)
|
||||||
addSonSkipIntLit(result, t)
|
addSonSkipIntLit(result, t)
|
||||||
result = instGenericContainer(c, info, result, allowMetaTypes = false)
|
result = instGenericContainer(c, info, result, allowMetaTypes = false)
|
||||||
|
|
@ -1917,7 +1917,7 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
it.sons[0] = newSymNode(f)
|
it.sons[0] = newSymNode(f)
|
||||||
e = fitNode(c, f.typ, e)
|
e = fitNode(c, f.typ, e)
|
||||||
# small hack here in a nkObjConstr the ``nkExprColonExpr`` node can have
|
# small hack here in a nkObjConstr the ``nkExprColonExpr`` node can have
|
||||||
# 3 childen the last being the field check
|
# 3 children the last being the field check
|
||||||
if check != nil:
|
if check != nil:
|
||||||
check.sons[0] = it.sons[0]
|
check.sons[0] = it.sons[0]
|
||||||
it.add(check)
|
it.add(check)
|
||||||
|
|
@ -2001,7 +2001,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
if result.kind == nkSym:
|
if result.kind == nkSym:
|
||||||
markIndirect(c, result.sym)
|
markIndirect(c, result.sym)
|
||||||
# if isGenericRoutine(result.sym):
|
# if isGenericRoutine(result.sym):
|
||||||
# localError(n.info, errInstantiateXExplicitely, s.name.s)
|
# localError(n.info, errInstantiateXExplicitly, s.name.s)
|
||||||
of nkSym:
|
of nkSym:
|
||||||
# because of the changed symbol binding, this does not mean that we
|
# because of the changed symbol binding, this does not mean that we
|
||||||
# don't have to check the symbol for semantics here again!
|
# don't have to check the symbol for semantics here again!
|
||||||
|
|
|
||||||
|
|
@ -243,7 +243,7 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
elif fn.kind == nkDotExpr:
|
elif fn.kind == nkDotExpr:
|
||||||
result.sons[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext)
|
result.sons[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext)
|
||||||
first = 1
|
first = 1
|
||||||
# Consider 'when defined(globalsSlot): ThreadVarSetValue(globalsSlot, ...)'
|
# Consider 'when declared(globalsSlot): ThreadVarSetValue(globalsSlot, ...)'
|
||||||
# in threads.nim: the subtle preprocessing here binds 'globalsSlot' which
|
# in threads.nim: the subtle preprocessing here binds 'globalsSlot' which
|
||||||
# is not exported and yet the generic 'threadProcWrapper' works correctly.
|
# is not exported and yet the generic 'threadProcWrapper' works correctly.
|
||||||
let flags = if mixinContext: flags+{withinMixin} else: flags
|
let flags = if mixinContext: flags+{withinMixin} else: flags
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
||||||
elif t.kind == tyGenericParam:
|
elif t.kind == tyGenericParam:
|
||||||
localError(a.info, errCannotInstantiateX, q.name.s)
|
localError(a.info, errCannotInstantiateX, q.name.s)
|
||||||
t = errorType(c)
|
t = errorType(c)
|
||||||
elif t.kind == tyGenericInvokation:
|
elif t.kind == tyGenericInvocation:
|
||||||
#t = instGenericContainer(c, a, t)
|
#t = instGenericContainer(c, a, t)
|
||||||
t = generateTypeInstance(c, pt, a, t)
|
t = generateTypeInstance(c, pt, a, t)
|
||||||
#t = ReplaceTypeVarsT(cl, t)
|
#t = ReplaceTypeVarsT(cl, t)
|
||||||
|
|
@ -174,17 +174,27 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
|
||||||
result.n = originalParams.shallowCopy
|
result.n = originalParams.shallowCopy
|
||||||
|
|
||||||
for i in 1 .. <result.len:
|
for i in 1 .. <result.len:
|
||||||
|
# twrong_field_caching requires these 'resetIdTable' calls:
|
||||||
|
if i > 1: resetIdTable(cl.symMap)
|
||||||
result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
|
result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
|
||||||
propagateToOwner(result, result.sons[i])
|
propagateToOwner(result, result.sons[i])
|
||||||
let param = replaceTypeVarsN(cl, originalParams[i])
|
internalAssert originalParams[i].kind == nkSym
|
||||||
result.n.sons[i] = param
|
when true:
|
||||||
if param.kind == nkSym:
|
let oldParam = originalParams[i].sym
|
||||||
# XXX: this won't be true for void params
|
let param = copySym(oldParam)
|
||||||
# implement pass-through of void params and
|
param.owner = prc
|
||||||
# the "sort by distance to point" container
|
param.typ = result.sons[i]
|
||||||
|
param.ast = oldParam.ast.copyTree
|
||||||
|
# don't be lazy here and call replaceTypeVarsN(cl, originalParams[i])!
|
||||||
|
result.n.sons[i] = newSymNode(param)
|
||||||
|
addDecl(c, param)
|
||||||
|
else:
|
||||||
|
let param = replaceTypeVarsN(cl, originalParams[i])
|
||||||
|
result.n.sons[i] = param
|
||||||
param.sym.owner = prc
|
param.sym.owner = prc
|
||||||
addDecl(c, param.sym)
|
addDecl(c, result.n.sons[i].sym)
|
||||||
|
|
||||||
|
resetIdTable(cl.symMap)
|
||||||
result.sons[0] = replaceTypeVarsT(cl, result.sons[0])
|
result.sons[0] = replaceTypeVarsT(cl, result.sons[0])
|
||||||
result.n.sons[0] = originalParams[0].copyTree
|
result.n.sons[0] = originalParams[0].copyTree
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ import
|
||||||
# Predefined effects:
|
# Predefined effects:
|
||||||
# io, time (time dependent), gc (performs GC'ed allocation), exceptions,
|
# io, time (time dependent), gc (performs GC'ed allocation), exceptions,
|
||||||
# side effect (accesses global), store (stores into *type*),
|
# side effect (accesses global), store (stores into *type*),
|
||||||
# store_unkown (performs some store) --> store(any)|store(x)
|
# store_unknown (performs some store) --> store(any)|store(x)
|
||||||
# load (loads from *type*), recursive (recursive call), unsafe,
|
# load (loads from *type*), recursive (recursive call), unsafe,
|
||||||
# endless (has endless loops), --> user effects are defined over *patterns*
|
# endless (has endless loops), --> user effects are defined over *patterns*
|
||||||
# --> a TR macro can annotate the proc with user defined annotations
|
# --> a TR macro can annotate the proc with user defined annotations
|
||||||
|
|
|
||||||
|
|
@ -369,7 +369,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
typ = def.typ
|
typ = def.typ
|
||||||
else:
|
else:
|
||||||
# BUGFIX: ``fitNode`` is needed here!
|
# BUGFIX: ``fitNode`` is needed here!
|
||||||
# check type compability between def.typ and typ
|
# check type compatibility between def.typ and typ
|
||||||
def = fitNode(c, typ, def)
|
def = fitNode(c, typ, def)
|
||||||
#changeType(def.skipConv, typ, check=true)
|
#changeType(def.skipConv, typ, check=true)
|
||||||
else:
|
else:
|
||||||
|
|
@ -667,8 +667,8 @@ proc checkForMetaFields(n: PNode) =
|
||||||
let t = n.sym.typ
|
let t = n.sym.typ
|
||||||
case t.kind
|
case t.kind
|
||||||
of tySequence, tySet, tyArray, tyOpenArray, tyVar, tyPtr, tyRef,
|
of tySequence, tySet, tyArray, tyOpenArray, tyVar, tyPtr, tyRef,
|
||||||
tyProc, tyGenericInvokation, tyGenericInst:
|
tyProc, tyGenericInvocation, tyGenericInst:
|
||||||
let start = ord(t.kind in {tyGenericInvokation, tyGenericInst})
|
let start = ord(t.kind in {tyGenericInvocation, tyGenericInst})
|
||||||
for i in start .. <t.sons.len:
|
for i in start .. <t.sons.len:
|
||||||
checkMeta(t.sons[i])
|
checkMeta(t.sons[i])
|
||||||
else:
|
else:
|
||||||
|
|
@ -912,7 +912,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
|
||||||
var t = s.typ.sons[1].skipTypes(abstractInst).lastSon.skipTypes(abstractInst)
|
var t = s.typ.sons[1].skipTypes(abstractInst).lastSon.skipTypes(abstractInst)
|
||||||
while true:
|
while true:
|
||||||
if t.kind == tyGenericBody: t = t.lastSon
|
if t.kind == tyGenericBody: t = t.lastSon
|
||||||
elif t.kind == tyGenericInvokation: t = t.sons[0]
|
elif t.kind == tyGenericInvocation: t = t.sons[0]
|
||||||
else: break
|
else: break
|
||||||
if t.kind in {tyObject, tyDistinct, tyEnum}:
|
if t.kind in {tyObject, tyDistinct, tyEnum}:
|
||||||
if t.deepCopy.isNil: t.deepCopy = s
|
if t.deepCopy.isNil: t.deepCopy = s
|
||||||
|
|
|
||||||
|
|
@ -436,7 +436,7 @@ proc semTemplBodyDirty(c: var TemplCtx, n: PNode): PNode =
|
||||||
of nkEmpty, nkSym..nkNilLit:
|
of nkEmpty, nkSym..nkNilLit:
|
||||||
discard
|
discard
|
||||||
else:
|
else:
|
||||||
# dotExpr is ambiguous: note that we explicitely allow 'x.TemplateParam',
|
# dotExpr is ambiguous: note that we explicitly allow 'x.TemplateParam',
|
||||||
# so we use the generic code for nkDotExpr too
|
# so we use the generic code for nkDotExpr too
|
||||||
if n.kind == nkDotExpr or n.kind == nkAccQuoted:
|
if n.kind == nkDotExpr or n.kind == nkAccQuoted:
|
||||||
let s = qualifiedLookUp(c.c, n, {})
|
let s = qualifiedLookUp(c.c, n, {})
|
||||||
|
|
@ -494,7 +494,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
|
||||||
semParamList(c, n.sons[paramsPos], gp, s)
|
semParamList(c, n.sons[paramsPos], gp, s)
|
||||||
# a template's parameters are not gensym'ed even if that was originally the
|
# a template's parameters are not gensym'ed even if that was originally the
|
||||||
# case as we determine whether it's a template parameter in the template
|
# case as we determine whether it's a template parameter in the template
|
||||||
# body by the absense of the skGenSym flag:
|
# body by the absence of the skGenSym flag:
|
||||||
for i in 1 .. s.typ.n.len-1:
|
for i in 1 .. s.typ.n.len-1:
|
||||||
s.typ.n.sons[i].sym.flags.excl sfGenSym
|
s.typ.n.sons[i].sym.flags.excl sfGenSym
|
||||||
if sonsLen(gp) > 0:
|
if sonsLen(gp) > 0:
|
||||||
|
|
@ -640,7 +640,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
result.sons[i] = semPatternBody(c, n.sons[i])
|
result.sons[i] = semPatternBody(c, n.sons[i])
|
||||||
else:
|
else:
|
||||||
# dotExpr is ambiguous: note that we explicitely allow 'x.TemplateParam',
|
# dotExpr is ambiguous: note that we explicitly allow 'x.TemplateParam',
|
||||||
# so we use the generic code for nkDotExpr too
|
# so we use the generic code for nkDotExpr too
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkDotExpr, nkAccQuoted:
|
of nkDotExpr, nkAccQuoted:
|
||||||
|
|
|
||||||
|
|
@ -609,9 +609,9 @@ proc addInheritedFieldsAux(c: PContext, check: var IntSet, pos: var int,
|
||||||
inc(pos)
|
inc(pos)
|
||||||
else: internalError(n.info, "addInheritedFieldsAux()")
|
else: internalError(n.info, "addInheritedFieldsAux()")
|
||||||
|
|
||||||
proc skipGenericInvokation(t: PType): PType {.inline.} =
|
proc skipGenericInvocation(t: PType): PType {.inline.} =
|
||||||
result = t
|
result = t
|
||||||
if result.kind == tyGenericInvokation:
|
if result.kind == tyGenericInvocation:
|
||||||
result = result.sons[0]
|
result = result.sons[0]
|
||||||
if result.kind == tyGenericBody:
|
if result.kind == tyGenericBody:
|
||||||
result = lastSon(result)
|
result = lastSon(result)
|
||||||
|
|
@ -620,7 +620,7 @@ proc addInheritedFields(c: PContext, check: var IntSet, pos: var int,
|
||||||
obj: PType) =
|
obj: PType) =
|
||||||
assert obj.kind == tyObject
|
assert obj.kind == tyObject
|
||||||
if (sonsLen(obj) > 0) and (obj.sons[0] != nil):
|
if (sonsLen(obj) > 0) and (obj.sons[0] != nil):
|
||||||
addInheritedFields(c, check, pos, obj.sons[0].skipGenericInvokation)
|
addInheritedFields(c, check, pos, obj.sons[0].skipGenericInvocation)
|
||||||
addInheritedFieldsAux(c, check, pos, obj.n)
|
addInheritedFieldsAux(c, check, pos, obj.n)
|
||||||
|
|
||||||
proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
|
proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
|
|
@ -632,7 +632,7 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
checkSonsLen(n, 3)
|
checkSonsLen(n, 3)
|
||||||
if n.sons[1].kind != nkEmpty:
|
if n.sons[1].kind != nkEmpty:
|
||||||
base = skipTypes(semTypeNode(c, n.sons[1].sons[0], nil), skipPtrs)
|
base = skipTypes(semTypeNode(c, n.sons[1].sons[0], nil), skipPtrs)
|
||||||
var concreteBase = skipGenericInvokation(base).skipTypes(skipPtrs)
|
var concreteBase = skipGenericInvocation(base).skipTypes(skipPtrs)
|
||||||
if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags:
|
if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags:
|
||||||
addInheritedFields(c, check, pos, concreteBase)
|
addInheritedFields(c, check, pos, concreteBase)
|
||||||
else:
|
else:
|
||||||
|
|
@ -777,12 +777,12 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||||
result = paramType
|
result = paramType
|
||||||
|
|
||||||
of tyGenericBody:
|
of tyGenericBody:
|
||||||
result = newTypeS(tyGenericInvokation, c)
|
result = newTypeS(tyGenericInvocation, c)
|
||||||
result.rawAddSon(paramType)
|
result.rawAddSon(paramType)
|
||||||
|
|
||||||
for i in 0 .. paramType.sonsLen - 2:
|
for i in 0 .. paramType.sonsLen - 2:
|
||||||
if paramType.sons[i].kind == tyStatic:
|
if paramType.sons[i].kind == tyStatic:
|
||||||
result.rawAddSon makeTypeFromExpr(c, ast.emptyNode) # aka 'tyUnkown'
|
result.rawAddSon makeTypeFromExpr(c, ast.emptyNode) # aka 'tyUnknown'
|
||||||
else:
|
else:
|
||||||
result.rawAddSon newTypeS(tyAnything, c)
|
result.rawAddSon newTypeS(tyAnything, c)
|
||||||
|
|
||||||
|
|
@ -823,7 +823,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||||
result = liftBody
|
result = liftBody
|
||||||
result.shouldHaveMeta
|
result.shouldHaveMeta
|
||||||
|
|
||||||
of tyGenericInvokation:
|
of tyGenericInvocation:
|
||||||
for i in 1 .. <paramType.sonsLen:
|
for i in 1 .. <paramType.sonsLen:
|
||||||
let lifted = liftingWalk(paramType.sons[i])
|
let lifted = liftingWalk(paramType.sons[i])
|
||||||
if lifted != nil: paramType.sons[i] = lifted
|
if lifted != nil: paramType.sons[i] = lifted
|
||||||
|
|
@ -900,7 +900,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
|
|
||||||
if hasDefault:
|
if hasDefault:
|
||||||
def = semExprWithType(c, a.sons[length-1])
|
def = semExprWithType(c, a.sons[length-1])
|
||||||
# check type compability between def.typ and typ:
|
# check type compatibility between def.typ and typ:
|
||||||
if typ == nil:
|
if typ == nil:
|
||||||
typ = def.typ
|
typ = def.typ
|
||||||
elif def != nil:
|
elif def != nil:
|
||||||
|
|
@ -991,7 +991,7 @@ proc semBlockType(c: PContext, n: PNode, prev: PType): PType =
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
dec(c.p.nestedBlockCounter)
|
dec(c.p.nestedBlockCounter)
|
||||||
|
|
||||||
proc semGenericParamInInvokation(c: PContext, n: PNode): PType =
|
proc semGenericParamInInvocation(c: PContext, n: PNode): PType =
|
||||||
result = semTypeNode(c, n, nil)
|
result = semTypeNode(c, n, nil)
|
||||||
|
|
||||||
proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
|
proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
|
||||||
|
|
@ -1004,7 +1004,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
|
||||||
if t.kind == tyCompositeTypeClass and t.base.kind == tyGenericBody:
|
if t.kind == tyCompositeTypeClass and t.base.kind == tyGenericBody:
|
||||||
t = t.base
|
t = t.base
|
||||||
|
|
||||||
result = newOrPrevType(tyGenericInvokation, prev, c)
|
result = newOrPrevType(tyGenericInvocation, prev, c)
|
||||||
addSonSkipIntLit(result, t)
|
addSonSkipIntLit(result, t)
|
||||||
|
|
||||||
template addToResult(typ) =
|
template addToResult(typ) =
|
||||||
|
|
@ -1015,7 +1015,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
|
||||||
|
|
||||||
if t.kind == tyForward:
|
if t.kind == tyForward:
|
||||||
for i in countup(1, sonsLen(n)-1):
|
for i in countup(1, sonsLen(n)-1):
|
||||||
var elem = semGenericParamInInvokation(c, n.sons[i])
|
var elem = semGenericParamInInvocation(c, n.sons[i])
|
||||||
addToResult(elem)
|
addToResult(elem)
|
||||||
return
|
return
|
||||||
elif t.kind != tyGenericBody:
|
elif t.kind != tyGenericBody:
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ proc searchInstTypes*(key: PType): PType =
|
||||||
if inst.sons.len < key.sons.len:
|
if inst.sons.len < key.sons.len:
|
||||||
# XXX: This happens for prematurely cached
|
# XXX: This happens for prematurely cached
|
||||||
# types such as TChannel[empty]. Why?
|
# types such as TChannel[empty]. Why?
|
||||||
# See the notes for PActor in handleGenericInvokation
|
# See the notes for PActor in handleGenericInvocation
|
||||||
return
|
return
|
||||||
block matchType:
|
block matchType:
|
||||||
for j in 1 .. high(key.sons):
|
for j in 1 .. high(key.sons):
|
||||||
|
|
@ -223,7 +223,7 @@ proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
|
||||||
result = errorType(cl.c)
|
result = errorType(cl.c)
|
||||||
# In order to prevent endless recursions, we must remember
|
# In order to prevent endless recursions, we must remember
|
||||||
# this bad lookup and replace it with errorType everywhere.
|
# this bad lookup and replace it with errorType everywhere.
|
||||||
# These code paths are only active in nimrod check
|
# These code paths are only active in "nim check"
|
||||||
idTablePut(cl.typeMap, t, result)
|
idTablePut(cl.typeMap, t, result)
|
||||||
elif result.kind == tyGenericParam and not cl.allowMetaTypes:
|
elif result.kind == tyGenericParam and not cl.allowMetaTypes:
|
||||||
internalError(cl.info, "substitution with generic parameter")
|
internalError(cl.info, "substitution with generic parameter")
|
||||||
|
|
@ -234,8 +234,8 @@ proc instCopyType*(cl: var TReplTypeVars, t: PType): PType =
|
||||||
result.flags.incl tfFromGeneric
|
result.flags.incl tfFromGeneric
|
||||||
result.flags.excl tfInstClearedFlags
|
result.flags.excl tfInstClearedFlags
|
||||||
|
|
||||||
proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
|
proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
||||||
# tyGenericInvokation[A, tyGenericInvokation[A, B]]
|
# tyGenericInvocation[A, tyGenericInvocation[A, B]]
|
||||||
# is difficult to handle:
|
# is difficult to handle:
|
||||||
var body = t.sons[0]
|
var body = t.sons[0]
|
||||||
if body.kind != tyGenericBody: internalError(cl.info, "no generic body")
|
if body.kind != tyGenericBody: internalError(cl.info, "no generic body")
|
||||||
|
|
@ -278,7 +278,7 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
|
||||||
|
|
||||||
for i in countup(1, sonsLen(t) - 1):
|
for i in countup(1, sonsLen(t) - 1):
|
||||||
var x = replaceTypeVarsT(cl, t.sons[i])
|
var x = replaceTypeVarsT(cl, t.sons[i])
|
||||||
assert x.kind != tyGenericInvokation
|
assert x.kind != tyGenericInvocation
|
||||||
header.sons[i] = x
|
header.sons[i] = x
|
||||||
propagateToOwner(header, x)
|
propagateToOwner(header, x)
|
||||||
idTablePut(cl.typeMap, body.sons[i-1], x)
|
idTablePut(cl.typeMap, body.sons[i-1], x)
|
||||||
|
|
@ -295,7 +295,7 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
|
||||||
#newbody.callConv = body.callConv
|
#newbody.callConv = body.callConv
|
||||||
# This type may be a generic alias and we want to resolve it here.
|
# This type may be a generic alias and we want to resolve it here.
|
||||||
# One step is enough, because the recursive nature of
|
# One step is enough, because the recursive nature of
|
||||||
# handleGenericInvokation will handle the alias-to-alias-to-alias case
|
# handleGenericInvocation will handle the alias-to-alias-to-alias case
|
||||||
if newbody.isGenericAlias: newbody = newbody.skipGenericAlias
|
if newbody.isGenericAlias: newbody = newbody.skipGenericAlias
|
||||||
rawAddSon(result, newbody)
|
rawAddSon(result, newbody)
|
||||||
checkPartialConstructedType(cl.info, newbody)
|
checkPartialConstructedType(cl.info, newbody)
|
||||||
|
|
@ -359,8 +359,8 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
||||||
if lookup != nil: return lookup
|
if lookup != nil: return lookup
|
||||||
|
|
||||||
case t.kind
|
case t.kind
|
||||||
of tyGenericInvokation:
|
of tyGenericInvocation:
|
||||||
result = handleGenericInvokation(cl, t)
|
result = handleGenericInvocation(cl, t)
|
||||||
|
|
||||||
of tyGenericBody:
|
of tyGenericBody:
|
||||||
localError(cl.info, errCannotInstantiateX, typeToString(t))
|
localError(cl.info, errCannotInstantiateX, typeToString(t))
|
||||||
|
|
|
||||||
|
|
@ -153,8 +153,8 @@ proc sumGeneric(t: PType): int =
|
||||||
of tyVar:
|
of tyVar:
|
||||||
# but do not make 'var T' more specific than 'T'!
|
# but do not make 'var T' more specific than 'T'!
|
||||||
t = t.sons[0]
|
t = t.sons[0]
|
||||||
of tyGenericInvokation, tyTuple:
|
of tyGenericInvocation, tyTuple:
|
||||||
result = ord(t.kind == tyGenericInvokation)
|
result = ord(t.kind == tyGenericInvocation)
|
||||||
for i in 0 .. <t.len: result += t.sons[i].sumGeneric
|
for i in 0 .. <t.len: result += t.sons[i].sumGeneric
|
||||||
break
|
break
|
||||||
of tyProc:
|
of tyProc:
|
||||||
|
|
@ -262,7 +262,7 @@ proc concreteType(c: TCandidate, t: PType): PType =
|
||||||
# example code that triggers it:
|
# example code that triggers it:
|
||||||
# proc sort[T](cmp: proc(a, b: T): int = cmp)
|
# proc sort[T](cmp: proc(a, b: T): int = cmp)
|
||||||
if result.kind != tyGenericParam: break
|
if result.kind != tyGenericParam: break
|
||||||
of tyGenericInvokation:
|
of tyGenericInvocation:
|
||||||
internalError("cannot resolve type: " & typeToString(t))
|
internalError("cannot resolve type: " & typeToString(t))
|
||||||
result = t
|
result = t
|
||||||
else:
|
else:
|
||||||
|
|
@ -462,7 +462,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||||
openScope(c)
|
openScope(c)
|
||||||
inc c.inTypeClass
|
inc c.inTypeClass
|
||||||
|
|
||||||
finally:
|
defer:
|
||||||
dec c.inTypeClass
|
dec c.inTypeClass
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
|
|
||||||
|
|
@ -585,7 +585,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
|
|
||||||
if a.kind == tyGenericInst and
|
if a.kind == tyGenericInst and
|
||||||
skipTypes(f, {tyVar}).kind notin {
|
skipTypes(f, {tyVar}).kind notin {
|
||||||
tyGenericBody, tyGenericInvokation,
|
tyGenericBody, tyGenericInvocation,
|
||||||
tyGenericInst, tyGenericParam} + tyTypeClasses:
|
tyGenericInst, tyGenericParam} + tyTypeClasses:
|
||||||
return typeRel(c, f, lastSon(a))
|
return typeRel(c, f, lastSon(a))
|
||||||
|
|
||||||
|
|
@ -877,10 +877,10 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
let ff = lastSon(f)
|
let ff = lastSon(f)
|
||||||
if ff != nil: result = typeRel(c, ff, a)
|
if ff != nil: result = typeRel(c, ff, a)
|
||||||
|
|
||||||
of tyGenericInvokation:
|
of tyGenericInvocation:
|
||||||
var x = a.skipGenericAlias
|
var x = a.skipGenericAlias
|
||||||
if x.kind == tyGenericInvokation or f.sons[0].kind != tyGenericBody:
|
if x.kind == tyGenericInvocation or f.sons[0].kind != tyGenericBody:
|
||||||
#InternalError("typeRel: tyGenericInvokation -> tyGenericInvokation")
|
#InternalError("typeRel: tyGenericInvocation -> tyGenericInvocation")
|
||||||
# simply no match for now:
|
# simply no match for now:
|
||||||
discard
|
discard
|
||||||
elif x.kind == tyGenericInst and
|
elif x.kind == tyGenericInst and
|
||||||
|
|
@ -897,7 +897,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
# we steal the generic parameters from the tyGenericBody:
|
# we steal the generic parameters from the tyGenericBody:
|
||||||
for i in countup(1, sonsLen(f) - 1):
|
for i in countup(1, sonsLen(f) - 1):
|
||||||
var x = PType(idTableGet(c.bindings, f.sons[0].sons[i - 1]))
|
var x = PType(idTableGet(c.bindings, f.sons[0].sons[i - 1]))
|
||||||
if x == nil or x.kind in {tyGenericInvokation, tyGenericParam}:
|
if x == nil or x.kind in {tyGenericInvocation, tyGenericParam}:
|
||||||
internalError("wrong instantiated type!")
|
internalError("wrong instantiated type!")
|
||||||
put(c.bindings, f.sons[i], x)
|
put(c.bindings, f.sons[i], x)
|
||||||
|
|
||||||
|
|
@ -1261,12 +1261,20 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||||
result = implicitConv(nkHiddenStdConv, f, result, m, c)
|
result = implicitConv(nkHiddenStdConv, f, result, m, c)
|
||||||
of isGeneric:
|
of isGeneric:
|
||||||
inc(m.genericMatches)
|
inc(m.genericMatches)
|
||||||
result = copyTree(arg)
|
when false:
|
||||||
result.typ = getInstantiatedType(c, arg, m, f)
|
if skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple:
|
||||||
# BUG: f may not be the right key!
|
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||||
if skipTypes(result.typ, abstractVar-{tyTypeDesc}).kind in {tyTuple}:
|
else:
|
||||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
result = arg.copyTree
|
||||||
# BUGFIX: use ``result.typ`` and not `f` here
|
else:
|
||||||
|
# XXX Why is this ever necessary? arg's type should not be retrofitted
|
||||||
|
# to match formal's type in this way!
|
||||||
|
result = copyTree(arg)
|
||||||
|
result.typ = getInstantiatedType(c, arg, m, f)
|
||||||
|
# BUG: f may not be the right key!
|
||||||
|
if skipTypes(result.typ, abstractVar-{tyTypeDesc}).kind in {tyTuple}:
|
||||||
|
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||||
|
# BUGFIX: use ``result.typ`` and not `f` here
|
||||||
of isFromIntLit:
|
of isFromIntLit:
|
||||||
# too lazy to introduce another ``*matches`` field, so we conflate
|
# too lazy to introduce another ``*matches`` field, so we conflate
|
||||||
# ``isIntConv`` and ``isIntLit`` here:
|
# ``isIntConv`` and ``isIntLit`` here:
|
||||||
|
|
|
||||||
|
|
@ -250,7 +250,7 @@ proc containsObject(t: PType): bool =
|
||||||
|
|
||||||
proc isObjectWithTypeFieldPredicate(t: PType): bool =
|
proc isObjectWithTypeFieldPredicate(t: PType): bool =
|
||||||
result = t.kind == tyObject and t.sons[0] == nil and
|
result = t.kind == tyObject and t.sons[0] == nil and
|
||||||
not (t.sym != nil and sfPure in t.sym.flags) and
|
not (t.sym != nil and {sfPure, sfInfixCall} * t.sym.flags != {}) and
|
||||||
tfFinal notin t.flags
|
tfFinal notin t.flags
|
||||||
|
|
||||||
proc analyseObjectWithTypeFieldAux(t: PType,
|
proc analyseObjectWithTypeFieldAux(t: PType,
|
||||||
|
|
@ -396,7 +396,7 @@ proc rangeToStr(n: PNode): string =
|
||||||
const
|
const
|
||||||
typeToStr: array[TTypeKind, string] = ["None", "bool", "Char", "empty",
|
typeToStr: array[TTypeKind, string] = ["None", "bool", "Char", "empty",
|
||||||
"Array Constructor [$1]", "nil", "expr", "stmt", "typeDesc",
|
"Array Constructor [$1]", "nil", "expr", "stmt", "typeDesc",
|
||||||
"GenericInvokation", "GenericBody", "GenericInst", "GenericParam",
|
"GenericInvocation", "GenericBody", "GenericInst", "GenericParam",
|
||||||
"distinct $1", "enum", "ordinal[$1]", "array[$1, $2]", "object", "tuple",
|
"distinct $1", "enum", "ordinal[$1]", "array[$1, $2]", "object", "tuple",
|
||||||
"set[$1]", "range[$1]", "ptr ", "ref ", "var ", "seq[$1]", "proc",
|
"set[$1]", "range[$1]", "ptr ", "ref ", "var ", "seq[$1]", "proc",
|
||||||
"pointer", "OpenArray[$1]", "string", "CString", "Forward",
|
"pointer", "OpenArray[$1]", "string", "CString", "Forward",
|
||||||
|
|
@ -432,9 +432,9 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||||
result = $t.n.intVal
|
result = $t.n.intVal
|
||||||
else:
|
else:
|
||||||
result = "int literal(" & $t.n.intVal & ")"
|
result = "int literal(" & $t.n.intVal & ")"
|
||||||
of tyGenericBody, tyGenericInst, tyGenericInvokation:
|
of tyGenericBody, tyGenericInst, tyGenericInvocation:
|
||||||
result = typeToString(t.sons[0]) & '['
|
result = typeToString(t.sons[0]) & '['
|
||||||
for i in countup(1, sonsLen(t) -1 -ord(t.kind != tyGenericInvokation)):
|
for i in countup(1, sonsLen(t) -1 -ord(t.kind != tyGenericInvocation)):
|
||||||
if i > 1: add(result, ", ")
|
if i > 1: add(result, ", ")
|
||||||
add(result, typeToString(t.sons[i], preferGenericArg))
|
add(result, typeToString(t.sons[i], preferGenericArg))
|
||||||
add(result, ']')
|
add(result, ']')
|
||||||
|
|
@ -649,7 +649,7 @@ proc lengthOrd(t: PType): BiggestInt =
|
||||||
type
|
type
|
||||||
TDistinctCompare* = enum ## how distinct types are to be compared
|
TDistinctCompare* = enum ## how distinct types are to be compared
|
||||||
dcEq, ## a and b should be the same type
|
dcEq, ## a and b should be the same type
|
||||||
dcEqIgnoreDistinct, ## compare symetrically: (distinct a) == b, a == b
|
dcEqIgnoreDistinct, ## compare symmetrically: (distinct a) == b, a == b
|
||||||
## or a == (distinct b)
|
## or a == (distinct b)
|
||||||
dcEqOrDistinctOf ## a equals b or a is distinct of b
|
dcEqOrDistinctOf ## a equals b or a is distinct of b
|
||||||
|
|
||||||
|
|
@ -941,7 +941,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||||
result = sameChildrenAux(a, b, c) and sameFlags(a, b)
|
result = sameChildrenAux(a, b, c) and sameFlags(a, b)
|
||||||
if result and ExactGenericParams in c.flags:
|
if result and ExactGenericParams in c.flags:
|
||||||
result = a.sym.position == b.sym.position
|
result = a.sym.position == b.sym.position
|
||||||
of tyGenericInvokation, tyGenericBody, tySequence,
|
of tyGenericInvocation, tyGenericBody, tySequence,
|
||||||
tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr,
|
tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr,
|
||||||
tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter,
|
tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter,
|
||||||
tyOrdinal, tyTypeClasses, tyFieldAccessor:
|
tyOrdinal, tyTypeClasses, tyFieldAccessor:
|
||||||
|
|
@ -1087,7 +1087,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
|
||||||
if taField notin flags: result = t
|
if taField notin flags: result = t
|
||||||
of tyTypeClasses:
|
of tyTypeClasses:
|
||||||
if not (tfGenericTypeParam in t.flags or taField notin flags): result = t
|
if not (tfGenericTypeParam in t.flags or taField notin flags): result = t
|
||||||
of tyGenericBody, tyGenericParam, tyGenericInvokation,
|
of tyGenericBody, tyGenericParam, tyGenericInvocation,
|
||||||
tyNone, tyForward, tyFromExpr, tyFieldAccessor:
|
tyNone, tyForward, tyFromExpr, tyFieldAccessor:
|
||||||
result = t
|
result = t
|
||||||
of tyNil:
|
of tyNil:
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ proc readOutput(p: Process): string =
|
||||||
discard p.waitForExit
|
discard p.waitForExit
|
||||||
|
|
||||||
proc opGorge*(cmd, input: string): string =
|
proc opGorge*(cmd, input: string): string =
|
||||||
var p = startCmd(cmd)
|
var p = startProcess(cmd, options={poEvalCommand})
|
||||||
if input.len != 0:
|
if input.len != 0:
|
||||||
p.inputStream.write(input)
|
p.inputStream.write(input)
|
||||||
p.inputStream.close()
|
p.inputStream.close()
|
||||||
|
|
|
||||||
|
|
@ -1246,7 +1246,7 @@ proc genGlobalInit(c: PCtx; n: PNode; s: PSym) =
|
||||||
c.globals.add(getNullValue(s.typ, n.info))
|
c.globals.add(getNullValue(s.typ, n.info))
|
||||||
s.position = c.globals.len
|
s.position = c.globals.len
|
||||||
# This is rather hard to support, due to the laziness of the VM code
|
# This is rather hard to support, due to the laziness of the VM code
|
||||||
# generator. See tests/compile/tmacro2 for why this is necesary:
|
# generator. See tests/compile/tmacro2 for why this is necessary:
|
||||||
# var decls{.compileTime.}: seq[PNimrodNode] = @[]
|
# var decls{.compileTime.}: seq[PNimrodNode] = @[]
|
||||||
let dest = c.getTemp(s.typ)
|
let dest = c.getTemp(s.typ)
|
||||||
c.gABx(n, opcLdGlobal, dest, s.position)
|
c.gABx(n, opcLdGlobal, dest, s.position)
|
||||||
|
|
|
||||||
|
|
@ -105,8 +105,8 @@ path="$lib/pure/unidecode"
|
||||||
@if macosx or freebsd:
|
@if macosx or freebsd:
|
||||||
cc = clang
|
cc = clang
|
||||||
tlsEmulation:on
|
tlsEmulation:on
|
||||||
gcc.options.always = "-w -fasm-blocks"
|
gcc.options.always = "-w"
|
||||||
gcc.cpp.options.always = "-w -fasm-blocks -fpermissive"
|
gcc.cpp.options.always = "-w -fpermissive"
|
||||||
@else:
|
@else:
|
||||||
gcc.options.always = "-w"
|
gcc.options.always = "-w"
|
||||||
gcc.cpp.options.always = "-w -fpermissive"
|
gcc.cpp.options.always = "-w -fpermissive"
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ doc.section.toc = """
|
||||||
</li>
|
</li>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Chunk of HTML emmited for each entry in the HTML table of contents.
|
# Chunk of HTML emitted for each entry in the HTML table of contents.
|
||||||
# Available variables are:
|
# Available variables are:
|
||||||
# * $desc: the actual docstring of the item.
|
# * $desc: the actual docstring of the item.
|
||||||
# * $header: the full version of name, including types, pragmas, tags, etc.
|
# * $header: the full version of name, including types, pragmas, tags, etc.
|
||||||
|
|
@ -45,7 +45,7 @@ $seeSrc
|
||||||
</dd>
|
</dd>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Chunk of HTML emmited for each entry in the HTML table of contents.
|
# Chunk of HTML emitted for each entry in the HTML table of contents.
|
||||||
# See doc.item for available substitution variables.
|
# See doc.item for available substitution variables.
|
||||||
doc.item.toc = """
|
doc.item.toc = """
|
||||||
<li><a class="reference" href="#$itemSymOrID"
|
<li><a class="reference" href="#$itemSymOrID"
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ Advanced commands:
|
||||||
track a file, currently not saved to disk
|
track a file, currently not saved to disk
|
||||||
--suggest suggest all possible symbols at position
|
--suggest suggest all possible symbols at position
|
||||||
--def list all possible definitions at position
|
--def list all possible definitions at position
|
||||||
--context list possible invokation context
|
--context list possible invocation context
|
||||||
--usages list all usages of the symbol at position
|
--usages list all usages of the symbol at position
|
||||||
--eval evaluates an expression
|
--eval evaluates an expression
|
||||||
//serve start the compiler as a service mode (CAAS)
|
//serve start the compiler as a service mode (CAAS)
|
||||||
|
|
@ -85,7 +85,7 @@ Advanced options:
|
||||||
that --dynlibOverride:lua matches
|
that --dynlibOverride:lua matches
|
||||||
dynlib: "liblua.so.3"
|
dynlib: "liblua.so.3"
|
||||||
--listCmd list the commands used to execute external programs
|
--listCmd list the commands used to execute external programs
|
||||||
--parallelBuild=0|1|... perform a parallel build
|
--parallelBuild:0|1|... perform a parallel build
|
||||||
value = number of processors (0 for auto-detect)
|
value = number of processors (0 for auto-detect)
|
||||||
--verbosity:0|1|2|3 set Nim's verbosity level (1 is default)
|
--verbosity:0|1|2|3 set Nim's verbosity level (1 is default)
|
||||||
--cs:none|partial set case sensitivity level (default: none);
|
--cs:none|partial set case sensitivity level (default: none);
|
||||||
|
|
|
||||||
|
|
@ -79,10 +79,3 @@ string str
|
||||||
identifier ident
|
identifier ident
|
||||||
indentation indent
|
indentation indent
|
||||||
------------------- ------------ --------------------------------------
|
------------------- ------------ --------------------------------------
|
||||||
|
|
||||||
|
|
||||||
Coding Guidelines
|
|
||||||
=================
|
|
||||||
|
|
||||||
For coding guidelines see the `Internals of the Nim Compiler
|
|
||||||
<intern.html#coding-guidelines>`_ documentation.
|
|
||||||
|
|
|
||||||
|
|
@ -225,7 +225,7 @@ The JavaScript target doesn't have any further interfacing considerations
|
||||||
since it also has garbage collection, but the C targets require you to
|
since it also has garbage collection, but the C targets require you to
|
||||||
initialize Nim's internals, which is done calling a ``NimMain`` function.
|
initialize Nim's internals, which is done calling a ``NimMain`` function.
|
||||||
Also, C code requires you to specify a forward declaration for functions or
|
Also, C code requires you to specify a forward declaration for functions or
|
||||||
the compiler will asume certain types for the return value and parameters
|
the compiler will assume certain types for the return value and parameters
|
||||||
which will likely make your program crash at runtime.
|
which will likely make your program crash at runtime.
|
||||||
|
|
||||||
The Nim compiler can generate a C interface header through the ``--header``
|
The Nim compiler can generate a C interface header through the ``--header``
|
||||||
|
|
@ -427,7 +427,7 @@ Custom data types
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
Just like strings, custom data types that are to be shared between Nim and
|
Just like strings, custom data types that are to be shared between Nim and
|
||||||
the backend will need careful consideration of who controlls who. If you want
|
the backend will need careful consideration of who controls who. If you want
|
||||||
to hand a Nim reference to C code, you will need to use `GC_ref
|
to hand a Nim reference to C code, you will need to use `GC_ref
|
||||||
<system.html#GC_ref>`_ to mark the reference as used, so it does not get
|
<system.html#GC_ref>`_ to mark the reference as used, so it does not get
|
||||||
freed. And for the C backend you will need to expose the `GC_unref
|
freed. And for the C backend you will need to expose the `GC_unref
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ integrations <https://github.com/Araq/Nim/wiki/Editor-Support>`_
|
||||||
already available.
|
already available.
|
||||||
|
|
||||||
|
|
||||||
Idetools invokation
|
Idetools invocation
|
||||||
===================
|
===================
|
||||||
|
|
||||||
Specifying the location of the query
|
Specifying the location of the query
|
||||||
|
|
@ -35,7 +35,7 @@ Specifying the location of the query
|
||||||
|
|
||||||
All of the available idetools commands require you to specify a
|
All of the available idetools commands require you to specify a
|
||||||
query location through the ``--track`` or ``--trackDirty`` switches.
|
query location through the ``--track`` or ``--trackDirty`` switches.
|
||||||
The general idetools invokations are::
|
The general idetools invocations are::
|
||||||
|
|
||||||
nim idetools --track:FILE,LINE,COL <switches> proj.nim
|
nim idetools --track:FILE,LINE,COL <switches> proj.nim
|
||||||
|
|
||||||
|
|
@ -129,7 +129,7 @@ the suggestions sorted first by scope (from innermost to outermost)
|
||||||
and then by item name.
|
and then by item name.
|
||||||
|
|
||||||
|
|
||||||
Invokation context
|
Invocation context
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
The ``--context`` idetools switch is very similar to the suggestions
|
The ``--context`` idetools switch is very similar to the suggestions
|
||||||
|
|
@ -163,7 +163,7 @@ running/debugged user project.
|
||||||
Compiler as a service (CAAS)
|
Compiler as a service (CAAS)
|
||||||
============================
|
============================
|
||||||
|
|
||||||
The ocasional use of idetools is acceptable for things like
|
The occasional use of idetools is acceptable for things like
|
||||||
definitions, where the user puts the cursor on a symbol or double
|
definitions, where the user puts the cursor on a symbol or double
|
||||||
clicks it and after a second or two the IDE displays where that
|
clicks it and after a second or two the IDE displays where that
|
||||||
symbol is defined. Such latencies would be terrible for features
|
symbol is defined. Such latencies would be terrible for features
|
||||||
|
|
@ -533,10 +533,10 @@ run it manually. First you have to compile the tester::
|
||||||
Running the ``caasdriver`` without parameters will attempt to process
|
Running the ``caasdriver`` without parameters will attempt to process
|
||||||
all the test cases in all three operation modes. If a test succeeds
|
all the test cases in all three operation modes. If a test succeeds
|
||||||
nothing will be printed and the process will exit with zero. If any
|
nothing will be printed and the process will exit with zero. If any
|
||||||
test fails, the specific line of the test preceeding the failure
|
test fails, the specific line of the test preceding the failure
|
||||||
and the failure itself will be dumped to stdout, along with a final
|
and the failure itself will be dumped to stdout, along with a final
|
||||||
indicator of the success state and operation mode. You can pass the
|
indicator of the success state and operation mode. You can pass the
|
||||||
parameter ``verbose`` to force all output even on successfull tests.
|
parameter ``verbose`` to force all output even on successful tests.
|
||||||
|
|
||||||
The normal operation mode is called ``ProcRun`` and it involves
|
The normal operation mode is called ``ProcRun`` and it involves
|
||||||
starting a process for each command or query, similar to running
|
starting a process for each command or query, similar to running
|
||||||
|
|
|
||||||
|
|
@ -236,7 +236,7 @@ too. Type converters fall into this category:
|
||||||
|
|
||||||
If in the above example module ``B`` is re-compiled, but ``A`` is not then
|
If in the above example module ``B`` is re-compiled, but ``A`` is not then
|
||||||
``B`` needs to be aware of ``toBool`` even though ``toBool`` is not referenced
|
``B`` needs to be aware of ``toBool`` even though ``toBool`` is not referenced
|
||||||
in ``B`` *explicitely*.
|
in ``B`` *explicitly*.
|
||||||
|
|
||||||
Both the multi method and the type converter problems are solved by storing
|
Both the multi method and the type converter problems are solved by storing
|
||||||
them in special sections in the ROD file that are loaded *unconditionally*
|
them in special sections in the ROD file that are loaded *unconditionally*
|
||||||
|
|
@ -370,7 +370,7 @@ needed as the data structures needs to be rebuilt periodically anyway.
|
||||||
|
|
||||||
Complete traversal is done in this way::
|
Complete traversal is done in this way::
|
||||||
|
|
||||||
for each page decriptor d:
|
for each page descriptor d:
|
||||||
for each bit in d:
|
for each bit in d:
|
||||||
if bit == 1:
|
if bit == 1:
|
||||||
traverse the pointer belonging to this bit
|
traverse the pointer belonging to this bit
|
||||||
|
|
@ -406,7 +406,7 @@ The generated code looks roughly like this:
|
||||||
setRef(&r->left)
|
setRef(&r->left)
|
||||||
}
|
}
|
||||||
|
|
||||||
Note that for systems with a continous stack (which most systems have)
|
Note that for systems with a continuous stack (which most systems have)
|
||||||
the check whether the ref is on the stack is very cheap (only two
|
the check whether the ref is on the stack is very cheap (only two
|
||||||
comparisons).
|
comparisons).
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -370,7 +370,7 @@ Miscellaneous
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
* `events <events.html>`_
|
* `events <events.html>`_
|
||||||
This module implements an event system that is not dependant on external
|
This module implements an event system that is not dependent on external
|
||||||
graphical toolkits.
|
graphical toolkits.
|
||||||
|
|
||||||
* `oids <oids.html>`_
|
* `oids <oids.html>`_
|
||||||
|
|
|
||||||
|
|
@ -25,9 +25,9 @@ with ``'``. An example::
|
||||||
|
|
||||||
ifStmt = 'if' expr ':' stmts ('elif' expr ':' stmts)* ('else' stmts)?
|
ifStmt = 'if' expr ':' stmts ('elif' expr ':' stmts)* ('else' stmts)?
|
||||||
|
|
||||||
The binary ``^*`` operator is used as a shorthand for 0 or more occurances
|
The binary ``^*`` operator is used as a shorthand for 0 or more occurrences
|
||||||
separated by its second argument; likewise ``^+`` means 1 or more
|
separated by its second argument; likewise ``^+`` means 1 or more
|
||||||
occurances: ``a ^+ b`` is short for ``a (b a)*``
|
occurrences: ``a ^+ b`` is short for ``a (b a)*``
|
||||||
and ``a ^* b`` is short for ``(a (b a)*)?``. Example::
|
and ``a ^* b`` is short for ``(a (b a)*)?``. Example::
|
||||||
|
|
||||||
arrayConstructor = '[' expr ^* ',' ']'
|
arrayConstructor = '[' expr ^* ',' ']'
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ Precedence level Operators First charact
|
||||||
Strong spaces
|
Strong spaces
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
The number of spaces preceeding a non-keyword operator affects precedence
|
The number of spaces preceding a non-keyword operator affects precedence
|
||||||
if the experimental parser directive ``#!strongSpaces`` is used. Indentation
|
if the experimental parser directive ``#!strongSpaces`` is used. Indentation
|
||||||
is not used to determine the number of spaces. If 2 or more operators have the
|
is not used to determine the number of spaces. If 2 or more operators have the
|
||||||
same number of preceding spaces the precedence table applies, so ``1 + 3 * 4``
|
same number of preceding spaces the precedence table applies, so ``1 + 3 * 4``
|
||||||
|
|
|
||||||
|
|
@ -1142,7 +1142,7 @@ modules like `db_sqlite <db_sqlite.html>`_.
|
||||||
Void type
|
Void type
|
||||||
---------
|
---------
|
||||||
|
|
||||||
The ``void`` type denotes the absense of any type. Parameters of
|
The ``void`` type denotes the absence of any type. Parameters of
|
||||||
type ``void`` are treated as non-existent, ``void`` as a return type means that
|
type ``void`` are treated as non-existent, ``void`` as a return type means that
|
||||||
the procedure does not return a value:
|
the procedure does not return a value:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,7 @@ found an ambiguity error is produced.
|
||||||
``nim dump`` shows the contents of the PATH.
|
``nim dump`` shows the contents of the PATH.
|
||||||
|
|
||||||
However before the PATH is used the current directory is checked for the
|
However before the PATH is used the current directory is checked for the
|
||||||
file's existance. So if PATH contains ``$lib`` and ``$lib/bar`` and the
|
file's existence. So if PATH contains ``$lib`` and ``$lib/bar`` and the
|
||||||
directory structure looks like this::
|
directory structure looks like this::
|
||||||
|
|
||||||
$lib/x.nim
|
$lib/x.nim
|
||||||
|
|
|
||||||
|
|
@ -25,9 +25,9 @@ Compile nimgrep with the command::
|
||||||
And copy the executable somewhere in your ``$PATH``.
|
And copy the executable somewhere in your ``$PATH``.
|
||||||
|
|
||||||
|
|
||||||
Command line switches
|
Command line switches
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
nimgrep [options] [pattern] [replacement] (file/directory)*
|
nimgrep [options] [pattern] [replacement] (file/directory)*
|
||||||
Options:
|
Options:
|
||||||
|
|
@ -37,7 +37,7 @@ Options:
|
||||||
--re pattern is a regular expression (default); extended
|
--re pattern is a regular expression (default); extended
|
||||||
syntax for the regular expression is always turned on
|
syntax for the regular expression is always turned on
|
||||||
--recursive process directories recursively
|
--recursive process directories recursively
|
||||||
--confirm confirm each occurence/replacement; there is a chance
|
--confirm confirm each occurrence/replacement; there is a chance
|
||||||
to abort any time without touching the file
|
to abort any time without touching the file
|
||||||
--stdin read pattern from stdin (to avoid the shell's confusing
|
--stdin read pattern from stdin (to avoid the shell's confusing
|
||||||
quoting rules)
|
quoting rules)
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ Object Oriented Programming
|
||||||
While Nim's support for object oriented programming (OOP) is minimalistic,
|
While Nim's support for object oriented programming (OOP) is minimalistic,
|
||||||
powerful OOP techniques can be used. OOP is seen as *one* way to design a
|
powerful OOP techniques can be used. OOP is seen as *one* way to design a
|
||||||
program, not *the only* way. Often a procedural approach leads to simpler
|
program, not *the only* way. Often a procedural approach leads to simpler
|
||||||
and more efficient code. In particular, prefering composition over inheritance
|
and more efficient code. In particular, preferring composition over inheritance
|
||||||
is often the better design.
|
is often the better design.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -142,7 +142,7 @@ An example:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
|
|
||||||
# This is an example how an abstract syntax tree could be modeled in Nim
|
# This is an example how an abstract syntax tree could be modelled in Nim
|
||||||
type
|
type
|
||||||
NodeKind = enum # the different node types
|
NodeKind = enum # the different node types
|
||||||
nkInt, # a leaf with an integer value
|
nkInt, # a leaf with an integer value
|
||||||
|
|
@ -335,7 +335,7 @@ As the example demonstrates, invocation of a multi-method cannot be ambiguous:
|
||||||
Collide 2 is preferred over collide 1 because the resolution works from left to
|
Collide 2 is preferred over collide 1 because the resolution works from left to
|
||||||
right. Thus ``Unit, Thing`` is preferred over ``Thing, Unit``.
|
right. Thus ``Unit, Thing`` is preferred over ``Thing, Unit``.
|
||||||
|
|
||||||
**Perfomance note**: Nim does not produce a virtual method table, but
|
**Performance note**: Nim does not produce a virtual method table, but
|
||||||
generates dispatch trees. This avoids the expensive indirect branch for method
|
generates dispatch trees. This avoids the expensive indirect branch for method
|
||||||
calls and enables inlining. However, other optimizations like compile time
|
calls and enables inlining. However, other optimizations like compile time
|
||||||
evaluation or dead code elimination do not work with methods.
|
evaluation or dead code elimination do not work with methods.
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ just declared as a native method which will be resolved at runtime. The scripts
|
||||||
nimbuild.sh and jnibuild.sh are in charge of building the Nim code and
|
nimbuild.sh and jnibuild.sh are in charge of building the Nim code and
|
||||||
generating the jni bridge from the java code respectively. Finally, the
|
generating the jni bridge from the java code respectively. Finally, the
|
||||||
ndk-build command from the android ndk tools has to be run to build the binary
|
ndk-build command from the android ndk tools has to be run to build the binary
|
||||||
libary which will be installed along the final apk.
|
library which will be installed along the final apk.
|
||||||
|
|
||||||
All these steps are wrapped in the ant build script through the customization
|
All these steps are wrapped in the ant build script through the customization
|
||||||
of the -post-compile rule. If you have the android ndk tools installed and you
|
of the -post-compile rule. If you have the android ndk tools installed and you
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@
|
||||||
[self.bText resignFirstResponder];
|
[self.bText resignFirstResponder];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Custom loadView method for backwards compatiblity.
|
/** Custom loadView method for backwards compatibility.
|
||||||
* Unfortunately I've been unable to coerce Xcode 4.4 to generate nib files
|
* Unfortunately I've been unable to coerce Xcode 4.4 to generate nib files
|
||||||
* which are compatible with my trusty iOS 3.0 ipod touch so in order to be
|
* which are compatible with my trusty iOS 3.0 ipod touch so in order to be
|
||||||
* fully compatible for all devices we have to build the interface manually in
|
* fully compatible for all devices we have to build the interface manually in
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ proc update*(todo: var TTodo; conn: TDbConn): bool =
|
||||||
##
|
##
|
||||||
## Use this method if you (or another entity) have modified the database and
|
## Use this method if you (or another entity) have modified the database and
|
||||||
## want to update the object you have with whatever the database has stored.
|
## want to update the object you have with whatever the database has stored.
|
||||||
## Returns true if the update suceeded, or false if the object was not found
|
## Returns true if the update succeeded, or false if the object was not found
|
||||||
## in the database any more, in which case you should probably get rid of the
|
## in the database any more, in which case you should probably get rid of the
|
||||||
## TTodo object.
|
## TTodo object.
|
||||||
assert(todo.id >= 0, "The identifier of the todo entry can't be negative")
|
assert(todo.id >= 0, "The identifier of the todo entry can't be negative")
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ template optRe{re(x)}(x: string{lit}): Regex =
|
||||||
g
|
g
|
||||||
|
|
||||||
template `=~`(s: string, pattern: Regex): bool =
|
template `=~`(s: string, pattern: Regex): bool =
|
||||||
when not definedInScope(matches):
|
when not declaredInScope(matches):
|
||||||
var matches {.inject.}: array[maxSubPatterns, string]
|
var matches {.inject.}: array[maxSubPatterns, string]
|
||||||
match(s, pattern, matches)
|
match(s, pattern, matches)
|
||||||
|
|
||||||
|
|
|
||||||
6
koch.nim
6
koch.nim
|
|
@ -270,13 +270,13 @@ when defined(withUpdate):
|
||||||
echo("Fetching updates from repo...")
|
echo("Fetching updates from repo...")
|
||||||
var pullout = execCmdEx(git & " pull origin master")
|
var pullout = execCmdEx(git & " pull origin master")
|
||||||
if pullout[1] != 0:
|
if pullout[1] != 0:
|
||||||
quit("An error has occured.")
|
quit("An error has occurred.")
|
||||||
else:
|
else:
|
||||||
if pullout[0].startsWith("Already up-to-date."):
|
if pullout[0].startsWith("Already up-to-date."):
|
||||||
quit("No new changes fetched from the repo. " &
|
quit("No new changes fetched from the repo. " &
|
||||||
"Local branch must be ahead of it. Exiting...")
|
"Local branch must be ahead of it. Exiting...")
|
||||||
else:
|
else:
|
||||||
quit("An error has occured.")
|
quit("An error has occurred.")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
echo("No repo or executable found!")
|
echo("No repo or executable found!")
|
||||||
|
|
@ -360,7 +360,7 @@ of cmdArgument:
|
||||||
of "boot": boot(op.cmdLineRest)
|
of "boot": boot(op.cmdLineRest)
|
||||||
of "clean": clean(op.cmdLineRest)
|
of "clean": clean(op.cmdLineRest)
|
||||||
of "web": web(op.cmdLineRest)
|
of "web": web(op.cmdLineRest)
|
||||||
of "website": website(op.cmdLineRest)
|
of "website": website(op.cmdLineRest & " --googleAnalytics:UA-48159761-1")
|
||||||
of "web0":
|
of "web0":
|
||||||
# undocumented command for Araq-the-merciful:
|
# undocumented command for Araq-the-merciful:
|
||||||
web(op.cmdLineRest & " --googleAnalytics:UA-48159761-1")
|
web(op.cmdLineRest & " --googleAnalytics:UA-48159761-1")
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ type
|
||||||
## is performed. Deprecated, do not use anymore!
|
## is performed. Deprecated, do not use anymore!
|
||||||
AquireEffect* {.deprecated.} = object of LockEffect ## \
|
AquireEffect* {.deprecated.} = object of LockEffect ## \
|
||||||
## effect that denotes that some lock is
|
## effect that denotes that some lock is
|
||||||
## aquired. Deprecated, do not use anymore!
|
## acquired. Deprecated, do not use anymore!
|
||||||
ReleaseEffect* {.deprecated.} = object of LockEffect ## \
|
ReleaseEffect* {.deprecated.} = object of LockEffect ## \
|
||||||
## effect that denotes that some lock is
|
## effect that denotes that some lock is
|
||||||
## released. Deprecated, do not use anymore!
|
## released. Deprecated, do not use anymore!
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ type
|
||||||
TNimrodTypeKind* = enum
|
TNimrodTypeKind* = enum
|
||||||
ntyNone, ntyBool, ntyChar, ntyEmpty,
|
ntyNone, ntyBool, ntyChar, ntyEmpty,
|
||||||
ntyArrayConstr, ntyNil, ntyExpr, ntyStmt,
|
ntyArrayConstr, ntyNil, ntyExpr, ntyStmt,
|
||||||
ntyTypeDesc, ntyGenericInvokation, ntyGenericBody, ntyGenericInst,
|
ntyTypeDesc, ntyGenericInvocation, ntyGenericBody, ntyGenericInst,
|
||||||
ntyGenericParam, ntyDistinct, ntyEnum, ntyOrdinal,
|
ntyGenericParam, ntyDistinct, ntyEnum, ntyOrdinal,
|
||||||
ntyArray, ntyObject, ntyTuple, ntySet,
|
ntyArray, ntyObject, ntyTuple, ntySet,
|
||||||
ntyRange, ntyPtr, ntyRef, ntyVar,
|
ntyRange, ntyPtr, ntyRef, ntyVar,
|
||||||
|
|
|
||||||
|
|
@ -1145,7 +1145,7 @@ proc formatNamedVars*(frmt: string, varnames: openArray[string],
|
||||||
proc defaultConfig*(): StringTableRef =
|
proc defaultConfig*(): StringTableRef =
|
||||||
## Returns a default configuration for embedded HTML generation.
|
## Returns a default configuration for embedded HTML generation.
|
||||||
##
|
##
|
||||||
## The returned ``StringTableRef`` contains the paramters used by the HTML
|
## The returned ``StringTableRef`` contains the parameters used by the HTML
|
||||||
## engine to build the final output. For information on what these parameters
|
## engine to build the final output. For information on what these parameters
|
||||||
## are and their purpose, please look up the file ``config/nimdoc.cfg``
|
## are and their purpose, please look up the file ``config/nimdoc.cfg``
|
||||||
## bundled with the compiler.
|
## bundled with the compiler.
|
||||||
|
|
|
||||||
|
|
@ -1732,12 +1732,10 @@ when hasSpawnH:
|
||||||
when defined(linux):
|
when defined(linux):
|
||||||
# better be safe than sorry; Linux has this flag, macosx doesn't, don't
|
# better be safe than sorry; Linux has this flag, macosx doesn't, don't
|
||||||
# know about the other OSes
|
# know about the other OSes
|
||||||
when defined(tcc):
|
|
||||||
# TCC doesn't define __USE_GNU, so we can't get the magic number from
|
# Non-GNU systems like TCC and musl-libc don't define __USE_GNU, so we
|
||||||
# spawn.h
|
# can't get the magic number from spawn.h
|
||||||
const POSIX_SPAWN_USEVFORK* = cint(0x40)
|
const POSIX_SPAWN_USEVFORK* = cint(0x40)
|
||||||
else:
|
|
||||||
var POSIX_SPAWN_USEVFORK* {.importc, header: "<spawn.h>".}: cint
|
|
||||||
else:
|
else:
|
||||||
# macosx lacks this, so we define the constant to be 0 to not affect
|
# macosx lacks this, so we define the constant to be 0 to not affect
|
||||||
# OR'ing of flags:
|
# OR'ing of flags:
|
||||||
|
|
|
||||||
|
|
@ -200,7 +200,7 @@ template schedule =
|
||||||
if minIdx >= 0:
|
if minIdx >= 0:
|
||||||
p.actors[minIdx].i.send(t)
|
p.actors[minIdx].i.send(t)
|
||||||
else:
|
else:
|
||||||
raise newException(EDeadThread, "cannot send message; thread died")
|
raise newException(DeadThreadError, "cannot send message; thread died")
|
||||||
|
|
||||||
proc spawn*[TIn, TOut](p: var TActorPool[TIn, TOut], input: TIn,
|
proc spawn*[TIn, TOut](p: var TActorPool[TIn, TOut], input: TIn,
|
||||||
action: proc (input: TIn): TOut {.thread.}
|
action: proc (input: TIn): TOut {.thread.}
|
||||||
|
|
|
||||||
|
|
@ -606,7 +606,7 @@ when defined(windows) or defined(nimdoc):
|
||||||
retFuture.fail(newException(OSError, osErrorMsg(err)))
|
retFuture.fail(newException(OSError, osErrorMsg(err)))
|
||||||
elif ret == 0 and bytesReceived == 0 and dataBuf.buf[0] == '\0':
|
elif ret == 0 and bytesReceived == 0 and dataBuf.buf[0] == '\0':
|
||||||
# We have to ensure that the buffer is empty because WSARecv will tell
|
# We have to ensure that the buffer is empty because WSARecv will tell
|
||||||
# us immediatelly when it was disconnected, even when there is still
|
# us immediately when it was disconnected, even when there is still
|
||||||
# data in the buffer.
|
# data in the buffer.
|
||||||
# We want to give the user as much data as we can. So we only return
|
# We want to give the user as much data as we can. So we only return
|
||||||
# the empty string (which signals a disconnection) when there is
|
# the empty string (which signals a disconnection) when there is
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ type
|
||||||
offset: int64
|
offset: int64
|
||||||
|
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
proc getDesiredAccess(mode: TFileMode): int32 =
|
proc getDesiredAccess(mode: FileMode): int32 =
|
||||||
case mode
|
case mode
|
||||||
of fmRead:
|
of fmRead:
|
||||||
result = GENERIC_READ
|
result = GENERIC_READ
|
||||||
|
|
@ -44,7 +44,7 @@ when defined(windows):
|
||||||
of fmReadWrite, fmReadWriteExisting:
|
of fmReadWrite, fmReadWriteExisting:
|
||||||
result = GENERIC_READ or GENERIC_WRITE
|
result = GENERIC_READ or GENERIC_WRITE
|
||||||
|
|
||||||
proc getCreationDisposition(mode: TFileMode, filename: string): int32 =
|
proc getCreationDisposition(mode: FileMode, filename: string): int32 =
|
||||||
case mode
|
case mode
|
||||||
of fmRead, fmReadWriteExisting:
|
of fmRead, fmReadWriteExisting:
|
||||||
OPEN_EXISTING
|
OPEN_EXISTING
|
||||||
|
|
@ -54,7 +54,7 @@ when defined(windows):
|
||||||
else:
|
else:
|
||||||
CREATE_NEW
|
CREATE_NEW
|
||||||
else:
|
else:
|
||||||
proc getPosixFlags(mode: TFileMode): cint =
|
proc getPosixFlags(mode: FileMode): cint =
|
||||||
case mode
|
case mode
|
||||||
of fmRead:
|
of fmRead:
|
||||||
result = O_RDONLY
|
result = O_RDONLY
|
||||||
|
|
@ -74,7 +74,7 @@ proc getFileSize(f: AsyncFile): int64 =
|
||||||
var high: DWord
|
var high: DWord
|
||||||
let low = getFileSize(f.fd.THandle, addr high)
|
let low = getFileSize(f.fd.THandle, addr high)
|
||||||
if low == INVALID_FILE_SIZE:
|
if low == INVALID_FILE_SIZE:
|
||||||
raiseOSError()
|
raiseOSError(osLastError())
|
||||||
return (high shl 32) or low
|
return (high shl 32) or low
|
||||||
|
|
||||||
proc openAsync*(filename: string, mode = fmRead): AsyncFile =
|
proc openAsync*(filename: string, mode = fmRead): AsyncFile =
|
||||||
|
|
@ -95,7 +95,7 @@ proc openAsync*(filename: string, mode = fmRead): AsyncFile =
|
||||||
nil, creationDisposition, flags, 0).TAsyncFd
|
nil, creationDisposition, flags, 0).TAsyncFd
|
||||||
|
|
||||||
if result.fd.THandle == INVALID_HANDLE_VALUE:
|
if result.fd.THandle == INVALID_HANDLE_VALUE:
|
||||||
raiseOSError()
|
raiseOSError(osLastError())
|
||||||
|
|
||||||
register(result.fd)
|
register(result.fd)
|
||||||
|
|
||||||
|
|
@ -108,7 +108,7 @@ proc openAsync*(filename: string, mode = fmRead): AsyncFile =
|
||||||
let perm = S_IRUSR or S_IWUSR or S_IRGRP or S_IWGRP or S_IROTH
|
let perm = S_IRUSR or S_IWUSR or S_IRGRP or S_IWGRP or S_IROTH
|
||||||
result.fd = open(filename, flags, perm).TAsyncFD
|
result.fd = open(filename, flags, perm).TAsyncFD
|
||||||
if result.fd.cint == -1:
|
if result.fd.cint == -1:
|
||||||
raiseOSError()
|
raiseOSError(osLastError())
|
||||||
|
|
||||||
register(result.fd)
|
register(result.fd)
|
||||||
|
|
||||||
|
|
@ -185,7 +185,7 @@ proc read*(f: AsyncFile, size: int): Future[string] =
|
||||||
if res < 0:
|
if res < 0:
|
||||||
let lastError = osLastError()
|
let lastError = osLastError()
|
||||||
if lastError.int32 != EAGAIN:
|
if lastError.int32 != EAGAIN:
|
||||||
retFuture.fail(newException(EOS, osErrorMsg(lastError)))
|
retFuture.fail(newException(OSError, osErrorMsg(lastError)))
|
||||||
else:
|
else:
|
||||||
result = false # We still want this callback to be called.
|
result = false # We still want this callback to be called.
|
||||||
elif res == 0:
|
elif res == 0:
|
||||||
|
|
@ -227,7 +227,7 @@ proc setFilePos*(f: AsyncFile, pos: int64) =
|
||||||
when not defined(windows):
|
when not defined(windows):
|
||||||
let ret = lseek(f.fd.cint, pos, SEEK_SET)
|
let ret = lseek(f.fd.cint, pos, SEEK_SET)
|
||||||
if ret == -1:
|
if ret == -1:
|
||||||
raiseOSError()
|
raiseOSError(osLastError())
|
||||||
|
|
||||||
proc readAll*(f: AsyncFile): Future[string] {.async.} =
|
proc readAll*(f: AsyncFile): Future[string] {.async.} =
|
||||||
## Reads all data from the specified file.
|
## Reads all data from the specified file.
|
||||||
|
|
@ -299,7 +299,7 @@ proc write*(f: AsyncFile, data: string): Future[void] =
|
||||||
if res < 0:
|
if res < 0:
|
||||||
let lastError = osLastError()
|
let lastError = osLastError()
|
||||||
if lastError.int32 != EAGAIN:
|
if lastError.int32 != EAGAIN:
|
||||||
retFuture.fail(newException(EOS, osErrorMsg(lastError)))
|
retFuture.fail(newException(OSError, osErrorMsg(lastError)))
|
||||||
else:
|
else:
|
||||||
result = false # We still want this callback to be called.
|
result = false # We still want this callback to be called.
|
||||||
else:
|
else:
|
||||||
|
|
@ -318,8 +318,8 @@ proc close*(f: AsyncFile) =
|
||||||
## Closes the file specified.
|
## Closes the file specified.
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
if not closeHandle(f.fd.THandle).bool:
|
if not closeHandle(f.fd.THandle).bool:
|
||||||
raiseOSError()
|
raiseOSError(osLastError())
|
||||||
else:
|
else:
|
||||||
if close(f.fd.cint) == -1:
|
if close(f.fd.cint) == -1:
|
||||||
raiseOSError()
|
raiseOSError(osLastError())
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,7 @@ proc createDir*(ftp: AsyncFtpClient, dir: string, recursive = false){.async.} =
|
||||||
assertReply reply, "257"
|
assertReply reply, "257"
|
||||||
|
|
||||||
proc chmod*(ftp: AsyncFtpClient, path: string,
|
proc chmod*(ftp: AsyncFtpClient, path: string,
|
||||||
permissions: set[TFilePermission]) {.async.} =
|
permissions: set[FilePermission]) {.async.} =
|
||||||
## Changes permission of ``path`` to ``permissions``.
|
## Changes permission of ``path`` to ``permissions``.
|
||||||
var userOctal = 0
|
var userOctal = 0
|
||||||
var groupOctal = 0
|
var groupOctal = 0
|
||||||
|
|
@ -188,7 +188,7 @@ proc retrText*(ftp: AsyncFtpClient, file: string): Future[string] {.async.} =
|
||||||
|
|
||||||
result = await ftp.getLines()
|
result = await ftp.getLines()
|
||||||
|
|
||||||
proc getFile(ftp: AsyncFtpClient, file: TFile, total: BiggestInt,
|
proc getFile(ftp: AsyncFtpClient, file: File, total: BiggestInt,
|
||||||
onProgressChanged: ProgressChangedProc) {.async.} =
|
onProgressChanged: ProgressChangedProc) {.async.} =
|
||||||
assert ftp.dsockConnected
|
assert ftp.dsockConnected
|
||||||
var progress = 0
|
var progress = 0
|
||||||
|
|
@ -240,7 +240,7 @@ proc retrFile*(ftp: AsyncFtpClient, file, dest: string,
|
||||||
|
|
||||||
await getFile(ftp, destFile, fileSize, onProgressChanged)
|
await getFile(ftp, destFile, fileSize, onProgressChanged)
|
||||||
|
|
||||||
proc doUpload(ftp: AsyncFtpClient, file: TFile,
|
proc doUpload(ftp: AsyncFtpClient, file: File,
|
||||||
onProgressChanged: ProgressChangedProc) {.async.} =
|
onProgressChanged: ProgressChangedProc) {.async.} =
|
||||||
assert ftp.dsockConnected
|
assert ftp.dsockConnected
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -675,7 +675,7 @@ when isMainModule:
|
||||||
echo(data)
|
echo(data)
|
||||||
echo("Finished reading! " & $no)
|
echo("Finished reading! " & $no)
|
||||||
|
|
||||||
proc testAccept(s: AsyncSocket, disp: PDispatcher, no: int) =
|
proc testAccept(s: AsyncSocket, disp: Dispatcher, no: int) =
|
||||||
echo("Accepting client! " & $no)
|
echo("Accepting client! " & $no)
|
||||||
var client: AsyncSocket
|
var client: AsyncSocket
|
||||||
new(client)
|
new(client)
|
||||||
|
|
@ -691,7 +691,7 @@ when isMainModule:
|
||||||
var d = newDispatcher()
|
var d = newDispatcher()
|
||||||
|
|
||||||
var s = asyncSocket()
|
var s = asyncSocket()
|
||||||
s.connect("amber.tenthbit.net", TPort(6667))
|
s.connect("amber.tenthbit.net", Port(6667))
|
||||||
s.handleConnect =
|
s.handleConnect =
|
||||||
proc (s: AsyncSocket) =
|
proc (s: AsyncSocket) =
|
||||||
testConnect(s, 1)
|
testConnect(s, 1)
|
||||||
|
|
@ -704,7 +704,7 @@ when isMainModule:
|
||||||
server.handleAccept =
|
server.handleAccept =
|
||||||
proc (s: AsyncSocket) =
|
proc (s: AsyncSocket) =
|
||||||
testAccept(s, d, 78)
|
testAccept(s, d, 78)
|
||||||
server.bindAddr(TPort(5555))
|
server.bindAddr(Port(5555))
|
||||||
server.listen()
|
server.listen()
|
||||||
d.register(server)
|
d.register(server)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ import strutils
|
||||||
##
|
##
|
||||||
## Quick start example:
|
## Quick start example:
|
||||||
##
|
##
|
||||||
## # Create a matrix wich first rotates, then scales and at last translates
|
## # Create a matrix which first rotates, then scales and at last translates
|
||||||
##
|
##
|
||||||
## var m:TMatrix2d=rotate(DEG90) & scale(2.0) & move(100.0,200.0)
|
## var m:TMatrix2d=rotate(DEG90) & scale(2.0) & move(100.0,200.0)
|
||||||
##
|
##
|
||||||
|
|
@ -256,7 +256,7 @@ proc `$`* (t:TMatrix2d):string {.noInit.} =
|
||||||
|
|
||||||
proc isUniform*(t:TMatrix2d,tol=1.0e-6):bool=
|
proc isUniform*(t:TMatrix2d,tol=1.0e-6):bool=
|
||||||
## Checks if the transform is uniform, that is
|
## Checks if the transform is uniform, that is
|
||||||
## perpendicular axes of equal lenght, which means (for example)
|
## perpendicular axes of equal length, which means (for example)
|
||||||
## it cannot transform a circle into an ellipse.
|
## it cannot transform a circle into an ellipse.
|
||||||
## `tol` is used as tolerance for both equal length comparison
|
## `tol` is used as tolerance for both equal length comparison
|
||||||
## and perp. comparison.
|
## and perp. comparison.
|
||||||
|
|
@ -305,7 +305,7 @@ proc equals*(m1:TMatrix2d,m2:TMatrix2d,tol=1.0e-6):bool=
|
||||||
abs(m1.ty-m2.ty)<=tol
|
abs(m1.ty-m2.ty)<=tol
|
||||||
|
|
||||||
proc `=~`*(m1,m2:TMatrix2d):bool=
|
proc `=~`*(m1,m2:TMatrix2d):bool=
|
||||||
## Checks if `m1`and `m2` is aproximately equal, using a
|
## Checks if `m1`and `m2` is approximately equal, using a
|
||||||
## tolerance of 1e-6.
|
## tolerance of 1e-6.
|
||||||
equals(m1,m2)
|
equals(m1,m2)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ import times
|
||||||
##
|
##
|
||||||
## Quick start example:
|
## Quick start example:
|
||||||
##
|
##
|
||||||
## # Create a matrix wich first rotates, then scales and at last translates
|
## # Create a matrix which first rotates, then scales and at last translates
|
||||||
##
|
##
|
||||||
## var m:TMatrix3d=rotate(PI,vector3d(1,1,2.5)) & scale(2.0) & move(100.0,200.0,300.0)
|
## var m:TMatrix3d=rotate(PI,vector3d(1,1,2.5)) & scale(2.0) & move(100.0,200.0,300.0)
|
||||||
##
|
##
|
||||||
|
|
@ -320,7 +320,7 @@ proc rotateZ*(angle:float):TMatrix3d {.noInit.}=
|
||||||
|
|
||||||
proc isUniform*(m:TMatrix3d,tol=1.0e-6):bool=
|
proc isUniform*(m:TMatrix3d,tol=1.0e-6):bool=
|
||||||
## Checks if the transform is uniform, that is
|
## Checks if the transform is uniform, that is
|
||||||
## perpendicular axes of equal lenght, which means (for example)
|
## perpendicular axes of equal length, which means (for example)
|
||||||
## it cannot transform a sphere into an ellipsoid.
|
## it cannot transform a sphere into an ellipsoid.
|
||||||
## `tol` is used as tolerance for both equal length comparison
|
## `tol` is used as tolerance for both equal length comparison
|
||||||
## and perpendicular comparison.
|
## and perpendicular comparison.
|
||||||
|
|
@ -483,7 +483,7 @@ proc equals*(m1:TMatrix3d,m2:TMatrix3d,tol=1.0e-6):bool=
|
||||||
abs(m1.tw-m2.tw)<=tol
|
abs(m1.tw-m2.tw)<=tol
|
||||||
|
|
||||||
proc `=~`*(m1,m2:TMatrix3d):bool=
|
proc `=~`*(m1,m2:TMatrix3d):bool=
|
||||||
## Checks if `m1` and `m2` is aproximately equal, using a
|
## Checks if `m1` and `m2` is approximately equal, using a
|
||||||
## tolerance of 1e-6.
|
## tolerance of 1e-6.
|
||||||
equals(m1,m2)
|
equals(m1,m2)
|
||||||
|
|
||||||
|
|
@ -788,7 +788,7 @@ proc angleTo*(v1,v2:TVector3d):float=
|
||||||
proc arbitraryAxis*(norm:TVector3d):TMatrix3d {.noInit.}=
|
proc arbitraryAxis*(norm:TVector3d):TMatrix3d {.noInit.}=
|
||||||
## Computes the rotation matrix that would transform
|
## Computes the rotation matrix that would transform
|
||||||
## world z vector into `norm`. The inverse of this matrix
|
## world z vector into `norm`. The inverse of this matrix
|
||||||
## is useful to tranform a planar 3d object to 2d space.
|
## is useful to transform a planar 3d object to 2d space.
|
||||||
## This is the same algorithm used to interpret DXF and DWG files.
|
## This is the same algorithm used to interpret DXF and DWG files.
|
||||||
const lim=1.0/64.0
|
const lim=1.0/64.0
|
||||||
var ax,ay,az:TVector3d
|
var ax,ay,az:TVector3d
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ proc openDefaultBrowser*(url: string) =
|
||||||
for b in getEnv("BROWSER").string.split(PathSep):
|
for b in getEnv("BROWSER").string.split(PathSep):
|
||||||
try:
|
try:
|
||||||
# we use ``startProcess`` here because we don't want to block!
|
# we use ``startProcess`` here because we don't want to block!
|
||||||
discard startProcess(command=b, args=[url], options={poUseShell})
|
discard startProcess(command=b, args=[url], options={poUsePath})
|
||||||
return
|
return
|
||||||
except OSError:
|
except OSError:
|
||||||
discard
|
discard
|
||||||
|
|
|
||||||
|
|
@ -404,7 +404,7 @@ proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int,
|
||||||
#echo("tomb old slot then set in new table")
|
#echo("tomb old slot then set in new table")
|
||||||
nextTable = copySlotAndCheck(table,idx)
|
nextTable = copySlotAndCheck(table,idx)
|
||||||
return setVal(nextTable, key, val, expVal, match)
|
return setVal(nextTable, key, val, expVal, match)
|
||||||
# Finaly ready to add new val to table
|
# Finally ready to add new val to table
|
||||||
while true:
|
while true:
|
||||||
if match and oldVal != expVal:
|
if match and oldVal != expVal:
|
||||||
#echo("set failed, no match oldVal= " & $oldVal & " expVal= " & $expVal)
|
#echo("set failed, no match oldVal= " & $oldVal & " expVal= " & $expVal)
|
||||||
|
|
|
||||||
|
|
@ -174,7 +174,7 @@ proc excl*[T](c: var CritBitTree[T], key: string) =
|
||||||
iterator leaves[T](n: Node[T]): Node[T] =
|
iterator leaves[T](n: Node[T]): Node[T] =
|
||||||
if n != nil:
|
if n != nil:
|
||||||
# XXX actually we could compute the necessary stack size in advance:
|
# XXX actually we could compute the necessary stack size in advance:
|
||||||
# it's rougly log2(c.count).
|
# it's roughly log2(c.count).
|
||||||
var stack = @[n]
|
var stack = @[n]
|
||||||
while stack.len > 0:
|
while stack.len > 0:
|
||||||
var it = stack.pop
|
var it = stack.pop
|
||||||
|
|
|
||||||
|
|
@ -191,9 +191,10 @@ proc `$`*(s: IntSet): string =
|
||||||
## The `$` operator for int sets.
|
## The `$` operator for int sets.
|
||||||
dollarImpl()
|
dollarImpl()
|
||||||
|
|
||||||
proc empty*(s: IntSet): bool {.inline.} =
|
proc empty*(s: IntSet): bool {.inline, deprecated.} =
|
||||||
## returns true if `s` is empty. This is safe to call even before
|
## returns true if `s` is empty. This is safe to call even before
|
||||||
## the set has been initialized with `initIntSet`.
|
## the set has been initialized with `initIntSet`. Note this never
|
||||||
|
## worked reliably and so is deprecated.
|
||||||
result = s.counter == 0
|
result = s.counter == 0
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
|
|
|
||||||
|
|
@ -320,7 +320,7 @@ template foldl*(sequence, operation: expr): expr =
|
||||||
##
|
##
|
||||||
## The ``operation`` parameter should be an expression which uses the
|
## The ``operation`` parameter should be an expression which uses the
|
||||||
## variables ``a`` and ``b`` for each step of the fold. Since this is a left
|
## variables ``a`` and ``b`` for each step of the fold. Since this is a left
|
||||||
## fold, for non associative binary operations like substraction think that
|
## fold, for non associative binary operations like subtraction think that
|
||||||
## the sequence of numbers 1, 2 and 3 will be parenthesized as (((1) - 2) -
|
## the sequence of numbers 1, 2 and 3 will be parenthesized as (((1) - 2) -
|
||||||
## 3). Example:
|
## 3). Example:
|
||||||
##
|
##
|
||||||
|
|
@ -328,12 +328,12 @@ template foldl*(sequence, operation: expr): expr =
|
||||||
## let
|
## let
|
||||||
## numbers = @[5, 9, 11]
|
## numbers = @[5, 9, 11]
|
||||||
## addition = foldl(numbers, a + b)
|
## addition = foldl(numbers, a + b)
|
||||||
## substraction = foldl(numbers, a - b)
|
## subtraction = foldl(numbers, a - b)
|
||||||
## multiplication = foldl(numbers, a * b)
|
## multiplication = foldl(numbers, a * b)
|
||||||
## words = @["nim", "is", "cool"]
|
## words = @["nim", "is", "cool"]
|
||||||
## concatenation = foldl(words, a & b)
|
## concatenation = foldl(words, a & b)
|
||||||
## assert addition == 25, "Addition is (((5)+9)+11)"
|
## assert addition == 25, "Addition is (((5)+9)+11)"
|
||||||
## assert substraction == -15, "Substraction is (((5)-9)-11)"
|
## assert subtraction == -15, "Subtraction is (((5)-9)-11)"
|
||||||
## assert multiplication == 495, "Multiplication is (((5)*9)*11)"
|
## assert multiplication == 495, "Multiplication is (((5)*9)*11)"
|
||||||
## assert concatenation == "nimiscool"
|
## assert concatenation == "nimiscool"
|
||||||
assert sequence.len > 0, "Can't fold empty sequences"
|
assert sequence.len > 0, "Can't fold empty sequences"
|
||||||
|
|
@ -356,7 +356,7 @@ template foldr*(sequence, operation: expr): expr =
|
||||||
##
|
##
|
||||||
## The ``operation`` parameter should be an expression which uses the
|
## The ``operation`` parameter should be an expression which uses the
|
||||||
## variables ``a`` and ``b`` for each step of the fold. Since this is a right
|
## variables ``a`` and ``b`` for each step of the fold. Since this is a right
|
||||||
## fold, for non associative binary operations like substraction think that
|
## fold, for non associative binary operations like subtraction think that
|
||||||
## the sequence of numbers 1, 2 and 3 will be parenthesized as (1 - (2 -
|
## the sequence of numbers 1, 2 and 3 will be parenthesized as (1 - (2 -
|
||||||
## (3))). Example:
|
## (3))). Example:
|
||||||
##
|
##
|
||||||
|
|
@ -364,12 +364,12 @@ template foldr*(sequence, operation: expr): expr =
|
||||||
## let
|
## let
|
||||||
## numbers = @[5, 9, 11]
|
## numbers = @[5, 9, 11]
|
||||||
## addition = foldr(numbers, a + b)
|
## addition = foldr(numbers, a + b)
|
||||||
## substraction = foldr(numbers, a - b)
|
## subtraction = foldr(numbers, a - b)
|
||||||
## multiplication = foldr(numbers, a * b)
|
## multiplication = foldr(numbers, a * b)
|
||||||
## words = @["nim", "is", "cool"]
|
## words = @["nim", "is", "cool"]
|
||||||
## concatenation = foldr(words, a & b)
|
## concatenation = foldr(words, a & b)
|
||||||
## assert addition == 25, "Addition is (5+(9+(11)))"
|
## assert addition == 25, "Addition is (5+(9+(11)))"
|
||||||
## assert substraction == 7, "Substraction is (5-(9-(11)))"
|
## assert subtraction == 7, "Subtraction is (5-(9-(11)))"
|
||||||
## assert multiplication == 495, "Multiplication is (5*(9*(11)))"
|
## assert multiplication == 495, "Multiplication is (5*(9*(11)))"
|
||||||
## assert concatenation == "nimiscool"
|
## assert concatenation == "nimiscool"
|
||||||
assert sequence.len > 0, "Can't fold empty sequences"
|
assert sequence.len > 0, "Can't fold empty sequences"
|
||||||
|
|
@ -507,12 +507,12 @@ when isMainModule:
|
||||||
let
|
let
|
||||||
numbers = @[5, 9, 11]
|
numbers = @[5, 9, 11]
|
||||||
addition = foldl(numbers, a + b)
|
addition = foldl(numbers, a + b)
|
||||||
substraction = foldl(numbers, a - b)
|
subtraction = foldl(numbers, a - b)
|
||||||
multiplication = foldl(numbers, a * b)
|
multiplication = foldl(numbers, a * b)
|
||||||
words = @["nim", "is", "cool"]
|
words = @["nim", "is", "cool"]
|
||||||
concatenation = foldl(words, a & b)
|
concatenation = foldl(words, a & b)
|
||||||
assert addition == 25, "Addition is (((5)+9)+11)"
|
assert addition == 25, "Addition is (((5)+9)+11)"
|
||||||
assert substraction == -15, "Substraction is (((5)-9)-11)"
|
assert subtraction == -15, "Subtraction is (((5)-9)-11)"
|
||||||
assert multiplication == 495, "Multiplication is (((5)*9)*11)"
|
assert multiplication == 495, "Multiplication is (((5)*9)*11)"
|
||||||
assert concatenation == "nimiscool"
|
assert concatenation == "nimiscool"
|
||||||
|
|
||||||
|
|
@ -520,12 +520,12 @@ when isMainModule:
|
||||||
let
|
let
|
||||||
numbers = @[5, 9, 11]
|
numbers = @[5, 9, 11]
|
||||||
addition = foldr(numbers, a + b)
|
addition = foldr(numbers, a + b)
|
||||||
substraction = foldr(numbers, a - b)
|
subtraction = foldr(numbers, a - b)
|
||||||
multiplication = foldr(numbers, a * b)
|
multiplication = foldr(numbers, a * b)
|
||||||
words = @["nim", "is", "cool"]
|
words = @["nim", "is", "cool"]
|
||||||
concatenation = foldr(words, a & b)
|
concatenation = foldr(words, a & b)
|
||||||
assert addition == 25, "Addition is (5+(9+(11)))"
|
assert addition == 25, "Addition is (5+(9+(11)))"
|
||||||
assert substraction == 7, "Substraction is (5-(9-(11)))"
|
assert subtraction == 7, "Subtraction is (5-(9-(11)))"
|
||||||
assert multiplication == 495, "Multiplication is (5*(9*(11)))"
|
assert multiplication == 495, "Multiplication is (5*(9*(11)))"
|
||||||
assert concatenation == "nimiscool"
|
assert concatenation == "nimiscool"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
## (also often named `dictionary`:idx: in other programming languages) that is
|
## (also often named `dictionary`:idx: in other programming languages) that is
|
||||||
## a mapping from keys to values. ``Table`` is the usual hash table,
|
## a mapping from keys to values. ``Table`` is the usual hash table,
|
||||||
## ``OrderedTable`` is like ``Table`` but remembers insertion order
|
## ``OrderedTable`` is like ``Table`` but remembers insertion order
|
||||||
## and ``CountTable`` is a mapping from a key to its number of occurances.
|
## and ``CountTable`` is a mapping from a key to its number of occurrences.
|
||||||
## For consistency with every other data type in Nim these have **value**
|
## For consistency with every other data type in Nim these have **value**
|
||||||
## semantics, this means that ``=`` performs a copy of the hash table.
|
## semantics, this means that ``=`` performs a copy of the hash table.
|
||||||
## For **reference** semantics use the ``Ref`` variant: ``TableRef``,
|
## For **reference** semantics use the ``Ref`` variant: ``TableRef``,
|
||||||
|
|
@ -231,31 +231,42 @@ template addImpl() {.dirty.} =
|
||||||
rawInsert(t, t.data, key, val, hc, j)
|
rawInsert(t, t.data, key, val, hc, j)
|
||||||
inc(t.counter)
|
inc(t.counter)
|
||||||
|
|
||||||
|
template maybeRehashPutImpl() {.dirty.} =
|
||||||
|
if mustRehash(len(t.data), t.counter):
|
||||||
|
enlarge(t)
|
||||||
|
index = rawGetKnownHC(t, key, hc)
|
||||||
|
index = -1 - index # important to transform for mgetOrPutImpl
|
||||||
|
rawInsert(t, t.data, key, val, hc, index)
|
||||||
|
inc(t.counter)
|
||||||
|
|
||||||
template putImpl() {.dirty.} =
|
template putImpl() {.dirty.} =
|
||||||
var hc: THash
|
var hc: THash
|
||||||
var index = rawGet(t, key, hc)
|
var index = rawGet(t, key, hc)
|
||||||
if index >= 0:
|
if index >= 0: t.data[index].val = val
|
||||||
t.data[index].val = val
|
else: maybeRehashPutImpl()
|
||||||
else:
|
|
||||||
if mustRehash(len(t.data), t.counter):
|
|
||||||
enlarge(t)
|
|
||||||
index = rawGetKnownHC(t, key, hc)
|
|
||||||
rawInsert(t, t.data, key, val, hc, -1 - index)
|
|
||||||
inc(t.counter)
|
|
||||||
|
|
||||||
when false:
|
template mgetOrPutImpl() {.dirty.} =
|
||||||
# not yet used:
|
var hc: THash
|
||||||
template hasKeyOrPutImpl() {.dirty.} =
|
var index = rawGet(t, key, hc)
|
||||||
var hc: THash
|
if index < 0: maybeRehashPutImpl() # not present: insert (flipping index)
|
||||||
var index = rawGet(t, key, hc)
|
result = t.data[index].val # either way return modifiable val
|
||||||
if index >= 0:
|
|
||||||
t.data[index].val = val
|
template hasKeyOrPutImpl() {.dirty.} =
|
||||||
result = true
|
var hc: THash
|
||||||
else:
|
var index = rawGet(t, key, hc)
|
||||||
if mustRehash(len(t.data), t.counter): enlarge(t)
|
if index < 0:
|
||||||
rawInsert(t, t.data, key, val)
|
result = false
|
||||||
inc(t.counter)
|
maybeRehashPutImpl()
|
||||||
result = false
|
else: result = true
|
||||||
|
|
||||||
|
proc mgetOrPut*[A, B](t: var Table[A, B], key: A, val: B): var B =
|
||||||
|
## retrieves value at ``t[key]`` or puts ``val`` if not present, either way
|
||||||
|
## returning a value which can be modified.
|
||||||
|
mgetOrPutImpl()
|
||||||
|
|
||||||
|
proc hasKeyOrPut*[A, B](t: var Table[A, B], key: A, val: B): bool =
|
||||||
|
## returns true iff `key` is in the table, otherwise inserts `value`.
|
||||||
|
hasKeyOrPutImpl()
|
||||||
|
|
||||||
proc `[]=`*[A, B](t: var Table[A, B], key: A, val: B) =
|
proc `[]=`*[A, B](t: var Table[A, B], key: A, val: B) =
|
||||||
## puts a (key, value)-pair into `t`.
|
## puts a (key, value)-pair into `t`.
|
||||||
|
|
@ -383,6 +394,15 @@ proc mget*[A, B](t: TableRef[A, B], key: A): var B =
|
||||||
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
|
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
|
||||||
t[].mget(key)
|
t[].mget(key)
|
||||||
|
|
||||||
|
proc mgetOrPut*[A, B](t: TableRef[A, B], key: A, val: B): var B =
|
||||||
|
## retrieves value at ``t[key]`` or puts ``val`` if not present, either way
|
||||||
|
## returning a value which can be modified.
|
||||||
|
t[].mgetOrPut(key, val)
|
||||||
|
|
||||||
|
proc hasKeyOrPut*[A, B](t: var TableRef[A, B], key: A, val: B): bool =
|
||||||
|
## returns true iff `key` is in the table, otherwise inserts `value`.
|
||||||
|
t[].hasKeyOrPut(key, val)
|
||||||
|
|
||||||
proc hasKey*[A, B](t: TableRef[A, B], key: A): bool =
|
proc hasKey*[A, B](t: TableRef[A, B], key: A): bool =
|
||||||
## returns true iff `key` is in the table `t`.
|
## returns true iff `key` is in the table `t`.
|
||||||
result = t[].hasKey(key)
|
result = t[].hasKey(key)
|
||||||
|
|
@ -539,6 +559,15 @@ proc add*[A, B](t: var OrderedTable[A, B], key: A, val: B) =
|
||||||
## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists.
|
## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists.
|
||||||
addImpl()
|
addImpl()
|
||||||
|
|
||||||
|
proc mgetOrPut*[A, B](t: var OrderedTable[A, B], key: A, val: B): var B =
|
||||||
|
## retrieves value at ``t[key]`` or puts ``value`` if not present, either way
|
||||||
|
## returning a value which can be modified.
|
||||||
|
mgetOrPutImpl()
|
||||||
|
|
||||||
|
proc hasKeyOrPut*[A, B](t: var OrderedTable[A, B], key: A, val: B): bool =
|
||||||
|
## returns true iff `key` is in the table, otherwise inserts `value`.
|
||||||
|
hasKeyOrPutImpl()
|
||||||
|
|
||||||
proc initOrderedTable*[A, B](initialSize=64): OrderedTable[A, B] =
|
proc initOrderedTable*[A, B](initialSize=64): OrderedTable[A, B] =
|
||||||
## creates a new ordered hash table that is empty.
|
## creates a new ordered hash table that is empty.
|
||||||
##
|
##
|
||||||
|
|
@ -658,6 +687,15 @@ proc mget*[A, B](t: OrderedTableRef[A, B], key: A): var B =
|
||||||
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
|
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
|
||||||
result = t[].mget(key)
|
result = t[].mget(key)
|
||||||
|
|
||||||
|
proc mgetOrPut*[A, B](t: OrderedTableRef[A, B], key: A, val: B): var B =
|
||||||
|
## retrieves value at ``t[key]`` or puts ``val`` if not present, either way
|
||||||
|
## returning a value which can be modified.
|
||||||
|
result = t[].mgetOrPut(key, val)
|
||||||
|
|
||||||
|
proc hasKeyOrPut*[A, B](t: var OrderedTableRef[A, B], key: A, val: B): bool =
|
||||||
|
## returns true iff `key` is in the table, otherwise inserts `val`.
|
||||||
|
result = t[].hasKeyOrPut(key, val)
|
||||||
|
|
||||||
proc hasKey*[A, B](t: OrderedTableRef[A, B], key: A): bool =
|
proc hasKey*[A, B](t: OrderedTableRef[A, B], key: A): bool =
|
||||||
## returns true iff `key` is in the table `t`.
|
## returns true iff `key` is in the table `t`.
|
||||||
result = t[].hasKey(key)
|
result = t[].hasKey(key)
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ proc `+`*(a, b: Color): Color =
|
||||||
colorOp(satPlus)
|
colorOp(satPlus)
|
||||||
|
|
||||||
proc `-`*(a, b: Color): Color =
|
proc `-`*(a, b: Color): Color =
|
||||||
## substracts two colors: This uses saturated artithmetic, so that each color
|
## subtracts two colors: This uses saturated artithmetic, so that each color
|
||||||
## component cannot overflow (255 is used as a maximum).
|
## component cannot overflow (255 is used as a maximum).
|
||||||
colorOp(satMinus)
|
colorOp(satMinus)
|
||||||
|
|
||||||
|
|
@ -392,7 +392,7 @@ proc parseColor*(name: string): Color =
|
||||||
result = Color(parseHexInt(name))
|
result = Color(parseHexInt(name))
|
||||||
else:
|
else:
|
||||||
var idx = binaryStrSearch(colorNames, name)
|
var idx = binaryStrSearch(colorNames, name)
|
||||||
if idx < 0: raise newException(ValueError, "unkown color: " & name)
|
if idx < 0: raise newException(ValueError, "unknown color: " & name)
|
||||||
result = colorNames[idx][1]
|
result = colorNames[idx][1]
|
||||||
|
|
||||||
proc isColor*(name: string): bool =
|
proc isColor*(name: string): bool =
|
||||||
|
|
|
||||||
|
|
@ -301,7 +301,7 @@ proc getCurrentEncoding*(): string =
|
||||||
|
|
||||||
proc open*(destEncoding = "UTF-8", srcEncoding = "CP1252"): EncodingConverter =
|
proc open*(destEncoding = "UTF-8", srcEncoding = "CP1252"): EncodingConverter =
|
||||||
## opens a converter that can convert from `srcEncoding` to `destEncoding`.
|
## opens a converter that can convert from `srcEncoding` to `destEncoding`.
|
||||||
## Raises `EIO` if it cannot fullfill the request.
|
## Raises `EIO` if it cannot fulfill the request.
|
||||||
when not defined(windows):
|
when not defined(windows):
|
||||||
result = iconvOpen(destEncoding, srcEncoding)
|
result = iconvOpen(destEncoding, srcEncoding)
|
||||||
if result == nil:
|
if result == nil:
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
## :Author: Alex Mitchell
|
## :Author: Alex Mitchell
|
||||||
##
|
##
|
||||||
## This module implements an event system that is not dependant on external
|
## This module implements an event system that is not dependent on external
|
||||||
## graphical toolkits. It was originally called ``NimEE`` because
|
## graphical toolkits. It was originally called ``NimEE`` because
|
||||||
## it was inspired by Python's PyEE module. There are two ways you can use
|
## it was inspired by Python's PyEE module. There are two ways you can use
|
||||||
## events: one is a python-inspired way; the other is more of a C-style way.
|
## events: one is a python-inspired way; the other is more of a C-style way.
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ type
|
||||||
FSMonitorObj = object of RootObj
|
FSMonitorObj = object of RootObj
|
||||||
fd: cint
|
fd: cint
|
||||||
handleEvent: proc (m: FSMonitor, ev: MonitorEvent) {.closure.}
|
handleEvent: proc (m: FSMonitor, ev: MonitorEvent) {.closure.}
|
||||||
targets: TTable[cint, string]
|
targets: Table[cint, string]
|
||||||
|
|
||||||
MonitorEventType* = enum ## Monitor event type
|
MonitorEventType* = enum ## Monitor event type
|
||||||
MonitorAccess, ## File was accessed.
|
MonitorAccess, ## File was accessed.
|
||||||
|
|
@ -64,7 +64,7 @@ type
|
||||||
const
|
const
|
||||||
MaxEvents = 100
|
MaxEvents = 100
|
||||||
|
|
||||||
proc newMonitor*(): PFSMonitor =
|
proc newMonitor*(): FSMonitor =
|
||||||
## Creates a new file system monitor.
|
## Creates a new file system monitor.
|
||||||
new(result)
|
new(result)
|
||||||
result.targets = initTable[cint, string]()
|
result.targets = initTable[cint, string]()
|
||||||
|
|
@ -72,7 +72,7 @@ proc newMonitor*(): PFSMonitor =
|
||||||
if result.fd < 0:
|
if result.fd < 0:
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
|
|
||||||
proc add*(monitor: PFSMonitor, target: string,
|
proc add*(monitor: FSMonitor, target: string,
|
||||||
filters = {MonitorAll}): cint {.discardable.} =
|
filters = {MonitorAll}): cint {.discardable.} =
|
||||||
## Adds ``target`` which may be a directory or a file to the list of
|
## Adds ``target`` which may be a directory or a file to the list of
|
||||||
## watched paths of ``monitor``.
|
## watched paths of ``monitor``.
|
||||||
|
|
@ -99,14 +99,14 @@ proc add*(monitor: PFSMonitor, target: string,
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
monitor.targets.add(result, target)
|
monitor.targets.add(result, target)
|
||||||
|
|
||||||
proc del*(monitor: PFSMonitor, wd: cint) =
|
proc del*(monitor: FSMonitor, wd: cint) =
|
||||||
## Removes watched directory or file as specified by ``wd`` from ``monitor``.
|
## Removes watched directory or file as specified by ``wd`` from ``monitor``.
|
||||||
##
|
##
|
||||||
## If ``wd`` is not a part of ``monitor`` an EOS error is raised.
|
## If ``wd`` is not a part of ``monitor`` an EOS error is raised.
|
||||||
if inotifyRmWatch(monitor.fd, wd) < 0:
|
if inotifyRmWatch(monitor.fd, wd) < 0:
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
|
|
||||||
proc getEvent(m: PFSMonitor, fd: cint): seq[TMonitorEvent] =
|
proc getEvent(m: FSMonitor, fd: cint): seq[MonitorEvent] =
|
||||||
result = @[]
|
result = @[]
|
||||||
let size = (sizeof(TINotifyEvent)+2000)*MaxEvents
|
let size = (sizeof(TINotifyEvent)+2000)*MaxEvents
|
||||||
var buffer = newString(size)
|
var buffer = newString(size)
|
||||||
|
|
@ -118,7 +118,7 @@ proc getEvent(m: PFSMonitor, fd: cint): seq[TMonitorEvent] =
|
||||||
var i = 0
|
var i = 0
|
||||||
while i < le:
|
while i < le:
|
||||||
var event = cast[ptr TINotifyEvent](addr(buffer[i]))
|
var event = cast[ptr TINotifyEvent](addr(buffer[i]))
|
||||||
var mev: TMonitorEvent
|
var mev: MonitorEvent
|
||||||
mev.wd = event.wd
|
mev.wd = event.wd
|
||||||
if event.len.int != 0:
|
if event.len.int != 0:
|
||||||
let cstr = event.name.addr.cstring
|
let cstr = event.name.addr.cstring
|
||||||
|
|
@ -137,7 +137,7 @@ proc getEvent(m: PFSMonitor, fd: cint): seq[TMonitorEvent] =
|
||||||
# Find the MovedFrom event.
|
# Find the MovedFrom event.
|
||||||
mev.oldPath = movedFrom[event.cookie.cint].old
|
mev.oldPath = movedFrom[event.cookie.cint].old
|
||||||
mev.newPath = "" # Set later
|
mev.newPath = "" # Set later
|
||||||
# Delete it from the TTable
|
# Delete it from the Table
|
||||||
movedFrom.del(event.cookie.cint)
|
movedFrom.del(event.cookie.cint)
|
||||||
elif (event.mask.int and IN_ACCESS) != 0: mev.kind = MonitorAccess
|
elif (event.mask.int and IN_ACCESS) != 0: mev.kind = MonitorAccess
|
||||||
elif (event.mask.int and IN_ATTRIB) != 0: mev.kind = MonitorAttrib
|
elif (event.mask.int and IN_ATTRIB) != 0: mev.kind = MonitorAttrib
|
||||||
|
|
@ -164,26 +164,26 @@ proc getEvent(m: PFSMonitor, fd: cint): seq[TMonitorEvent] =
|
||||||
# If movedFrom events have not been matched with a moveTo. File has
|
# If movedFrom events have not been matched with a moveTo. File has
|
||||||
# been moved to an unwatched location, emit a MonitorDelete.
|
# been moved to an unwatched location, emit a MonitorDelete.
|
||||||
for cookie, t in pairs(movedFrom):
|
for cookie, t in pairs(movedFrom):
|
||||||
var mev: TMonitorEvent
|
var mev: MonitorEvent
|
||||||
mev.kind = MonitorDelete
|
mev.kind = MonitorDelete
|
||||||
mev.wd = t.wd
|
mev.wd = t.wd
|
||||||
mev.name = t.old
|
mev.name = t.old
|
||||||
result.add(mev)
|
result.add(mev)
|
||||||
|
|
||||||
proc FSMonitorRead(h: PObject) =
|
proc FSMonitorRead(h: RootRef) =
|
||||||
var events = PFSMonitor(h).getEvent(PFSMonitor(h).fd)
|
var events = FSMonitor(h).getEvent(FSMonitor(h).fd)
|
||||||
#var newEv: TMonitorEvent
|
#var newEv: MonitorEvent
|
||||||
for ev in events:
|
for ev in events:
|
||||||
var target = PFSMonitor(h).targets[ev.wd]
|
var target = FSMonitor(h).targets[ev.wd]
|
||||||
var newEv = ev
|
var newEv = ev
|
||||||
if newEv.kind == MonitorMoved:
|
if newEv.kind == MonitorMoved:
|
||||||
newEv.oldPath = target / newEv.oldPath
|
newEv.oldPath = target / newEv.oldPath
|
||||||
newEv.newPath = target / newEv.name
|
newEv.newPath = target / newEv.name
|
||||||
else:
|
else:
|
||||||
newEv.fullName = target / newEv.name
|
newEv.fullName = target / newEv.name
|
||||||
PFSMonitor(h).handleEvent(PFSMonitor(h), newEv)
|
FSMonitor(h).handleEvent(FSMonitor(h), newEv)
|
||||||
|
|
||||||
proc toDelegate(m: PFSMonitor): PDelegate =
|
proc toDelegate(m: FSMonitor): Delegate =
|
||||||
result = newDelegate()
|
result = newDelegate()
|
||||||
result.deleVal = m
|
result.deleVal = m
|
||||||
result.fd = (type(result.fd))(m.fd)
|
result.fd = (type(result.fd))(m.fd)
|
||||||
|
|
@ -191,8 +191,8 @@ proc toDelegate(m: PFSMonitor): PDelegate =
|
||||||
result.handleRead = FSMonitorRead
|
result.handleRead = FSMonitorRead
|
||||||
result.open = true
|
result.open = true
|
||||||
|
|
||||||
proc register*(d: PDispatcher, monitor: PFSMonitor,
|
proc register*(d: Dispatcher, monitor: FSMonitor,
|
||||||
handleEvent: proc (m: PFSMonitor, ev: TMonitorEvent) {.closure.}) =
|
handleEvent: proc (m: FSMonitor, ev: MonitorEvent) {.closure.}) =
|
||||||
## Registers ``monitor`` with dispatcher ``d``.
|
## Registers ``monitor`` with dispatcher ``d``.
|
||||||
monitor.handleEvent = handleEvent
|
monitor.handleEvent = handleEvent
|
||||||
var deleg = toDelegate(monitor)
|
var deleg = toDelegate(monitor)
|
||||||
|
|
@ -204,7 +204,7 @@ when isMainModule:
|
||||||
var monitor = newMonitor()
|
var monitor = newMonitor()
|
||||||
echo monitor.add("/home/dom/inotifytests/")
|
echo monitor.add("/home/dom/inotifytests/")
|
||||||
disp.register(monitor,
|
disp.register(monitor,
|
||||||
proc (m: PFSMonitor, ev: TMonitorEvent) =
|
proc (m: FSMonitor, ev: MonitorEvent) =
|
||||||
echo("Got event: ", ev.kind)
|
echo("Got event: ", ev.kind)
|
||||||
if ev.kind == MonitorMoved:
|
if ev.kind == MonitorMoved:
|
||||||
echo("From ", ev.oldPath, " to ", ev.newPath)
|
echo("From ", ev.oldPath, " to ", ev.newPath)
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ type
|
||||||
EInvalidReply: ReplyError, EFTP: FTPError
|
EInvalidReply: ReplyError, EFTP: FTPError
|
||||||
].}
|
].}
|
||||||
|
|
||||||
proc ftpClient*(address: string, port = TPort(21),
|
proc ftpClient*(address: string, port = Port(21),
|
||||||
user, pass = ""): FtpClient =
|
user, pass = ""): FtpClient =
|
||||||
## Create a ``FtpClient`` object.
|
## Create a ``FtpClient`` object.
|
||||||
new(result)
|
new(result)
|
||||||
|
|
@ -120,10 +120,10 @@ proc ftpClient*(address: string, port = TPort(21),
|
||||||
result.csock = socket()
|
result.csock = socket()
|
||||||
if result.csock == invalidSocket: raiseOSError(osLastError())
|
if result.csock == invalidSocket: raiseOSError(osLastError())
|
||||||
|
|
||||||
template blockingOperation(sock: TSocket, body: stmt) {.immediate.} =
|
template blockingOperation(sock: Socket, body: stmt) {.immediate.} =
|
||||||
body
|
body
|
||||||
|
|
||||||
template blockingOperation(sock: asyncio.PAsyncSocket, body: stmt) {.immediate.} =
|
template blockingOperation(sock: asyncio.AsyncSocket, body: stmt) {.immediate.} =
|
||||||
sock.setBlocking(true)
|
sock.setBlocking(true)
|
||||||
body
|
body
|
||||||
sock.setBlocking(false)
|
sock.setBlocking(false)
|
||||||
|
|
@ -145,14 +145,14 @@ proc send*[T](ftp: FtpBase[T], m: string): TaintedString =
|
||||||
|
|
||||||
proc assertReply(received: TaintedString, expected: string) =
|
proc assertReply(received: TaintedString, expected: string) =
|
||||||
if not received.string.startsWith(expected):
|
if not received.string.startsWith(expected):
|
||||||
raise newException(EInvalidReply,
|
raise newException(ReplyError,
|
||||||
"Expected reply '$1' got: $2" % [
|
"Expected reply '$1' got: $2" % [
|
||||||
expected, received.string])
|
expected, received.string])
|
||||||
|
|
||||||
proc assertReply(received: TaintedString, expected: varargs[string]) =
|
proc assertReply(received: TaintedString, expected: varargs[string]) =
|
||||||
for i in items(expected):
|
for i in items(expected):
|
||||||
if received.string.startsWith(i): return
|
if received.string.startsWith(i): return
|
||||||
raise newException(EInvalidReply,
|
raise newException(ReplyError,
|
||||||
"Expected reply '$1' got: $2" %
|
"Expected reply '$1' got: $2" %
|
||||||
[expected.join("' or '"), received.string])
|
[expected.join("' or '"), received.string])
|
||||||
|
|
||||||
|
|
@ -161,7 +161,7 @@ proc createJob[T](ftp: FtpBase[T],
|
||||||
nimcall,gcsafe.},
|
nimcall,gcsafe.},
|
||||||
cmd: FTPJobType) =
|
cmd: FTPJobType) =
|
||||||
if ftp.jobInProgress:
|
if ftp.jobInProgress:
|
||||||
raise newException(EFTP, "Unable to do two jobs at once.")
|
raise newException(FTPError, "Unable to do two jobs at once.")
|
||||||
ftp.jobInProgress = true
|
ftp.jobInProgress = true
|
||||||
new(ftp.job)
|
new(ftp.job)
|
||||||
ftp.job.prc = prc
|
ftp.job.prc = prc
|
||||||
|
|
@ -182,11 +182,11 @@ proc deleteJob[T](ftp: FtpBase[T]) =
|
||||||
ftp.job.file.close()
|
ftp.job.file.close()
|
||||||
ftp.dsock.close()
|
ftp.dsock.close()
|
||||||
|
|
||||||
proc handleTask(s: PAsyncSocket, ftp: PAsyncFTPClient) =
|
proc handleTask(s: AsyncSocket, ftp: AsyncFTPClient) =
|
||||||
if ftp.jobInProgress:
|
if ftp.jobInProgress:
|
||||||
if ftp.job.typ in {JRetr, JStore}:
|
if ftp.job.typ in {JRetr, JStore}:
|
||||||
if epochTime() - ftp.job.lastProgressReport >= 1.0:
|
if epochTime() - ftp.job.lastProgressReport >= 1.0:
|
||||||
var r: TFTPEvent
|
var r: FTPEvent
|
||||||
ftp.job.lastProgressReport = epochTime()
|
ftp.job.lastProgressReport = epochTime()
|
||||||
r.typ = EvTransferProgress
|
r.typ = EvTransferProgress
|
||||||
r.bytesTotal = ftp.job.total
|
r.bytesTotal = ftp.job.total
|
||||||
|
|
@ -195,22 +195,22 @@ proc handleTask(s: PAsyncSocket, ftp: PAsyncFTPClient) =
|
||||||
r.filename = ftp.job.filename
|
r.filename = ftp.job.filename
|
||||||
r.currentJob = ftp.job.typ
|
r.currentJob = ftp.job.typ
|
||||||
ftp.job.oneSecond = 0
|
ftp.job.oneSecond = 0
|
||||||
ftp.handleEvent(PAsyncFTPClient(ftp), r)
|
ftp.handleEvent(ftp, r)
|
||||||
|
|
||||||
proc handleWrite(s: PAsyncSocket, ftp: PAsyncFTPClient) =
|
proc handleWrite(s: AsyncSocket, ftp: AsyncFTPClient) =
|
||||||
if ftp.jobInProgress:
|
if ftp.jobInProgress:
|
||||||
if ftp.job.typ == JStore:
|
if ftp.job.typ == JStore:
|
||||||
assert (not ftp.job.prc(ftp, true))
|
assert (not ftp.job.prc(ftp, true))
|
||||||
|
|
||||||
proc handleConnect(s: PAsyncSocket, ftp: PAsyncFTPClient) =
|
proc handleConnect(s: AsyncSocket, ftp: AsyncFTPClient) =
|
||||||
ftp.dsockConnected = true
|
ftp.dsockConnected = true
|
||||||
assert(ftp.jobInProgress)
|
assert(ftp.jobInProgress)
|
||||||
if ftp.job.typ == JStore:
|
if ftp.job.typ == JStore:
|
||||||
s.setHandleWrite(proc (s: PAsyncSocket) = handleWrite(s, ftp))
|
s.setHandleWrite(proc (s: AsyncSocket) = handleWrite(s, ftp))
|
||||||
else:
|
else:
|
||||||
s.delHandleWrite()
|
s.delHandleWrite()
|
||||||
|
|
||||||
proc handleRead(s: PAsyncSocket, ftp: PAsyncFTPClient) =
|
proc handleRead(s: AsyncSocket, ftp: AsyncFTPClient) =
|
||||||
assert ftp.jobInProgress
|
assert ftp.jobInProgress
|
||||||
assert ftp.job.typ != JStore
|
assert ftp.job.typ != JStore
|
||||||
# This can never return true, because it shouldn't check for code
|
# This can never return true, because it shouldn't check for code
|
||||||
|
|
@ -219,19 +219,19 @@ proc handleRead(s: PAsyncSocket, ftp: PAsyncFTPClient) =
|
||||||
|
|
||||||
proc pasv[T](ftp: FtpBase[T]) =
|
proc pasv[T](ftp: FtpBase[T]) =
|
||||||
## Negotiate a data connection.
|
## Negotiate a data connection.
|
||||||
when T is TSocket:
|
when T is Socket:
|
||||||
ftp.dsock = socket()
|
ftp.dsock = socket()
|
||||||
if ftp.dsock == invalidSocket: raiseOSError(osLastError())
|
if ftp.dsock == invalidSocket: raiseOSError(osLastError())
|
||||||
elif T is PAsyncSocket:
|
elif T is AsyncSocket:
|
||||||
ftp.dsock = asyncSocket()
|
ftp.dsock = asyncSocket()
|
||||||
ftp.dsock.handleRead =
|
ftp.dsock.handleRead =
|
||||||
proc (s: PAsyncSocket) =
|
proc (s: AsyncSocket) =
|
||||||
handleRead(s, ftp)
|
handleRead(s, ftp)
|
||||||
ftp.dsock.handleConnect =
|
ftp.dsock.handleConnect =
|
||||||
proc (s: PAsyncSocket) =
|
proc (s: AsyncSocket) =
|
||||||
handleConnect(s, ftp)
|
handleConnect(s, ftp)
|
||||||
ftp.dsock.handleTask =
|
ftp.dsock.handleTask =
|
||||||
proc (s: PAsyncSocket) =
|
proc (s: AsyncSocket) =
|
||||||
handleTask(s, ftp)
|
handleTask(s, ftp)
|
||||||
ftp.disp.register(ftp.dsock)
|
ftp.disp.register(ftp.dsock)
|
||||||
else:
|
else:
|
||||||
|
|
@ -244,8 +244,8 @@ proc pasv[T](ftp: FtpBase[T]) =
|
||||||
var ip = nums[0.. -3]
|
var ip = nums[0.. -3]
|
||||||
var port = nums[-2.. -1]
|
var port = nums[-2.. -1]
|
||||||
var properPort = port[0].parseInt()*256+port[1].parseInt()
|
var properPort = port[0].parseInt()*256+port[1].parseInt()
|
||||||
ftp.dsock.connect(ip.join("."), TPort(properPort.toU16))
|
ftp.dsock.connect(ip.join("."), Port(properPort.toU16))
|
||||||
when T is PAsyncSocket:
|
when T is AsyncSocket:
|
||||||
ftp.dsockConnected = false
|
ftp.dsockConnected = false
|
||||||
else:
|
else:
|
||||||
ftp.dsockConnected = true
|
ftp.dsockConnected = true
|
||||||
|
|
@ -255,10 +255,10 @@ proc normalizePathSep(path: string): string =
|
||||||
|
|
||||||
proc connect*[T](ftp: FtpBase[T]) =
|
proc connect*[T](ftp: FtpBase[T]) =
|
||||||
## Connect to the FTP server specified by ``ftp``.
|
## Connect to the FTP server specified by ``ftp``.
|
||||||
when T is PAsyncSocket:
|
when T is AsyncSocket:
|
||||||
blockingOperation(ftp.csock):
|
blockingOperation(ftp.csock):
|
||||||
ftp.csock.connect(ftp.address, ftp.port)
|
ftp.csock.connect(ftp.address, ftp.port)
|
||||||
elif T is TSocket:
|
elif T is Socket:
|
||||||
ftp.csock.connect(ftp.address, ftp.port)
|
ftp.csock.connect(ftp.address, ftp.port)
|
||||||
else:
|
else:
|
||||||
{.fatal: "Incorrect socket instantiation".}
|
{.fatal: "Incorrect socket instantiation".}
|
||||||
|
|
@ -292,13 +292,13 @@ proc getLines[T](ftp: FtpBase[T], async: bool = false): bool =
|
||||||
## It doesn't if `async` is true, because it doesn't check for 226 then.
|
## It doesn't if `async` is true, because it doesn't check for 226 then.
|
||||||
if ftp.dsockConnected:
|
if ftp.dsockConnected:
|
||||||
var r = TaintedString""
|
var r = TaintedString""
|
||||||
when T is PAsyncSocket:
|
when T is AsyncSocket:
|
||||||
if ftp.asyncDSock.readLine(r):
|
if ftp.asyncDSock.readLine(r):
|
||||||
if r.string == "":
|
if r.string == "":
|
||||||
ftp.dsockConnected = false
|
ftp.dsockConnected = false
|
||||||
else:
|
else:
|
||||||
ftp.job.lines.add(r.string & "\n")
|
ftp.job.lines.add(r.string & "\n")
|
||||||
elif T is TSocket:
|
elif T is Socket:
|
||||||
assert(not async)
|
assert(not async)
|
||||||
ftp.dsock.readLine(r)
|
ftp.dsock.readLine(r)
|
||||||
if r.string == "":
|
if r.string == "":
|
||||||
|
|
@ -309,7 +309,7 @@ proc getLines[T](ftp: FtpBase[T], async: bool = false): bool =
|
||||||
{.fatal: "Incorrect socket instantiation".}
|
{.fatal: "Incorrect socket instantiation".}
|
||||||
|
|
||||||
if not async:
|
if not async:
|
||||||
var readSocks: seq[TSocket] = @[ftp.csock]
|
var readSocks: seq[Socket] = @[ftp.csock]
|
||||||
# This is only needed here. Asyncio gets this socket...
|
# This is only needed here. Asyncio gets this socket...
|
||||||
blockingOperation(ftp.csock):
|
blockingOperation(ftp.csock):
|
||||||
if readSocks.select(1) != 0 and ftp.csock in readSocks:
|
if readSocks.select(1) != 0 and ftp.csock in readSocks:
|
||||||
|
|
@ -372,7 +372,7 @@ proc createDir*[T](ftp: FtpBase[T], dir: string, recursive: bool = false) =
|
||||||
assertReply reply, "257"
|
assertReply reply, "257"
|
||||||
|
|
||||||
proc chmod*[T](ftp: FtpBase[T], path: string,
|
proc chmod*[T](ftp: FtpBase[T], path: string,
|
||||||
permissions: set[TFilePermission]) =
|
permissions: set[FilePermission]) =
|
||||||
## Changes permission of ``path`` to ``permissions``.
|
## Changes permission of ``path`` to ``permissions``.
|
||||||
var userOctal = 0
|
var userOctal = 0
|
||||||
var groupOctal = 0
|
var groupOctal = 0
|
||||||
|
|
@ -431,8 +431,8 @@ proc getFile[T](ftp: FtpBase[T], async = false): bool =
|
||||||
var bytesRead = 0
|
var bytesRead = 0
|
||||||
var returned = false
|
var returned = false
|
||||||
if async:
|
if async:
|
||||||
when T is TSocket:
|
when T is Socket:
|
||||||
raise newException(EFTP, "FTPClient must be async.")
|
raise newException(FTPError, "FTPClient must be async.")
|
||||||
else:
|
else:
|
||||||
bytesRead = ftp.dsock.recvAsync(r, BufferSize)
|
bytesRead = ftp.dsock.recvAsync(r, BufferSize)
|
||||||
returned = bytesRead != -1
|
returned = bytesRead != -1
|
||||||
|
|
@ -447,9 +447,9 @@ proc getFile[T](ftp: FtpBase[T], async = false): bool =
|
||||||
elif returned and r2 == "":
|
elif returned and r2 == "":
|
||||||
ftp.dsockConnected = false
|
ftp.dsockConnected = false
|
||||||
|
|
||||||
when T is TSocket:
|
when T is Socket:
|
||||||
if not async:
|
if not async:
|
||||||
var readSocks: seq[TSocket] = @[ftp.csock]
|
var readSocks: seq[Socket] = @[ftp.csock]
|
||||||
blockingOperation(ftp.csock):
|
blockingOperation(ftp.csock):
|
||||||
if readSocks.select(1) != 0 and ftp.csock in readSocks:
|
if readSocks.select(1) != 0 and ftp.csock in readSocks:
|
||||||
assertReply ftp.expectReply(), "226"
|
assertReply ftp.expectReply(), "226"
|
||||||
|
|
@ -467,10 +467,10 @@ proc retrFile*[T](ftp: FtpBase[T], file, dest: string, async = false) =
|
||||||
var reply = ftp.send("RETR " & file.normalizePathSep)
|
var reply = ftp.send("RETR " & file.normalizePathSep)
|
||||||
assertReply reply, ["125", "150"]
|
assertReply reply, ["125", "150"]
|
||||||
if {'(', ')'} notin reply.string:
|
if {'(', ')'} notin reply.string:
|
||||||
raise newException(EInvalidReply, "Reply has no file size.")
|
raise newException(ReplyError, "Reply has no file size.")
|
||||||
var fileSize: BiggestInt
|
var fileSize: BiggestInt
|
||||||
if reply.string.captureBetween('(', ')').parseBiggestInt(fileSize) == 0:
|
if reply.string.captureBetween('(', ')').parseBiggestInt(fileSize) == 0:
|
||||||
raise newException(EInvalidReply, "Reply has no file size.")
|
raise newException(ReplyError, "Reply has no file size.")
|
||||||
|
|
||||||
ftp.job.total = fileSize
|
ftp.job.total = fileSize
|
||||||
ftp.job.lastProgressReport = epochTime()
|
ftp.job.lastProgressReport = epochTime()
|
||||||
|
|
@ -545,10 +545,10 @@ proc close*[T](ftp: FtpBase[T]) =
|
||||||
ftp.csock.close()
|
ftp.csock.close()
|
||||||
ftp.dsock.close()
|
ftp.dsock.close()
|
||||||
|
|
||||||
proc csockHandleRead(s: PAsyncSocket, ftp: PAsyncFTPClient) =
|
proc csockHandleRead(s: AsyncSocket, ftp: AsyncFTPClient) =
|
||||||
if ftp.jobInProgress:
|
if ftp.jobInProgress:
|
||||||
assertReply ftp.expectReply(), "226" # Make sure the transfer completed.
|
assertReply ftp.expectReply(), "226" # Make sure the transfer completed.
|
||||||
var r: TFTPEvent
|
var r: FTPEvent
|
||||||
case ftp.job.typ
|
case ftp.job.typ
|
||||||
of JRetrText:
|
of JRetrText:
|
||||||
r.typ = EvLines
|
r.typ = EvLines
|
||||||
|
|
@ -557,21 +557,21 @@ proc csockHandleRead(s: PAsyncSocket, ftp: PAsyncFTPClient) =
|
||||||
r.typ = EvRetr
|
r.typ = EvRetr
|
||||||
r.filename = ftp.job.filename
|
r.filename = ftp.job.filename
|
||||||
if ftp.job.progress != ftp.job.total:
|
if ftp.job.progress != ftp.job.total:
|
||||||
raise newException(EFTP, "Didn't download full file.")
|
raise newException(FTPError, "Didn't download full file.")
|
||||||
of JStore:
|
of JStore:
|
||||||
r.typ = EvStore
|
r.typ = EvStore
|
||||||
r.filename = ftp.job.filename
|
r.filename = ftp.job.filename
|
||||||
if ftp.job.progress != ftp.job.total:
|
if ftp.job.progress != ftp.job.total:
|
||||||
raise newException(EFTP, "Didn't upload full file.")
|
raise newException(FTPError, "Didn't upload full file.")
|
||||||
ftp.deleteJob()
|
ftp.deleteJob()
|
||||||
|
|
||||||
ftp.handleEvent(ftp, r)
|
ftp.handleEvent(ftp, r)
|
||||||
|
|
||||||
proc asyncFTPClient*(address: string, port = TPort(21),
|
proc asyncFTPClient*(address: string, port = Port(21),
|
||||||
user, pass = "",
|
user, pass = "",
|
||||||
handleEvent: proc (ftp: PAsyncFTPClient, ev: TFTPEvent) {.closure,gcsafe.} =
|
handleEvent: proc (ftp: AsyncFTPClient, ev: FTPEvent) {.closure,gcsafe.} =
|
||||||
(proc (ftp: PAsyncFTPClient, ev: TFTPEvent) = discard)): PAsyncFTPClient =
|
(proc (ftp: AsyncFTPClient, ev: FTPEvent) = discard)): AsyncFTPClient =
|
||||||
## Create a ``PAsyncFTPClient`` object.
|
## Create a ``AsyncFTPClient`` object.
|
||||||
##
|
##
|
||||||
## Use this if you want to use asyncio's dispatcher.
|
## Use this if you want to use asyncio's dispatcher.
|
||||||
var dres: AsyncFtpClient
|
var dres: AsyncFtpClient
|
||||||
|
|
@ -588,7 +588,7 @@ proc asyncFTPClient*(address: string, port = TPort(21),
|
||||||
csockHandleRead(s, dres)
|
csockHandleRead(s, dres)
|
||||||
result = dres
|
result = dres
|
||||||
|
|
||||||
proc register*(d: PDispatcher, ftp: PAsyncFTPClient): PDelegate {.discardable.} =
|
proc register*(d: Dispatcher, ftp: AsyncFTPClient): Delegate {.discardable.} =
|
||||||
## Registers ``ftp`` with dispatcher ``d``.
|
## Registers ``ftp`` with dispatcher ``d``.
|
||||||
ftp.disp = d
|
ftp.disp = d
|
||||||
return ftp.disp.register(ftp.csock)
|
return ftp.disp.register(ftp.csock)
|
||||||
|
|
|
||||||
|
|
@ -552,7 +552,7 @@ proc parse(x: var XmlParser, errors: var seq[string]): XmlNode =
|
||||||
proc parseHtml*(s: Stream, filename: string,
|
proc parseHtml*(s: Stream, filename: string,
|
||||||
errors: var seq[string]): XmlNode =
|
errors: var seq[string]): XmlNode =
|
||||||
## parses the XML from stream `s` and returns a ``PXmlNode``. Every
|
## parses the XML from stream `s` and returns a ``PXmlNode``. Every
|
||||||
## occured parsing error is added to the `errors` sequence.
|
## occurred parsing error is added to the `errors` sequence.
|
||||||
var x: XmlParser
|
var x: XmlParser
|
||||||
open(x, s, filename, {reportComments, reportWhitespace})
|
open(x, s, filename, {reportComments, reportWhitespace})
|
||||||
next(x)
|
next(x)
|
||||||
|
|
@ -581,7 +581,7 @@ proc parseHtml*(s: Stream): XmlNode =
|
||||||
|
|
||||||
proc loadHtml*(path: string, errors: var seq[string]): XmlNode =
|
proc loadHtml*(path: string, errors: var seq[string]): XmlNode =
|
||||||
## Loads and parses HTML from file specified by ``path``, and returns
|
## Loads and parses HTML from file specified by ``path``, and returns
|
||||||
## a ``PXmlNode``. Every occured parsing error is added to
|
## a ``PXmlNode``. Every occurred parsing error is added to
|
||||||
## the `errors` sequence.
|
## the `errors` sequence.
|
||||||
var s = newFileStream(path, fmRead)
|
var s = newFileStream(path, fmRead)
|
||||||
if s == nil: raise newException(IOError, "Unable to read file: " & path)
|
if s == nil: raise newException(IOError, "Unable to read file: " & path)
|
||||||
|
|
|
||||||
|
|
@ -385,7 +385,7 @@ proc request*(url: string, httpMethod: string, extraHeaders = "",
|
||||||
userAgent = defUserAgent, proxy: Proxy = nil): Response =
|
userAgent = defUserAgent, proxy: Proxy = nil): Response =
|
||||||
## | Requests ``url`` with the custom method string specified by the
|
## | Requests ``url`` with the custom method string specified by the
|
||||||
## | ``httpMethod`` parameter.
|
## | ``httpMethod`` parameter.
|
||||||
## | Extra headers can be specified and must be seperated by ``\c\L``
|
## | Extra headers can be specified and must be separated by ``\c\L``
|
||||||
## | An optional timeout can be specified in miliseconds, if reading from the
|
## | An optional timeout can be specified in miliseconds, if reading from the
|
||||||
## server takes longer than specified an ETimeout exception will be raised.
|
## server takes longer than specified an ETimeout exception will be raised.
|
||||||
var r = if proxy == nil: parseUri(url) else: proxy.url
|
var r = if proxy == nil: parseUri(url) else: proxy.url
|
||||||
|
|
@ -436,7 +436,7 @@ proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
|
||||||
body = "", sslContext = defaultSSLContext, timeout = -1,
|
body = "", sslContext = defaultSSLContext, timeout = -1,
|
||||||
userAgent = defUserAgent, proxy: Proxy = nil): Response =
|
userAgent = defUserAgent, proxy: Proxy = nil): Response =
|
||||||
## | Requests ``url`` with the specified ``httpMethod``.
|
## | Requests ``url`` with the specified ``httpMethod``.
|
||||||
## | Extra headers can be specified and must be seperated by ``\c\L``
|
## | Extra headers can be specified and must be separated by ``\c\L``
|
||||||
## | An optional timeout can be specified in miliseconds, if reading from the
|
## | An optional timeout can be specified in miliseconds, if reading from the
|
||||||
## server takes longer than specified an ETimeout exception will be raised.
|
## server takes longer than specified an ETimeout exception will be raised.
|
||||||
result = request(url, $httpMethod, extraHeaders, body, sslContext, timeout,
|
result = request(url, $httpMethod, extraHeaders, body, sslContext, timeout,
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ import
|
||||||
|
|
||||||
type
|
type
|
||||||
JsonEventKind* = enum ## enumeration of all events that may occur when parsing
|
JsonEventKind* = enum ## enumeration of all events that may occur when parsing
|
||||||
jsonError, ## an error ocurred during parsing
|
jsonError, ## an error occurred during parsing
|
||||||
jsonEof, ## end of file reached
|
jsonEof, ## end of file reached
|
||||||
jsonString, ## a string literal
|
jsonString, ## a string literal
|
||||||
jsonInt, ## an integer literal
|
jsonInt, ## an integer literal
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
## This module implements a simple logger. It has been designed to be as simple
|
## This module implements a simple logger. It has been designed to be as simple
|
||||||
## as possible to avoid bloat, if this library does not fullfill your needs,
|
## as possible to avoid bloat, if this library does not fulfill your needs,
|
||||||
## write your own.
|
## write your own.
|
||||||
##
|
##
|
||||||
## Format strings support the following variables which must be prefixed with
|
## Format strings support the following variables which must be prefixed with
|
||||||
|
|
|
||||||
|
|
@ -258,7 +258,7 @@ proc socketError*(socket: Socket, err: int = -1, async = false,
|
||||||
of SSL_ERROR_WANT_X509_LOOKUP:
|
of SSL_ERROR_WANT_X509_LOOKUP:
|
||||||
raiseSSLError("Function for x509 lookup has been called.")
|
raiseSSLError("Function for x509 lookup has been called.")
|
||||||
of SSL_ERROR_SYSCALL:
|
of SSL_ERROR_SYSCALL:
|
||||||
var errStr = "IO error has occured "
|
var errStr = "IO error has occurred "
|
||||||
let sslErr = ErrPeekLastError()
|
let sslErr = ErrPeekLastError()
|
||||||
if sslErr == 0 and err == 0:
|
if sslErr == 0 and err == 0:
|
||||||
errStr.add "because an EOF was observed that violates the protocol"
|
errStr.add "because an EOF was observed that violates the protocol"
|
||||||
|
|
@ -887,7 +887,7 @@ proc connectAsync(socket: Socket, name: string, port = Port(0),
|
||||||
af: Domain = AF_INET) {.tags: [ReadIOEffect].} =
|
af: Domain = AF_INET) {.tags: [ReadIOEffect].} =
|
||||||
## A variant of ``connect`` for non-blocking sockets.
|
## A variant of ``connect`` for non-blocking sockets.
|
||||||
##
|
##
|
||||||
## This procedure will immediatelly return, it will not block until a connection
|
## This procedure will immediately return, it will not block until a connection
|
||||||
## is made. It is up to the caller to make sure the connection has been established
|
## is made. It is up to the caller to make sure the connection has been established
|
||||||
## by checking (using ``select``) whether the socket is writeable.
|
## by checking (using ``select``) whether the socket is writeable.
|
||||||
##
|
##
|
||||||
|
|
|
||||||
|
|
@ -185,7 +185,7 @@ const
|
||||||
proc osErrorMsg*(): string {.rtl, extern: "nos$1", deprecated.} =
|
proc osErrorMsg*(): string {.rtl, extern: "nos$1", deprecated.} =
|
||||||
## Retrieves the operating system's error flag, ``errno``.
|
## Retrieves the operating system's error flag, ``errno``.
|
||||||
## On Windows ``GetLastError`` is checked before ``errno``.
|
## On Windows ``GetLastError`` is checked before ``errno``.
|
||||||
## Returns "" if no error occured.
|
## Returns "" if no error occurred.
|
||||||
##
|
##
|
||||||
## **Deprecated since version 0.9.4**: use the other ``osErrorMsg`` proc.
|
## **Deprecated since version 0.9.4**: use the other ``osErrorMsg`` proc.
|
||||||
|
|
||||||
|
|
@ -1099,7 +1099,7 @@ when defined(windows):
|
||||||
var
|
var
|
||||||
env = getEnvironmentStringsW()
|
env = getEnvironmentStringsW()
|
||||||
e = env
|
e = env
|
||||||
if e == nil: return # an error occured
|
if e == nil: return # an error occurred
|
||||||
while true:
|
while true:
|
||||||
var eend = strEnd(e)
|
var eend = strEnd(e)
|
||||||
add(environment, $e)
|
add(environment, $e)
|
||||||
|
|
@ -1110,7 +1110,7 @@ when defined(windows):
|
||||||
var
|
var
|
||||||
env = getEnvironmentStringsA()
|
env = getEnvironmentStringsA()
|
||||||
e = env
|
e = env
|
||||||
if e == nil: return # an error occured
|
if e == nil: return # an error occurred
|
||||||
while true:
|
while true:
|
||||||
var eend = strEnd(e)
|
var eend = strEnd(e)
|
||||||
add(environment, $e)
|
add(environment, $e)
|
||||||
|
|
@ -1182,7 +1182,7 @@ proc putEnv*(key, val: string) {.tags: [WriteEnvEffect].} =
|
||||||
## If an error occurs, `EInvalidEnvVar` is raised.
|
## If an error occurs, `EInvalidEnvVar` is raised.
|
||||||
|
|
||||||
# Note: by storing the string in the environment sequence,
|
# Note: by storing the string in the environment sequence,
|
||||||
# we gurantee that we don't free the memory before the program
|
# we guarantee that we don't free the memory before the program
|
||||||
# ends (this is needed for POSIX compliance). It is also needed so that
|
# ends (this is needed for POSIX compliance). It is also needed so that
|
||||||
# the process itself may access its modified environment variables!
|
# the process itself may access its modified environment variables!
|
||||||
var indx = findEnvVar(key)
|
var indx = findEnvVar(key)
|
||||||
|
|
@ -1454,7 +1454,7 @@ proc createHardlink*(src, dest: string) =
|
||||||
proc parseCmdLine*(c: string): seq[string] {.
|
proc parseCmdLine*(c: string): seq[string] {.
|
||||||
noSideEffect, rtl, extern: "nos$1".} =
|
noSideEffect, rtl, extern: "nos$1".} =
|
||||||
## Splits a command line into several components;
|
## Splits a command line into several components;
|
||||||
## This proc is only occassionally useful, better use the `parseopt` module.
|
## This proc is only occasionally useful, better use the `parseopt` module.
|
||||||
##
|
##
|
||||||
## On Windows, it uses the following parsing rules
|
## On Windows, it uses the following parsing rules
|
||||||
## (see http://msdn.microsoft.com/en-us/library/17w5ykft.aspx ):
|
## (see http://msdn.microsoft.com/en-us/library/17w5ykft.aspx ):
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,7 @@ proc startProcess*(command: string,
|
||||||
## of `args` to `command` carefully escaping/quoting any special characters,
|
## of `args` to `command` carefully escaping/quoting any special characters,
|
||||||
## since it will be passed *as is* to the system shell. Each system/shell may
|
## since it will be passed *as is* to the system shell. Each system/shell may
|
||||||
## feature different escaping rules, so try to avoid this kind of shell
|
## feature different escaping rules, so try to avoid this kind of shell
|
||||||
## invokation if possible as it leads to non portable software.
|
## invocation if possible as it leads to non portable software.
|
||||||
##
|
##
|
||||||
## Return value: The newly created process object. Nil is never returned,
|
## Return value: The newly created process object. Nil is never returned,
|
||||||
## but ``EOS`` is raised in case of an error.
|
## but ``EOS`` is raised in case of an error.
|
||||||
|
|
@ -260,7 +260,7 @@ proc execProcesses*(cmds: openArray[string],
|
||||||
for i in 0..m-1:
|
for i in 0..m-1:
|
||||||
if beforeRunEvent != nil:
|
if beforeRunEvent != nil:
|
||||||
beforeRunEvent(i)
|
beforeRunEvent(i)
|
||||||
q[i] = startCmd(cmds[i], options=options)
|
q[i] = startProcess(cmds[i], options=options + {poEvalCommand})
|
||||||
when defined(noBusyWaiting):
|
when defined(noBusyWaiting):
|
||||||
var r = 0
|
var r = 0
|
||||||
for i in m..high(cmds):
|
for i in m..high(cmds):
|
||||||
|
|
@ -275,7 +275,7 @@ proc execProcesses*(cmds: openArray[string],
|
||||||
if q[r] != nil: close(q[r])
|
if q[r] != nil: close(q[r])
|
||||||
if beforeRunEvent != nil:
|
if beforeRunEvent != nil:
|
||||||
beforeRunEvent(i)
|
beforeRunEvent(i)
|
||||||
q[r] = startCmd(cmds[i], options=options)
|
q[r] = startProcess(cmds[i], options=options + {poEvalCommand})
|
||||||
r = (r + 1) mod n
|
r = (r + 1) mod n
|
||||||
else:
|
else:
|
||||||
var i = m
|
var i = m
|
||||||
|
|
@ -288,7 +288,7 @@ proc execProcesses*(cmds: openArray[string],
|
||||||
if q[r] != nil: close(q[r])
|
if q[r] != nil: close(q[r])
|
||||||
if beforeRunEvent != nil:
|
if beforeRunEvent != nil:
|
||||||
beforeRunEvent(i)
|
beforeRunEvent(i)
|
||||||
q[r] = startCmd(cmds[i], options=options)
|
q[r] = startProcess(cmds[i], options=options + {poEvalCommand})
|
||||||
inc(i)
|
inc(i)
|
||||||
if i > high(cmds): break
|
if i > high(cmds): break
|
||||||
for j in 0..m-1:
|
for j in 0..m-1:
|
||||||
|
|
@ -298,7 +298,7 @@ proc execProcesses*(cmds: openArray[string],
|
||||||
for i in 0..high(cmds):
|
for i in 0..high(cmds):
|
||||||
if beforeRunEvent != nil:
|
if beforeRunEvent != nil:
|
||||||
beforeRunEvent(i)
|
beforeRunEvent(i)
|
||||||
var p = startCmd(cmds[i], options=options)
|
var p = startProcess(cmds[i], options=options + {poEvalCommand})
|
||||||
result = max(waitForExit(p), result)
|
result = max(waitForExit(p), result)
|
||||||
close(p)
|
close(p)
|
||||||
|
|
||||||
|
|
@ -644,14 +644,14 @@ elif not defined(useNimRtl):
|
||||||
var pid: TPid
|
var pid: TPid
|
||||||
|
|
||||||
var sysArgs = allocCStringArray(sysArgsRaw)
|
var sysArgs = allocCStringArray(sysArgsRaw)
|
||||||
finally: deallocCStringArray(sysArgs)
|
defer: deallocCStringArray(sysArgs)
|
||||||
|
|
||||||
var sysEnv = if env == nil:
|
var sysEnv = if env == nil:
|
||||||
envToCStringArray()
|
envToCStringArray()
|
||||||
else:
|
else:
|
||||||
envToCStringArray(env)
|
envToCStringArray(env)
|
||||||
|
|
||||||
finally: deallocCStringArray(sysEnv)
|
defer: deallocCStringArray(sysEnv)
|
||||||
|
|
||||||
var data: TStartProcessData
|
var data: TStartProcessData
|
||||||
data.sysCommand = sysCommand
|
data.sysCommand = sysCommand
|
||||||
|
|
@ -748,7 +748,7 @@ elif not defined(useNimRtl):
|
||||||
if pipe(data.pErrorPipe) != 0:
|
if pipe(data.pErrorPipe) != 0:
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
|
|
||||||
finally:
|
defer:
|
||||||
discard close(data.pErrorPipe[readIdx])
|
discard close(data.pErrorPipe[readIdx])
|
||||||
|
|
||||||
var pid: TPid
|
var pid: TPid
|
||||||
|
|
@ -956,7 +956,7 @@ proc execCmdEx*(command: string, options: set[ProcessOption] = {
|
||||||
exitCode: int] {.tags: [ExecIOEffect, ReadIOEffect], gcsafe.} =
|
exitCode: int] {.tags: [ExecIOEffect, ReadIOEffect], gcsafe.} =
|
||||||
## a convenience proc that runs the `command`, grabs all its output and
|
## a convenience proc that runs the `command`, grabs all its output and
|
||||||
## exit code and returns both.
|
## exit code and returns both.
|
||||||
var p = startCmd(command, options)
|
var p = startProcess(command, options=options + {poEvalCommand})
|
||||||
var outp = outputStream(p)
|
var outp = outputStream(p)
|
||||||
result = (TaintedString"", -1)
|
result = (TaintedString"", -1)
|
||||||
var line = newStringOfCap(120).TaintedString
|
var line = newStringOfCap(120).TaintedString
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ type
|
||||||
cfgSectionStart, ## a ``[section]`` has been parsed
|
cfgSectionStart, ## a ``[section]`` has been parsed
|
||||||
cfgKeyValuePair, ## a ``key=value`` pair has been detected
|
cfgKeyValuePair, ## a ``key=value`` pair has been detected
|
||||||
cfgOption, ## a ``--key=value`` command line option
|
cfgOption, ## a ``--key=value`` command line option
|
||||||
cfgError ## an error ocurred during parsing
|
cfgError ## an error occurred during parsing
|
||||||
|
|
||||||
CfgEvent* = object of RootObj ## describes a parsing event
|
CfgEvent* = object of RootObj ## describes a parsing event
|
||||||
case kind*: CfgEventKind ## the kind of the event
|
case kind*: CfgEventKind ## the kind of the event
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ proc initOptParser*(cmdline: string): OptParser {.rtl, deprecated.} =
|
||||||
## Initalizes option parses with cmdline. Splits cmdline in on spaces
|
## Initalizes option parses with cmdline. Splits cmdline in on spaces
|
||||||
## and calls initOptParser(openarray[string])
|
## and calls initOptParser(openarray[string])
|
||||||
## Do not use.
|
## Do not use.
|
||||||
if cmdline == "": # backward compatibilty
|
if cmdline == "": # backward compatibility
|
||||||
return initOptParser(seq[string](nil))
|
return initOptParser(seq[string](nil))
|
||||||
else:
|
else:
|
||||||
return initOptParser(cmdline.split)
|
return initOptParser(cmdline.split)
|
||||||
|
|
|
||||||
|
|
@ -181,7 +181,7 @@ proc parseWhile*(s: string, token: var string, validChars: set[char],
|
||||||
token = substr(s, start, i-1)
|
token = substr(s, start, i-1)
|
||||||
|
|
||||||
proc captureBetween*(s: string, first: char, second = '\0', start = 0): string =
|
proc captureBetween*(s: string, first: char, second = '\0', start = 0): string =
|
||||||
## Finds the first occurence of ``first``, then returns everything from there
|
## Finds the first occurrence of ``first``, then returns everything from there
|
||||||
## up to ``second``(if ``second`` is '\0', then ``first`` is used).
|
## up to ``second``(if ``second`` is '\0', then ``first`` is used).
|
||||||
var i = skipUntil(s, first, start)+1+start
|
var i = skipUntil(s, first, start)+1+start
|
||||||
result = ""
|
result = ""
|
||||||
|
|
@ -240,7 +240,7 @@ proc parseBiggestFloat*(s: string, number: var BiggestFloat, start = 0): int {.
|
||||||
proc parseFloat*(s: string, number: var float, start = 0): int {.
|
proc parseFloat*(s: string, number: var float, start = 0): int {.
|
||||||
rtl, extern: "npuParseFloat", noSideEffect.} =
|
rtl, extern: "npuParseFloat", noSideEffect.} =
|
||||||
## parses a float starting at `start` and stores the value into `number`.
|
## parses a float starting at `start` and stores the value into `number`.
|
||||||
## Result is the number of processed chars or 0 if there occured a parsing
|
## Result is the number of processed chars or 0 if there occurred a parsing
|
||||||
## error.
|
## error.
|
||||||
var bf: BiggestFloat
|
var bf: BiggestFloat
|
||||||
result = parseBiggestFloat(s, bf, start)
|
result = parseBiggestFloat(s, bf, start)
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ import
|
||||||
|
|
||||||
type
|
type
|
||||||
XmlEventKind* = enum ## enumation of all events that may occur when parsing
|
XmlEventKind* = enum ## enumation of all events that may occur when parsing
|
||||||
xmlError, ## an error ocurred during parsing
|
xmlError, ## an error occurred during parsing
|
||||||
xmlEof, ## end of file reached
|
xmlEof, ## end of file reached
|
||||||
xmlCharData, ## character data
|
xmlCharData, ## character data
|
||||||
xmlWhitespace, ## whitespace has been parsed
|
xmlWhitespace, ## whitespace has been parsed
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ proc isConc(r: Rope): bool {.inline.} = return isNil(r.data)
|
||||||
# Note that the left and right pointers are not needed for leafs.
|
# Note that the left and right pointers are not needed for leafs.
|
||||||
# Leaves have relatively high memory overhead (~30 bytes on a 32
|
# Leaves have relatively high memory overhead (~30 bytes on a 32
|
||||||
# bit machine) and we produce many of them. This is why we cache and
|
# bit machine) and we produce many of them. This is why we cache and
|
||||||
# share leafs accross different rope trees.
|
# share leafs across different rope trees.
|
||||||
# To cache them they are inserted in another tree, a splay tree for best
|
# To cache them they are inserted in another tree, a splay tree for best
|
||||||
# performance. But for the caching tree we use the leaf's left and right
|
# performance. But for the caching tree we use the leaf's left and right
|
||||||
# pointers.
|
# pointers.
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ type
|
||||||
when defined(nimdoc):
|
when defined(nimdoc):
|
||||||
type
|
type
|
||||||
Selector* = ref object
|
Selector* = ref object
|
||||||
## An object which holds file descripters to be checked for read/write
|
## An object which holds file descriptors to be checked for read/write
|
||||||
## status.
|
## status.
|
||||||
fds: Table[SocketHandle, SelectorKey]
|
fds: Table[SocketHandle, SelectorKey]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -851,7 +851,7 @@ proc connectAsync*(socket: Socket, name: string, port = Port(0),
|
||||||
af: Domain = AF_INET) {.tags: [ReadIOEffect].} =
|
af: Domain = AF_INET) {.tags: [ReadIOEffect].} =
|
||||||
## A variant of ``connect`` for non-blocking sockets.
|
## A variant of ``connect`` for non-blocking sockets.
|
||||||
##
|
##
|
||||||
## This procedure will immediatelly return, it will not block until a connection
|
## This procedure will immediately return, it will not block until a connection
|
||||||
## is made. It is up to the caller to make sure the connection has been established
|
## is made. It is up to the caller to make sure the connection has been established
|
||||||
## by checking (using ``select``) whether the socket is writeable.
|
## by checking (using ``select``) whether the socket is writeable.
|
||||||
##
|
##
|
||||||
|
|
@ -1467,7 +1467,7 @@ proc recvAsync*(socket: Socket, s: var TaintedString): bool {.
|
||||||
of SSL_ERROR_ZERO_RETURN:
|
of SSL_ERROR_ZERO_RETURN:
|
||||||
raiseSslError("TLS/SSL connection failed to initiate, socket closed prematurely.")
|
raiseSslError("TLS/SSL connection failed to initiate, socket closed prematurely.")
|
||||||
of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT:
|
of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT:
|
||||||
raiseSslError("Unexpected error occured.") # This should just not happen.
|
raiseSslError("Unexpected error occurred.") # This should just not happen.
|
||||||
of SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_READ:
|
of SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_READ:
|
||||||
return false
|
return false
|
||||||
of SSL_ERROR_WANT_X509_LOOKUP:
|
of SSL_ERROR_WANT_X509_LOOKUP:
|
||||||
|
|
@ -1610,7 +1610,7 @@ proc sendAsync*(socket: Socket, data: string): int {.tags: [WriteIOEffect].} =
|
||||||
of SSL_ERROR_ZERO_RETURN:
|
of SSL_ERROR_ZERO_RETURN:
|
||||||
raiseSslError("TLS/SSL connection failed to initiate, socket closed prematurely.")
|
raiseSslError("TLS/SSL connection failed to initiate, socket closed prematurely.")
|
||||||
of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT:
|
of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT:
|
||||||
raiseSslError("Unexpected error occured.") # This should just not happen.
|
raiseSslError("Unexpected error occurred.") # This should just not happen.
|
||||||
of SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_READ:
|
of SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_READ:
|
||||||
return 0
|
return 0
|
||||||
of SSL_ERROR_WANT_X509_LOOKUP:
|
of SSL_ERROR_WANT_X509_LOOKUP:
|
||||||
|
|
|
||||||
|
|
@ -122,41 +122,41 @@ proc read[T](s: Stream, result: var T) =
|
||||||
raise newEIO("cannot read from stream")
|
raise newEIO("cannot read from stream")
|
||||||
|
|
||||||
proc readChar*(s: Stream): char =
|
proc readChar*(s: Stream): char =
|
||||||
## reads a char from the stream `s`. Raises `EIO` if an error occured.
|
## reads a char from the stream `s`. Raises `EIO` if an error occurred.
|
||||||
## Returns '\0' as an EOF marker.
|
## Returns '\0' as an EOF marker.
|
||||||
if readData(s, addr(result), sizeof(result)) != 1: result = '\0'
|
if readData(s, addr(result), sizeof(result)) != 1: result = '\0'
|
||||||
|
|
||||||
proc readBool*(s: Stream): bool =
|
proc readBool*(s: Stream): bool =
|
||||||
## reads a bool from the stream `s`. Raises `EIO` if an error occured.
|
## reads a bool from the stream `s`. Raises `EIO` if an error occurred.
|
||||||
read(s, result)
|
read(s, result)
|
||||||
|
|
||||||
proc readInt8*(s: Stream): int8 =
|
proc readInt8*(s: Stream): int8 =
|
||||||
## reads an int8 from the stream `s`. Raises `EIO` if an error occured.
|
## reads an int8 from the stream `s`. Raises `EIO` if an error occurred.
|
||||||
read(s, result)
|
read(s, result)
|
||||||
|
|
||||||
proc readInt16*(s: Stream): int16 =
|
proc readInt16*(s: Stream): int16 =
|
||||||
## reads an int16 from the stream `s`. Raises `EIO` if an error occured.
|
## reads an int16 from the stream `s`. Raises `EIO` if an error occurred.
|
||||||
read(s, result)
|
read(s, result)
|
||||||
|
|
||||||
proc readInt32*(s: Stream): int32 =
|
proc readInt32*(s: Stream): int32 =
|
||||||
## reads an int32 from the stream `s`. Raises `EIO` if an error occured.
|
## reads an int32 from the stream `s`. Raises `EIO` if an error occurred.
|
||||||
read(s, result)
|
read(s, result)
|
||||||
|
|
||||||
proc readInt64*(s: Stream): int64 =
|
proc readInt64*(s: Stream): int64 =
|
||||||
## reads an int64 from the stream `s`. Raises `EIO` if an error occured.
|
## reads an int64 from the stream `s`. Raises `EIO` if an error occurred.
|
||||||
read(s, result)
|
read(s, result)
|
||||||
|
|
||||||
proc readFloat32*(s: Stream): float32 =
|
proc readFloat32*(s: Stream): float32 =
|
||||||
## reads a float32 from the stream `s`. Raises `EIO` if an error occured.
|
## reads a float32 from the stream `s`. Raises `EIO` if an error occurred.
|
||||||
read(s, result)
|
read(s, result)
|
||||||
|
|
||||||
proc readFloat64*(s: Stream): float64 =
|
proc readFloat64*(s: Stream): float64 =
|
||||||
## reads a float64 from the stream `s`. Raises `EIO` if an error occured.
|
## reads a float64 from the stream `s`. Raises `EIO` if an error occurred.
|
||||||
read(s, result)
|
read(s, result)
|
||||||
|
|
||||||
proc readStr*(s: Stream, length: int): TaintedString =
|
proc readStr*(s: Stream, length: int): TaintedString =
|
||||||
## reads a string of length `length` from the stream `s`. Raises `EIO` if
|
## reads a string of length `length` from the stream `s`. Raises `EIO` if
|
||||||
## an error occured.
|
## an error occurred.
|
||||||
result = newString(length).TaintedString
|
result = newString(length).TaintedString
|
||||||
var L = readData(s, addr(string(result)[0]), length)
|
var L = readData(s, addr(string(result)[0]), length)
|
||||||
if L != length: setLen(result.string, L)
|
if L != length: setLen(result.string, L)
|
||||||
|
|
@ -183,7 +183,7 @@ proc readLine*(s: Stream, line: var TaintedString): bool =
|
||||||
|
|
||||||
proc readLine*(s: Stream): TaintedString =
|
proc readLine*(s: Stream): TaintedString =
|
||||||
## Reads a line from a stream `s`. Note: This is not very efficient. Raises
|
## Reads a line from a stream `s`. Note: This is not very efficient. Raises
|
||||||
## `EIO` if an error occured.
|
## `EIO` if an error occurred.
|
||||||
result = TaintedString""
|
result = TaintedString""
|
||||||
while true:
|
while true:
|
||||||
var c = readChar(s)
|
var c = readChar(s)
|
||||||
|
|
|
||||||
|
|
@ -395,11 +395,13 @@ proc toHex*(x: BiggestInt, len: int): string {.noSideEffect,
|
||||||
const
|
const
|
||||||
HexChars = "0123456789ABCDEF"
|
HexChars = "0123456789ABCDEF"
|
||||||
var
|
var
|
||||||
shift: BiggestInt
|
n = x
|
||||||
result = newString(len)
|
result = newString(len)
|
||||||
for j in countdown(len-1, 0):
|
for j in countdown(len-1, 0):
|
||||||
result[j] = HexChars[toU32(x shr shift) and 0xF'i32]
|
result[j] = HexChars[n and 0xF]
|
||||||
shift = shift + 4
|
n = n shr 4
|
||||||
|
# handle negative overflow
|
||||||
|
if n == 0 and x < 0: n = -1
|
||||||
|
|
||||||
proc intToStr*(x: int, minchars: int = 1): string {.noSideEffect,
|
proc intToStr*(x: int, minchars: int = 1): string {.noSideEffect,
|
||||||
rtl, extern: "nsuIntToStr".} =
|
rtl, extern: "nsuIntToStr".} =
|
||||||
|
|
@ -815,8 +817,8 @@ proc rfind*(s: string, sub: char, start: int = -1): int {.noSideEffect,
|
||||||
|
|
||||||
proc count*(s: string, sub: string, overlapping: bool = false): int {.noSideEffect,
|
proc count*(s: string, sub: string, overlapping: bool = false): int {.noSideEffect,
|
||||||
rtl, extern: "nsuCountString".} =
|
rtl, extern: "nsuCountString".} =
|
||||||
## Count the occurences of a substring `sub` in the string `s`.
|
## Count the occurrences of a substring `sub` in the string `s`.
|
||||||
## Overlapping occurences of `sub` only count when `overlapping`
|
## Overlapping occurrences of `sub` only count when `overlapping`
|
||||||
## is set to true.
|
## is set to true.
|
||||||
var i = 0
|
var i = 0
|
||||||
while true:
|
while true:
|
||||||
|
|
@ -831,14 +833,14 @@ proc count*(s: string, sub: string, overlapping: bool = false): int {.noSideEffe
|
||||||
|
|
||||||
proc count*(s: string, sub: char): int {.noSideEffect,
|
proc count*(s: string, sub: char): int {.noSideEffect,
|
||||||
rtl, extern: "nsuCountChar".} =
|
rtl, extern: "nsuCountChar".} =
|
||||||
## Count the occurences of the character `sub` in the string `s`.
|
## Count the occurrences of the character `sub` in the string `s`.
|
||||||
for c in s:
|
for c in s:
|
||||||
if c == sub:
|
if c == sub:
|
||||||
inc result
|
inc result
|
||||||
|
|
||||||
proc count*(s: string, subs: set[char]): int {.noSideEffect,
|
proc count*(s: string, subs: set[char]): int {.noSideEffect,
|
||||||
rtl, extern: "nsuCountCharSet".} =
|
rtl, extern: "nsuCountCharSet".} =
|
||||||
## Count the occurences of the group of character `subs` in the string `s`.
|
## Count the occurrences of the group of character `subs` in the string `s`.
|
||||||
for c in s:
|
for c in s:
|
||||||
if c in subs:
|
if c in subs:
|
||||||
inc result
|
inc result
|
||||||
|
|
@ -898,7 +900,7 @@ proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect,
|
||||||
rtl, extern: "nsuReplaceWord".} =
|
rtl, extern: "nsuReplaceWord".} =
|
||||||
## Replaces `sub` in `s` by the string `by`.
|
## Replaces `sub` in `s` by the string `by`.
|
||||||
##
|
##
|
||||||
## Each occurance of `sub` has to be surrounded by word boundaries
|
## Each occurrence of `sub` has to be surrounded by word boundaries
|
||||||
## (comparable to ``\\w`` in regular expressions), otherwise it is not
|
## (comparable to ``\\w`` in regular expressions), otherwise it is not
|
||||||
## replaced.
|
## replaced.
|
||||||
const wordChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\128'..'\255'}
|
const wordChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\128'..'\255'}
|
||||||
|
|
|
||||||
|
|
@ -353,11 +353,11 @@ when isMainModule:
|
||||||
|
|
||||||
proc `%`(formatstr: string, a: openarray[string]): string =
|
proc `%`(formatstr: string, a: openarray[string]): string =
|
||||||
result = newStringOfCap(formatstr.len + a.len shl 4)
|
result = newStringOfCap(formatstr.len + a.len shl 4)
|
||||||
addf(result, formatstr.TSubex, a)
|
addf(result, formatstr.Subex, a)
|
||||||
|
|
||||||
proc `%`(formatstr: string, a: string): string =
|
proc `%`(formatstr: string, a: string): string =
|
||||||
result = newStringOfCap(formatstr.len + a.len)
|
result = newStringOfCap(formatstr.len + a.len)
|
||||||
addf(result, formatstr.TSubex, [a])
|
addf(result, formatstr.Subex, [a])
|
||||||
|
|
||||||
|
|
||||||
doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c"
|
doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c"
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ type
|
||||||
|
|
||||||
{.deprecated: [TUrl: Url, TUri: Uri].}
|
{.deprecated: [TUrl: Url, TUri: Uri].}
|
||||||
|
|
||||||
|
{.push warning[deprecated]: off.}
|
||||||
proc `$`*(url: Url): string {.deprecated.} =
|
proc `$`*(url: Url): string {.deprecated.} =
|
||||||
## **Deprecated since 0.9.6**: Use ``Uri`` instead.
|
## **Deprecated since 0.9.6**: Use ``Uri`` instead.
|
||||||
return string(url)
|
return string(url)
|
||||||
|
|
@ -44,6 +45,7 @@ proc add*(url: var Url, a: Url) {.deprecated.} =
|
||||||
##
|
##
|
||||||
## **Deprecated since 0.9.6**: Use ``Uri`` instead.
|
## **Deprecated since 0.9.6**: Use ``Uri`` instead.
|
||||||
url = url / a
|
url = url / a
|
||||||
|
{.pop.}
|
||||||
|
|
||||||
proc parseAuthority(authority: string, result: var Uri) =
|
proc parseAuthority(authority: string, result: var Uri) =
|
||||||
var i = 0
|
var i = 0
|
||||||
|
|
|
||||||
|
|
@ -642,7 +642,7 @@ proc isEmpty(s: string): bool =
|
||||||
return true
|
return true
|
||||||
|
|
||||||
proc normalize*(n: PNode) =
|
proc normalize*(n: PNode) =
|
||||||
## Merges all seperated TextNodes together, and removes any empty TextNodes
|
## Merges all separated TextNodes together, and removes any empty TextNodes
|
||||||
var curTextNode: PNode = nil
|
var curTextNode: PNode = nil
|
||||||
var i: int = 0
|
var i: int = 0
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ proc parse(x: var XmlParser, errors: var seq[string]): XmlNode =
|
||||||
proc parseXml*(s: Stream, filename: string,
|
proc parseXml*(s: Stream, filename: string,
|
||||||
errors: var seq[string]): XmlNode =
|
errors: var seq[string]): XmlNode =
|
||||||
## parses the XML from stream `s` and returns a ``PXmlNode``. Every
|
## parses the XML from stream `s` and returns a ``PXmlNode``. Every
|
||||||
## occured parsing error is added to the `errors` sequence.
|
## occurred parsing error is added to the `errors` sequence.
|
||||||
var x: XmlParser
|
var x: XmlParser
|
||||||
open(x, s, filename, {reportComments})
|
open(x, s, filename, {reportComments})
|
||||||
while true:
|
while true:
|
||||||
|
|
@ -129,7 +129,7 @@ proc parseXml*(s: Stream): XmlNode =
|
||||||
|
|
||||||
proc loadXml*(path: string, errors: var seq[string]): XmlNode =
|
proc loadXml*(path: string, errors: var seq[string]): XmlNode =
|
||||||
## Loads and parses XML from file specified by ``path``, and returns
|
## Loads and parses XML from file specified by ``path``, and returns
|
||||||
## a ``PXmlNode``. Every occured parsing error is added to the `errors`
|
## a ``PXmlNode``. Every occurred parsing error is added to the `errors`
|
||||||
## sequence.
|
## sequence.
|
||||||
var s = newFileStream(path, fmRead)
|
var s = newFileStream(path, fmRead)
|
||||||
if s == nil: raise newException(IOError, "Unable to read file: " & path)
|
if s == nil: raise newException(IOError, "Unable to read file: " & path)
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ type
|
||||||
expr* {.magic: Expr.} ## meta type to denote an expression (for templates)
|
expr* {.magic: Expr.} ## meta type to denote an expression (for templates)
|
||||||
stmt* {.magic: Stmt.} ## meta type to denote a statement (for templates)
|
stmt* {.magic: Stmt.} ## meta type to denote a statement (for templates)
|
||||||
typedesc* {.magic: TypeDesc.} ## meta type to denote a type description
|
typedesc* {.magic: TypeDesc.} ## meta type to denote a type description
|
||||||
void* {.magic: "VoidType".} ## meta type to denote the absense of any type
|
void* {.magic: "VoidType".} ## meta type to denote the absence of any type
|
||||||
auto* = expr
|
auto* = expr
|
||||||
any* = distinct auto
|
any* = distinct auto
|
||||||
|
|
||||||
|
|
@ -124,7 +124,7 @@ proc declared*(x: expr): bool {.magic: "Defined", noSideEffect.}
|
||||||
## feature or not:
|
## feature or not:
|
||||||
##
|
##
|
||||||
## .. code-block:: Nim
|
## .. code-block:: Nim
|
||||||
## when not defined(strutils.toUpper):
|
## when not declared(strutils.toUpper):
|
||||||
## # provide our own toUpper proc here, because strutils is
|
## # provide our own toUpper proc here, because strutils is
|
||||||
## # missing it.
|
## # missing it.
|
||||||
|
|
||||||
|
|
@ -357,7 +357,7 @@ type
|
||||||
##
|
##
|
||||||
## See the full `exception hierarchy`_.
|
## See the full `exception hierarchy`_.
|
||||||
IOError* = object of SystemError ## \
|
IOError* = object of SystemError ## \
|
||||||
## Raised if an IO error occured.
|
## Raised if an IO error occurred.
|
||||||
##
|
##
|
||||||
## See the full `exception hierarchy`_.
|
## See the full `exception hierarchy`_.
|
||||||
OSError* = object of SystemError ## \
|
OSError* = object of SystemError ## \
|
||||||
|
|
@ -370,11 +370,11 @@ type
|
||||||
##
|
##
|
||||||
## See the full `exception hierarchy`_.
|
## See the full `exception hierarchy`_.
|
||||||
ResourceExhaustedError* = object of SystemError ## \
|
ResourceExhaustedError* = object of SystemError ## \
|
||||||
## Raised if a resource request could not be fullfilled.
|
## Raised if a resource request could not be fulfilled.
|
||||||
##
|
##
|
||||||
## See the full `exception hierarchy`_.
|
## See the full `exception hierarchy`_.
|
||||||
ArithmeticError* = object of Exception ## \
|
ArithmeticError* = object of Exception ## \
|
||||||
## Raised if any kind of arithmetic error occured.
|
## Raised if any kind of arithmetic error occurred.
|
||||||
##
|
##
|
||||||
## See the full `exception hierarchy`_.
|
## See the full `exception hierarchy`_.
|
||||||
DivByZeroError* = object of ArithmeticError ## \
|
DivByZeroError* = object of ArithmeticError ## \
|
||||||
|
|
@ -578,7 +578,7 @@ proc len*(x: cstring): int {.magic: "LengthStr", noSideEffect.}
|
||||||
proc len*[I, T](x: array[I, T]): int {.magic: "LengthArray", noSideEffect.}
|
proc len*[I, T](x: array[I, T]): int {.magic: "LengthArray", noSideEffect.}
|
||||||
proc len*[T](x: seq[T]): int {.magic: "LengthSeq", noSideEffect.}
|
proc len*[T](x: seq[T]): int {.magic: "LengthSeq", noSideEffect.}
|
||||||
## returns the length of an array, an openarray, a sequence or a string.
|
## returns the length of an array, an openarray, a sequence or a string.
|
||||||
## This is rougly the same as ``high(T)-low(T)+1``, but its resulting type is
|
## This is roughly the same as ``high(T)-low(T)+1``, but its resulting type is
|
||||||
## always an int.
|
## always an int.
|
||||||
|
|
||||||
# set routines:
|
# set routines:
|
||||||
|
|
@ -865,7 +865,7 @@ proc contains*[T](x: set[T], y: T): bool {.magic: "InSet", noSideEffect.}
|
||||||
## passes its arguments in reverse order.
|
## passes its arguments in reverse order.
|
||||||
|
|
||||||
proc contains*[T](s: Slice[T], value: T): bool {.noSideEffect, inline.} =
|
proc contains*[T](s: Slice[T], value: T): bool {.noSideEffect, inline.} =
|
||||||
## Checks if `value` is withing the range of `s`; returns true iff
|
## Checks if `value` is within the range of `s`; returns true iff
|
||||||
## `value >= s.a and value <= s.b`
|
## `value >= s.a and value <= s.b`
|
||||||
##
|
##
|
||||||
## .. code-block:: Nim
|
## .. code-block:: Nim
|
||||||
|
|
@ -2457,7 +2457,7 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
proc getFileSize*(f: File): int64 {.tags: [ReadIOEffect], benign.}
|
proc getFileSize*(f: File): int64 {.tags: [ReadIOEffect], benign.}
|
||||||
## retrieves the file size (in bytes) of `f`.
|
## retrieves the file size (in bytes) of `f`.
|
||||||
|
|
||||||
proc readBytes*(f: File, a: var openArray[int8], start, len: int): int {.
|
proc readBytes*(f: File, a: var openArray[int8|uint8], start, len: int): int {.
|
||||||
tags: [ReadIOEffect], benign.}
|
tags: [ReadIOEffect], benign.}
|
||||||
## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
|
## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
|
||||||
## the actual number of bytes that have been read which may be less than
|
## the actual number of bytes that have been read which may be less than
|
||||||
|
|
@ -2475,7 +2475,7 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
## the actual number of bytes that have been read which may be less than
|
## the actual number of bytes that have been read which may be less than
|
||||||
## `len` (if not as many bytes are remaining), but not greater.
|
## `len` (if not as many bytes are remaining), but not greater.
|
||||||
|
|
||||||
proc writeBytes*(f: File, a: openArray[int8], start, len: int): int {.
|
proc writeBytes*(f: File, a: openArray[int8|uint8], start, len: int): int {.
|
||||||
tags: [WriteIOEffect], benign.}
|
tags: [WriteIOEffect], benign.}
|
||||||
## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
|
## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
|
||||||
## the number of actual written bytes, which may be less than `len` in case
|
## the number of actual written bytes, which may be less than `len` in case
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ proc raiseOverflow {.compilerproc, noinline, noreturn.} =
|
||||||
sysFatal(OverflowError, "over- or underflow")
|
sysFatal(OverflowError, "over- or underflow")
|
||||||
|
|
||||||
proc raiseDivByZero {.compilerproc, noinline, noreturn.} =
|
proc raiseDivByZero {.compilerproc, noinline, noreturn.} =
|
||||||
sysFatal(DivByZeroError, "divison by zero")
|
sysFatal(DivByZeroError, "division by zero")
|
||||||
|
|
||||||
proc addInt64(a, b: int64): int64 {.compilerProc, inline.} =
|
proc addInt64(a, b: int64): int64 {.compilerProc, inline.} =
|
||||||
result = a +% b
|
result = a +% b
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ proc addChar(s: NimString, c: char): NimString {.compilerProc, benign.}
|
||||||
|
|
||||||
type
|
type
|
||||||
TLibHandle = pointer # private type
|
TLibHandle = pointer # private type
|
||||||
TProcAddr = pointer # libary loading and loading of procs:
|
TProcAddr = pointer # library loading and loading of procs:
|
||||||
|
|
||||||
proc nimLoadLibrary(path: string): TLibHandle {.compilerproc.}
|
proc nimLoadLibrary(path: string): TLibHandle {.compilerproc.}
|
||||||
proc nimUnloadLibrary(lib: TLibHandle) {.compilerproc.}
|
proc nimUnloadLibrary(lib: TLibHandle) {.compilerproc.}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
# This file implements the ability to call native procs from libraries.
|
# This file implements the ability to call native procs from libraries.
|
||||||
# It is not possible to do this in a platform independant way, unfortunately.
|
# It is not possible to do this in a platform independent way, unfortunately.
|
||||||
# However, the interface has been designed to take platform differences into
|
# However, the interface has been designed to take platform differences into
|
||||||
# account and been ported to all major platforms.
|
# account and been ported to all major platforms.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -884,7 +884,7 @@ elif stackIncreases:
|
||||||
var
|
var
|
||||||
jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int
|
jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int
|
||||||
# a little hack to get the size of a TJmpBuf in the generated C code
|
# a little hack to get the size of a TJmpBuf in the generated C code
|
||||||
# in a platform independant way
|
# in a platform independent way
|
||||||
|
|
||||||
template forEachStackSlot(gch, gcMark: expr) {.immediate, dirty.} =
|
template forEachStackSlot(gch, gcMark: expr) {.immediate, dirty.} =
|
||||||
var registers: C_JmpBuf
|
var registers: C_JmpBuf
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,7 @@ type
|
||||||
# cycle roots table that uses a cheap linear scan
|
# cycle roots table that uses a cheap linear scan
|
||||||
# to find only possitively dead objects.
|
# to find only possitively dead objects.
|
||||||
# One strategy is to perform it only for new objects
|
# One strategy is to perform it only for new objects
|
||||||
# allocated between the invocations of CollectZCT.
|
# allocated between the invocations of collectZCT.
|
||||||
# This index indicates the start of the range of
|
# This index indicates the start of the range of
|
||||||
# such new objects within the table.
|
# such new objects within the table.
|
||||||
when withRealTime:
|
when withRealTime:
|
||||||
|
|
@ -140,7 +140,7 @@ var
|
||||||
gch* {.rtlThreadVar.}: TGcHeap
|
gch* {.rtlThreadVar.}: TGcHeap
|
||||||
|
|
||||||
when not defined(useNimRtl):
|
when not defined(useNimRtl):
|
||||||
InstantiateForRegion(gch.region)
|
instantiateForRegion(gch.region)
|
||||||
|
|
||||||
template acquire(gch: TGcHeap) =
|
template acquire(gch: TGcHeap) =
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
|
|
@ -233,11 +233,11 @@ template addCycleRoot(cycleRoots: var TCellSeq, c: PCell) =
|
||||||
|
|
||||||
proc cellToUsr(cell: PCell): pointer {.inline.} =
|
proc cellToUsr(cell: PCell): pointer {.inline.} =
|
||||||
# convert object (=pointer to refcount) to pointer to userdata
|
# convert object (=pointer to refcount) to pointer to userdata
|
||||||
result = cast[pointer](cast[TAddress](cell)+%TAddress(sizeof(TCell)))
|
result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(TCell)))
|
||||||
|
|
||||||
proc usrToCell*(usr: pointer): PCell {.inline.} =
|
proc usrToCell*(usr: pointer): PCell {.inline.} =
|
||||||
# convert pointer to userdata to object (=pointer to refcount)
|
# convert pointer to userdata to object (=pointer to refcount)
|
||||||
result = cast[PCell](cast[TAddress](usr)-%TAddress(sizeof(TCell)))
|
result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(TCell)))
|
||||||
|
|
||||||
proc canbeCycleRoot(c: PCell): bool {.inline.} =
|
proc canbeCycleRoot(c: PCell): bool {.inline.} =
|
||||||
result = ntfAcyclic notin c.typ.flags
|
result = ntfAcyclic notin c.typ.flags
|
||||||
|
|
@ -255,10 +255,10 @@ when BitsPerPage mod (sizeof(int)*8) != 0:
|
||||||
|
|
||||||
# forward declarations:
|
# forward declarations:
|
||||||
proc collectCT(gch: var TGcHeap)
|
proc collectCT(gch: var TGcHeap)
|
||||||
proc IsOnStack*(p: pointer): bool {.noinline.}
|
proc isOnStack*(p: pointer): bool {.noinline.}
|
||||||
proc forAllChildren(cell: PCell, op: TWalkOp)
|
proc forAllChildren(cell: PCell, op: TWalkOp)
|
||||||
proc doOperation(p: pointer, op: TWalkOp)
|
proc doOperation(p: pointer, op: TWalkOp)
|
||||||
proc forAllChildrenAux(dest: Pointer, mt: PNimType, op: TWalkOp)
|
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp)
|
||||||
# we need the prototype here for debugging purposes
|
# we need the prototype here for debugging purposes
|
||||||
|
|
||||||
proc prepareDealloc(cell: PCell) =
|
proc prepareDealloc(cell: PCell) =
|
||||||
|
|
@ -432,7 +432,7 @@ proc nimGCunrefNoCycle(p: pointer) {.compilerProc, inline.} =
|
||||||
sysAssert(allocInv(gch.region), "end nimGCunrefNoCycle 2")
|
sysAssert(allocInv(gch.region), "end nimGCunrefNoCycle 2")
|
||||||
sysAssert(allocInv(gch.region), "end nimGCunrefNoCycle 5")
|
sysAssert(allocInv(gch.region), "end nimGCunrefNoCycle 5")
|
||||||
|
|
||||||
template doAsgnRef(dest: ppointer, src: pointer,
|
template doAsgnRef(dest: PPointer, src: pointer,
|
||||||
heapType = LocalHeap, cycleFlag = MaybeCyclic): stmt =
|
heapType = LocalHeap, cycleFlag = MaybeCyclic): stmt =
|
||||||
sysAssert(not isOnStack(dest), "asgnRef")
|
sysAssert(not isOnStack(dest), "asgnRef")
|
||||||
# BUGFIX: first incRef then decRef!
|
# BUGFIX: first incRef then decRef!
|
||||||
|
|
@ -440,20 +440,20 @@ template doAsgnRef(dest: ppointer, src: pointer,
|
||||||
if dest[] != nil: doDecRef(usrToCell(dest[]), heapType, cycleFlag)
|
if dest[] != nil: doDecRef(usrToCell(dest[]), heapType, cycleFlag)
|
||||||
dest[] = src
|
dest[] = src
|
||||||
|
|
||||||
proc asgnRef(dest: ppointer, src: pointer) {.compilerProc, inline.} =
|
proc asgnRef(dest: PPointer, src: pointer) {.compilerProc, inline.} =
|
||||||
# the code generator calls this proc!
|
# the code generator calls this proc!
|
||||||
doAsgnRef(dest, src, LocalHeap, MaybeCyclic)
|
doAsgnRef(dest, src, LocalHeap, MaybeCyclic)
|
||||||
|
|
||||||
proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerProc, inline.} =
|
proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerProc, inline.} =
|
||||||
# the code generator calls this proc if it is known at compile time that no
|
# the code generator calls this proc if it is known at compile time that no
|
||||||
# cycle is possible.
|
# cycle is possible.
|
||||||
doAsgnRef(dest, src, LocalHeap, Acyclic)
|
doAsgnRef(dest, src, LocalHeap, Acyclic)
|
||||||
|
|
||||||
proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerProc.} =
|
proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerProc.} =
|
||||||
# unsureAsgnRef updates the reference counters only if dest is not on the
|
# unsureAsgnRef updates the reference counters only if dest is not on the
|
||||||
# stack. It is used by the code generator if it cannot decide wether a
|
# stack. It is used by the code generator if it cannot decide wether a
|
||||||
# reference is in the stack or not (this can happen for var parameters).
|
# reference is in the stack or not (this can happen for var parameters).
|
||||||
if not IsOnStack(dest):
|
if not isOnStack(dest):
|
||||||
if src != nil: doIncRef(usrToCell(src))
|
if src != nil: doIncRef(usrToCell(src))
|
||||||
# XXX we must detect a shared heap here
|
# XXX we must detect a shared heap here
|
||||||
# better idea may be to just eliminate the need for unsureAsgnRef
|
# better idea may be to just eliminate the need for unsureAsgnRef
|
||||||
|
|
@ -470,16 +470,16 @@ proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerProc.} =
|
||||||
|
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
# shared heap version of the above procs
|
# shared heap version of the above procs
|
||||||
proc asgnRefSh(dest: ppointer, src: pointer) {.compilerProc, inline.} =
|
proc asgnRefSh(dest: PPointer, src: pointer) {.compilerProc, inline.} =
|
||||||
doAsgnRef(dest, src, SharedHeap, MaybeCyclic)
|
doAsgnRef(dest, src, SharedHeap, MaybeCyclic)
|
||||||
|
|
||||||
proc asgnRefNoCycleSh(dest: ppointer, src: pointer) {.compilerProc, inline.} =
|
proc asgnRefNoCycleSh(dest: PPointer, src: pointer) {.compilerProc, inline.} =
|
||||||
doAsgnRef(dest, src, SharedHeap, Acyclic)
|
doAsgnRef(dest, src, SharedHeap, Acyclic)
|
||||||
|
|
||||||
proc initGC() =
|
proc initGC() =
|
||||||
when not defined(useNimRtl):
|
when not defined(useNimRtl):
|
||||||
when traceGC:
|
when traceGC:
|
||||||
for i in low(TCellState)..high(TCellState): Init(states[i])
|
for i in low(TCellState)..high(TCellState): init(states[i])
|
||||||
gch.cycleThreshold = InitialCycleThreshold
|
gch.cycleThreshold = InitialCycleThreshold
|
||||||
gch.stat.stackScans = 0
|
gch.stat.stackScans = 0
|
||||||
gch.stat.cycleCollections = 0
|
gch.stat.cycleCollections = 0
|
||||||
|
|
@ -491,11 +491,11 @@ proc initGC() =
|
||||||
init(gch.zct)
|
init(gch.zct)
|
||||||
init(gch.tempStack)
|
init(gch.tempStack)
|
||||||
init(gch.freeStack)
|
init(gch.freeStack)
|
||||||
Init(gch.cycleRoots)
|
init(gch.cycleRoots)
|
||||||
Init(gch.decStack)
|
init(gch.decStack)
|
||||||
|
|
||||||
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
|
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
|
||||||
var d = cast[TAddress](dest)
|
var d = cast[ByteAddress](dest)
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op)
|
of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op)
|
||||||
of nkList:
|
of nkList:
|
||||||
|
|
@ -503,7 +503,7 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
|
||||||
# inlined for speed
|
# inlined for speed
|
||||||
if n.sons[i].kind == nkSlot:
|
if n.sons[i].kind == nkSlot:
|
||||||
if n.sons[i].typ.kind in {tyRef, tyString, tySequence}:
|
if n.sons[i].typ.kind in {tyRef, tyString, tySequence}:
|
||||||
doOperation(cast[ppointer](d +% n.sons[i].offset)[], op)
|
doOperation(cast[PPointer](d +% n.sons[i].offset)[], op)
|
||||||
else:
|
else:
|
||||||
forAllChildrenAux(cast[pointer](d +% n.sons[i].offset),
|
forAllChildrenAux(cast[pointer](d +% n.sons[i].offset),
|
||||||
n.sons[i].typ, op)
|
n.sons[i].typ, op)
|
||||||
|
|
@ -514,19 +514,19 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
|
||||||
if m != nil: forAllSlotsAux(dest, m, op)
|
if m != nil: forAllSlotsAux(dest, m, op)
|
||||||
of nkNone: sysAssert(false, "forAllSlotsAux")
|
of nkNone: sysAssert(false, "forAllSlotsAux")
|
||||||
|
|
||||||
proc forAllChildrenAux(dest: Pointer, mt: PNimType, op: TWalkOp) =
|
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) =
|
||||||
var d = cast[TAddress](dest)
|
var d = cast[ByteAddress](dest)
|
||||||
if dest == nil: return # nothing to do
|
if dest == nil: return # nothing to do
|
||||||
if ntfNoRefs notin mt.flags:
|
if ntfNoRefs notin mt.flags:
|
||||||
case mt.Kind
|
case mt.kind
|
||||||
of tyRef, tyString, tySequence: # leaf:
|
of tyRef, tyString, tySequence: # leaf:
|
||||||
doOperation(cast[ppointer](d)[], op)
|
doOperation(cast[PPointer](d)[], op)
|
||||||
of tyObject, tyTuple:
|
of tyObject, tyTuple:
|
||||||
forAllSlotsAux(dest, mt.node, op)
|
forAllSlotsAux(dest, mt.node, op)
|
||||||
of tyArray, tyArrayConstr, tyOpenArray:
|
of tyArray, tyArrayConstr, tyOpenArray:
|
||||||
for i in 0..(mt.size div mt.base.size)-1:
|
for i in 0..(mt.size div mt.base.size)-1:
|
||||||
forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op)
|
forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op)
|
||||||
else: nil
|
else: discard
|
||||||
|
|
||||||
proc forAllChildren(cell: PCell, op: TWalkOp) =
|
proc forAllChildren(cell: PCell, op: TWalkOp) =
|
||||||
sysAssert(cell != nil, "forAllChildren: 1")
|
sysAssert(cell != nil, "forAllChildren: 1")
|
||||||
|
|
@ -536,18 +536,18 @@ proc forAllChildren(cell: PCell, op: TWalkOp) =
|
||||||
if marker != nil:
|
if marker != nil:
|
||||||
marker(cellToUsr(cell), op.int)
|
marker(cellToUsr(cell), op.int)
|
||||||
else:
|
else:
|
||||||
case cell.typ.Kind
|
case cell.typ.kind
|
||||||
of tyRef: # common case
|
of tyRef: # common case
|
||||||
forAllChildrenAux(cellToUsr(cell), cell.typ.base, op)
|
forAllChildrenAux(cellToUsr(cell), cell.typ.base, op)
|
||||||
of tySequence:
|
of tySequence:
|
||||||
var d = cast[TAddress](cellToUsr(cell))
|
var d = cast[ByteAddress](cellToUsr(cell))
|
||||||
var s = cast[PGenericSeq](d)
|
var s = cast[PGenericSeq](d)
|
||||||
if s != nil:
|
if s != nil:
|
||||||
let baseAddr = d +% GenericSeqSize
|
let baseAddr = d +% GenericSeqSize
|
||||||
for i in 0..s.len-1:
|
for i in 0..s.len-1:
|
||||||
forAllChildrenAux(cast[pointer](baseAddr +% i *% cell.typ.base.size),
|
forAllChildrenAux(cast[pointer](baseAddr +% i *% cell.typ.base.size),
|
||||||
cell.typ.base, op)
|
cell.typ.base, op)
|
||||||
else: nil
|
else: discard
|
||||||
|
|
||||||
proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
|
proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
|
||||||
# we check the last 8 entries (cache line) for a slot that could be reused.
|
# we check the last 8 entries (cache line) for a slot that could be reused.
|
||||||
|
|
@ -605,7 +605,7 @@ proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap, rc1: bool): pointer =
|
||||||
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
|
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
|
||||||
sysAssert(allocInv(gch.region), "rawNewObj after rawAlloc")
|
sysAssert(allocInv(gch.region), "rawNewObj after rawAlloc")
|
||||||
|
|
||||||
sysAssert((cast[TAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
|
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
|
||||||
|
|
||||||
res.typ = typ
|
res.typ = typ
|
||||||
|
|
||||||
|
|
@ -708,10 +708,10 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
|
||||||
# call user-defined move code
|
# call user-defined move code
|
||||||
# call user-defined default constructor
|
# call user-defined default constructor
|
||||||
copyMem(res, ol, oldsize + sizeof(TCell))
|
copyMem(res, ol, oldsize + sizeof(TCell))
|
||||||
zeroMem(cast[pointer](cast[TAddress](res)+% oldsize +% sizeof(TCell)),
|
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)),
|
||||||
newsize-oldsize)
|
newsize-oldsize)
|
||||||
|
|
||||||
sysAssert((cast[TAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
|
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
|
||||||
sysAssert(res.refcount shr rcShift <=% 1, "growObj: 4")
|
sysAssert(res.refcount shr rcShift <=% 1, "growObj: 4")
|
||||||
|
|
||||||
when false:
|
when false:
|
||||||
|
|
@ -786,10 +786,10 @@ type
|
||||||
FromChildren,
|
FromChildren,
|
||||||
FromRoot
|
FromRoot
|
||||||
|
|
||||||
proc CollectZCT(gch: var TGcHeap): bool
|
proc collectZCT(gch: var TGcHeap): bool
|
||||||
|
|
||||||
template pseudoRecursion(typ: TRecursionType, body: stmt): stmt =
|
template pseudoRecursion(typ: TRecursionType, body: stmt): stmt =
|
||||||
#
|
discard
|
||||||
|
|
||||||
proc trimCycleRoots(gch: var TGcHeap, startIdx = gch.cycleRootsTrimIdx) =
|
proc trimCycleRoots(gch: var TGcHeap, startIdx = gch.cycleRootsTrimIdx) =
|
||||||
var i = startIdx
|
var i = startIdx
|
||||||
|
|
@ -967,17 +967,17 @@ proc collectCycles(gch: var TGcHeap) =
|
||||||
maybedeads,
|
maybedeads,
|
||||||
collected
|
collected
|
||||||
|
|
||||||
Deinit(gch.cycleRoots)
|
deinit(gch.cycleRoots)
|
||||||
Init(gch.cycleRoots)
|
init(gch.cycleRoots)
|
||||||
|
|
||||||
Deinit(gch.freeStack)
|
deinit(gch.freeStack)
|
||||||
Init(gch.freeStack)
|
init(gch.freeStack)
|
||||||
|
|
||||||
when MarkingSkipsAcyclicObjects:
|
when MarkingSkipsAcyclicObjects:
|
||||||
# Collect the acyclic objects that became unreachable due to collected
|
# Collect the acyclic objects that became unreachable due to collected
|
||||||
# cyclic objects.
|
# cyclic objects.
|
||||||
discard CollectZCT(gch)
|
discard collectZCT(gch)
|
||||||
# CollectZCT may add new cycle candidates and we may decide to loop here
|
# collectZCT may add new cycle candidates and we may decide to loop here
|
||||||
# if gch.cycleRoots.len > 0: repeat
|
# if gch.cycleRoots.len > 0: repeat
|
||||||
|
|
||||||
var gcDebugging* = false
|
var gcDebugging* = false
|
||||||
|
|
@ -988,7 +988,7 @@ proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
|
||||||
# the addresses are not as cells on the stack, so turn them to cells:
|
# the addresses are not as cells on the stack, so turn them to cells:
|
||||||
sysAssert(allocInv(gch.region), "gcMark begin")
|
sysAssert(allocInv(gch.region), "gcMark begin")
|
||||||
var cell = usrToCell(p)
|
var cell = usrToCell(p)
|
||||||
var c = cast[TAddress](cell)
|
var c = cast[ByteAddress](cell)
|
||||||
if c >% PageSize:
|
if c >% PageSize:
|
||||||
# fast check: does it look like a cell?
|
# fast check: does it look like a cell?
|
||||||
var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell))
|
var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell))
|
||||||
|
|
@ -997,6 +997,7 @@ proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
|
||||||
if objStart.color != rcReallyDead:
|
if objStart.color != rcReallyDead:
|
||||||
if gcDebugging:
|
if gcDebugging:
|
||||||
# writeCell("marking ", objStart)
|
# writeCell("marking ", objStart)
|
||||||
|
discard
|
||||||
else:
|
else:
|
||||||
inc objStart.refcount, rcIncrement
|
inc objStart.refcount, rcIncrement
|
||||||
gch.decStack.add objStart
|
gch.decStack.add objStart
|
||||||
|
|
@ -1009,6 +1010,7 @@ proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
|
||||||
# coincidence due to the conservative stack marking.
|
# coincidence due to the conservative stack marking.
|
||||||
when debugGC:
|
when debugGC:
|
||||||
# writeCell("marking dead object", objStart)
|
# writeCell("marking dead object", objStart)
|
||||||
|
discard
|
||||||
when false:
|
when false:
|
||||||
if isAllocatedPtr(gch.region, cell):
|
if isAllocatedPtr(gch.region, cell):
|
||||||
sysAssert false, "allocated pointer but not interior?"
|
sysAssert false, "allocated pointer but not interior?"
|
||||||
|
|
@ -1024,12 +1026,12 @@ proc markThreadStacks(gch: var TGcHeap) =
|
||||||
while it != nil:
|
while it != nil:
|
||||||
# mark registers:
|
# mark registers:
|
||||||
for i in 0 .. high(it.registers): gcMark(gch, it.registers[i])
|
for i in 0 .. high(it.registers): gcMark(gch, it.registers[i])
|
||||||
var sp = cast[TAddress](it.stackBottom)
|
var sp = cast[ByteAddress](it.stackBottom)
|
||||||
var max = cast[TAddress](it.stackTop)
|
var max = cast[ByteAddress](it.stackTop)
|
||||||
# XXX stack direction?
|
# XXX stack direction?
|
||||||
# XXX unroll this loop:
|
# XXX unroll this loop:
|
||||||
while sp <=% max:
|
while sp <=% max:
|
||||||
gcMark(gch, cast[ppointer](sp)[])
|
gcMark(gch, cast[PPointer](sp)[])
|
||||||
sp = sp +% sizeof(pointer)
|
sp = sp +% sizeof(pointer)
|
||||||
it = it.next
|
it = it.next
|
||||||
|
|
||||||
|
|
@ -1051,8 +1053,8 @@ when not defined(useNimRtl):
|
||||||
# the first init must be the one that defines the stack bottom:
|
# the first init must be the one that defines the stack bottom:
|
||||||
if gch.stackBottom == nil: gch.stackBottom = theStackBottom
|
if gch.stackBottom == nil: gch.stackBottom = theStackBottom
|
||||||
else:
|
else:
|
||||||
var a = cast[TAddress](theStackBottom) # and not PageMask - PageSize*2
|
var a = cast[ByteAddress](theStackBottom) # and not PageMask - PageSize*2
|
||||||
var b = cast[TAddress](gch.stackBottom)
|
var b = cast[ByteAddress](gch.stackBottom)
|
||||||
#c_fprintf(c_stdout, "old: %p new: %p;\n",gch.stackBottom,theStackBottom)
|
#c_fprintf(c_stdout, "old: %p new: %p;\n",gch.stackBottom,theStackBottom)
|
||||||
when stackIncreases:
|
when stackIncreases:
|
||||||
gch.stackBottom = cast[pointer](min(a, b))
|
gch.stackBottom = cast[pointer](min(a, b))
|
||||||
|
|
@ -1067,15 +1069,15 @@ proc stackSize(): int {.noinline.} =
|
||||||
var
|
var
|
||||||
jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int
|
jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int
|
||||||
# a little hack to get the size of a TJmpBuf in the generated C code
|
# a little hack to get the size of a TJmpBuf in the generated C code
|
||||||
# in a platform independant way
|
# in a platform independent way
|
||||||
|
|
||||||
when defined(sparc): # For SPARC architecture.
|
when defined(sparc): # For SPARC architecture.
|
||||||
proc isOnStack(p: pointer): bool =
|
proc isOnStack(p: pointer): bool =
|
||||||
var stackTop {.volatile.}: pointer
|
var stackTop {.volatile.}: pointer
|
||||||
stackTop = addr(stackTop)
|
stackTop = addr(stackTop)
|
||||||
var b = cast[TAddress](gch.stackBottom)
|
var b = cast[ByteAddress](gch.stackBottom)
|
||||||
var a = cast[TAddress](stackTop)
|
var a = cast[ByteAddress](stackTop)
|
||||||
var x = cast[TAddress](p)
|
var x = cast[ByteAddress](p)
|
||||||
result = a <=% x and x <=% b
|
result = a <=% x and x <=% b
|
||||||
|
|
||||||
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
|
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
|
||||||
|
|
@ -1092,7 +1094,7 @@ when defined(sparc): # For SPARC architecture.
|
||||||
# Addresses decrease as the stack grows.
|
# Addresses decrease as the stack grows.
|
||||||
while sp <= max:
|
while sp <= max:
|
||||||
gcMark(gch, sp[])
|
gcMark(gch, sp[])
|
||||||
sp = cast[ppointer](cast[TAddress](sp) +% sizeof(pointer))
|
sp = cast[PPointer](cast[ByteAddress](sp) +% sizeof(pointer))
|
||||||
|
|
||||||
elif defined(ELATE):
|
elif defined(ELATE):
|
||||||
{.error: "stack marking code is to be written for this architecture".}
|
{.error: "stack marking code is to be written for this architecture".}
|
||||||
|
|
@ -1104,20 +1106,20 @@ elif stackIncreases:
|
||||||
proc isOnStack(p: pointer): bool =
|
proc isOnStack(p: pointer): bool =
|
||||||
var stackTop {.volatile.}: pointer
|
var stackTop {.volatile.}: pointer
|
||||||
stackTop = addr(stackTop)
|
stackTop = addr(stackTop)
|
||||||
var a = cast[TAddress](gch.stackBottom)
|
var a = cast[ByteAddress](gch.stackBottom)
|
||||||
var b = cast[TAddress](stackTop)
|
var b = cast[ByteAddress](stackTop)
|
||||||
var x = cast[TAddress](p)
|
var x = cast[ByteAddress](p)
|
||||||
result = a <=% x and x <=% b
|
result = a <=% x and x <=% b
|
||||||
|
|
||||||
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
|
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
|
||||||
var registers: C_JmpBuf
|
var registers: C_JmpBuf
|
||||||
if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
|
if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
|
||||||
var max = cast[TAddress](gch.stackBottom)
|
var max = cast[ByteAddress](gch.stackBottom)
|
||||||
var sp = cast[TAddress](addr(registers)) +% jmpbufSize -% sizeof(pointer)
|
var sp = cast[ByteAddress](addr(registers)) +% jmpbufSize -% sizeof(pointer)
|
||||||
# sp will traverse the JMP_BUF as well (jmp_buf size is added,
|
# sp will traverse the JMP_BUF as well (jmp_buf size is added,
|
||||||
# otherwise sp would be below the registers structure).
|
# otherwise sp would be below the registers structure).
|
||||||
while sp >=% max:
|
while sp >=% max:
|
||||||
gcMark(gch, cast[ppointer](sp)[])
|
gcMark(gch, cast[PPointer](sp)[])
|
||||||
sp = sp -% sizeof(pointer)
|
sp = sp -% sizeof(pointer)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
@ -1127,9 +1129,9 @@ else:
|
||||||
proc isOnStack(p: pointer): bool =
|
proc isOnStack(p: pointer): bool =
|
||||||
var stackTop {.volatile.}: pointer
|
var stackTop {.volatile.}: pointer
|
||||||
stackTop = addr(stackTop)
|
stackTop = addr(stackTop)
|
||||||
var b = cast[TAddress](gch.stackBottom)
|
var b = cast[ByteAddress](gch.stackBottom)
|
||||||
var a = cast[TAddress](stackTop)
|
var a = cast[ByteAddress](stackTop)
|
||||||
var x = cast[TAddress](p)
|
var x = cast[ByteAddress](p)
|
||||||
result = a <=% x and x <=% b
|
result = a <=% x and x <=% b
|
||||||
|
|
||||||
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
|
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
|
||||||
|
|
@ -1141,18 +1143,18 @@ else:
|
||||||
if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
|
if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
|
||||||
when MinimumStackMarking:
|
when MinimumStackMarking:
|
||||||
# mark the registers
|
# mark the registers
|
||||||
var jmpbufPtr = cast[TAddress](addr(registers))
|
var jmpbufPtr = cast[ByteAddress](addr(registers))
|
||||||
var jmpbufEnd = jmpbufPtr +% jmpbufSize
|
var jmpbufEnd = jmpbufPtr +% jmpbufSize
|
||||||
|
|
||||||
while jmpbufPtr <=% jmpbufEnd:
|
while jmpbufPtr <=% jmpbufEnd:
|
||||||
gcMark(gch, cast[ppointer](jmpbufPtr)[])
|
gcMark(gch, cast[PPointer](jmpbufPtr)[])
|
||||||
jmpbufPtr = jmpbufPtr +% sizeof(pointer)
|
jmpbufPtr = jmpbufPtr +% sizeof(pointer)
|
||||||
|
|
||||||
var sp = cast[TAddress](gch.stackTop)
|
var sp = cast[ByteAddress](gch.stackTop)
|
||||||
else:
|
else:
|
||||||
var sp = cast[TAddress](addr(registers))
|
var sp = cast[ByteAddress](addr(registers))
|
||||||
# mark the user stack
|
# mark the user stack
|
||||||
var max = cast[TAddress](gch.stackBottom)
|
var max = cast[ByteAddress](gch.stackBottom)
|
||||||
# loop unrolled:
|
# loop unrolled:
|
||||||
while sp <% max - 8*sizeof(pointer):
|
while sp <% max - 8*sizeof(pointer):
|
||||||
gcMark(gch, cast[PStackSlice](sp)[0])
|
gcMark(gch, cast[PStackSlice](sp)[0])
|
||||||
|
|
@ -1166,7 +1168,7 @@ else:
|
||||||
sp = sp +% sizeof(pointer)*8
|
sp = sp +% sizeof(pointer)*8
|
||||||
# last few entries:
|
# last few entries:
|
||||||
while sp <=% max:
|
while sp <=% max:
|
||||||
gcMark(gch, cast[ppointer](sp)[])
|
gcMark(gch, cast[PPointer](sp)[])
|
||||||
sp = sp +% sizeof(pointer)
|
sp = sp +% sizeof(pointer)
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
|
@ -1202,7 +1204,7 @@ proc releaseCell(gch: var TGcHeap, cell: PCell) =
|
||||||
# recursion).
|
# recursion).
|
||||||
# We can ignore it now as the ZCT cleaner will reach it soon.
|
# We can ignore it now as the ZCT cleaner will reach it soon.
|
||||||
|
|
||||||
proc CollectZCT(gch: var TGcHeap): bool =
|
proc collectZCT(gch: var TGcHeap): bool =
|
||||||
const workPackage = 100
|
const workPackage = 100
|
||||||
var L = addr(gch.zct.len)
|
var L = addr(gch.zct.len)
|
||||||
|
|
||||||
|
|
@ -1213,8 +1215,8 @@ proc CollectZCT(gch: var TGcHeap): bool =
|
||||||
|
|
||||||
while L[] > 0:
|
while L[] > 0:
|
||||||
var c = gch.zct.d[0]
|
var c = gch.zct.d[0]
|
||||||
sysAssert c.isBitUp(rcZct), "CollectZCT: rcZct missing!"
|
sysAssert c.isBitUp(rcZct), "collectZCT: rcZct missing!"
|
||||||
sysAssert(isAllocatedPtr(gch.region, c), "CollectZCT: isAllocatedPtr")
|
sysAssert(isAllocatedPtr(gch.region, c), "collectZCT: isAllocatedPtr")
|
||||||
|
|
||||||
# remove from ZCT:
|
# remove from ZCT:
|
||||||
c.clearBit(rcZct)
|
c.clearBit(rcZct)
|
||||||
|
|
@ -1263,7 +1265,7 @@ proc unmarkStackAndRegisters(gch: var TGcHeap) =
|
||||||
# XXX no need for an atomic dec here:
|
# XXX no need for an atomic dec here:
|
||||||
if c.refcount--(LocalHeap):
|
if c.refcount--(LocalHeap):
|
||||||
# the object survived only because of a stack reference
|
# the object survived only because of a stack reference
|
||||||
# it still doesn't have heap refernces
|
# it still doesn't have heap references
|
||||||
addZCT(gch.zct, c)
|
addZCT(gch.zct, c)
|
||||||
|
|
||||||
if canbeCycleRoot(c):
|
if canbeCycleRoot(c):
|
||||||
|
|
@ -1295,7 +1297,7 @@ proc collectCTBody(gch: var TGcHeap) =
|
||||||
sysAssert gch.zct.len == 0, "zct is not null after collect cycles"
|
sysAssert gch.zct.len == 0, "zct is not null after collect cycles"
|
||||||
inc(gch.stat.cycleCollections)
|
inc(gch.stat.cycleCollections)
|
||||||
gch.cycleThreshold = max(InitialCycleThreshold, getOccupiedMem() *
|
gch.cycleThreshold = max(InitialCycleThreshold, getOccupiedMem() *
|
||||||
cycleIncrease)
|
CycleIncrease)
|
||||||
gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold)
|
gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold)
|
||||||
unmarkStackAndRegisters(gch)
|
unmarkStackAndRegisters(gch)
|
||||||
sysAssert(allocInv(gch.region), "collectCT: end")
|
sysAssert(allocInv(gch.region), "collectCT: end")
|
||||||
|
|
@ -1346,10 +1348,10 @@ when not defined(useNimRtl):
|
||||||
|
|
||||||
proc GC_setStrategy(strategy: GC_Strategy) =
|
proc GC_setStrategy(strategy: GC_Strategy) =
|
||||||
case strategy
|
case strategy
|
||||||
of gcThroughput: nil
|
of gcThroughput: discard
|
||||||
of gcResponsiveness: nil
|
of gcResponsiveness: discard
|
||||||
of gcOptimizeSpace: nil
|
of gcOptimizeSpace: discard
|
||||||
of gcOptimizeTime: nil
|
of gcOptimizeTime: discard
|
||||||
|
|
||||||
proc GC_enableMarkAndSweep() =
|
proc GC_enableMarkAndSweep() =
|
||||||
gch.cycleThreshold = InitialCycleThreshold
|
gch.cycleThreshold = InitialCycleThreshold
|
||||||
|
|
|
||||||
|
|
@ -476,7 +476,7 @@ elif stackIncreases:
|
||||||
var
|
var
|
||||||
jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int
|
jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int
|
||||||
# a little hack to get the size of a TJmpBuf in the generated C code
|
# a little hack to get the size of a TJmpBuf in the generated C code
|
||||||
# in a platform independant way
|
# in a platform independent way
|
||||||
|
|
||||||
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
|
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
|
||||||
var registers: C_JmpBuf
|
var registers: C_JmpBuf
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue