This commit is contained in:
Araq
2013-11-25 13:06:11 +01:00
52 changed files with 3526 additions and 2362 deletions

View File

@@ -712,7 +712,6 @@ type
# -1 means that the size is unkwown
align*: int # the type's alignment requirements
loc*: TLoc
testeeName*: PIdent # the test variable in user-defined type classes
TPair*{.final.} = object
key*, val*: PObject
@@ -1088,7 +1087,6 @@ proc assignType(dest, src: PType) =
dest.size = src.size
dest.align = src.align
dest.destructor = src.destructor
dest.testeeName = src.testeeName
# this fixes 'type TLock = TSysLock':
if src.sym != nil:
if dest.sym != nil:

View File

@@ -583,7 +583,7 @@ proc CallCCompiler*(projectfile: string) =
else:
rawMessage(errGenerated, " execution of an external program failed; " &
"rerun with --parallelBuild:1 to see the error message")
if optNoLinking notin gGlobalOptions and cmds.len > 0:
if optNoLinking notin gGlobalOptions:
# call the linker:
var it = PStrEntry(toLink.head)
var objfiles = ""

View File

@@ -436,7 +436,14 @@ type
# only 8 bytes.
line*, col*: int16
fileIndex*: int32
TErrorOutput* = enum
eStdOut
eStdErr
eInMemory
TErrorOutputs* = set[TErrorOutput]
ERecoverableError* = object of EInvalidValue
ESuggestDone* = object of EBase
@@ -534,13 +541,27 @@ var
gHintCounter*: int = 0
gWarnCounter*: int = 0
gErrorMax*: int = 1 # stop after gErrorMax errors
gSilence*: int # == 0 if we produce any output at all
when useCaas:
var stdoutSocket*: TSocket
proc UnknownLineInfo*(): TLineInfo =
result.line = int16(-1)
result.col = int16(-1)
result.fileIndex = -1
var
msgContext: seq[TLineInfo] = @[]
lastError = UnknownLineInfo()
bufferedMsgs*: seq[string]
errorOutputs* = {eStdOut, eStdErr}
proc clearBufferedMsgs* =
bufferedMsgs = nil
proc SuggestWriteln*(s: string) =
if gSilence == 0:
if eStdOut in errorOutputs:
when useCaas:
if isNil(stdoutSocket): Writeln(stdout, s)
else:
@@ -548,6 +569,9 @@ proc SuggestWriteln*(s: string) =
stdoutSocket.send(s & "\c\L")
else:
Writeln(stdout, s)
if eInMemory in errorOutputs:
bufferedMsgs.safeAdd(s)
proc SuggestQuit*() =
if not isServing:
@@ -570,14 +594,6 @@ const
RawWarningFormat* = "Warning: $1"
RawHintFormat* = "Hint: $1"
proc UnknownLineInfo*(): TLineInfo =
result.line = int16(-1)
result.col = int16(-1)
result.fileIndex = -1
var
msgContext: seq[TLineInfo] = @[]
proc getInfoContextLen*(): int = return msgContext.len
proc setInfoContextLen*(L: int) = setLen(msgContext, L)
@@ -642,14 +658,18 @@ proc addCheckpoint*(filename: string, line: int) =
proc OutWriteln*(s: string) =
## Writes to stdout. Always.
if gSilence == 0: Writeln(stdout, s)
if eStdOut in errorOutputs: Writeln(stdout, s)
proc MsgWriteln*(s: string) =
## Writes to stdout. If --stdout option is given, writes to stderr instead.
if gSilence == 0:
if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
if optStdout in gGlobalOptions: Writeln(stderr, s)
else: Writeln(stdout, s)
if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
if optStdout in gGlobalOptions:
if eStdErr in errorOutputs: Writeln(stderr, s)
else:
if eStdOut in errorOutputs: Writeln(stdout, s)
if eInMemory in errorOutputs: bufferedMsgs.safeAdd(s)
proc coordToStr(coord: int): string =
if coord == -1: result = "???"
@@ -736,9 +756,6 @@ proc rawMessage*(msg: TMsgKind, args: openarray[string]) =
proc rawMessage*(msg: TMsgKind, arg: string) =
rawMessage(msg, [arg])
var
lastError = UnknownLineInfo()
proc writeSurroundingSrc(info: TLineInfo) =
const indent = " "
MsgWriteln(indent & info.sourceLine.ropeToStr)

View File

@@ -1624,10 +1624,23 @@ proc parseObject(p: var TParser): PNode =
return
addSon(result, parseObjectPart(p))
proc parseTypeClassParam(p: var TParser): PNode =
if p.tok.tokType == tkVar:
getTok(p)
result = newNode(nkVarTy)
result.addSon(p.parseSymbol)
else:
result = p.parseSymbol
proc parseTypeClass(p: var TParser): PNode =
result = newNodeP(nkTypeClassTy, p)
getTok(p)
addSon(result, p.parseSymbol)
var args = newNode(nkArgList)
addSon(result, args)
addSon(args, p.parseTypeClassParam)
while p.tok.TokType == tkComma:
getTok(p)
addSon(args, p.parseTypeClassParam)
if p.tok.tokType == tkCurlyDotLe and p.validInd:
addSon(result, parsePragma(p))
else:

View File

@@ -36,7 +36,8 @@ proc semParamList(c: PContext, n, genericParams: PNode, s: PSym)
proc addParams(c: PContext, n: PNode, kind: TSymKind)
proc maybeAddResult(c: PContext, s: PSym, n: PNode)
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc tryExpr(c: PContext, n: PNode,
flags: TExprFlags = {}, bufferErrors = false): PNode
proc fixImmediateParams(n: PNode): PNode
proc activate(c: PContext, n: PNode)
proc semQuoteAst(c: PContext, n: PNode): PNode

View File

@@ -60,6 +60,7 @@ type
threadEntries*: TSymSeq # list of thread entries to check
AmbiguousSymbols*: TIntSet # ids of all ambiguous symbols (cannot
# store this info in the syms themselves!)
InTypeClass*: int # > 0 if we are in a user-defined type class
InGenericContext*: int # > 0 if we are in a generic type
InUnrolledContext*: int # > 0 if we are unrolling a loop
InCompilesContext*: int # > 0 if we are in a ``compiles`` magic
@@ -72,7 +73,8 @@ type
libs*: TLinkedList # all libs used by this module
semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
semTryExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
semTryExpr*: proc (c: PContext, n: PNode,flags: TExprFlags = {},
bufferErrors = false): PNode {.nimcall.}
semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet
semOverloadedCall*: proc (c: PContext, n, nOrig: PNode,

View File

@@ -299,7 +299,7 @@ proc semOf(c: PContext, n: PNode): PNode =
n.typ = getSysType(tyBool)
result = n
proc IsOpImpl(c: PContext, n: PNode): PNode =
proc isOpImpl(c: PContext, n: PNode): PNode =
InternalAssert n.sonsLen == 3 and
n[1].kind == nkSym and n[1].sym.kind == skType and
n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
@@ -321,10 +321,19 @@ proc IsOpImpl(c: PContext, n: PNode): PNode =
else:
var match: bool
let t2 = n[2].typ
if t2.kind == tyTypeClass:
case t2.kind
of tyTypeClass:
var m: TCandidate
InitCandidate(m, t2)
match = matchUserTypeClass(c, m, emptyNode, t2, t1) != nil
of tyOrdinal:
var m: TCandidate
InitCandidate(m, t2)
match = isOrdinalType(t1)
of tySequence, tyArray, tySet:
var m: TCandidate
InitCandidate(m, t2)
match = typeRel(m, t2, t1) != isNone
else:
match = sameType(t1, t2)
@@ -353,7 +362,7 @@ proc semIs(c: PContext, n: PNode): PNode =
let t1 = n[1].typ.sons[0]
# BUGFIX: don't evaluate this too early: ``T is void``
if not containsGenericType(t1): result = IsOpImpl(c, n)
if not containsGenericType(t1): result = isOpImpl(c, n)
proc semOpAux(c: PContext, n: PNode) =
const flags = {efDetermineType}
@@ -763,7 +772,8 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
analyseIfAddressTakenInCall(c, result)
if callee.magic != mNone:
result = magicsAfterOverloadResolution(c, result, flags)
result = evalAtCompileTime(c, result)
if c.InTypeClass == 0:
result = evalAtCompileTime(c, result)
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
# this seems to be a hotspot in the compiler!
@@ -814,7 +824,7 @@ proc buildEchoStmt(c: PContext, n: PNode): PNode =
proc semExprNoType(c: PContext, n: PNode): PNode =
result = semExpr(c, n, {efWantStmt})
discardCheck(result)
discardCheck(c, result)
proc isTypeExpr(n: PNode): bool =
case n.kind
@@ -1208,7 +1218,7 @@ proc semProcBody(c: PContext, n: PNode): PNode =
a.sons[1] = result
result = semAsgn(c, a)
else:
discardCheck(result)
discardCheck(c, result)
closeScope(c)
proc SemYieldVarResult(c: PContext, n: PNode, restype: PType) =
@@ -1429,12 +1439,12 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
newNode(nkCall, n.info, quotes)])
result = semExpandToAst(c, result)
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
proc tryExpr(c: PContext, n: PNode,
flags: TExprFlags = {}, bufferErrors = false): PNode =
# watch out, hacks ahead:
let oldErrorCount = msgs.gErrorCounter
let oldErrorMax = msgs.gErrorMax
inc c.InCompilesContext
inc msgs.gSilence
# do not halt after first error:
msgs.gErrorMax = high(int)
@@ -1443,6 +1453,8 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
openScope(c)
let oldOwnerLen = len(gOwners)
let oldGenerics = c.generics
let oldErrorOutputs = errorOutputs
errorOutputs = if bufferErrors: {eInMemory} else: {}
let oldContextLen = msgs.getInfoContextLen()
let oldInGenericContext = c.InGenericContext
@@ -1465,7 +1477,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
setlen(gOwners, oldOwnerLen)
c.currentScope = oldScope
dec c.InCompilesContext
dec msgs.gSilence
errorOutputs = oldErrorOutputs
msgs.gErrorCounter = oldErrorCount
msgs.gErrorMax = oldErrorMax

View File

@@ -132,7 +132,7 @@ proc fixNilType(n: PNode) =
for it in n: fixNilType(it)
n.typ = nil
proc discardCheck(result: PNode) =
proc discardCheck(c: PContext, result: PNode) =
if result.typ != nil and result.typ.kind notin {tyStmt, tyEmpty}:
if result.kind == nkNilLit:
result.typ = nil
@@ -142,6 +142,10 @@ proc discardCheck(result: PNode) =
while n.kind in skipForDiscardable:
n = n.lastSon
n.typ = nil
elif c.InTypeClass > 0 and result.typ.kind == tyBool:
let verdict = semConstExpr(c, result)
if verdict.intVal == 0:
localError(result.info, "type class predicate failed.")
elif result.typ.kind != tyError and gCmd != cmdInteractive:
if result.typ.kind == tyNil:
fixNilType(result)
@@ -169,7 +173,7 @@ proc semIf(c: PContext, n: PNode): PNode =
typ = commonType(typ, it.sons[0].typ)
else: illFormedAst(it)
if isEmptyType(typ) or typ.kind == tyNil or not hasElse:
for it in n: discardCheck(it.lastSon)
for it in n: discardCheck(c, it.lastSon)
result.kind = nkIfStmt
# propagate any enforced VoidContext:
if typ == EnforceVoidContext: result.typ = EnforceVoidContext
@@ -230,7 +234,7 @@ proc semCase(c: PContext, n: PNode): PNode =
localError(n.info, errNotAllCasesCovered)
closeScope(c)
if isEmptyType(typ) or typ.kind == tyNil or not hasElse:
for i in 1..n.len-1: discardCheck(n.sons[i].lastSon)
for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon)
# propagate any enforced VoidContext:
if typ == EnforceVoidContext:
result.typ = EnforceVoidContext
@@ -275,8 +279,8 @@ proc semTry(c: PContext, n: PNode): PNode =
typ = commonType(typ, a.sons[length-1].typ)
dec c.p.inTryStmt
if isEmptyType(typ) or typ.kind == tyNil:
discardCheck(n.sons[0])
for i in 1..n.len-1: discardCheck(n.sons[i].lastSon)
discardCheck(c, n.sons[0])
for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon)
if typ == EnforceVoidContext:
result.typ = EnforceVoidContext
else:
@@ -879,8 +883,9 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
openScope(c)
if n.sons[genericParamsPos].kind != nkEmpty:
illFormedAst(n) # process parameters:
if n.sons[paramsPos].kind != nkEmpty:
semParamList(c, n.sons[ParamsPos], nil, s)
if n.sons[paramsPos].kind != nkEmpty:
var gp = newNodeI(nkGenericParams, n.info)
semParamList(c, n.sons[ParamsPos], gp, s)
ParamsTypeCheck(c, s.typ)
else:
s.typ = newTypeS(tyProc, c)
@@ -1104,24 +1109,24 @@ proc finishMethod(c: PContext, s: PSym) =
methodDef(s, false)
proc semMethod(c: PContext, n: PNode): PNode =
if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "method")
if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "method")
result = semProcAux(c, n, skMethod, methodPragmas)
var s = result.sons[namePos].sym
if not isGenericRoutine(s):
if not isGenericRoutine(s) and result.sons[bodyPos].kind != nkEmpty:
if hasObjParam(s):
methodDef(s, false)
methodDef(s, fromCache=false)
else:
LocalError(n.info, errXNeedsParamObjectType, "method")
localError(n.info, errXNeedsParamObjectType, "method")
proc semConverterDef(c: PContext, n: PNode): PNode =
if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "converter")
if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "converter")
checkSonsLen(n, bodyPos + 1)
result = semProcAux(c, n, skConverter, converterPragmas)
var s = result.sons[namePos].sym
var t = s.typ
if t.sons[0] == nil: LocalError(n.info, errXNeedsReturnType, "converter")
if sonsLen(t) != 2: LocalError(n.info, errXRequiresOneArgument, "converter")
if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "converter")
if sonsLen(t) != 2: localError(n.info, errXRequiresOneArgument, "converter")
addConverter(c, s)
proc semMacroDef(c: PContext, n: PNode): PNode =
@@ -1129,9 +1134,9 @@ proc semMacroDef(c: PContext, n: PNode): PNode =
result = semProcAux(c, n, skMacro, macroPragmas)
var s = result.sons[namePos].sym
var t = s.typ
if t.sons[0] == nil: LocalError(n.info, errXNeedsReturnType, "macro")
if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "macro")
if n.sons[bodyPos].kind == nkEmpty:
LocalError(n.info, errImplOfXexpected, s.name.s)
localError(n.info, errImplOfXexpected, s.name.s)
proc evalInclude(c: PContext, n: PNode): PNode =
result = newNodeI(nkStmtList, n.info)
@@ -1221,7 +1226,7 @@ proc semStmtList(c: PContext, n: PNode): PNode =
voidContext = true
n.typ = EnforceVoidContext
if i != last or voidContext:
discardCheck(n.sons[i])
discardCheck(c, n.sons[i])
else:
n.typ = n.sons[i].typ
if not isEmptyType(n.typ):

View File

@@ -876,8 +876,7 @@ proc freshType(res, prev: PType): PType {.inline.} =
proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
# if n.sonsLen == 0: return newConstraint(c, tyTypeClass)
result = newOrPrevType(tyTypeClass, prev, c)
result.testeeName = considerAcc(n[0])
result.n = n[3]
result.n = n
let
pragmas = n[1]

View File

@@ -85,6 +85,7 @@ proc initCandidate*(c: var TCandidate, callee: PSym, binding: PNode,
c.calleeSym = callee
c.calleeScope = calleeScope
initIdTable(c.bindings)
c.errors = nil
if binding != nil and callee.kind in RoutineKinds:
var typeParams = callee.ast[genericParamsPos]
for i in 1..min(sonsLen(typeParams), sonsLen(binding)-1):
@@ -202,7 +203,7 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1): string =
add(result, argTypeToString(arg))
if i != sonsLen(n) - 1: add(result, ", ")
proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation
proc typeRel*(c: var TCandidate, f, a: PType): TTypeRelation
proc concreteType(c: TCandidate, t: PType): PType =
case t.kind
of tyArrayConstr:
@@ -750,40 +751,55 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
# pushInfoContext(arg.info)
openScope(c)
inc c.InTypeClass
var testee = newSym(skParam, f.testeeName, f.sym, f.sym.info)
testee.typ = a
addDecl(c, testee)
finally:
dec c.InTypeClass
closeScope(c)
for param in f.n[0]:
var
dummyName: PNode
dummyType: PType
if param.kind == nkVarTy:
dummyName = param[0]
dummyType = makeVarType(c, a)
else:
dummyName = param
dummyType = a
InternalAssert dummyName.kind == nkIdent
var dummyParam = newSym(skType, dummyName.ident, f.sym, f.sym.info)
dummyParam.typ = dummyType
addDecl(c, dummyParam)
for stmt in f.n[3]:
var e = c.semTryExpr(c, copyTree(stmt), bufferErrors = false)
m.errors = bufferedMsgs
clearBufferedMsgs()
if e == nil: return nil
for stmt in f.n:
var e = c.semTryExpr(c, copyTree(stmt))
if e == nil:
let expStr = renderTree(stmt, {renderNoComments})
m.errors.safeAdd("can't compile " & expStr & " for " & a.typeToString)
return nil
case e.kind
of nkReturnStmt:
nil
of nkReturnStmt: nil
of nkTypeSection: nil
of nkConstDef: nil
else:
if e.typ.kind == tyBool:
let verdict = c.semConstExpr(c, e)
if verdict.intVal == 0:
let expStr = renderTree(stmt, {renderNoComments})
m.errors.safeAdd(expStr & " doesn't hold for " & a.typeToString)
return nil
closeScope(c)
else: nil
result = arg
put(m.bindings, f, a)
proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, argType: PType,
argSemantized, argOrig: PNode): PNode =
var arg = argSemantized
var r: TTypeRelation
let fMaybeExpr = f.skipTypes({tyDistinct})
var
r: TTypeRelation
arg = argSemantized
let
a = if c.InTypeClass > 0: argType.skipTypes({tyTypeDesc})
else: argType
fMaybeExpr = f.skipTypes({tyDistinct})
case fMaybeExpr.kind
of tyExpr:
if fMaybeExpr.sonsLen == 0:

View File

@@ -621,7 +621,7 @@ type
proc initSameTypeClosure: TSameTypeClosure =
# we do the initialization lazily for performance (avoids memory allocations)
nil
proc containsOrIncl(c: var TSameTypeClosure, a, b: PType): bool =
result = not IsNil(c.s) and c.s.contains((a.id, b.id))
if not result:
@@ -750,9 +750,9 @@ template IfFastObjectTypeCheckFailed(a, b: PType, body: stmt) {.immediate.} =
proc sameObjectTypes*(a, b: PType): bool =
# specialized for efficiency (sigmatch uses it)
IfFastObjectTypeCheckFailed(a, b):
IfFastObjectTypeCheckFailed(a, b):
var c = initSameTypeClosure()
result = sameTypeAux(a, b, c)
result = sameTypeAux(a, b, c)
proc sameDistinctTypes*(a, b: PType): bool {.inline.} =
result = sameObjectTypes(a, b)
@@ -808,11 +808,11 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
if containsOrIncl(c, a, b): return true
proc sameFlags(a, b: PType): bool {.inline.} =
result = eqTypeFlags*a.flags == eqTypeFlags*b.flags
result = eqTypeFlags*a.flags == eqTypeFlags*b.flags
if x == y: return true
var a = skipTypes(x, {tyGenericInst})
var b = skipTypes(y, {tyGenericInst})
var b = skipTypes(y, {tyGenericInst})
assert(a != nil)
assert(b != nil)
if a.kind != b.kind:
@@ -824,7 +824,7 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
if a.kind != b.kind: return false
of dcEqOrDistinctOf:
while a.kind == tyDistinct: a = a.sons[0]
if a.kind != b.kind: return false
if a.kind != b.kind: return false
case a.Kind
of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString,
tyInt..tyBigNum, tyStmt:
@@ -837,15 +837,19 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
result = sameObjectStructures(a, b, c) and sameFlags(a, b)
of tyDistinct:
CycleCheck()
if c.cmp == dcEq: result = sameDistinctTypes(a, b) and sameFlags(a, b)
else: result = sameTypeAux(a.sons[0], b.sons[0], c) and sameFlags(a, b)
if c.cmp == dcEq:
if sameFlags(a, b):
IfFastObjectTypeCheckFailed(a, b):
result = sameTypeAux(a.sons[0], b.sons[0], c)
else:
result = sameTypeAux(a.sons[0], b.sons[0], c) and sameFlags(a, b)
of tyEnum, tyForward, tyProxy:
# XXX generic enums do not make much sense, but require structural checking
result = a.id == b.id and sameFlags(a, b)
of tyTuple:
CycleCheck()
result = sameTuple(a, b, c) and sameFlags(a, b)
of tyGenericInst:
of tyGenericInst:
result = sameTypeAux(lastSon(a), lastSon(b), c)
of tyTypeDesc:
if c.cmp == dcEqIgnoreDistinct: result = false
@@ -858,7 +862,7 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr,
tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter,
tyOrdinal, tyTypeClass:
CycleCheck()
CycleCheck()
result = sameChildrenAux(a, b, c) and sameFlags(a, b)
if result and (a.kind == tyProc):
result = a.callConv == b.callConv
@@ -867,7 +871,7 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
result = SameTypeOrNilAux(a.sons[0], b.sons[0], c) and
SameValue(a.n.sons[0], b.n.sons[0]) and
SameValue(a.n.sons[1], b.n.sons[1])
of tyNone: result = false
of tyNone: result = false
proc sameType*(x, y: PType): bool =
var c = initSameTypeClosure()

View File

@@ -13,7 +13,7 @@ Introduction
This document describes how the GC works and how to tune it for
(soft) `realtime systems`:idx:.
The basic algorithm is *Deferrent Reference Counting* with cycle detection.
The basic algorithm is *Deferred Reference Counting* with cycle detection.
References on the stack are not counted for better performance (and easier C
code generation). The GC **never** scans the whole heap but it may scan the
delta-subgraph of the heap that changed since its last run.

View File

@@ -52,6 +52,11 @@ For a release version use::
nimrod c koch.nim
./koch boot -d:release
And for a debug version compatible with GDB::
nimrod c koch.nim
./koch boot --debuginfo --linedir:on
The ``koch`` program is Nimrod's maintenance script. It is a replacement for
make and shell scripting with the advantage that it is much more portable.
@@ -64,7 +69,7 @@ Coding Guidelines
* Max line length is 80 characters.
* Provide spaces around binary operators if that enhances readability.
* Use a space after a colon, but not before it.
* Start types with a capital ``T``, unless they are pointers which start
* Start types with a capital ``T``, unless they are pointers/references which start
with ``P``.

View File

@@ -64,6 +64,8 @@ Core
Collections and algorithms
--------------------------
* `algorithm <algorithm.html>`_
Implements some common generic algorithms like sort or binary search.
* `tables <tables.html>`_
Nimrod hash table support. Contains tables, ordered tables and count tables.
* `sets <sets.html>`_

View File

@@ -893,11 +893,12 @@ integers from 0 to ``len(A)-1``. An array expression may be constructed by the
array constructor ``[]``.
`Sequences`:idx: are similar to arrays but of dynamic length which may change
during runtime (like strings). A sequence ``S`` is always indexed by integers
from 0 to ``len(S)-1`` and its bounds are checked. Sequences can be
constructed by the array constructor ``[]`` in conjunction with the array to
sequence operator ``@``. Another way to allocate space for a sequence is to
call the built-in ``newSeq`` procedure.
during runtime (like strings). Sequences are implemented as growable arrays,
allocating pieces of memory as items are added. A sequence ``S`` is always
indexed by integers from 0 to ``len(S)-1`` and its bounds are checked.
Sequences can be constructed by the array constructor ``[]`` in conjunction
with the array to sequence operator ``@``. Another way to allocate space for a
sequence is to call the built-in ``newSeq`` procedure.
A sequence may be passed to a parameter that is of type *open array*.
@@ -3288,27 +3289,36 @@ Declarative type classes are written in the following form:
for value in c:
type(value) is T
The identifiers following the `generic` keyword are treated as variables of
the matched type and the body of the type class consists of arbitrary code that
must be valid under these circumstances.
Specifically, the type class will be matched if:
The type class will be matched if:
a) all of the expressions within the body can be compiled for the tested type
b) all statically evaluatable boolean expressions in the body must be true
Please note that the ``is`` operator allows you to easily verify the precise type
signatures of the required operations, but since type inference and default
parameters are still applied in the provided block, it's also possible to encode
usage protocols that doesn't reveal implementation details.
The identifiers following the `generic` keyword represent instances of the
currently matched type. These instances can act both as variables of the type,
when used in contexts, where a value is expected, and as the type itself, when
used in a contexts, where a type is expected.
Please note that the ``is`` operator allows you to easily verify the precise
type signatures of the required operations, but since type inference and
default parameters are still applied in the provided block, it's also possible
to encode usage protocols that doesn't reveal implementation details.
As a special rule providing further convenience when writing type classes, any
type value appearing in a callable expression will be treated as a variable of
the designated type for overload resolution purposes, unless the type value was
passed in its explicit ``typedesc[T]`` form:
.. code-block:: nimrod
type
OutputStream = generic S
write(var S, string)
Much like generics, the user defined type classes will be instantiated exactly
once for each tested type and any static code included within them will also be
executed once.
Return Type Inference
---------------------
@@ -4673,9 +4683,10 @@ A proc can be marked with the `noStackFrame`:idx: pragma to tell the compiler
it should not generate a stack frame for the proc. There are also no exit
statements like ``return result;`` generated and the generated C function is
declared as ``__declspec(naked)`` or ``__attribute__((naked))`` (depending on
the used C compiler). This is useful for procs that only consist of an
assembler statement.
the used C compiler).
**Note**: This pragma should only be used by procs which consist solely of assembler
statements.
error pragma
------------

View File

@@ -610,7 +610,7 @@ allow to silently throw away a return value:
discard yes("May I ask a pointless question?")
The return value can be ignored implicitely if the called proc/iterator has
The return value can be ignored implicitly if the called proc/iterator has
been declared with the ``discardable`` pragma:
.. code-block:: nimrod
@@ -1077,7 +1077,7 @@ can also be used to include elements (and ranges of elements):
TCharSet = set[char]
var
x: TCharSet
x = {'a'..'z', '0'..'9'} # This constructs a set that conains the
x = {'a'..'z', '0'..'9'} # This constructs a set that contains the
# letters from 'a' to 'z' and the digits
# from '0' to '9'
@@ -1201,7 +1201,7 @@ to specify a range from zero to the specified index minus one:
Sequences
---------
`Sequences`:idx: are similar to arrays but of dynamic length which may change
during runtime (like strings). Since sequences are resizeable they are always
during runtime (like strings). Since sequences are resizable they are always
allocated on the heap and garbage collected.
Sequences are always indexed with an ``int`` starting at position 0.
@@ -1547,7 +1547,7 @@ exported symbols. An alternative that only imports listed symbols is the
Include statement
-----------------
The `include`:idx: statement does something fundametally different than
The `include`:idx: statement does something fundamentally different than
importing a module: it merely includes the contents of a file. The ``include``
statement is useful to split up a large module into several files:

View File

@@ -868,6 +868,12 @@ proc parseLine(p: var TRstParser, father: PRstNode) =
case p.tok[p.idx].kind
of tkWhite, tkWord, tkOther, tkPunct: parseInline(p, father)
else: break
proc parseUntilNewline(p: var TRstParser, father: PRstNode) =
while True:
case p.tok[p.idx].kind
of tkWhite, tkWord, tkAdornment, tkOther, tkPunct: parseInline(p, father)
of tkEof, tkIndent: break
proc parseSection(p: var TRstParser, result: PRstNode)
proc parseField(p: var TRstParser): PRstNode =
@@ -1078,7 +1084,7 @@ proc parseParagraph(p: var TRstParser, result: PRstNode) =
proc parseHeadline(p: var TRstParser): PRstNode =
result = newRstNode(rnHeadline)
parseLine(p, result)
parseUntilNewLine(p, result)
assert(p.tok[p.idx].kind == tkIndent)
assert(p.tok[p.idx + 1].kind == tkAdornment)
var c = p.tok[p.idx + 1].symbol[0]
@@ -1172,7 +1178,7 @@ proc parseOverline(p: var TRstParser): PRstNode =
inc(p.idx, 2)
result = newRstNode(rnOverline)
while true:
parseLine(p, result)
parseUntilNewline(p, result)
if p.tok[p.idx].kind == tkIndent:
inc(p.idx)
if p.tok[p.idx - 1].ival > currInd(p):

View File

@@ -81,6 +81,8 @@ else:
## A type representing a directory stream.
type
TSocketHandle* = distinct cint # The type used to represent socket descriptors
Tdirent* {.importc: "struct dirent",
header: "<dirent.h>", final, pure.} = object ## dirent_t struct
d_ino*: TIno ## File serial number.
@@ -1791,7 +1793,7 @@ proc dlopen*(a1: cstring, a2: cint): pointer {.importc, header: "<dlfcn.h>".}
proc dlsym*(a1: pointer, a2: cstring): pointer {.importc, header: "<dlfcn.h>".}
proc creat*(a1: cstring, a2: Tmode): cint {.importc, header: "<fcntl.h>".}
proc fcntl*(a1: cint, a2: cint): cint {.varargs, importc, header: "<fcntl.h>".}
proc fcntl*(a1: cint | TSocketHandle, a2: cint): cint {.varargs, importc, header: "<fcntl.h>".}
proc open*(a1: cstring, a2: cint): cint {.varargs, importc, header: "<fcntl.h>".}
proc posix_fadvise*(a1: cint, a2, a3: Toff, a4: cint): cint {.
importc, header: "<fcntl.h>".}
@@ -2068,7 +2070,7 @@ proc access*(a1: cstring, a2: cint): cint {.importc, header: "<unistd.h>".}
proc alarm*(a1: cint): cint {.importc, header: "<unistd.h>".}
proc chdir*(a1: cstring): cint {.importc, header: "<unistd.h>".}
proc chown*(a1: cstring, a2: Tuid, a3: Tgid): cint {.importc, header: "<unistd.h>".}
proc close*(a1: cint): cint {.importc, header: "<unistd.h>".}
proc close*(a1: cint | TSocketHandle): cint {.importc, header: "<unistd.h>".}
proc confstr*(a1: cint, a2: cstring, a3: int): int {.importc, header: "<unistd.h>".}
proc crypt*(a1, a2: cstring): cstring {.importc, header: "<unistd.h>".}
proc ctermid*(a1: cstring): cstring {.importc, header: "<unistd.h>".}
@@ -2346,9 +2348,9 @@ proc strerror*(errnum: cint): cstring {.importc, header: "<string.h>".}
proc hstrerror*(herrnum: cint): cstring {.importc, header: "<netdb.h>".}
proc FD_CLR*(a1: cint, a2: var Tfd_set) {.importc, header: "<sys/select.h>".}
proc FD_ISSET*(a1: cint, a2: var Tfd_set): cint {.
proc FD_ISSET*(a1: cint | TSocketHandle, a2: var Tfd_set): cint {.
importc, header: "<sys/select.h>".}
proc FD_SET*(a1: cint, a2: var Tfd_set) {.importc, header: "<sys/select.h>".}
proc FD_SET*(a1: cint | TSocketHandle, a2: var Tfd_set) {.importc, header: "<sys/select.h>".}
proc FD_ZERO*(a1: var Tfd_set) {.importc, header: "<sys/select.h>".}
proc pselect*(a1: cint, a2, a3, a4: ptr Tfd_set, a5: ptr ttimespec,
@@ -2428,44 +2430,49 @@ proc CMSG_NXTHDR*(mhdr: ptr TMsgHdr, cmsg: ptr TCMsgHdr): ptr TCmsgHdr {.
proc CMSG_FIRSTHDR*(mhdr: ptr TMsgHdr): ptr TCMsgHdr {.
importc, header: "<sys/socket.h>".}
proc accept*(a1: cint, a2: ptr Tsockaddr, a3: ptr Tsocklen): cint {.
const
INVALID_SOCKET* = TSocketHandle(-1)
proc `==`*(x, y: TSocketHandle): bool {.borrow.}
proc accept*(a1: TSocketHandle, a2: ptr Tsockaddr, a3: ptr Tsocklen): TSocketHandle {.
importc, header: "<sys/socket.h>".}
proc bindSocket*(a1: cint, a2: ptr Tsockaddr, a3: Tsocklen): cint {.
proc bindSocket*(a1: TSocketHandle, a2: ptr Tsockaddr, a3: Tsocklen): cint {.
importc: "bind", header: "<sys/socket.h>".}
## is Posix's ``bind``, because ``bind`` is a reserved word
proc connect*(a1: cint, a2: ptr Tsockaddr, a3: Tsocklen): cint {.
proc connect*(a1: TSocketHandle, a2: ptr Tsockaddr, a3: Tsocklen): cint {.
importc, header: "<sys/socket.h>".}
proc getpeername*(a1: cint, a2: ptr Tsockaddr, a3: ptr Tsocklen): cint {.
proc getpeername*(a1: TSocketHandle, a2: ptr Tsockaddr, a3: ptr Tsocklen): cint {.
importc, header: "<sys/socket.h>".}
proc getsockname*(a1: cint, a2: ptr Tsockaddr, a3: ptr Tsocklen): cint {.
proc getsockname*(a1: TSocketHandle, a2: ptr Tsockaddr, a3: ptr Tsocklen): cint {.
importc, header: "<sys/socket.h>".}
proc getsockopt*(a1, a2, a3: cint, a4: pointer, a5: ptr Tsocklen): cint {.
proc getsockopt*(a1: TSocketHandle, a2, a3: cint, a4: pointer, a5: ptr Tsocklen): cint {.
importc, header: "<sys/socket.h>".}
proc listen*(a1, a2: cint): cint {.
proc listen*(a1: TSocketHandle, a2: cint): cint {.
importc, header: "<sys/socket.h>".}
proc recv*(a1: cint, a2: pointer, a3: int, a4: cint): int {.
proc recv*(a1: TSocketHandle, a2: pointer, a3: int, a4: cint): int {.
importc, header: "<sys/socket.h>".}
proc recvfrom*(a1: cint, a2: pointer, a3: int, a4: cint,
proc recvfrom*(a1: TSocketHandle, a2: pointer, a3: int, a4: cint,
a5: ptr Tsockaddr, a6: ptr Tsocklen): int {.
importc, header: "<sys/socket.h>".}
proc recvmsg*(a1: cint, a2: ptr Tmsghdr, a3: cint): int {.
proc recvmsg*(a1: TSocketHandle, a2: ptr Tmsghdr, a3: cint): int {.
importc, header: "<sys/socket.h>".}
proc send*(a1: cint, a2: pointer, a3: int, a4: cint): int {.
proc send*(a1: TSocketHandle, a2: pointer, a3: int, a4: cint): int {.
importc, header: "<sys/socket.h>".}
proc sendmsg*(a1: cint, a2: ptr Tmsghdr, a3: cint): int {.
proc sendmsg*(a1: TSocketHandle, a2: ptr Tmsghdr, a3: cint): int {.
importc, header: "<sys/socket.h>".}
proc sendto*(a1: cint, a2: pointer, a3: int, a4: cint, a5: ptr Tsockaddr,
proc sendto*(a1: TSocketHandle, a2: pointer, a3: int, a4: cint, a5: ptr Tsockaddr,
a6: Tsocklen): int {.
importc, header: "<sys/socket.h>".}
proc setsockopt*(a1, a2, a3: cint, a4: pointer, a5: Tsocklen): cint {.
proc setsockopt*(a1: TSocketHandle, a2, a3: cint, a4: pointer, a5: Tsocklen): cint {.
importc, header: "<sys/socket.h>".}
proc shutdown*(a1, a2: cint): cint {.
proc shutdown*(a1: TSocketHandle, a2: cint): cint {.
importc, header: "<sys/socket.h>".}
proc socket*(a1, a2, a3: cint): cint {.
proc socket*(a1, a2, a3: cint): TSocketHandle {.
importc, header: "<sys/socket.h>".}
proc sockatmark*(a1: cint): cint {.
importc, header: "<sys/socket.h>".}

View File

@@ -89,13 +89,13 @@ import sockets, os
## getSocket(s).accept(client)
when defined(windows):
from winlean import TTimeVal, TFdSet, FD_ZERO, FD_SET, FD_ISSET, select
from winlean import TTimeVal, TSocketHandle, TFdSet, FD_ZERO, FD_SET, FD_ISSET, select
else:
from posix import TTimeVal, TFdSet, FD_ZERO, FD_SET, FD_ISSET, select
from posix import TTimeVal, TSocketHandle, TFdSet, FD_ZERO, FD_SET, FD_ISSET, select
type
TDelegate* = object
fd*: cint
fd*: TSocketHandle
deleVal*: PObject
handleRead*: proc (h: PObject) {.nimcall.}
@@ -213,6 +213,7 @@ proc asyncSockHandleRead(h: PObject) =
else:
PAsyncSocket(h).handleAccept(PAsyncSocket(h))
proc close*(sock: PAsyncSocket)
proc asyncSockHandleWrite(h: PObject) =
when defined(ssl):
if PAsyncSocket(h).socket.isSSL and not
@@ -230,15 +231,19 @@ proc asyncSockHandleWrite(h: PObject) =
else:
if PAsyncSocket(h).sendBuffer != "":
let sock = PAsyncSocket(h)
let bytesSent = sock.socket.sendAsync(sock.sendBuffer)
assert bytesSent > 0
if bytesSent != sock.sendBuffer.len:
sock.sendBuffer = sock.sendBuffer[bytesSent .. -1]
elif bytesSent == sock.sendBuffer.len:
sock.sendBuffer = ""
if PAsyncSocket(h).handleWrite != nil:
PAsyncSocket(h).handleWrite(PAsyncSocket(h))
try:
let bytesSent = sock.socket.sendAsync(sock.sendBuffer)
assert bytesSent > 0
if bytesSent != sock.sendBuffer.len:
sock.sendBuffer = sock.sendBuffer[bytesSent .. -1]
elif bytesSent == sock.sendBuffer.len:
sock.sendBuffer = ""
if PAsyncSocket(h).handleWrite != nil:
PAsyncSocket(h).handleWrite(PAsyncSocket(h))
except EOS:
# Most likely the socket closed before the full buffer could be sent to it.
sock.close() # TODO: Provide a handleError for users?
else:
if PAsyncSocket(h).handleWrite != nil:
PAsyncSocket(h).handleWrite(PAsyncSocket(h))

View File

@@ -1,117 +1,127 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements a base64 encoder and decoder.
const
cb64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
proc encode*(s: string, lineLen = 75, newLine="\13\10"): string =
## encodes `s` into base64 representation. After `lineLen` characters, a
## `newline` is added.
var total = ((len(s) + 2) div 3) * 4
var numLines = (total + lineLen - 1) div lineLen
#
#
# Nimrod's Runtime Library
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements a base64 encoder and decoder.
const
cb64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
template encodeInternal(s: expr, lineLen: int, newLine: string): stmt {.immediate.} =
## encodes `s` into base64 representation. After `lineLen` characters, a
## `newline` is added.
var total = ((len(s) + 2) div 3) * 4
var numLines = (total + lineLen - 1) div lineLen
if numLines > 0: inc(total, (numLines-1) * newLine.len)
result = newString(total)
var i = 0
var r = 0
var currLine = 0
while i < s.len - 2:
var a = ord(s[i])
var b = ord(s[i+1])
var c = ord(s[i+2])
result[r] = cb64[a shr 2]
result[r+1] = cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
result[r+2] = cb64[((b and 0x0F) shl 2) or ((c and 0xC0) shr 6)]
result[r+3] = cb64[c and 0x3F]
inc(r, 4)
inc(i, 3)
inc(currLine, 4)
if currLine >= lineLen and i != s.len-2:
for x in items(newLine):
result[r] = x
inc(r)
currLine = 0
if i < s.len-1:
var a = ord(s[i])
var b = ord(s[i+1])
result[r] = cb64[a shr 2]
result[r+1] = cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
result[r+2] = cb64[((b and 0x0F) shl 2)]
result[r+3] = '='
if r+4 != result.len:
setLen(result, r+4)
elif i < s.len:
var a = ord(s[i])
result[r] = cb64[a shr 2]
result[r+1] = cb64[(a and 3) shl 4]
result[r+2] = '='
result[r+3] = '='
if r+4 != result.len:
setLen(result, r+4)
else:
assert(r == result.len)
proc decodeByte(b: char): int {.inline.} =
case b
of '+': result = ord('>')
of '0'..'9': result = ord(b) + 4
of 'A'..'Z': result = ord(b) - ord('A')
of 'a'..'z': result = ord(b) - 71
else: result = 63
proc decode*(s: string): string =
## decodes a string in base64 representation back into its original form.
## Whitespace is skipped.
const Whitespace = {' ', '\t', '\v', '\r', '\l', '\f'}
var total = ((len(s) + 3) div 4) * 3
# total is an upper bound, as we will skip arbitrary whitespace:
result = newString(total)
var i = 0
var r = 0
while true:
while s[i] in Whitespace: inc(i)
if i < s.len-3:
var a = s[i].decodeByte
var b = s[i+1].decodeByte
var c = s[i+2].decodeByte
var d = s[i+3].decodeByte
result[r] = chr((a shl 2) and 0xff or ((b shr 4) and 0x03))
result[r+1] = chr((b shl 4) and 0xff or ((c shr 2) and 0x0F))
result[r+2] = chr((c shl 6) and 0xff or (d and 0x3F))
inc(r, 3)
inc(i, 4)
else: break
assert i == s.len
# adjust the length:
if i > 0 and s[i-1] == '=':
dec(r)
if i > 1 and s[i-2] == '=': dec(r)
setLen(result, r)
when isMainModule:
assert encode("leasure.") == "bGVhc3VyZS4="
assert encode("easure.") == "ZWFzdXJlLg=="
assert encode("asure.") == "YXN1cmUu"
assert encode("sure.") == "c3VyZS4="
const longText = """Man is distinguished, not only by his reason, but by this
singular passion from other animals, which is a lust of the mind,
that by a perseverance of delight in the continued and indefatigable
generation of knowledge, exceeds the short vehemence of any carnal
pleasure."""
const tests = ["", "abc", "xyz", "man", "leasure.", "sure.", "easure.",
"asure.", longText]
for t in items(tests):
assert decode(encode(t)) == t
result = newString(total)
var i = 0
var r = 0
var currLine = 0
while i < s.len - 2:
var a = ord(s[i])
var b = ord(s[i+1])
var c = ord(s[i+2])
result[r] = cb64[a shr 2]
result[r+1] = cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
result[r+2] = cb64[((b and 0x0F) shl 2) or ((c and 0xC0) shr 6)]
result[r+3] = cb64[c and 0x3F]
inc(r, 4)
inc(i, 3)
inc(currLine, 4)
if currLine >= lineLen and i != s.len-2:
for x in items(newLine):
result[r] = x
inc(r)
currLine = 0
if i < s.len-1:
var a = ord(s[i])
var b = ord(s[i+1])
result[r] = cb64[a shr 2]
result[r+1] = cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
result[r+2] = cb64[((b and 0x0F) shl 2)]
result[r+3] = '='
if r+4 != result.len:
setLen(result, r+4)
elif i < s.len:
var a = ord(s[i])
result[r] = cb64[a shr 2]
result[r+1] = cb64[(a and 3) shl 4]
result[r+2] = '='
result[r+3] = '='
if r+4 != result.len:
setLen(result, r+4)
else:
assert(r == result.len)
proc encode*[T:TInteger|char](s: openarray[T], lineLen = 75, newLine="\13\10"): string =
## encodes `s` into base64 representation. After `lineLen` characters, a
## `newline` is added.
encodeInternal(s, lineLen, newLine)
proc encode*(s: string, lineLen = 75, newLine="\13\10"): string =
## encodes `s` into base64 representation. After `lineLen` characters, a
## `newline` is added.
encodeInternal(s, lineLen, newLine)
proc decodeByte(b: char): int {.inline.} =
case b
of '+': result = ord('>')
of '0'..'9': result = ord(b) + 4
of 'A'..'Z': result = ord(b) - ord('A')
of 'a'..'z': result = ord(b) - 71
else: result = 63
proc decode*(s: string): string =
## decodes a string in base64 representation back into its original form.
## Whitespace is skipped.
const Whitespace = {' ', '\t', '\v', '\r', '\l', '\f'}
var total = ((len(s) + 3) div 4) * 3
# total is an upper bound, as we will skip arbitrary whitespace:
result = newString(total)
var i = 0
var r = 0
while true:
while s[i] in Whitespace: inc(i)
if i < s.len-3:
var a = s[i].decodeByte
var b = s[i+1].decodeByte
var c = s[i+2].decodeByte
var d = s[i+3].decodeByte
result[r] = chr((a shl 2) and 0xff or ((b shr 4) and 0x03))
result[r+1] = chr((b shl 4) and 0xff or ((c shr 2) and 0x0F))
result[r+2] = chr((c shl 6) and 0xff or (d and 0x3F))
inc(r, 3)
inc(i, 4)
else: break
assert i == s.len
# adjust the length:
if i > 0 and s[i-1] == '=':
dec(r)
if i > 1 and s[i-2] == '=': dec(r)
setLen(result, r)
when isMainModule:
assert encode("leasure.") == "bGVhc3VyZS4="
assert encode("easure.") == "ZWFzdXJlLg=="
assert encode("asure.") == "YXN1cmUu"
assert encode("sure.") == "c3VyZS4="
const longText = """Man is distinguished, not only by his reason, but by this
singular passion from other animals, which is a lust of the mind,
that by a perseverance of delight in the continued and indefatigable
generation of knowledge, exceeds the short vehemence of any carnal
pleasure."""
const tests = ["", "abc", "xyz", "man", "leasure.", "sure.", "easure.",
"asure.", longText]
for t in items(tests):
assert decode(encode(t)) == t

View File

@@ -0,0 +1,581 @@
#nimrod c -t:-march=i686 --cpu:amd64 --threads:on -d:release lockfreehash.nim
import baseutils, unsigned, math, hashes
const
minTableSize = 8
reProbeLimit = 12
minCopyWork = 4096
intSize = sizeof(int)
when sizeof(int) == 4: # 32bit
type
TRaw = range[0..1073741823]
## The range of uint values that can be stored directly in a value slot
## when on a 32 bit platform
elif sizeof(int) == 8: # 64bit
type
TRaw = range[0..4611686018427387903]
## The range of uint values that can be stored directly in a value slot
## when on a 64 bit platform
else: echo("unsupported platform")
type
TEntry = tuple
key: int
value: int
TEntryArr = ptr array[0..10_000_000, TEntry]
PConcTable[K,V] = ptr object {.pure.}
len: int
used: int
active: int
copyIdx: int
copyDone: int
next: PConcTable[K,V]
data: TEntryArr
proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int,
expVal: int, match: bool): int
#------------------------------------------------------------------------------
# Create a new table
proc newLFTable*[K,V](size: int = minTableSize): PConcTable[K,V] =
let
dataLen = max(nextPowerOfTwo(size), minTableSize)
dataSize = dataLen*sizeof(TEntry)
dataMem = allocShared0(dataSize)
tableSize = 7 * intSize
tableMem = allocShared0(tableSize)
table = cast[PConcTable[K,V]](tableMem)
table.len = dataLen
table.used = 0
table.active = 0
table.copyIdx = 0
table.copyDone = 0
table.next = nil
table.data = cast[TEntryArr](dataMem)
result = table
#------------------------------------------------------------------------------
# Delete a table
proc deleteConcTable[K,V](tbl: PConcTable[K,V]) =
deallocShared(tbl.data)
deallocShared(tbl)
#------------------------------------------------------------------------------
proc `[]`[K,V](table: var PConcTable[K,V], i: int): var TEntry {.inline.} =
table.data[i]
#------------------------------------------------------------------------------
# State flags stored in ptr
proc pack[T](x: T): int {.inline.} =
result = (cast[int](x) shl 2)
#echo("packKey ",cast[int](x) , " -> ", result)
# Pop the flags off returning a 4 byte aligned ptr to our Key or Val
proc pop(x: int): int {.inline.} =
result = x and 0xFFFFFFFC'i32
# Pop the raw value off of our Key or Val
proc popRaw(x: int): int {.inline.} =
result = x shr 2
# Pop the flags off returning a 4 byte aligned ptr to our Key or Val
proc popPtr[V](x: int): ptr V {.inline.} =
result = cast[ptr V](pop(x))
#echo("popPtr " & $x & " -> " & $cast[int](result))
# Ghost (sentinel)
# K or V is no longer valid use new table
const Ghost = 0xFFFFFFFC
proc isGhost(x: int): bool {.inline.} =
result = x == 0xFFFFFFFC
# Tombstone
# applied to V = K is dead
proc isTomb(x: int): bool {.inline.} =
result = (x and 0x00000002) != 0
proc setTomb(x: int): int {.inline.} =
result = x or 0x00000002
# Prime
# K or V is in new table copied from old
proc isPrime(x: int): bool {.inline.} =
result = (x and 0x00000001) != 0
proc setPrime(x: int): int {.inline.} =
result = x or 0x00000001
#------------------------------------------------------------------------------
##This is for i32 only need to override for i64
proc hashInt(x: int):int {.inline.} =
var h = uint32(x) #shr 2'u32
h = h xor (h shr 16'u32)
h *= 0x85ebca6b'u32
h = h xor (h shr 13'u32)
h *= 0xc2b2ae35'u32
h = h xor (h shr 16'u32)
result = int(h)
#------------------------------------------------------------------------------
proc resize[K,V](self: PConcTable[K,V]): PConcTable[K,V] =
var next = atomic_load_n(self.next.addr, ATOMIC_RELAXED)
#echo("next = " & $cast[int](next))
if next != nil:
#echo("A new table already exists, copy in progress")
return next
var
oldLen = atomic_load_n(self.len.addr, ATOMIC_RELAXED)
newTable = newLFTable[K,V](oldLen*2)
success = atomic_compare_exchange_n(self.next.addr, next.addr, newTable,
false, ATOMIC_RELAXED, ATOMIC_RELAXED)
if not success:
echo("someone beat us to it! delete table we just created and return his " & $cast[int](next))
deleteConcTable(newTable)
return next
else:
echo("Created New Table! " & $cast[int](newTable) & " Size = " & $newTable.len)
return newTable
#------------------------------------------------------------------------------
#proc keyEQ[K](key1: ptr K, key2: ptr K): bool {.inline.} =
proc keyEQ[K](key1: int, key2: int): bool {.inline.} =
result = false
when K is TRaw:
if key1 == key2:
result = true
else:
var
p1 = popPtr[K](key1)
p2 = popPtr[K](key2)
if p1 != nil and p2 != nil:
if cast[int](p1) == cast[int](p2):
return true
if p1[] == p2[]:
return true
#------------------------------------------------------------------------------
#proc tableFull(self: var PConcTable[K,V]) : bool {.inline.} =
#------------------------------------------------------------------------------
proc copySlot[K,V](idx: int, oldTbl: var PConcTable[K,V], newTbl: var PConcTable[K,V]): bool =
#echo("Copy idx " & $idx)
var
oldVal = 0
oldkey = 0
ok = false
result = false
#Block the key so no other threads waste time here
while not ok:
ok = atomic_compare_exchange_n(oldTbl[idx].key.addr, oldKey.addr,
setTomb(oldKey), false, ATOMIC_RELAXED, ATOMIC_RELAXED)
#echo("oldKey was = " & $oldKey & " set it to tomb " & $setTomb(oldKey))
#Prevent new values from appearing in the old table by priming
oldVal = atomic_load_n(oldTbl[idx].value.addr, ATOMIC_RELAXED)
while not isPrime(oldVal):
var box = if oldVal == NULL or isTomb(oldVal) : oldVal.setTomb.setPrime
else: oldVal.setPrime
if atomic_compare_exchange_n(oldTbl[idx].value.addr, oldVal.addr,
box, false, ATOMIC_RELAXED, ATOMIC_RELAXED):
if isPrime(box) and isTomb(box):
return true
oldVal = box
break
#echo("oldVal was = ", oldVal, " set it to prime ", box)
if isPrime(oldVal) and isTomb(oldVal):
#when not (K is TRaw):
# deallocShared(popPtr[K](oldKey))
return false
if isTomb(oldVal):
echo("oldVal is Tomb!!!, should not happen")
if pop(oldVal) != NULL:
result = setVal(newTbl, pop(oldKey), pop(oldVal), NULL, true) == NULL
if result:
#echo("Copied a Slot! idx= " & $idx & " key= " & $oldKey & " val= " & $oldVal)
else:
#echo("copy slot failed")
# Our copy is done so we disable the old slot
while not ok:
ok = atomic_compare_exchange_n(oldTbl[idx].value.addr, oldVal.addr,
oldVal.setTomb.setPrime , false, ATOMIC_RELAXED, ATOMIC_RELAXED)
#echo("disabled old slot")
#echo"---------------------"
#------------------------------------------------------------------------------
proc promote[K,V](table: var PConcTable[K,V]) =
var
newData = atomic_load_n(table.next.data.addr, ATOMIC_RELAXED)
newLen = atomic_load_n(table.next.len.addr, ATOMIC_RELAXED)
newUsed = atomic_load_n(table.next.used.addr, ATOMIC_RELAXED)
deallocShared(table.data)
atomic_store_n(table.data.addr, newData, ATOMIC_RELAXED)
atomic_store_n(table.len.addr, newLen, ATOMIC_RELAXED)
atomic_store_n(table.used.addr, newUsed, ATOMIC_RELAXED)
atomic_store_n(table.copyIdx.addr, 0, ATOMIC_RELAXED)
atomic_store_n(table.copyDone.addr, 0, ATOMIC_RELAXED)
deallocShared(table.next)
atomic_store_n(table.next.addr, nil, ATOMIC_RELAXED)
echo("new table swapped!")
#------------------------------------------------------------------------------
proc checkAndPromote[K,V](table: var PConcTable[K,V], workDone: int): bool =
var
oldLen = atomic_load_n(table.len.addr, ATOMIC_RELAXED)
copyDone = atomic_load_n(table.copyDone.addr, ATOMIC_RELAXED)
ok: bool
result = false
if workDone > 0:
#echo("len to copy =" & $oldLen)
#echo("copyDone + workDone = " & $copyDone & " + " & $workDone)
while not ok:
ok = atomic_compare_exchange_n(table.copyDone.addr, copyDone.addr,
copyDone + workDone, false, ATOMIC_RELAXED, ATOMIC_RELAXED)
#if ok: echo("set copyDone")
# If the copy is done we can promote this table
if copyDone + workDone >= oldLen:
# Swap new data
#echo("work is done!")
table.promote
result = true
#------------------------------------------------------------------------------
proc copySlotAndCheck[K,V](table: var PConcTable[K,V], idx: int):
PConcTable[K,V] =
var
newTable = cast[PConcTable[K,V]](atomic_load_n(table.next.addr, ATOMIC_RELAXED))
result = newTable
if newTable != nil and copySlot(idx, table, newTable):
#echo("copied a single slot, idx = " & $idx)
if checkAndPromote(table, 1): return table
#------------------------------------------------------------------------------
proc helpCopy[K,V](table: var PConcTable[K,V]): PConcTable[K,V] =
var
newTable = cast[PConcTable[K,V]](atomic_load_n(table.next.addr, ATOMIC_RELAXED))
result = newTable
if newTable != nil:
var
oldLen = atomic_load_n(table.len.addr, ATOMIC_RELAXED)
copyDone = atomic_load_n(table.copyDone.addr, ATOMIC_RELAXED)
copyIdx = 0
work = min(oldLen, minCopyWork)
#panicStart = -1
workDone = 0
if copyDone < oldLen:
var ok: bool
while not ok:
ok = atomic_compare_exchange_n(table.copyIdx.addr, copyIdx.addr,
copyIdx + work, false, ATOMIC_RELAXED, ATOMIC_RELAXED)
#echo("copy idx = ", copyIdx)
for i in 0..work-1:
var idx = (copyIdx + i) and (oldLen - 1)
if copySlot(idx, table, newTable):
workDone += 1
if workDone > 0:
#echo("did work ", workDone, " on thread ", cast[int](myThreadID[pointer]()))
if checkAndPromote(table, workDone): return table
# In case a thread finished all the work then got stalled before promotion
if checkAndPromote(table, 0): return table
#------------------------------------------------------------------------------
proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int,
expVal: int, match: bool): int =
#echo("-try set- in table ", " key = ", (popPtr[K](key)[]), " val = ", val)
when K is TRaw:
var idx = hashInt(key)
else:
var idx = popPtr[K](key)[].hash
var
nextTable: PConcTable[K,V]
probes = 1
# spin until we find a key slot or build and jump to next table
while true:
idx = idx and (table.len - 1)
#echo("try set idx = " & $idx & "for" & $key)
var
probedKey = NULL
openKey = atomic_compare_exchange_n(table[idx].key.addr, probedKey.addr,
key, false, ATOMIC_RELAXED, ATOMIC_RELAXED)
if openKey:
if val.isTomb:
#echo("val was tomb, bail, no reason to set an open slot to tomb")
return val
#increment used slots
#echo("found an open slot, total used = " &
#$atomic_add_fetch(table.used.addr, 1, ATOMIC_RELAXED))
discard atomic_add_fetch(table.used.addr, 1, ATOMIC_RELAXED)
break # We found an open slot
#echo("set idx ", idx, " key = ", key, " probed = ", probedKey)
if keyEQ[K](probedKey, key):
#echo("we found the matching slot")
break # We found a matching slot
if (not(expVal != NULL and match)) and (probes >= reProbeLimit or key.isTomb):
if key.isTomb: echo("Key is Tombstone")
#if probes >= reProbeLimit: echo("Too much probing " & $probes)
#echo("try to resize")
#create next bigger table
nextTable = resize(table)
#help do some copying
#echo("help copy old table to new")
nextTable = helpCopy(table)
#now setVal in the new table instead
#echo("jumping to next table to set val")
return setVal(nextTable, key, val, expVal, match)
else:
idx += 1
probes += 1
# Done spinning for a new slot
var oldVal = atomic_load_n(table[idx].value.addr, ATOMIC_RELAXED)
if val == oldVal:
#echo("this val is alredy in the slot")
return oldVal
nextTable = atomic_load_n(table.next.addr, ATOMIC_SEQ_CST)
if nextTable == nil and
((oldVal == NULL and
(probes >= reProbeLimit or table.used / table.len > 0.8)) or
(isPrime(oldVal))):
if table.used / table.len > 0.8: echo("resize because usage ratio = " &
$(table.used / table.len))
if isPrime(oldVal): echo("old val isPrime, should be a rare mem ordering event")
nextTable = resize(table)
if nextTable != nil:
#echo("tomb old slot then set in new table")
nextTable = copySlotAndCheck(table,idx)
return setVal(nextTable, key, val, expVal, match)
# Finaly ready to add new val to table
while true:
if match and oldVal != expVal:
#echo("set failed, no match oldVal= " & $oldVal & " expVal= " & $expVal)
return oldVal
if atomic_compare_exchange_n(table[idx].value.addr, oldVal.addr,
val, false, ATOMIC_RELEASE, ATOMIC_RELAXED):
#echo("val set at table " & $cast[int](table))
if expVal != NULL:
if (oldVal == NULL or isTomb(oldVal)) and not isTomb(val):
discard atomic_add_fetch(table.active.addr, 1, ATOMIC_RELAXED)
elif not (oldVal == NULL or isTomb(oldVal)) and isTomb(val):
discard atomic_add_fetch(table.active.addr, -1, ATOMIC_RELAXED)
if oldVal == NULL and expVal != NULL:
return setTomb(oldVal)
else: return oldVal
if isPrime(oldVal):
nextTable = copySlotAndCheck(table, idx)
return setVal(nextTable, key, val, expVal, match)
#------------------------------------------------------------------------------
proc getVal[K,V](table: var PConcTable[K,V], key: int): int =
#echo("-try get- key = " & $key)
when K is TRaw:
var idx = hashInt(key)
else:
var idx = popPtr[K](key)[].hash
#echo("get idx ", idx)
var
probes = 0
val: int
while true:
idx = idx and (table.len - 1)
var
newTable: PConcTable[K,V] # = atomic_load_n(table.next.addr, ATOMIC_ACQUIRE)
probedKey = atomic_load_n(table[idx].key.addr, ATOMIC_SEQ_CST)
if keyEQ[K](probedKey, key):
#echo("found key after ", probes+1)
val = atomic_load_n(table[idx].value.addr, ATOMIC_ACQUIRE)
if not isPrime(val):
if isTomb(val):
#echo("val was tomb but not prime")
return NULL
else:
#echo("-GotIt- idx = ", idx, " key = ", key, " val ", val )
return val
else:
newTable = copySlotAndCheck(table, idx)
return getVal(newTable, key)
else:
#echo("probe ", probes, " idx = ", idx, " key = ", key, " found ", probedKey )
if probes >= reProbeLimit*4 or key.isTomb:
if newTable == nil:
#echo("too many probes and no new table ", key, " ", idx )
return NULL
else:
newTable = helpCopy(table)
return getVal(newTable, key)
idx += 1
probes += 1
#------------------------------------------------------------------------------
#proc set*(table: var PConcTable[TRaw,TRaw], key: TRaw, val: TRaw) =
# discard setVal(table, pack(key), pack(key), NULL, false)
#proc set*[V](table: var PConcTable[TRaw,V], key: TRaw, val: ptr V) =
# discard setVal(table, pack(key), cast[int](val), NULL, false)
proc set*[K,V](table: var PConcTable[K,V], key: var K, val: var V) =
when not (K is TRaw):
var newKey = cast[int](copyShared(key))
else:
var newKey = pack(key)
when not (V is TRaw):
var newVal = cast[int](copyShared(val))
else:
var newVal = pack(val)
var oldPtr = pop(setVal(table, newKey, newVal, NULL, false))
#echo("oldPtr = ", cast[int](oldPtr), " newPtr = ", cast[int](newPtr))
when not (V is TRaw):
if newVal != oldPtr and oldPtr != NULL:
deallocShared(cast[ptr V](oldPtr))
proc get*[K,V](table: var PConcTable[K,V], key: var K): V =
when not (V is TRaw):
when not (K is TRaw):
return popPtr[V](getVal(table, cast[int](key.addr)))[]
else:
return popPtr[V](getVal(table, pack(key)))[]
else:
when not (K is TRaw):
return popRaw(getVal(table, cast[int](key.addr)))
else:
return popRaw(getVal(table, pack(key)))
#proc `[]`[K,V](table: var PConcTable[K,V], key: K): PEntry[K,V] {.inline.} =
# getVal(table, key)
#proc `[]=`[K,V](table: var PConcTable[K,V], key: K, val: V): PEntry[K,V] {.inline.} =
# setVal(table, key, val)
#Tests ----------------------------
when isMainModule:
import locks, times, mersenne
const
numTests = 100000
numThreads = 10
type
TTestObj = tuple
thr: int
f0: int
f1: int
TData = tuple[k: string,v: TTestObj]
PDataArr = array[0..numTests-1, TData]
Dict = PConcTable[string,TTestObj]
var
thr: array[0..numThreads-1, TThread[Dict]]
table = newLFTable[string,TTestObj](8)
rand = newMersenneTwister(2525)
proc createSampleData(len: int): PDataArr =
#result = cast[PDataArr](allocShared0(sizeof(TData)*numTests))
for i in 0..len-1:
result[i].k = "mark" & $(i+1)
#echo("mark" & $(i+1), " ", hash("mark" & $(i+1)))
result[i].v.thr = 0
result[i].v.f0 = i+1
result[i].v.f1 = 0
#echo("key = " & $(i+1) & " Val ptr = " & $cast[int](result[i].v.addr))
proc threadProc(tp: Dict) {.thread.} =
var t = cpuTime();
for i in 1..numTests:
var key = "mark" & $(i)
var got = table.get(key)
got.thr = cast[int](myThreadID[pointer]())
got.f1 = got.f1 + 1
table.set(key, got)
t = cpuTime() - t
echo t
var testData = createSampleData(numTests)
for i in 0..numTests-1:
table.set(testData[i].k, testData[i].v)
var i = 0
while i < numThreads:
createThread(thr[i], threadProc, table)
i += 1
joinThreads(thr)
var fails = 0
for i in 0..numTests-1:
var got = table.get(testData[i].k)
if got.f0 != i+1 or got.f1 != numThreads:
fails += 1
echo(got)
echo("Failed read or write = ", fails)
#for i in 1..numTests:
# echo(i, " = ", hashInt(i) and 8191)
deleteConcTable(table)

View File

@@ -0,0 +1,41 @@
#------------------------------------------------------------------------------
## Useful Constants
const NULL* = 0
#------------------------------------------------------------------------------
## Memory Utility Functions
proc newHeap*[T](): ptr T =
result = cast[ptr T](alloc0(sizeof(T)))
proc copyNew*[T](x: var T): ptr T =
var
size = sizeof(T)
mem = alloc(size)
copyMem(mem, x.addr, size)
return cast[ptr T](mem)
proc copyTo*[T](val: var T, dest: int) =
copyMem(pointer(dest), val.addr, sizeof(T))
proc allocType*[T](): pointer = alloc(sizeof(T))
proc newShared*[T](): ptr T =
result = cast[ptr T](allocShared0(sizeof(T)))
proc copyShared*[T](x: var T): ptr T =
var
size = sizeof(T)
mem = allocShared(size)
copyMem(mem, x.addr, size)
return cast[ptr T](mem)
#------------------------------------------------------------------------------
## Pointer arithmetic
proc `+`*(p: pointer, i: int): pointer {.inline.} =
cast[pointer](cast[int](p) + i)

View File

@@ -117,6 +117,57 @@ proc filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): seq[T] =
## assert f2 == @["yellow"]
accumulateResult(filter(seq1, pred))
proc delete*[T](s: var seq[T], first=0, last=0) =
## Deletes in `s` the items at position `first` .. `last`. This modifies
## `s` itself, it does not return a copy.
##
## Example:
##
##.. code-block:: nimrod
## let outcome = @[1,1,1,1,1,1,1,1]
## var dest = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
## dest.delete(3, 8)
## assert outcome == dest
var i = first
var j = last+1
var newLen = len(s)-j+i
while i < newLen:
s[i].shallowCopy(s[j])
inc(i)
inc(j)
setlen(s, newLen)
proc insert*[T](dest: var seq[T], src: openArray[T], pos=0) =
## Inserts items from `src` into `dest` at position `pos`. This modifies
## `dest` itself, it does not return a copy.
##
## Example:
##
##.. code-block:: nimrod
## var dest = @[1,1,1,1,1,1,1,1]
## let
## src = @[2,2,2,2,2,2]
## outcome = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
## dest.insert(src, 3)
## assert dest == outcome
var j = len(dest) - 1
var i = len(dest) + len(src) - 1
dest.setLen(i + 1)
# Move items after `pos` to the end of the sequence.
while j >= pos:
dest[i].shallowCopy(dest[j])
dec(i)
dec(j)
# Insert items from `dest` into `dest` at `pos`
inc(j)
for item in src:
dest[j] = item
inc(j)
template filterIt*(seq1, pred: expr): expr {.immediate.} =
## Returns a new sequence with all the items that fulfilled the predicate.
##
@@ -312,4 +363,22 @@ when isMainModule:
assert multiplication == 495, "Multiplication is (5*(9*(11)))"
assert concatenation == "nimrodiscool"
block: # delete tests
let outcome = @[1,1,1,1,1,1,1,1]
var dest = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
dest.delete(3, 8)
assert outcome == dest, """\
Deleting range 3-9 from [1,1,1,2,2,2,2,2,2,1,1,1,1,1]
is [1,1,1,1,1,1,1,1]"""
block: # insert tests
var dest = @[1,1,1,1,1,1,1,1]
let
src = @[2,2,2,2,2,2]
outcome = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
dest.insert(src, 3)
assert dest == outcome, """\
Inserting [2,2,2,2,2,2] into [1,1,1,1,1,1,1,1]
at 3 is [1,1,1,2,2,2,2,2,2,1,1,1,1,1]"""
echo "Finished doc tests"

View File

@@ -129,7 +129,8 @@ proc expectReply(ftp: PFTPClient): TaintedString =
proc send*(ftp: PFTPClient, m: string): TaintedString =
## Send a message to the server, and wait for a primary reply.
## ``\c\L`` is added for you.
ftp.getCSock().send(m & "\c\L")
blockingOperation(ftp.getCSock()):
ftp.getCSock().send(m & "\c\L")
return ftp.expectReply()
proc assertReply(received: TaintedString, expected: string) =

View File

@@ -224,11 +224,13 @@ type
TAsyncHTTPServer = object of TServer
asyncSocket: PAsyncSocket
proc open*(s: var TServer, port = TPort(80)) =
proc open*(s: var TServer, port = TPort(80), reuseAddr = false) =
## creates a new server at port `port`. If ``port == 0`` a free port is
## acquired that can be accessed later by the ``port`` proc.
s.socket = socket(AF_INET)
if s.socket == InvalidSocket: OSError(OSLastError())
if reuseAddr:
s.socket.setSockOpt(OptReuseAddr, True)
bindAddr(s.socket, port)
listen(s.socket)
@@ -399,8 +401,9 @@ proc nextAsync(s: PAsyncHTTPServer) =
var value = ""
i = header.parseUntil(key, ':')
inc(i) # skip :
i += header.skipWhiteSpace(i)
i += header.parseUntil(value, {'\c', '\L'}, i)
if i < header.len:
i += header.skipWhiteSpace(i)
i += header.parseUntil(value, {'\c', '\L'}, i)
s.headers[key] = value
else:
s.client.close()
@@ -475,7 +478,8 @@ proc nextAsync(s: PAsyncHTTPServer) =
proc asyncHTTPServer*(handleRequest: proc (server: PAsyncHTTPServer, client: TSocket,
path, query: string): bool {.closure.},
port = TPort(80), address = ""): PAsyncHTTPServer =
port = TPort(80), address = "",
reuseAddr = false): PAsyncHTTPServer =
## Creates an Asynchronous HTTP server at ``port``.
var capturedRet: PAsyncHTTPServer
new(capturedRet)
@@ -486,6 +490,8 @@ proc asyncHTTPServer*(handleRequest: proc (server: PAsyncHTTPServer, client: TSo
let quit = handleRequest(capturedRet, capturedRet.client, capturedRet.path,
capturedRet.query)
if quit: capturedRet.asyncSocket.close()
if reuseAddr:
capturedRet.asyncSocket.setSockOpt(OptReuseAddr, True)
capturedRet.asyncSocket.bindAddr(port, address)
capturedRet.asyncSocket.listen()

View File

@@ -98,6 +98,7 @@ type
params*: seq[string] ## Parameters of the IRC message
origin*: string ## The channel/user that this msg originated from
raw*: string ## Raw IRC message
timestamp*: TTime ## UNIX epoch time the message was received
proc send*(irc: PIRC, message: string, sendImmediately = false) =
## Sends ``message`` as a raw command. It adds ``\c\L`` for you.
@@ -160,9 +161,10 @@ proc isNumber(s: string): bool =
result = i == s.len and s.len > 0
proc parseMessage(msg: string): TIRCEvent =
result.typ = EvMsg
result.cmd = MUnknown
result.raw = msg
result.typ = EvMsg
result.cmd = MUnknown
result.raw = msg
result.timestamp = times.getTime()
var i = 0
# Process the prefix
if msg[i] == ':':

39
lib/pure/mersenne.nim Normal file
View File

@@ -0,0 +1,39 @@
import unsigned
type
TMersenneTwister* = object
mt: array[0..623, uint32]
index: int
proc newMersenneTwister*(seed: int): TMersenneTwister =
result.index = 0
result.mt[0]= uint32(seed)
for i in 1..623'u32:
result.mt[i]= (0x6c078965'u32 * (result.mt[i-1] xor (result.mt[i-1] shr 30'u32)) + i)
proc generateNumbers(m: var TMersenneTwister) =
for i in 0..623:
var y = (m.mt[i] and 0x80000000'u32) + (m.mt[(i+1) mod 624] and 0x7fffffff'u32)
m.mt[i] = m.mt[(i+397) mod 624] xor uint32(y shr 1'u32)
if (y mod 2'u32) != 0:
m.mt[i] = m.mt[i] xor 0x9908b0df'u32
proc getNum*(m: var TMersenneTwister): int =
if m.index == 0:
generateNumbers(m)
var y = m.mt[m.index]
y = y xor (y shr 11'u32)
y = y xor ((7'u32 shl y) and 0x9d2c5680'u32)
y = y xor ((15'u32 shl y) and 0xefc60000'u32)
y = y xor (y shr 18'u32)
m.index = (m.index+1) mod 624
return int(y)
# Test
when isMainModule:
var mt = newMersenneTwister(2525)
for i in 0..99:
echo mt.getNum

View File

@@ -1,7 +1,7 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -52,6 +52,10 @@ proc oidToString*(oid: TOid, str: cstring) =
inc(i)
str[24] = '\0'
proc `$`*(oid: TOid): string =
result = newString(25)
oidToString(oid, result)
var
incr: int
fuzz: int32

View File

@@ -24,10 +24,10 @@ type
TProcess = object of TObject
when defined(windows):
FProcessHandle: Thandle
inputHandle, outputHandle, errorHandle: TFileHandle
inHandle, outHandle, errHandle: TFileHandle
id: THandle
else:
inputHandle, outputHandle, errorHandle: TFileHandle
inHandle, outHandle, errHandle: TFileHandle
inStream, outStream, errStream: PStream
id: TPid
exitCode: cint
@@ -113,23 +113,47 @@ proc peekExitCode*(p: PProcess): int {.tags: [].}
## return -1 if the process is still running. Otherwise the process' exit code
proc inputStream*(p: PProcess): PStream {.rtl, extern: "nosp$1", tags: [].}
## returns ``p``'s input stream for writing to
## returns ``p``'s input stream for writing to.
##
## **Warning**: The returned `PStream` should not be closed manually as it
## is closed when closing the PProcess ``p``.
proc outputStream*(p: PProcess): PStream {.rtl, extern: "nosp$1", tags: [].}
## returns ``p``'s output stream for reading from
## returns ``p``'s output stream for reading from.
##
## **Warning**: The returned `PStream` should not be closed manually as it
## is closed when closing the PProcess ``p``.
proc errorStream*(p: PProcess): PStream {.rtl, extern: "nosp$1", tags: [].}
## returns ``p``'s output stream for reading from
## returns ``p``'s error stream for reading from.
##
## **Warning**: The returned `PStream` should not be closed manually as it
## is closed when closing the PProcess ``p``.
proc inputHandle*(p: PProcess): TFileHandle {.rtl, extern: "nosp$1",
tags: [].} =
## returns ``p``'s input file handle for writing to.
##
## **Warning**: The returned `TFileHandle` should not be closed manually as
## it is closed when closing the PProcess ``p``.
result = p.inHandle
proc outputHandle*(p: PProcess): TFileHandle {.rtl, extern: "nosp$1",
tags: [].} =
## returns ``p``'s output file handle for reading from.
##
## **Warning**: The returned `TFileHandle` should not be closed manually as
## it is closed when closing the PProcess ``p``.
result = p.outHandle
proc errorHandle*(p: PProcess): TFileHandle {.rtl, extern: "nosp$1",
tags: [].} =
## returns ``p``'s error file handle for reading from.
##
## **Warning**: The returned `TFileHandle` should not be closed manually as
## it is closed when closing the PProcess ``p``.
result = p.errHandle
when defined(macosx) or defined(bsd):
const
CTL_HW = 6
@@ -212,8 +236,8 @@ proc execProcesses*(cmds: openArray[string],
inc(i)
if i > high(cmds): break
for j in 0..m-1:
if q[j] != nil: close(q[j])
result = max(waitForExit(q[j]), result)
if q[j] != nil: close(q[j])
else:
for i in 0..high(cmds):
var p = startCmd(cmds[i], options=options)
@@ -339,16 +363,16 @@ when defined(Windows) and not defined(useNimRtl):
HE = HO
else:
CreatePipeHandles(HE, Si.hStdError)
result.inputHandle = TFileHandle(hi)
result.outputHandle = TFileHandle(ho)
result.errorHandle = TFileHandle(he)
result.inHandle = TFileHandle(hi)
result.outHandle = TFileHandle(ho)
result.errHandle = TFileHandle(he)
else:
SI.hStdError = GetStdHandle(STD_ERROR_HANDLE)
SI.hStdInput = GetStdHandle(STD_INPUT_HANDLE)
SI.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE)
result.inputHandle = TFileHandle(si.hStdInput)
result.outputHandle = TFileHandle(si.hStdOutput)
result.errorHandle = TFileHandle(si.hStdError)
result.inHandle = TFileHandle(si.hStdInput)
result.outHandle = TFileHandle(si.hStdOutput)
result.errHandle = TFileHandle(si.hStdError)
var cmdl: cstring
when false: # poUseShell in options:
@@ -389,9 +413,9 @@ when defined(Windows) and not defined(useNimRtl):
proc close(p: PProcess) =
when false:
# somehow this does not work on Windows:
discard CloseHandle(p.inputHandle)
discard CloseHandle(p.outputHandle)
discard CloseHandle(p.errorHandle)
discard CloseHandle(p.inHandle)
discard CloseHandle(p.outHandle)
discard CloseHandle(p.errHandle)
discard CloseHandle(p.FProcessHandle)
proc suspend(p: PProcess) =
@@ -425,13 +449,13 @@ when defined(Windows) and not defined(useNimRtl):
return res
proc inputStream(p: PProcess): PStream =
result = newFileHandleStream(p.inputHandle)
result = newFileHandleStream(p.inHandle)
proc outputStream(p: PProcess): PStream =
result = newFileHandleStream(p.outputHandle)
result = newFileHandleStream(p.outHandle)
proc errorStream(p: PProcess): PStream =
result = newFileHandleStream(p.errorHandle)
result = newFileHandleStream(p.errHandle)
proc execCmd(command: string): int =
var
@@ -626,20 +650,20 @@ elif not defined(useNimRtl):
if poParentStreams in options:
# does not make much sense, but better than nothing:
result.inputHandle = 0
result.outputHandle = 1
result.inHandle = 0
result.outHandle = 1
if poStdErrToStdOut in options:
result.errorHandle = result.outputHandle
result.errHandle = result.outHandle
else:
result.errorHandle = 2
result.errHandle = 2
else:
result.inputHandle = p_stdin[writeIdx]
result.outputHandle = p_stdout[readIdx]
result.inHandle = p_stdin[writeIdx]
result.outHandle = p_stdout[readIdx]
if poStdErrToStdOut in options:
result.errorHandle = result.outputHandle
result.errHandle = result.outHandle
discard close(p_stderr[readIdx])
else:
result.errorHandle = p_stderr[readIdx]
result.errHandle = p_stderr[readIdx]
discard close(p_stderr[writeIdx])
discard close(p_stdin[readIdx])
discard close(p_stdout[writeIdx])
@@ -648,9 +672,9 @@ elif not defined(useNimRtl):
if p.inStream != nil: close(p.inStream)
if p.outStream != nil: close(p.outStream)
if p.errStream != nil: close(p.errStream)
discard close(p.inputHandle)
discard close(p.outputHandle)
discard close(p.errorHandle)
discard close(p.inHandle)
discard close(p.outHandle)
discard close(p.errHandle)
proc suspend(p: PProcess) =
if kill(-p.id, SIGSTOP) != 0'i32: OSError(OSLastError())
@@ -696,17 +720,17 @@ elif not defined(useNimRtl):
proc inputStream(p: PProcess): PStream =
if p.inStream == nil:
createStream(p.inStream, p.inputHandle, fmWrite)
createStream(p.inStream, p.inHandle, fmWrite)
return p.inStream
proc outputStream(p: PProcess): PStream =
if p.outStream == nil:
createStream(p.outStream, p.outputHandle, fmRead)
createStream(p.outStream, p.outHandle, fmRead)
return p.outStream
proc errorStream(p: PProcess): PStream =
if p.errStream == nil:
createStream(p.errStream, p.errorHandle, fmRead)
createStream(p.errStream, p.errHandle, fmRead)
return p.errStream
proc csystem(cmd: cstring): cint {.nodecl, importc: "system".}
@@ -717,14 +741,14 @@ elif not defined(useNimRtl):
proc createFdSet(fd: var TFdSet, s: seq[PProcess], m: var int) =
FD_ZERO(fd)
for i in items(s):
m = max(m, int(i.outputHandle))
FD_SET(cint(i.outputHandle), fd)
m = max(m, int(i.outHandle))
FD_SET(cint(i.outHandle), fd)
proc pruneProcessSet(s: var seq[PProcess], fd: var TFdSet) =
var i = 0
var L = s.len
while i < L:
if FD_ISSET(cint(s[i].outputHandle), fd) != 0'i32:
if FD_ISSET(cint(s[i].outHandle), fd) != 0'i32:
s[i] = s[L-1]
dec(L)
else:

View File

@@ -95,7 +95,8 @@ proc recvBuffer(s: var TScgiState, L: int) =
scgiError("could not read all data")
setLen(s.input, L)
proc open*(s: var TScgiState, port = TPort(4000), address = "127.0.0.1") =
proc open*(s: var TScgiState, port = TPort(4000), address = "127.0.0.1",
reuseAddr = False) =
## opens a connection.
s.bufLen = 4000
s.input = newString(s.buflen) # will be reused
@@ -104,6 +105,8 @@ proc open*(s: var TScgiState, port = TPort(4000), address = "127.0.0.1") =
new(s.client) # Initialise s.client for `next`
if s.server == InvalidSocket: scgiError("could not open socket")
#s.server.connect(connectionName, port)
if reuseAddr:
s.server.setSockOpt(OptReuseAddr, True)
bindAddr(s.server, port, address)
listen(s.server)
@@ -243,7 +246,8 @@ proc handleAccept(sock: PAsyncSocket, s: PAsyncScgiState) =
proc open*(handleRequest: proc (client: PAsyncSocket,
input: string, headers: PStringTable) {.closure.},
port = TPort(4000), address = "127.0.0.1"): PAsyncScgiState =
port = TPort(4000), address = "127.0.0.1",
reuseAddr = false): PAsyncScgiState =
## Creates an ``PAsyncScgiState`` object which serves as a SCGI server.
##
## After the execution of ``handleRequest`` the client socket will be closed
@@ -252,6 +256,8 @@ proc open*(handleRequest: proc (client: PAsyncSocket,
new(cres)
cres.asyncServer = AsyncSocket()
cres.asyncServer.handleAccept = proc (s: PAsyncSocket) = handleAccept(s, cres)
if reuseAddr:
cres.asyncServer.setSockOpt(OptReuseAddr, True)
bindAddr(cres.asyncServer, port, address)
listen(cres.asyncServer)
cres.handleRequest = handleRequest

View File

@@ -31,6 +31,7 @@ when hostos == "solaris":
import os, parseutils
from times import epochTime
import unsigned
when defined(ssl):
import openssl
@@ -62,7 +63,7 @@ const
type
TSocketImpl = object ## socket type
fd: cint
fd: TSocketHandle
case isBuffered: bool # determines whether this socket is buffered.
of true:
buffer: array[0..BufferSize, char]
@@ -82,7 +83,7 @@ type
TSocket* = ref TSocketImpl
TPort* = distinct int16 ## port type
TPort* = distinct uint16 ## port type
TDomain* = enum ## domain, which specifies the protocol family of the
## created socket. Other domains than those that are listed
@@ -118,6 +119,10 @@ type
length*: int
addrList*: seq[string]
TSOBool* = enum ## Boolean socket options.
OptAcceptConn, OptBroadcast, OptDebug, OptDontRoute, OptKeepAlive,
OptOOBInline, OptReuseAddr
TRecvLineResult* = enum ## result for recvLineAsync
RecvFullLine, RecvPartialLine, RecvDisconnected, RecvFail
@@ -126,7 +131,19 @@ type
ETimeout* = object of ESynch
proc newTSocket(fd: int32, isBuff: bool): TSocket =
let
InvalidSocket*: TSocket = nil ## invalid socket
when defined(windows):
let
OSInvalidSocket = winlean.INVALID_SOCKET
else:
let
OSInvalidSocket = posix.INVALID_SOCKET
proc newTSocket(fd: TSocketHandle, isBuff: bool): TSocket =
if fd == OSInvalidSocket:
return nil
new(result)
result.fd = fd
result.isBuffered = isBuff
@@ -134,15 +151,11 @@ proc newTSocket(fd: int32, isBuff: bool): TSocket =
result.currPos = 0
result.nonblocking = false
let
InvalidSocket*: TSocket = nil ## invalid socket
proc `==`*(a, b: TPort): bool {.borrow.}
## ``==`` for ports.
proc `$`*(p: TPort): string =
proc `$`*(p: TPort): string {.borrow.}
## returns the port number as a string
result = $ze(int16(p))
proc ntohl*(x: int32): int32 =
## Converts 32-bit integers from network to host byte order.
@@ -211,7 +224,9 @@ else:
proc socket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
protocol: TProtocol = IPPROTO_TCP, buffered = true): TSocket =
## Creates a new socket; returns `InvalidSocket` if an error occurs.
## Creates a new socket; returns `InvalidSocket` if an error occurs.
# TODO: Perhaps this should just raise EOS when an error occurs.
when defined(Windows):
result = newTSocket(winlean.socket(ord(domain), ord(typ), ord(protocol)), buffered)
else:
@@ -456,7 +471,7 @@ template acceptAddrPlain(noClientRet, successRet: expr,
var sock = accept(server.fd, cast[ptr TSockAddr](addr(sockAddress)),
addr(addrLen))
if sock < 0:
if sock == OSInvalidSocket:
let err = OSLastError()
when defined(windows):
if err.int32 == WSAEINPROGRESS:
@@ -529,7 +544,7 @@ proc acceptAddr*(server: TSocket, client: var TSocket, address: var string) {.
SSLError("Unknown error")
proc setBlocking*(s: TSocket, blocking: bool) {.tags: [].}
## sets blocking mode on socket
## Sets blocking mode on socket
when defined(ssl):
proc acceptAddrSSL*(server: TSocket, client: var TSocket,
@@ -623,24 +638,32 @@ proc close*(socket: TSocket) =
discard SSLShutdown(socket.sslHandle)
proc getServByName*(name, proto: string): TServent {.tags: [FReadIO].} =
## well-known getservbyname proc.
## Searches the database from the beginning and finds the first entry for
## which the service name specified by ``name`` matches the s_name member
## and the protocol name specified by ``proto`` matches the s_proto member.
##
## On posix this will search through the ``/etc/services`` file.
when defined(Windows):
var s = winlean.getservbyname(name, proto)
else:
var s = posix.getservbyname(name, proto)
if s == nil: OSError(OSLastError())
if s == nil: raise newException(EOS, "Service not found.")
result.name = $s.s_name
result.aliases = cstringArrayToSeq(s.s_aliases)
result.port = TPort(s.s_port)
result.proto = $s.s_proto
proc getServByPort*(port: TPort, proto: string): TServent {.tags: [FReadIO].} =
## well-known getservbyport proc.
## Searches the database from the beginning and finds the first entry for
## which the port specified by ``port`` matches the s_port member and the
## protocol name specified by ``proto`` matches the s_proto member.
##
## On posix this will search through the ``/etc/services`` file.
when defined(Windows):
var s = winlean.getservbyport(ze(int16(port)).cint, proto)
else:
var s = posix.getservbyport(ze(int16(port)).cint, proto)
if s == nil: OSError(OSLastError())
if s == nil: raise newException(EOS, "Service not found.")
result.name = $s.s_name
result.aliases = cstringArrayToSeq(s.s_aliases)
result.port = TPort(s.s_port)
@@ -676,7 +699,7 @@ proc getHostByAddr*(ip: string): THostEnt {.tags: [FReadIO].} =
result.length = int(s.h_length)
proc getHostByName*(name: string): THostEnt {.tags: [FReadIO].} =
## well-known gethostbyname proc.
## This function will lookup the IP address of a hostname.
when defined(Windows):
var s = winlean.gethostbyname(name)
else:
@@ -714,6 +737,34 @@ proc setSockOptInt*(socket: TSocket, level, optname, optval: int) {.
sizeof(value).TSockLen) < 0'i32:
OSError(OSLastError())
proc toCInt(opt: TSOBool): cint =
case opt
of OptAcceptConn: SO_ACCEPTCONN
of OptBroadcast: SO_BROADCAST
of OptDebug: SO_DEBUG
of OptDontRoute: SO_DONTROUTE
of OptKeepAlive: SO_KEEPALIVE
of OptOOBInline: SO_OOBINLINE
of OptReuseAddr: SO_REUSEADDR
proc getSockOpt*(socket: TSocket, opt: TSOBool, level = SOL_SOCKET): bool {.
tags: [FReadIO].} =
## Retrieves option ``opt`` as a boolean value.
var res: cint
var size = sizeof(res).TSockLen
if getsockopt(socket.fd, cint(level), toCInt(opt),
addr(res), addr(size)) < 0'i32:
OSError(OSLastError())
result = res != 0
proc setSockOpt*(socket: TSocket, opt: TSOBool, value: bool, level = SOL_SOCKET) {.
tags: [FWriteIO].} =
## Sets option ``opt`` to a boolean value specified by ``value``.
var valuei = cint(if value: 1 else: 0)
if setsockopt(socket.fd, cint(level), toCInt(opt), addr(valuei),
sizeof(valuei).TSockLen) < 0'i32:
OSError(OSLastError())
proc connect*(socket: TSocket, address: string, port = TPort(0),
af: TDomain = AF_INET) {.tags: [FReadIO].} =
## Connects socket to ``address``:``port``. ``Address`` can be an IP address or a
@@ -866,11 +917,6 @@ proc timeValFromMilliseconds(timeout = 500): TTimeVal =
var seconds = timeout div 1000
result.tv_sec = seconds.int32
result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
#proc recvfrom*(s: TWinSocket, buf: cstring, len, flags: cint,
# fromm: ptr TSockAddr, fromlen: ptr cint): cint
#proc sendto*(s: TWinSocket, buf: cstring, len, flags: cint,
# to: ptr TSockAddr, tolen: cint): cint
proc createFdSet(fd: var TFdSet, s: seq[TSocket], m: var int) =
FD_ZERO(fd)
@@ -1608,14 +1654,14 @@ when defined(Windows):
FIONBIO = IOC_IN.int32 or ((sizeof(int32) and IOCPARM_MASK) shl 16) or
(102 shl 8) or 126
proc ioctlsocket(s: TWinSocket, cmd: clong,
proc ioctlsocket(s: TSocketHandle, cmd: clong,
argptr: ptr clong): cint {.
stdcall, importc:"ioctlsocket", dynlib: "ws2_32.dll".}
proc setBlocking(s: TSocket, blocking: bool) =
when defined(Windows):
var mode = clong(ord(not blocking)) # 1 for non-blocking, 0 for blocking
if ioctlsocket(TWinSocket(s.fd), FIONBIO, addr(mode)) == -1:
if ioctlsocket(TSocketHandle(s.fd), FIONBIO, addr(mode)) == -1:
OSError(OSLastError())
else: # BSD sockets
var x: int = fcntl(s.fd, F_GETFL, 0)
@@ -1656,9 +1702,12 @@ proc connect*(socket: TSocket, address: string, port = TPort(0), timeout: int,
proc isSSL*(socket: TSocket): bool = return socket.isSSL
## Determines whether ``socket`` is a SSL socket.
proc getFD*(socket: TSocket): cint = return socket.fd
proc getFD*(socket: TSocket): TSocketHandle = return socket.fd
## Returns the socket's file descriptor
proc isBlocking*(socket: TSocket): bool = not socket.nonblocking
## Determines whether ``socket`` is blocking.
when defined(Windows):
var wsa: TWSADATA
if WSAStartup(0x0101'i16, addr wsa) != 0: OSError(OSLastError())

View File

@@ -246,7 +246,8 @@ proc toSeconds(a: TTimeInfo, interval: TTimeInterval): float =
else:
curMonth.inc()
result += float(newinterv.days * 24 * 60 * 60)
result += float(newinterv.minutes * 60 * 60)
result += float(newinterv.hours * 60 * 60)
result += float(newinterv.minutes * 60)
result += float(newinterv.seconds)
result += newinterv.miliseconds / 1000

View File

@@ -55,31 +55,31 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
result = TRune(ord(s[i]))
when doInc: inc(i)
elif ord(s[i]) shr 5 == 0b110:
assert(ord(s[i+1]) shr 6 == 0b10)
# assert(ord(s[i+1]) shr 6 == 0b10)
result = TRune((ord(s[i]) and (ones(5))) shl 6 or
(ord(s[i+1]) and ones(6)))
when doInc: inc(i, 2)
elif ord(s[i]) shr 4 == 0b1110:
assert(ord(s[i+1]) shr 6 == 0b10)
assert(ord(s[i+2]) shr 6 == 0b10)
# assert(ord(s[i+1]) shr 6 == 0b10)
# assert(ord(s[i+2]) shr 6 == 0b10)
result = TRune((ord(s[i]) and ones(4)) shl 12 or
(ord(s[i+1]) and ones(6)) shl 6 or
(ord(s[i+2]) and ones(6)))
when doInc: inc(i, 3)
elif ord(s[i]) shr 3 == 0b11110:
assert(ord(s[i+1]) shr 6 == 0b10)
assert(ord(s[i+2]) shr 6 == 0b10)
assert(ord(s[i+3]) shr 6 == 0b10)
# assert(ord(s[i+1]) shr 6 == 0b10)
# assert(ord(s[i+2]) shr 6 == 0b10)
# assert(ord(s[i+3]) shr 6 == 0b10)
result = TRune((ord(s[i]) and ones(3)) shl 18 or
(ord(s[i+1]) and ones(6)) shl 12 or
(ord(s[i+2]) and ones(6)) shl 6 or
(ord(s[i+3]) and ones(6)))
when doInc: inc(i, 4)
elif ord(s[i]) shr 2 == 0b111110:
assert(ord(s[i+1]) shr 6 == 0b10)
assert(ord(s[i+2]) shr 6 == 0b10)
assert(ord(s[i+3]) shr 6 == 0b10)
assert(ord(s[i+4]) shr 6 == 0b10)
# assert(ord(s[i+1]) shr 6 == 0b10)
# assert(ord(s[i+2]) shr 6 == 0b10)
# assert(ord(s[i+3]) shr 6 == 0b10)
# assert(ord(s[i+4]) shr 6 == 0b10)
result = TRune((ord(s[i]) and ones(2)) shl 24 or
(ord(s[i+1]) and ones(6)) shl 18 or
(ord(s[i+2]) and ones(6)) shl 12 or
@@ -87,11 +87,11 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
(ord(s[i+4]) and ones(6)))
when doInc: inc(i, 5)
elif ord(s[i]) shr 1 == 0b1111110:
assert(ord(s[i+1]) shr 6 == 0b10)
assert(ord(s[i+2]) shr 6 == 0b10)
assert(ord(s[i+3]) shr 6 == 0b10)
assert(ord(s[i+4]) shr 6 == 0b10)
assert(ord(s[i+5]) shr 6 == 0b10)
# assert(ord(s[i+1]) shr 6 == 0b10)
# assert(ord(s[i+2]) shr 6 == 0b10)
# assert(ord(s[i+3]) shr 6 == 0b10)
# assert(ord(s[i+4]) shr 6 == 0b10)
# assert(ord(s[i+5]) shr 6 == 0b10)
result = TRune((ord(s[i]) and ones(1)) shl 30 or
(ord(s[i+1]) and ones(6)) shl 24 or
(ord(s[i+2]) and ones(6)) shl 18 or

View File

@@ -849,7 +849,7 @@ const
## a string that describes the application type. Possible values:
## "console", "gui", "lib".
seqShallowFlag = 1 shl (sizeof(int)*8-1)
seqShallowFlag = low(int)
proc compileOption*(option: string): bool {.
magic: "CompileOption", noSideEffect.}
@@ -1795,7 +1795,7 @@ when defined(JS):
elif hostOS != "standalone":
{.push stack_trace:off, profiler:off.}
proc add*(x: var string, y: cstring) {.noStackFrame.} =
proc add*(x: var string, y: cstring) =
var i = 0
while y[i] != '\0':
add(x, y[i])

View File

@@ -520,11 +520,18 @@ proc allocInv(a: TMemRegion): bool =
for s in low(a.freeSmallChunks)..high(a.freeSmallChunks):
var c = a.freeSmallChunks[s]
while c != nil:
if c.next == c: return false
if c.size != s * MemAlign: return false
if c.next == c:
echo "[SYSASSERT] c.next == c"
return false
if c.size != s * MemAlign:
echo "[SYSASSERT] c.size != s * MemAlign"
return false
var it = c.freeList
while it != nil:
if it.zeroField != 0: return false
if it.zeroField != 0:
echo "[SYSASSERT] it.zeroField != 0"
cprintf("%ld %p\n", it.zeroField, it)
return false
it = it.next
c = c.next
result = true
@@ -591,6 +598,7 @@ proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer =
add(a, a.root, cast[TAddress](result), cast[TAddress](result)+%size)
sysAssert(isAccessible(a, result), "rawAlloc 14")
sysAssert(allocInv(a), "rawAlloc: end")
when logAlloc: cprintf("rawAlloc: %ld %p\n", requestedSize, result)
proc rawAlloc0(a: var TMemRegion, requestedSize: int): pointer =
result = rawAlloc(a, requestedSize)
@@ -638,6 +646,7 @@ proc rawDealloc(a: var TMemRegion, p: pointer) =
del(a, a.root, cast[int](addr(c.data)))
freeBigChunk(a, c)
sysAssert(allocInv(a), "rawDealloc: end")
when logAlloc: cprintf("rawDealloc: %p\n", p)
proc isAllocatedPtr(a: TMemRegion, p: pointer): bool =
if isAccessible(a, p):

View File

@@ -9,68 +9,207 @@
# Atomic operations for Nimrod.
when (defined(gcc) or defined(llvm_gcc)) and hasThreadSupport and
not defined(windows):
proc sync_add_and_fetch(p: var int, val: int): int {.
importc: "__sync_add_and_fetch", nodecl.}
proc sync_sub_and_fetch(p: var int, val: int): int {.
importc: "__sync_sub_and_fetch", nodecl.}
when (defined(gcc) or defined(llvm_gcc)) and hasThreadSupport:
type
AtomMemModel* = enum
ATOMIC_RELAXED,
## No barriers or synchronization.
ATOMIC_CONSUME,
## Data dependency only for both barrier and synchronization with another thread.
ATOMIC_ACQUIRE,
## Barrier to hoisting of code and synchronizes with release (or stronger)
## semantic stores from another thread.
ATOMIC_RELEASE,
## Barrier to sinking of code and synchronizes with acquire (or stronger)
## semantic loads from another thread.
ATOMIC_ACQ_REL,
## Full barrier in both directions and synchronizes with acquire loads
## and release stores in another thread.
ATOMIC_SEQ_CST
## Full barrier in both directions and synchronizes with acquire loads
## and release stores in all threads.
TAtomType* = TNumber|pointer|ptr|char
## Type Class representing valid types for use with atomic procs
proc atomic_load_n*[T: TAtomType](p: ptr T, mem: AtomMemModel): T {.
importc: "__atomic_load_n", nodecl.}
## This proc implements an atomic load operation. It returns the contents at p.
## ATOMIC_RELAXED, ATOMIC_SEQ_CST, ATOMIC_ACQUIRE, ATOMIC_CONSUME.
proc atomic_load*[T: TAtomType](p: ptr T, ret: ptr T, mem: AtomMemModel) {.
importc: "__atomic_load", nodecl.}
## This is the generic version of an atomic load. It returns the contents at p in ret.
proc atomic_store_n*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel) {.
importc: "__atomic_store_n", nodecl.}
## This proc implements an atomic store operation. It writes val at p.
## ATOMIC_RELAXED, ATOMIC_SEQ_CST, and ATOMIC_RELEASE.
proc atomic_store*[T: TAtomType](p: ptr T, val: ptr T, mem: AtomMemModel) {.
importc: "__atomic_store", nodecl.}
## This is the generic version of an atomic store. It stores the value of val at p
proc atomic_exchange_n*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_exchange_n", nodecl.}
## This proc implements an atomic exchange operation. It writes val at p,
## and returns the previous contents at p.
## ATOMIC_RELAXED, ATOMIC_SEQ_CST, ATOMIC_ACQUIRE, ATOMIC_RELEASE, ATOMIC_ACQ_REL
proc atomic_exchange*[T: TAtomType](p: ptr T, val: ptr T, ret: ptr T, mem: AtomMemModel) {.
importc: "__atomic_exchange", nodecl.}
## This is the generic version of an atomic exchange. It stores the contents at val at p.
## The original value at p is copied into ret.
proc atomic_compare_exchange_n*[T: TAtomType](p: ptr T, expected: ptr T, desired: T,
weak: bool, success_memmodel: AtomMemModel, failure_memmodel: AtomMemModel): bool {.
importc: "__atomic_compare_exchange_n ", nodecl.}
## This proc implements an atomic compare and exchange operation. This compares the
## contents at p with the contents at expected and if equal, writes desired at p.
## If they are not equal, the current contents at p is written into expected.
## Weak is true for weak compare_exchange, and false for the strong variation.
## Many targets only offer the strong variation and ignore the parameter.
## When in doubt, use the strong variation.
## True is returned if desired is written at p and the execution is considered
## to conform to the memory model specified by success_memmodel. There are no
## restrictions on what memory model can be used here. False is returned otherwise,
## and the execution is considered to conform to failure_memmodel. This memory model
## cannot be __ATOMIC_RELEASE nor __ATOMIC_ACQ_REL. It also cannot be a stronger model
## than that specified by success_memmodel.
proc atomic_compare_exchange*[T: TAtomType](p: ptr T, expected: ptr T, desired: ptr T,
weak: bool, success_memmodel: AtomMemModel, failure_memmodel: AtomMemModel): bool {.
importc: "__atomic_compare_exchange_n ", nodecl.}
## This proc implements the generic version of atomic_compare_exchange.
## The proc is virtually identical to atomic_compare_exchange_n, except the desired
## value is also a pointer.
## Perform the operation return the new value, all memory models are valid
proc atomic_add_fetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_add_fetch", nodecl.}
proc atomic_sub_fetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_sub_fetch", nodecl.}
proc atomic_or_fetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_or_fetch ", nodecl.}
proc atomic_and_fetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_and_fetch", nodecl.}
proc atomic_xor_fetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_xor_fetch", nodecl.}
proc atomic_nand_fetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_nand_fetch ", nodecl.}
## Perform the operation return the old value, all memory models are valid
proc atomic_fetch_add*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_add ", nodecl.}
proc atomic_fetch_sub*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_sub ", nodecl.}
proc atomic_fetch_or*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_or ", nodecl.}
proc atomic_fetch_and*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_and ", nodecl.}
proc atomic_fetch_xor*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_xor ", nodecl.}
proc atomic_fetch_nand*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_nand", nodecl.}
proc atomic_test_and_set*(p: pointer, mem: AtomMemModel): bool {.
importc: "__atomic_test_and_set ", nodecl.}
## This built-in function performs an atomic test-and-set operation on the byte at p.
## The byte is set to some implementation defined nonzero “set” value and the return
## value is true if and only if the previous contents were “set”.
## All memory models are valid.
proc atomic_clear*(p: pointer, mem: AtomMemModel) {.
importc: "__atomic_clear", nodecl.}
## This built-in function performs an atomic clear operation at p.
## After the operation, at p contains 0.
## ATOMIC_RELAXED, ATOMIC_SEQ_CST, ATOMIC_RELEASE
proc atomic_thread_fence*(mem: AtomMemModel) {.
importc: "__atomic_thread_fence ", nodecl.}
## This built-in function acts as a synchronization fence between threads based
## on the specified memory model. All memory orders are valid.
proc atomic_signal_fence*(mem: AtomMemModel) {.
importc: "__atomic_signal_fence ", nodecl.}
## This built-in function acts as a synchronization fence between a thread and
## signal handlers based in the same thread. All memory orders are valid.
proc atomic_always_lock_free*(size: int, p: pointer): bool {.
importc: "__atomic_always_lock_free ", nodecl.}
## This built-in function returns true if objects of size bytes always generate
## lock free atomic instructions for the target architecture. size must resolve
## to a compile-time constant and the result also resolves to a compile-time constant.
## ptr is an optional pointer to the object that may be used to determine alignment.
## A value of 0 indicates typical alignment should be used. The compiler may also
## ignore this parameter.
proc atomic_is_lock_free*(size: int, p: pointer): bool {.
importc: "__atomic_is_lock_free ", nodecl.}
## This built-in function returns true if objects of size bytes always generate
## lock free atomic instructions for the target architecture. If it is not known
## to be lock free a call is made to a runtime routine named __atomic_is_lock_free.
## ptr is an optional pointer to the object that may be used to determine alignment.
## A value of 0 indicates typical alignment should be used. The compiler may also
## ignore this parameter.
elif defined(vcc) and hasThreadSupport:
proc sync_add_and_fetch(p: var int, val: int): int {.
proc add_and_fetch*(p: ptr int, val: int): int {.
importc: "NimXadd", nodecl.}
else:
proc sync_add_and_fetch(p: var int, val: int): int {.inline.} =
inc(p, val)
result = p
proc add_and_fetch*(p: ptr int, val: int): int {.inline.} =
inc(p[], val)
result = p[]
proc atomicInc(memLoc: var int, x: int = 1): int =
when hasThreadSupport:
result = sync_add_and_fetch(memLoc, x)
# atomic compare and swap (CAS) funcitons to implement lock-free algorithms
#if defined(windows) and not defined(gcc) and hasThreadSupport:
# proc InterlockedCompareExchangePointer(mem: ptr pointer,
# newValue: pointer, comparand: pointer) : pointer {.nodecl,
# importc: "InterlockedCompareExchangePointer", header:"windows.h".}
# proc compareAndSwap*[T](mem: ptr T,
# expected: T, newValue: T): bool {.inline.}=
# ## Returns true if successfully set value at mem to newValue when value
# ## at mem == expected
# return InterlockedCompareExchangePointer(addr(mem),
# addr(newValue), addr(expected))[] == expected
#elif not hasThreadSupport:
# proc compareAndSwap*[T](mem: ptr T,
# expected: T, newValue: T): bool {.inline.} =
# ## Returns true if successfully set value at mem to newValue when value
# ## at mem == expected
# var oldval = mem[]
# if oldval == expected:
# mem[] = newValue
# return true
# return false
# Some convenient functions
proc atomicInc*(memLoc: var int, x: int = 1): int =
when defined(gcc) and hasThreadSupport:
result = atomic_add_fetch(memLoc.addr, x, ATOMIC_RELAXED)
else:
inc(memLoc, x)
result = memLoc
proc atomicDec(memLoc: var int, x: int = 1): int =
when hasThreadSupport:
when defined(sync_sub_and_fetch):
result = sync_sub_and_fetch(memLoc, x)
proc atomicDec*(memLoc: var int, x: int = 1): int =
when defined(gcc) and hasThreadSupport:
when defined(atomic_sub_fetch):
result = atomic_sub_fetch(memLoc.addr, x, ATOMIC_RELAXED)
else:
result = sync_add_and_fetch(memLoc, -x)
result = atomic_add_fetch(memLoc.addr, -x, ATOMIC_RELAXED)
else:
dec(memLoc, x)
result = memLoc
# atomic compare and swap (CAS) funcitons to implement lock-free algorithms
when (defined(gcc) or defined(llvm_gcc)) and hasThreadSupport:
proc compareAndSwap*[T: ptr|ref|pointer](mem: var T, expected: T, newValue: T): bool {.nodecl,
importc: " __sync_bool_compare_and_swap".}
## Returns true if successfully set value at mem to newValue when value
## at mem == expected
elif defined(windows) and hasThreadSupport:
proc InterlockedCompareExchangePointer(mem: ptr pointer,
newValue: pointer, comparand: pointer) : pointer {.nodecl,
importc: "InterlockedCompareExchangePointer", header:"windows.h".}
proc compareAndSwap*[T: ptr|ref|pointer](mem: var T,
expected: T, newValue: T): bool {.inline.}=
## Returns true if successfully set value at mem to newValue when value
## at mem == expected
return InterlockedCompareExchangePointer(addr(mem),
newValue, expected) == expected
elif not hasThreadSupport:
proc compareAndSwap*[T: ptr|ref|pointer](mem: var T,
expected: T, newValue: T): bool {.inline.} =
## Returns true if successfully set value at mem to newValue when value
## at mem == expected
var oldval = mem
if oldval == expected:
mem = newValue
return true
return false

View File

@@ -9,7 +9,7 @@
# Garbage Collector
#
# The basic algorithm is *Deferrent Reference Counting* with cycle detection.
# The basic algorithm is *Deferred Reference Counting* with cycle detection.
# This is achieved by combining a Deutsch-Bobrow garbage collector
# together with Christoper's partial mark-sweep garbage collector.
#
@@ -407,12 +407,17 @@ proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
return
add(gch.zct, res)
{.push stackTrace: off, profiler:off.}
proc gcInvariant*(msg: string) =
sysAssert(allocInv(gch.region), msg)
{.pop.}
proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer =
# generates a new object and sets its reference counter to 0
sysAssert(allocInv(gch.region), "rawNewObj begin")
acquire(gch)
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
collectCT(gch)
sysAssert(allocInv(gch.region), "rawNewObj begin")
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
gcAssert((cast[TAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
# now it is buffered in the ZCT
@@ -517,7 +522,9 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
writeCell("growObj new cell", res)
gcTrace(ol, csZctFreed)
gcTrace(res, csAllocated)
when reallyDealloc: rawDealloc(gch.region, ol)
when reallyDealloc:
sysAssert(allocInv(gch.region), "growObj before dealloc")
rawDealloc(gch.region, ol)
else:
sysAssert(ol.typ != nil, "growObj: 5")
zeroMem(ol, sizeof(TCell))
@@ -537,7 +544,9 @@ proc freeCyclicCell(gch: var TGcHeap, c: PCell) =
prepareDealloc(c)
gcTrace(c, csCycFreed)
when logGC: writeCell("cycle collector dealloc cell", c)
when reallyDealloc: rawDealloc(gch.region, c)
when reallyDealloc:
sysAssert(allocInv(gch.region), "free cyclic cell")
rawDealloc(gch.region, c)
else:
gcAssert(c.typ != nil, "freeCyclicCell")
zeroMem(c, sizeof(TCell))
@@ -910,7 +919,9 @@ proc collectZCT(gch: var TGcHeap): bool =
# access invalid memory. This is done by prepareDealloc():
prepareDealloc(c)
forAllChildren(c, waZctDecRef)
when reallyDealloc: rawDealloc(gch.region, c)
when reallyDealloc:
sysAssert(allocInv(gch.region), "collectZCT: rawDealloc")
rawDealloc(gch.region, c)
else:
sysAssert(c.typ != nil, "collectZCT 2")
zeroMem(c, sizeof(TCell))

View File

@@ -387,8 +387,7 @@ template `--`(rc: TRefCount): expr =
rc <% rcIncrement
template `--` (rc: TRefCount, heapType: THeapType): expr =
(when heapType == SharedHeap: atomicDec(rc, rcIncrement) <% rcIncrement
else: --rc)
(when heapType == SharedHeap: atomicDec(rc, rcIncrement) <% rcIncrement else: --rc)
template doDecRef(cc: PCell,
heapType = LocalHeap,

View File

@@ -28,6 +28,7 @@ const
reallyOsDealloc = true
coalescRight = true
coalescLeft = true
logAlloc = false
type
PPointer = ptr pointer

View File

@@ -334,6 +334,9 @@ const
proc WSAGetLastError*(): cint {.importc: "WSAGetLastError", dynlib: ws2dll.}
type
TSocketHandle* = distinct int
type
TWSAData* {.pure, final, importc: "WSADATA", header: "Winsock2.h".} = object
wVersion, wHighVersion: int16
@@ -389,12 +392,10 @@ type
h_addrtype*: int16
h_length*: int16
h_addr_list*: cstringArray
TWinSocket* = cint
TFdSet* {.pure, final.} = object
fd_count*: cint # unsigned
fd_array*: array[0..FD_SETSIZE-1, TWinSocket]
fd_array*: array[0..FD_SETSIZE-1, TSocketHandle]
TTimeval* {.pure, final.} = object
tv_sec*, tv_usec*: int32
@@ -413,6 +414,22 @@ type
var
SOMAXCONN* {.importc, header: "Winsock2.h".}: cint
INVALID_SOCKET* {.importc, header: "Winsock2.h".}: TSocketHandle
SOL_SOCKET* {.importc, header: "Winsock2.h".}: cint
SO_DEBUG* {.importc, header: "Winsock2.h".}: cint ## turn on debugging info recording
SO_ACCEPTCONN* {.importc, header: "Winsock2.h".}: cint # socket has had listen()
SO_REUSEADDR* {.importc, header: "Winsock2.h".}: cint # allow local address reuse
SO_KEEPALIVE* {.importc, header: "Winsock2.h".}: cint # keep connections alive
SO_DONTROUTE* {.importc, header: "Winsock2.h".}: cint # just use interface addresses
SO_BROADCAST* {.importc, header: "Winsock2.h".}: cint # permit sending of broadcast msgs
SO_USELOOPBACK* {.importc, header: "Winsock2.h".}: cint # bypass hardware when possible
SO_LINGER* {.importc, header: "Winsock2.h".}: cint # linger on close if data present
SO_OOBINLINE* {.importc, header: "Winsock2.h".}: cint # leave received OOB data in line
SO_DONTLINGER* {.importc, header: "Winsock2.h".}: cint
SO_EXCLUSIVEADDRUSE* {.importc, header: "Winsock2.h".}: cint # disallow local address reuse
proc `==`*(x, y: TSocketHandle): bool {.borrow.}
proc getservbyname*(name, proto: cstring): ptr TServent {.
stdcall, importc: "getservbyname", dynlib: ws2dll.}
@@ -426,45 +443,45 @@ proc gethostbyaddr*(ip: ptr TInAddr, len: cuint, theType: cint): ptr THostEnt {.
proc gethostbyname*(name: cstring): ptr THostEnt {.
stdcall, importc: "gethostbyname", dynlib: ws2dll.}
proc socket*(af, typ, protocol: cint): TWinSocket {.
proc socket*(af, typ, protocol: cint): TSocketHandle {.
stdcall, importc: "socket", dynlib: ws2dll.}
proc closesocket*(s: TWinSocket): cint {.
proc closesocket*(s: TSocketHandle): cint {.
stdcall, importc: "closesocket", dynlib: ws2dll.}
proc accept*(s: TWinSocket, a: ptr TSockAddr, addrlen: ptr TSockLen): TWinSocket {.
proc accept*(s: TSocketHandle, a: ptr TSockAddr, addrlen: ptr TSockLen): TSocketHandle {.
stdcall, importc: "accept", dynlib: ws2dll.}
proc bindSocket*(s: TWinSocket, name: ptr TSockAddr, namelen: TSockLen): cint {.
proc bindSocket*(s: TSocketHandle, name: ptr TSockAddr, namelen: TSockLen): cint {.
stdcall, importc: "bind", dynlib: ws2dll.}
proc connect*(s: TWinSocket, name: ptr TSockAddr, namelen: TSockLen): cint {.
proc connect*(s: TSocketHandle, name: ptr TSockAddr, namelen: TSockLen): cint {.
stdcall, importc: "connect", dynlib: ws2dll.}
proc getsockname*(s: TWinSocket, name: ptr TSockAddr,
proc getsockname*(s: TSocketHandle, name: ptr TSockAddr,
namelen: ptr TSockLen): cint {.
stdcall, importc: "getsockname", dynlib: ws2dll.}
proc getsockopt*(s: TWinSocket, level, optname: cint, optval: pointer,
proc getsockopt*(s: TSocketHandle, level, optname: cint, optval: pointer,
optlen: ptr TSockLen): cint {.
stdcall, importc: "getsockopt", dynlib: ws2dll.}
proc setsockopt*(s: TWinSocket, level, optname: cint, optval: pointer,
proc setsockopt*(s: TSocketHandle, level, optname: cint, optval: pointer,
optlen: TSockLen): cint {.
stdcall, importc: "setsockopt", dynlib: ws2dll.}
proc listen*(s: TWinSocket, backlog: cint): cint {.
proc listen*(s: TSocketHandle, backlog: cint): cint {.
stdcall, importc: "listen", dynlib: ws2dll.}
proc recv*(s: TWinSocket, buf: pointer, len, flags: cint): cint {.
proc recv*(s: TSocketHandle, buf: pointer, len, flags: cint): cint {.
stdcall, importc: "recv", dynlib: ws2dll.}
proc recvfrom*(s: TWinSocket, buf: cstring, len, flags: cint,
proc recvfrom*(s: TSocketHandle, buf: cstring, len, flags: cint,
fromm: ptr TSockAddr, fromlen: ptr Tsocklen): cint {.
stdcall, importc: "recvfrom", dynlib: ws2dll.}
proc select*(nfds: cint, readfds, writefds, exceptfds: ptr TFdSet,
timeout: ptr TTimeval): cint {.
stdcall, importc: "select", dynlib: ws2dll.}
proc send*(s: TWinSocket, buf: pointer, len, flags: cint): cint {.
proc send*(s: TSocketHandle, buf: pointer, len, flags: cint): cint {.
stdcall, importc: "send", dynlib: ws2dll.}
proc sendto*(s: TWinSocket, buf: pointer, len, flags: cint,
proc sendto*(s: TSocketHandle, buf: pointer, len, flags: cint,
to: ptr TSockAddr, tolen: Tsocklen): cint {.
stdcall, importc: "sendto", dynlib: ws2dll.}
proc shutdown*(s: TWinSocket, how: cint): cint {.
proc shutdown*(s: TSocketHandle, how: cint): cint {.
stdcall, importc: "shutdown", dynlib: ws2dll.}
proc getnameinfo*(a1: ptr Tsockaddr, a2: Tsocklen,
@@ -475,13 +492,13 @@ proc getnameinfo*(a1: ptr Tsockaddr, a2: Tsocklen,
proc inet_addr*(cp: cstring): int32 {.
stdcall, importc: "inet_addr", dynlib: ws2dll.}
proc WSAFDIsSet(s: TWinSocket, FDSet: var TFDSet): bool {.
proc WSAFDIsSet(s: TSocketHandle, FDSet: var TFDSet): bool {.
stdcall, importc: "__WSAFDIsSet", dynlib: ws2dll.}
proc FD_ISSET*(Socket: TWinSocket, FDSet: var TFDSet): cint =
proc FD_ISSET*(Socket: TSocketHandle, FDSet: var TFDSet): cint =
result = if WSAFDIsSet(Socket, FDSet): 1'i32 else: 0'i32
proc FD_SET*(Socket: TWinSocket, FDSet: var TFDSet) =
proc FD_SET*(Socket: TSocketHandle, FDSet: var TFDSet) =
if FDSet.fd_count < FD_SETSIZE:
FDSet.fd_array[int(FDSet.fd_count)] = Socket
inc(FDSet.fd_count)

View File

@@ -36,23 +36,23 @@ else:
const
dllname = "libGL.so"
const
GLX_USE_GL* = 1
GLX_BUFFER_SIZE* = 2
GLX_LEVEL* = 3
GLX_RGBA* = 4
GLX_DOUBLEBUFFER* = 5
GLX_STEREO* = 6
GLX_AUX_BUFFERS* = 7
GLX_RED_SIZE* = 8
GLX_GREEN_SIZE* = 9
GLX_BLUE_SIZE* = 10
GLX_ALPHA_SIZE* = 11
GLX_DEPTH_SIZE* = 12
GLX_STENCIL_SIZE* = 13
GLX_ACCUM_RED_SIZE* = 14
GLX_ACCUM_GREEN_SIZE* = 15
GLX_ACCUM_BLUE_SIZE* = 16
GLX_ACCUM_ALPHA_SIZE* = 17 # GLX_EXT_visual_info extension
GLX_USE_GL* = 1'i32
GLX_BUFFER_SIZE* = 2'i32
GLX_LEVEL* = 3'i32
GLX_RGBA* = 4'i32
GLX_DOUBLEBUFFER* = 5'i32
GLX_STEREO* = 6'i32
GLX_AUX_BUFFERS* = 7'i32
GLX_RED_SIZE* = 8'i32
GLX_GREEN_SIZE* = 9'i32
GLX_BLUE_SIZE* = 10'i32
GLX_ALPHA_SIZE* = 11'i32
GLX_DEPTH_SIZE* = 12'i32
GLX_STENCIL_SIZE* = 13'i32
GLX_ACCUM_RED_SIZE* = 14'i32
GLX_ACCUM_GREEN_SIZE* = 15'i32
GLX_ACCUM_BLUE_SIZE* = 16'i32
GLX_ACCUM_ALPHA_SIZE* = 17'i32 # GLX_EXT_visual_info extension
GLX_X_VISUAL_TYPE_EXT* = 0x00000022
GLX_TRANSPARENT_TYPE_EXT* = 0x00000023
GLX_TRANSPARENT_INDEX_VALUE_EXT* = 0x00000024

View File

@@ -45,6 +45,7 @@ when defined(WINDOWS):
const
DLLSSLName = "(ssleay32|libssl32).dll"
DLLUtilName = "libeay32.dll"
from winlean import TSocketHandle
else:
const
versions = "(|.1.0.0|.0.9.9|.0.9.8|.0.9.7|.0.9.6|.0.9.5|.0.9.4)"
@@ -56,6 +57,7 @@ else:
const
DLLSSLName = "libssl.so" & versions
DLLUtilName = "libcrypto.so" & versions
from posix import TSocketHandle
type
SslStruct {.final, pure.} = object
@@ -225,7 +227,7 @@ proc SSL_CTX_use_PrivateKey_file*(ctx: PSSL_CTX,
proc SSL_CTX_check_private_key*(ctx: PSSL_CTX): cInt{.cdecl, dynlib: DLLSSLName,
importc.}
proc SSL_set_fd*(ssl: PSSL, fd: cint): cint{.cdecl, dynlib: DLLSSLName, importc.}
proc SSL_set_fd*(ssl: PSSL, fd: TSocketHandle): cint{.cdecl, dynlib: DLLSSLName, importc.}
proc SSL_shutdown*(ssl: PSSL): cInt{.cdecl, dynlib: DLLSSLName, importc.}
proc SSL_connect*(ssl: PSSL): cint{.cdecl, dynlib: DLLSSLName, importc.}

File diff suppressed because it is too large Load Diff

View File

@@ -1811,210 +1811,217 @@ proc XSetAuthorization*(para1: cstring, para2: cint, para3: cstring, para4: cint
# _Xmbtowc?
# _Xwctomb?
#
when defined(MACROS):
proc ConnectionNumber*(dpy: PDisplay): cint
proc RootWindow*(dpy: PDisplay, scr: cint): TWindow
proc DefaultScreen*(dpy: PDisplay): cint
proc DefaultRootWindow*(dpy: PDisplay): TWindow
proc DefaultVisual*(dpy: PDisplay, scr: cint): PVisual
proc DefaultGC*(dpy: PDisplay, scr: cint): TGC
proc BlackPixel*(dpy: PDisplay, scr: cint): culong
proc WhitePixel*(dpy: PDisplay, scr: cint): culong
proc QLength*(dpy: PDisplay): cint
proc DisplayWidth*(dpy: PDisplay, scr: cint): cint
proc DisplayHeight*(dpy: PDisplay, scr: cint): cint
proc DisplayWidthMM*(dpy: PDisplay, scr: cint): cint
proc DisplayHeightMM*(dpy: PDisplay, scr: cint): cint
proc DisplayPlanes*(dpy: PDisplay, scr: cint): cint
proc DisplayCells*(dpy: PDisplay, scr: cint): cint
proc ScreenCount*(dpy: PDisplay): cint
proc ServerVendor*(dpy: PDisplay): cstring
proc ProtocolVersion*(dpy: PDisplay): cint
proc ProtocolRevision*(dpy: PDisplay): cint
proc VendorRelease*(dpy: PDisplay): cint
proc DisplayString*(dpy: PDisplay): cstring
proc DefaultDepth*(dpy: PDisplay, scr: cint): cint
proc DefaultColormap*(dpy: PDisplay, scr: cint): TColormap
proc BitmapUnit*(dpy: PDisplay): cint
proc BitmapBitOrder*(dpy: PDisplay): cint
proc BitmapPad*(dpy: PDisplay): cint
proc ImageByteOrder*(dpy: PDisplay): cint
proc NextRequest*(dpy: PDisplay): culong
proc LastKnownRequestProcessed*(dpy: PDisplay): culong
proc ScreenOfDisplay*(dpy: PDisplay, scr: cint): PScreen
proc DefaultScreenOfDisplay*(dpy: PDisplay): PScreen
proc DisplayOfScreen*(s: PScreen): PDisplay
proc RootWindowOfScreen*(s: PScreen): TWindow
proc BlackPixelOfScreen*(s: PScreen): culong
proc WhitePixelOfScreen*(s: PScreen): culong
proc DefaultColormapOfScreen*(s: PScreen): TColormap
proc DefaultDepthOfScreen*(s: PScreen): cint
proc DefaultGCOfScreen*(s: PScreen): TGC
proc DefaultVisualOfScreen*(s: PScreen): PVisual
proc WidthOfScreen*(s: PScreen): cint
proc HeightOfScreen*(s: PScreen): cint
proc WidthMMOfScreen*(s: PScreen): cint
proc HeightMMOfScreen*(s: PScreen): cint
proc PlanesOfScreen*(s: PScreen): cint
proc CellsOfScreen*(s: PScreen): cint
proc MinCmapsOfScreen*(s: PScreen): cint
proc MaxCmapsOfScreen*(s: PScreen): cint
proc DoesSaveUnders*(s: PScreen): TBool
proc DoesBackingStore*(s: PScreen): cint
proc EventMaskOfScreen*(s: PScreen): clong
proc XAllocID*(dpy: PDisplay): TXID
#when defined(MACROS):
proc ConnectionNumber*(dpy: PDisplay): cint
proc RootWindow*(dpy: PDisplay, scr: cint): TWindow
proc DefaultScreen*(dpy: PDisplay): cint
proc DefaultRootWindow*(dpy: PDisplay): TWindow
proc DefaultVisual*(dpy: PDisplay, scr: cint): PVisual
proc DefaultGC*(dpy: PDisplay, scr: cint): TGC
proc BlackPixel*(dpy: PDisplay, scr: cint): culong
proc WhitePixel*(dpy: PDisplay, scr: cint): culong
proc QLength*(dpy: PDisplay): cint
proc DisplayWidth*(dpy: PDisplay, scr: cint): cint
proc DisplayHeight*(dpy: PDisplay, scr: cint): cint
proc DisplayWidthMM*(dpy: PDisplay, scr: cint): cint
proc DisplayHeightMM*(dpy: PDisplay, scr: cint): cint
proc DisplayPlanes*(dpy: PDisplay, scr: cint): cint
proc DisplayCells*(dpy: PDisplay, scr: cint): cint
proc ScreenCount*(dpy: PDisplay): cint
proc ServerVendor*(dpy: PDisplay): cstring
proc ProtocolVersion*(dpy: PDisplay): cint
proc ProtocolRevision*(dpy: PDisplay): cint
proc VendorRelease*(dpy: PDisplay): cint
proc DisplayString*(dpy: PDisplay): cstring
proc DefaultDepth*(dpy: PDisplay, scr: cint): cint
proc DefaultColormap*(dpy: PDisplay, scr: cint): TColormap
proc BitmapUnit*(dpy: PDisplay): cint
proc BitmapBitOrder*(dpy: PDisplay): cint
proc BitmapPad*(dpy: PDisplay): cint
proc ImageByteOrder*(dpy: PDisplay): cint
proc NextRequest*(dpy: PDisplay): culong
proc LastKnownRequestProcessed*(dpy: PDisplay): culong
proc ScreenOfDisplay*(dpy: PDisplay, scr: cint): PScreen
proc DefaultScreenOfDisplay*(dpy: PDisplay): PScreen
proc DisplayOfScreen*(s: PScreen): PDisplay
proc RootWindowOfScreen*(s: PScreen): TWindow
proc BlackPixelOfScreen*(s: PScreen): culong
proc WhitePixelOfScreen*(s: PScreen): culong
proc DefaultColormapOfScreen*(s: PScreen): TColormap
proc DefaultDepthOfScreen*(s: PScreen): cint
proc DefaultGCOfScreen*(s: PScreen): TGC
proc DefaultVisualOfScreen*(s: PScreen): PVisual
proc WidthOfScreen*(s: PScreen): cint
proc HeightOfScreen*(s: PScreen): cint
proc WidthMMOfScreen*(s: PScreen): cint
proc HeightMMOfScreen*(s: PScreen): cint
proc PlanesOfScreen*(s: PScreen): cint
proc CellsOfScreen*(s: PScreen): cint
proc MinCmapsOfScreen*(s: PScreen): cint
proc MaxCmapsOfScreen*(s: PScreen): cint
proc DoesSaveUnders*(s: PScreen): TBool
proc DoesBackingStore*(s: PScreen): cint
proc EventMaskOfScreen*(s: PScreen): clong
proc XAllocID*(dpy: PDisplay): TXID
# implementation
when defined(MACROS):
proc ConnectionNumber(dpy: PDisplay): cint =
ConnectionNumber = (PXPrivDisplay(dpy))[] .fd
#when defined(MACROS):
template privDisp : expr = cast[PXPrivDisplay](dpy)
proc ConnectionNumber(dpy: PDisplay): cint =
privDisp.fd
proc RootWindow(dpy: PDisplay, scr: cint): TWindow =
RootWindow = (ScreenOfDisplay(dpy, scr))[] .root
proc RootWindow(dpy: PDisplay, scr: cint): TWindow =
ScreenOfDisplay(dpy, scr).root
proc DefaultScreen(dpy: PDisplay): cint =
DefaultScreen = (PXPrivDisplay(dpy))[] .default_screen
proc DefaultScreen(dpy: PDisplay): cint =
privDisp.default_screen
proc DefaultRootWindow(dpy: PDisplay): TWindow =
DefaultRootWindow = (ScreenOfDisplay(dpy, DefaultScreen(dpy)))[] .root
proc DefaultRootWindow(dpy: PDisplay): TWindow =
ScreenOfDisplay(dpy, DefaultScreen(dpy)).root
proc DefaultVisual(dpy: PDisplay, scr: cint): PVisual =
DefaultVisual = (ScreenOfDisplay(dpy, scr))[] .root_visual
proc DefaultVisual(dpy: PDisplay, scr: cint): PVisual =
ScreenOfDisplay(dpy, scr).root_visual
proc DefaultGC(dpy: PDisplay, scr: cint): TGC =
DefaultGC = (ScreenOfDisplay(dpy, scr))[] .default_gc
proc DefaultGC(dpy: PDisplay, scr: cint): TGC =
ScreenOfDisplay(dpy, scr).default_gc
proc BlackPixel(dpy: PDisplay, scr: cint): culong =
BlackPixel = (ScreenOfDisplay(dpy, scr))[] .black_pixel
proc BlackPixel(dpy: PDisplay, scr: cint): culong =
ScreenOfDisplay(dpy, scr).black_pixel
proc WhitePixel(dpy: PDisplay, scr: cint): culong =
WhitePixel = (ScreenOfDisplay(dpy, scr))[] .white_pixel
proc WhitePixel(dpy: PDisplay, scr: cint): culong =
ScreenOfDisplay(dpy, scr).white_pixel
proc QLength(dpy: PDisplay): cint =
QLength = (PXPrivDisplay(dpy))[] .qlen
proc QLength(dpy: PDisplay): cint =
privDisp.qlen
proc DisplayWidth(dpy: PDisplay, scr: cint): cint =
DisplayWidth = (ScreenOfDisplay(dpy, scr))[] .width
proc DisplayWidth(dpy: PDisplay, scr: cint): cint =
ScreenOfDisplay(dpy, scr).width
proc DisplayHeight(dpy: PDisplay, scr: cint): cint =
DisplayHeight = (ScreenOfDisplay(dpy, scr))[] .height
proc DisplayHeight(dpy: PDisplay, scr: cint): cint =
ScreenOfDisplay(dpy, scr).height
proc DisplayWidthMM(dpy: PDisplay, scr: cint): cint =
DisplayWidthMM = (ScreenOfDisplay(dpy, scr))[] .mwidth
proc DisplayWidthMM(dpy: PDisplay, scr: cint): cint =
ScreenOfDisplay(dpy, scr).mwidth
proc DisplayHeightMM(dpy: PDisplay, scr: cint): cint =
DisplayHeightMM = (ScreenOfDisplay(dpy, scr))[] .mheight
proc DisplayHeightMM(dpy: PDisplay, scr: cint): cint =
ScreenOfDisplay(dpy, scr).mheight
proc DisplayPlanes(dpy: PDisplay, scr: cint): cint =
DisplayPlanes = (ScreenOfDisplay(dpy, scr))[] .root_depth
proc DisplayPlanes(dpy: PDisplay, scr: cint): cint =
ScreenOfDisplay(dpy, scr).root_depth
proc DisplayCells(dpy: PDisplay, scr: cint): cint =
DisplayCells = (DefaultVisual(dpy, scr))[] .map_entries
proc DisplayCells(dpy: PDisplay, scr: cint): cint =
DefaultVisual(dpy, scr).map_entries
proc ScreenCount(dpy: PDisplay): cint =
ScreenCount = (PXPrivDisplay(dpy))[] .nscreens
proc ScreenCount(dpy: PDisplay): cint =
privDisp.nscreens
proc ServerVendor(dpy: PDisplay): cstring =
ServerVendor = (PXPrivDisplay(dpy))[] .vendor
proc ServerVendor(dpy: PDisplay): cstring =
privDisp.vendor
proc ProtocolVersion(dpy: PDisplay): cint =
ProtocolVersion = (PXPrivDisplay(dpy))[] .proto_major_version
proc ProtocolVersion(dpy: PDisplay): cint =
privDisp.proto_major_version
proc ProtocolRevision(dpy: PDisplay): cint =
ProtocolRevision = (PXPrivDisplay(dpy))[] .proto_minor_version
proc ProtocolRevision(dpy: PDisplay): cint =
privDisp.proto_minor_version
proc VendorRelease(dpy: PDisplay): cint =
VendorRelease = (PXPrivDisplay(dpy))[] .release
proc VendorRelease(dpy: PDisplay): cint =
privDisp.release
proc DisplayString(dpy: PDisplay): cstring =
DisplayString = (PXPrivDisplay(dpy))[] .display_name
proc DisplayString(dpy: PDisplay): cstring =
privDisp.display_name
proc DefaultDepth(dpy: PDisplay, scr: cint): cint =
DefaultDepth = (ScreenOfDisplay(dpy, scr))[] .root_depth
proc DefaultDepth(dpy: PDisplay, scr: cint): cint =
ScreenOfDisplay(dpy, scr).root_depth
proc DefaultColormap(dpy: PDisplay, scr: cint): TColormap =
DefaultColormap = (ScreenOfDisplay(dpy, scr))[] .cmap
proc DefaultColormap(dpy: PDisplay, scr: cint): TColormap =
ScreenOfDisplay(dpy, scr).cmap
proc BitmapUnit(dpy: PDisplay): cint =
BitmapUnit = (PXPrivDisplay(dpy))[] .bitmap_unit
proc BitmapUnit(dpy: PDisplay): cint =
privDisp.bitmap_unit
proc BitmapBitOrder(dpy: PDisplay): cint =
BitmapBitOrder = (PXPrivDisplay(dpy))[] .bitmap_bit_order
proc BitmapBitOrder(dpy: PDisplay): cint =
privDisp.bitmap_bit_order
proc BitmapPad(dpy: PDisplay): cint =
BitmapPad = (PXPrivDisplay(dpy))[] .bitmap_pad
proc BitmapPad(dpy: PDisplay): cint =
privDisp.bitmap_pad
proc ImageByteOrder(dpy: PDisplay): cint =
ImageByteOrder = (PXPrivDisplay(dpy))[] .byte_order
proc ImageByteOrder(dpy: PDisplay): cint =
privDisp.byte_order
proc NextRequest(dpy: PDisplay): culong =
NextRequest = ((PXPrivDisplay(dpy))[] .request) + 1
import unsigned
proc NextRequest(dpy: PDisplay): culong =
privDisp.request + 1.culong
proc LastKnownRequestProcessed(dpy: PDisplay): culong =
LastKnownRequestProcessed = (PXPrivDisplay(dpy))[] .last_request_read
proc LastKnownRequestProcessed(dpy: PDisplay): culong =
privDisp.last_request_read
proc ScreenOfDisplay(dpy: PDisplay, scr: cint): PScreen =
ScreenOfDisplay = addr((((PXPrivDisplay(dpy))[] .screens)[scr]))
# from fowltek/pointer_arithm, required for ScreenOfDisplay()
proc offset[A] (some: ptr A; b: int): ptr A =
cast[ptr A](cast[int](some) + (b * sizeof(A)))
proc ScreenOfDisplay(dpy: PDisplay, scr: cint): PScreen =
#addr(((privDisp.screens)[scr]))
privDisp.screens.offset(scr.int)
proc DefaultScreenOfDisplay(dpy: PDisplay): PScreen =
DefaultScreenOfDisplay = ScreenOfDisplay(dpy, DefaultScreen(dpy))
proc DefaultScreenOfDisplay(dpy: PDisplay): PScreen =
ScreenOfDisplay(dpy, DefaultScreen(dpy))
proc DisplayOfScreen(s: PScreen): PDisplay =
DisplayOfScreen = s[] .display
proc DisplayOfScreen(s: PScreen): PDisplay =
s.display
proc RootWindowOfScreen(s: PScreen): TWindow =
RootWindowOfScreen = s[] .root
proc RootWindowOfScreen(s: PScreen): TWindow =
s.root
proc BlackPixelOfScreen(s: PScreen): culong =
BlackPixelOfScreen = s[] .black_pixel
proc BlackPixelOfScreen(s: PScreen): culong =
s.black_pixel
proc WhitePixelOfScreen(s: PScreen): culong =
WhitePixelOfScreen = s[] .white_pixel
proc WhitePixelOfScreen(s: PScreen): culong =
s.white_pixel
proc DefaultColormapOfScreen(s: PScreen): TColormap =
DefaultColormapOfScreen = s[] .cmap
proc DefaultColormapOfScreen(s: PScreen): TColormap =
s.cmap
proc DefaultDepthOfScreen(s: PScreen): cint =
DefaultDepthOfScreen = s[] .root_depth
proc DefaultDepthOfScreen(s: PScreen): cint =
s.root_depth
proc DefaultGCOfScreen(s: PScreen): TGC =
DefaultGCOfScreen = s[] .default_gc
proc DefaultGCOfScreen(s: PScreen): TGC =
s.default_gc
proc DefaultVisualOfScreen(s: PScreen): PVisual =
DefaultVisualOfScreen = s[] .root_visual
proc DefaultVisualOfScreen(s: PScreen): PVisual =
s.root_visual
proc WidthOfScreen(s: PScreen): cint =
WidthOfScreen = s[] .width
proc WidthOfScreen(s: PScreen): cint =
s.width
proc HeightOfScreen(s: PScreen): cint =
HeightOfScreen = s[] .height
proc HeightOfScreen(s: PScreen): cint =
s.height
proc WidthMMOfScreen(s: PScreen): cint =
WidthMMOfScreen = s[] .mwidth
proc WidthMMOfScreen(s: PScreen): cint =
s.mwidth
proc HeightMMOfScreen(s: PScreen): cint =
HeightMMOfScreen = s[] .mheight
proc HeightMMOfScreen(s: PScreen): cint =
s.mheight
proc PlanesOfScreen(s: PScreen): cint =
PlanesOfScreen = s[] .root_depth
proc PlanesOfScreen(s: PScreen): cint =
s.root_depth
proc CellsOfScreen(s: PScreen): cint =
CellsOfScreen = (DefaultVisualOfScreen(s))[] .map_entries
proc CellsOfScreen(s: PScreen): cint =
DefaultVisualOfScreen(s).map_entries
proc MinCmapsOfScreen(s: PScreen): cint =
MinCmapsOfScreen = s[] .min_maps
proc MinCmapsOfScreen(s: PScreen): cint =
s.min_maps
proc MaxCmapsOfScreen(s: PScreen): cint =
MaxCmapsOfScreen = s[] .max_maps
proc MaxCmapsOfScreen(s: PScreen): cint =
s.max_maps
proc DoesSaveUnders(s: PScreen): TBool =
DoesSaveUnders = s[] .save_unders
proc DoesSaveUnders(s: PScreen): TBool =
s.save_unders
proc DoesBackingStore(s: PScreen): cint =
DoesBackingStore = s[] .backing_store
proc DoesBackingStore(s: PScreen): cint =
s.backing_store
proc EventMaskOfScreen(s: PScreen): clong =
EventMaskOfScreen = s[] .root_input_mask
proc EventMaskOfScreen(s: PScreen): clong =
s.root_input_mask
proc XAllocID(dpy: PDisplay): TXID =
XAllocID = (PXPrivDisplay(dpy))[] .resource_alloc(dpy)
proc XAllocID(dpy: PDisplay): TXID =
privDisp.resource_alloc(dpy)

View File

@@ -1,6 +1,6 @@
import
x, xlib, keysym
x, xlib, keysym, unsigned
#const
# libX11* = "libX11.so"
@@ -356,57 +356,57 @@ proc XWMGeometry*(para1: PDisplay, para2: cint, para3: cstring, para4: cstring,
dynlib: libX11, importc.}
proc XXorRegion*(para1: TRegion, para2: TRegion, para3: TRegion): cint{.cdecl,
dynlib: libX11, importc.}
when defined(MACROS):
proc XDestroyImage*(ximage: PXImage): cint
proc XGetPixel*(ximage: PXImage, x, y: cint): culong
proc XPutPixel*(ximage: PXImage, x, y: cint, pixel: culong): cint
proc XSubImage*(ximage: PXImage, x, y: cint, width, height: cuint): PXImage
proc XAddPixel*(ximage: PXImage, value: clong): cint
proc IsKeypadKey*(keysym: TKeySym): bool
proc IsPrivateKeypadKey*(keysym: TKeySym): bool
proc IsCursorKey*(keysym: TKeySym): bool
proc IsPFKey*(keysym: TKeySym): bool
proc IsFunctionKey*(keysym: TKeySym): bool
proc IsMiscFunctionKey*(keysym: TKeySym): bool
proc IsModifierKey*(keysym: TKeySym): bool
#function XUniqueContext : TXContext;
#function XStringToContext(_string : Pchar) : TXContext;
#when defined(MACROS):
proc XDestroyImage*(ximage: PXImage): cint
proc XGetPixel*(ximage: PXImage, x, y: cint): culong
proc XPutPixel*(ximage: PXImage, x, y: cint, pixel: culong): cint
proc XSubImage*(ximage: PXImage, x, y: cint, width, height: cuint): PXImage
proc XAddPixel*(ximage: PXImage, value: clong): cint
proc IsKeypadKey*(keysym: TKeySym): bool
proc IsPrivateKeypadKey*(keysym: TKeySym): bool
proc IsCursorKey*(keysym: TKeySym): bool
proc IsPFKey*(keysym: TKeySym): bool
proc IsFunctionKey*(keysym: TKeySym): bool
proc IsMiscFunctionKey*(keysym: TKeySym): bool
proc IsModifierKey*(keysym: TKeySym): bool
#function XUniqueContext : TXContext;
#function XStringToContext(_string : Pchar) : TXContext;
# implementation
when defined(MACROS):
proc XDestroyImage(ximage: PXImage): cint =
XDestroyImage = ximage[] .f.destroy_image(ximage)
#when defined(MACROS):
proc XDestroyImage(ximage: PXImage): cint =
ximage.f.destroy_image(ximage)
proc XGetPixel(ximage: PXImage, x, y: cint): culong =
XGetPixel = ximage[] .f.get_pixel(ximage, x, y)
proc XGetPixel(ximage: PXImage, x, y: cint): culong =
ximage.f.get_pixel(ximage, x, y)
proc XPutPixel(ximage: PXImage, x, y: cint, pixel: culong): cint =
XPutPixel = ximage[] .f.put_pixel(ximage, x, y, pixel)
proc XPutPixel(ximage: PXImage, x, y: cint, pixel: culong): cint =
ximage.f.put_pixel(ximage, x, y, pixel)
proc XSubImage(ximage: PXImage, x, y: cint, width, height: cuint): PXImage =
XSubImage = ximage[] .f.sub_image(ximage, x, y, width, height)
proc XSubImage(ximage: PXImage, x, y: cint, width, height: cuint): PXImage =
ximage.f.sub_image(ximage, x, y, width, height)
proc XAddPixel(ximage: PXImage, value: clong): cint =
XAddPixel = ximage[] .f.add_pixel(ximage, value)
proc XAddPixel(ximage: PXImage, value: clong): cint =
ximage.f.add_pixel(ximage, value)
proc IsKeypadKey(keysym: TKeySym): bool =
IsKeypadKey = (keysym >= XK_KP_Space) and (keysym <= XK_KP_Equal)
proc IsKeypadKey(keysym: TKeySym): bool =
(keysym >= XK_KP_Space) and (keysym <= XK_KP_Equal)
proc IsPrivateKeypadKey(keysym: TKeySym): bool =
IsPrivateKeypadKey = (keysym >= 0x11000000) and (keysym <= 0x1100FFFF)
proc IsPrivateKeypadKey(keysym: TKeySym): bool =
(keysym >= 0x11000000.TKeySym) and (keysym <= 0x1100FFFF.TKeySym)
proc IsCursorKey(keysym: TKeySym): bool =
IsCursorKey = (keysym >= XK_Home) and (keysym < XK_Select)
proc IsCursorKey(keysym: TKeySym): bool =
(keysym >= XK_Home) and (keysym < XK_Select)
proc IsPFKey(keysym: TKeySym): bool =
IsPFKey = (keysym >= XK_KP_F1) and (keysym <= XK_KP_F4)
proc IsPFKey(keysym: TKeySym): bool =
(keysym >= XK_KP_F1) and (keysym <= XK_KP_F4)
proc IsFunctionKey(keysym: TKeySym): bool =
IsFunctionKey = (keysym >= XK_F1) and (keysym <= XK_F35)
proc IsFunctionKey(keysym: TKeySym): bool =
(keysym >= XK_F1) and (keysym <= XK_F35)
proc IsMiscFunctionKey(keysym: TKeySym): bool =
IsMiscFunctionKey = (keysym >= XK_Select) and (keysym <= XK_Break)
proc IsMiscFunctionKey(keysym: TKeySym): bool =
(keysym >= XK_Select) and (keysym <= XK_Break)
proc IsModifierKey(keysym: TKeySym): bool =
IsModifierKey = ((keysym >= XK_Shift_L) And (keysym <= XK_Hyper_R)) Or
(keysym == XK_Mode_switch) Or (keysym == XK_Num_Lock)
proc IsModifierKey(keysym: TKeySym): bool =
((keysym >= XK_Shift_L) And (keysym <= XK_Hyper_R)) Or
(keysym == XK_Mode_switch) Or (keysym == XK_Num_Lock)

View File

@@ -102,6 +102,7 @@ proc compress2*(dest: pbytef, destLen: puLongf, source: pbytef,
proc uncompress*(dest: pbytef, destLen: puLongf, source: pbytef,
sourceLen: uLong): cint{.cdecl, dynlib: libz,
importc: "uncompress".}
proc compressBound*(sourceLen: uLong): uLong {.cdecl, dynlib: libz, importc.}
proc gzopen*(path: cstring, mode: cstring): gzFile{.cdecl, dynlib: libz,
importc: "gzopen".}
proc gzdopen*(fd: int32, mode: cstring): gzFile{.cdecl, dynlib: libz,

View File

@@ -9,7 +9,7 @@ the C source of an older version of the compiler are needed to bootstrap the
latest version. The C sources are available in a separate repo [here](http://github.com/nimrod-code/csources).
Pre-compiled snapshots of the compiler are also available on
[Nimbuild](http://build.nimrod-code.org/). Your platform however may not
[Nimbuild](http://build.nimrod-lang.org/). Your platform however may not
currently be built for.
The compiler currently supports the following platform and architecture
@@ -47,9 +47,11 @@ The above steps can be performed on Windows in a similar fashion, the
instead of ``build.sh``.
## Getting help
A [forum](http://forum.nimrod-code.org/) is available if you have any questions,
and you can also get help in the IRC channel
on [Freenode](irc://irc.freenode.net/nimrod) in #nimrod.
A [forum](http://forum.nimrod-lang.org/) is available if you have any
questions, and you can also get help in the IRC channel on
[Freenode](irc://irc.freenode.net/nimrod) in #nimrod. If you ask questions on
[StackOverflow use the nimrod
tag](http://stackoverflow.com/questions/tagged/nimrod).
## License
The compiler and the standard library are licensed under the MIT license,

View File

@@ -9,7 +9,7 @@ the C source of an older version of the compiler are needed to bootstrap the
latest version. The C sources are available in a separate repo [here](http://github.com/nimrod-code/csources).
Pre-compiled snapshots of the compiler are also available on
[Nimbuild](http://build.nimrod-code.org/). Your platform however may not
[Nimbuild](http://build.nimrod-lang.org/). Your platform however may not
currently be built for.
The compiler currently supports the following platform and architecture
@@ -47,9 +47,11 @@ The above steps can be performed on Windows in a similar fashion, the
instead of ``build.sh``.
## Getting help
A [forum](http://forum.nimrod-code.org/) is available if you have any questions,
and you can also get help in the IRC channel
on [Freenode](irc://irc.freenode.net/nimrod) in #nimrod.
A [forum](http://forum.nimrod-lang.org/) is available if you have any
questions, and you can also get help in the IRC channel on
[Freenode](irc://irc.freenode.net/nimrod) in #nimrod. If you ask questions on
[StackOverflow use the nimrod
tag](http://stackoverflow.com/questions/tagged/nimrod).
## License
The compiler and the standard library are licensed under the MIT license,

View File

@@ -9,9 +9,9 @@ static int cvariable = 420;
""".}
proc embedsC() {.noStackFrame.} =
proc embedsC() =
var nimrodVar = 89
{.emit: """fprintf(stdout, "%d\n", cvariable + (int)`nimrodVar`);""".}
{.emit: """printf("%d\n", cvariable + (int)`nimrodVar`);""".}
embedsC()

View File

@@ -10,6 +10,10 @@ type
TBar[T; I: expr[int]] = object
data: array[I, T]
TA1[T; I: expr[int]] = array[I, T]
TA2[T; I: expr[int]] = array[0..I, T]
TA3[T; I: expr[int]] = array[I-1, T]
proc takeFoo(x: TFoo) =
echo "abracadabra"
echo TFoo.Val
@@ -20,3 +24,8 @@ takeFoo(x)
var y: TBar[float, 4]
echo high(y.data)
var
t1: TA1
t2: TA2
t3: TA3

View File

@@ -0,0 +1,28 @@
discard """
output: "Sortable\nSortable\nContainer"
"""
import typetraits
type
TObj = object
x: int
Sortable = generic x, y
(x < y) is bool
ObjectContainer = generic C
C.len is ordinal
for v in items(C):
v.type is tuple|object
proc foo(c: ObjectContainer) =
echo "Container"
proc foo(x: Sortable) =
echo "Sortable"
foo 10
foo "test"
foo(@[TObj(x: 10), TObj(x: 20)])

View File

@@ -54,7 +54,7 @@ case $uos in
myos="linux"
LINK_FLAGS="$LINK_FLAGS -ldl -lm"
;;
*freebsd* )
*freebsd* | *dragonfly* )
myos="freebsd"
LINK_FLAGS="$LINK_FLAGS -lm"
;;