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

View file

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

View file

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

View file

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

View file

@ -1624,10 +1624,23 @@ proc parseObject(p: var TParser): PNode =
return return
addSon(result, parseObjectPart(p)) 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 = proc parseTypeClass(p: var TParser): PNode =
result = newNodeP(nkTypeClassTy, p) result = newNodeP(nkTypeClassTy, p)
getTok(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: if p.tok.tokType == tkCurlyDotLe and p.validInd:
addSon(result, parsePragma(p)) addSon(result, parsePragma(p))
else: 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 addParams(c: PContext, n: PNode, kind: TSymKind)
proc maybeAddResult(c: PContext, s: PSym, n: PNode) proc maybeAddResult(c: PContext, s: PSym, n: PNode)
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType 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 fixImmediateParams(n: PNode): PNode
proc activate(c: PContext, n: PNode) proc activate(c: PContext, n: PNode)
proc semQuoteAst(c: PContext, n: PNode): PNode proc semQuoteAst(c: PContext, n: PNode): PNode

View file

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

View file

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

View file

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

View file

@ -85,6 +85,7 @@ proc initCandidate*(c: var TCandidate, callee: PSym, binding: PNode,
c.calleeSym = callee c.calleeSym = callee
c.calleeScope = calleeScope c.calleeScope = calleeScope
initIdTable(c.bindings) initIdTable(c.bindings)
c.errors = nil
if binding != nil and callee.kind in RoutineKinds: if binding != nil and callee.kind in RoutineKinds:
var typeParams = callee.ast[genericParamsPos] var typeParams = callee.ast[genericParamsPos]
for i in 1..min(sonsLen(typeParams), sonsLen(binding)-1): 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)) add(result, argTypeToString(arg))
if i != sonsLen(n) - 1: add(result, ", ") 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 = proc concreteType(c: TCandidate, t: PType): PType =
case t.kind case t.kind
of tyArrayConstr: of tyArrayConstr:
@ -750,40 +751,55 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
# pushInfoContext(arg.info) # pushInfoContext(arg.info)
openScope(c) openScope(c)
inc c.InTypeClass
var testee = newSym(skParam, f.testeeName, f.sym, f.sym.info) finally:
testee.typ = a dec c.InTypeClass
addDecl(c, testee) 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 case e.kind
of nkReturnStmt: of nkReturnStmt: nil
nil
of nkTypeSection: nil of nkTypeSection: nil
of nkConstDef: nil of nkConstDef: nil
else: else: nil
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)
result = arg result = arg
put(m.bindings, f, a) 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 = argSemantized, argOrig: PNode): PNode =
var arg = argSemantized var
var r: TTypeRelation r: TTypeRelation
let fMaybeExpr = f.skipTypes({tyDistinct}) arg = argSemantized
let
a = if c.InTypeClass > 0: argType.skipTypes({tyTypeDesc})
else: argType
fMaybeExpr = f.skipTypes({tyDistinct})
case fMaybeExpr.kind case fMaybeExpr.kind
of tyExpr: of tyExpr:
if fMaybeExpr.sonsLen == 0: if fMaybeExpr.sonsLen == 0:

View file

@ -837,8 +837,12 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
result = sameObjectStructures(a, b, c) and sameFlags(a, b) result = sameObjectStructures(a, b, c) and sameFlags(a, b)
of tyDistinct: of tyDistinct:
CycleCheck() CycleCheck()
if c.cmp == dcEq: result = sameDistinctTypes(a, b) and sameFlags(a, b) if c.cmp == dcEq:
else: result = sameTypeAux(a.sons[0], b.sons[0], c) and sameFlags(a, b) 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: of tyEnum, tyForward, tyProxy:
# XXX generic enums do not make much sense, but require structural checking # XXX generic enums do not make much sense, but require structural checking
result = a.id == b.id and sameFlags(a, b) result = a.id == b.id and sameFlags(a, b)

View file

@ -13,7 +13,7 @@ Introduction
This document describes how the GC works and how to tune it for This document describes how the GC works and how to tune it for
(soft) `realtime systems`:idx:. (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 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 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. 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 nimrod c koch.nim
./koch boot -d:release ./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 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. 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. * Max line length is 80 characters.
* Provide spaces around binary operators if that enhances readability. * Provide spaces around binary operators if that enhances readability.
* Use a space after a colon, but not before it. * 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``. with ``P``.

View file

@ -64,6 +64,8 @@ Core
Collections and algorithms Collections and algorithms
-------------------------- --------------------------
* `algorithm <algorithm.html>`_
Implements some common generic algorithms like sort or binary search.
* `tables <tables.html>`_ * `tables <tables.html>`_
Nimrod hash table support. Contains tables, ordered tables and count tables. Nimrod hash table support. Contains tables, ordered tables and count tables.
* `sets <sets.html>`_ * `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 ``[]``. array constructor ``[]``.
`Sequences`:idx: are similar to arrays but of dynamic length which may change `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 during runtime (like strings). Sequences are implemented as growable arrays,
from 0 to ``len(S)-1`` and its bounds are checked. Sequences can be allocating pieces of memory as items are added. A sequence ``S`` is always
constructed by the array constructor ``[]`` in conjunction with the array to indexed by integers from 0 to ``len(S)-1`` and its bounds are checked.
sequence operator ``@``. Another way to allocate space for a sequence is to Sequences can be constructed by the array constructor ``[]`` in conjunction
call the built-in ``newSeq`` procedure. 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*. 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: for value in c:
type(value) is T type(value) is T
The type class will be matched if:
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:
a) all of the expressions within the body can be compiled for the tested type 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 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 The identifiers following the `generic` keyword represent instances of the
signatures of the required operations, but since type inference and default currently matched type. These instances can act both as variables of the type,
parameters are still applied in the provided block, it's also possible to encode when used in contexts, where a value is expected, and as the type itself, when
usage protocols that doesn't reveal implementation details. 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 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 once for each tested type and any static code included within them will also be
executed once. executed once.
Return Type Inference 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 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 statements like ``return result;`` generated and the generated C function is
declared as ``__declspec(naked)`` or ``__attribute__((naked))`` (depending on declared as ``__declspec(naked)`` or ``__attribute__((naked))`` (depending on
the used C compiler). This is useful for procs that only consist of an the used C compiler).
assembler statement.
**Note**: This pragma should only be used by procs which consist solely of assembler
statements.
error pragma error pragma
------------ ------------

View file

@ -610,7 +610,7 @@ allow to silently throw away a return value:
discard yes("May I ask a pointless question?") 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: been declared with the ``discardable`` pragma:
.. code-block:: nimrod .. code-block:: nimrod
@ -1077,7 +1077,7 @@ can also be used to include elements (and ranges of elements):
TCharSet = set[char] TCharSet = set[char]
var var
x: TCharSet 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 # letters from 'a' to 'z' and the digits
# from '0' to '9' # from '0' to '9'
@ -1201,7 +1201,7 @@ to specify a range from zero to the specified index minus one:
Sequences Sequences
--------- ---------
`Sequences`:idx: are similar to arrays but of dynamic length which may change `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. allocated on the heap and garbage collected.
Sequences are always indexed with an ``int`` starting at position 0. 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 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`` 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: statement is useful to split up a large module into several files:

View file

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

View file

@ -81,6 +81,8 @@ else:
## A type representing a directory stream. ## A type representing a directory stream.
type type
TSocketHandle* = distinct cint # The type used to represent socket descriptors
Tdirent* {.importc: "struct dirent", Tdirent* {.importc: "struct dirent",
header: "<dirent.h>", final, pure.} = object ## dirent_t struct header: "<dirent.h>", final, pure.} = object ## dirent_t struct
d_ino*: TIno ## File serial number. 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 dlsym*(a1: pointer, a2: cstring): pointer {.importc, header: "<dlfcn.h>".}
proc creat*(a1: cstring, a2: Tmode): cint {.importc, header: "<fcntl.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 open*(a1: cstring, a2: cint): cint {.varargs, importc, header: "<fcntl.h>".}
proc posix_fadvise*(a1: cint, a2, a3: Toff, a4: cint): cint {. proc posix_fadvise*(a1: cint, a2, a3: Toff, a4: cint): cint {.
importc, header: "<fcntl.h>".} 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 alarm*(a1: cint): cint {.importc, header: "<unistd.h>".}
proc chdir*(a1: cstring): 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 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 confstr*(a1: cint, a2: cstring, a3: int): int {.importc, header: "<unistd.h>".}
proc crypt*(a1, a2: cstring): cstring {.importc, header: "<unistd.h>".} proc crypt*(a1, a2: cstring): cstring {.importc, header: "<unistd.h>".}
proc ctermid*(a1: 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 hstrerror*(herrnum: cint): cstring {.importc, header: "<netdb.h>".}
proc FD_CLR*(a1: cint, a2: var Tfd_set) {.importc, header: "<sys/select.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>".} 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 FD_ZERO*(a1: var Tfd_set) {.importc, header: "<sys/select.h>".}
proc pselect*(a1: cint, a2, a3, a4: ptr Tfd_set, a5: ptr ttimespec, 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 {. proc CMSG_FIRSTHDR*(mhdr: ptr TMsgHdr): ptr TCMsgHdr {.
importc, header: "<sys/socket.h>".} 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>".} 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>".} importc: "bind", header: "<sys/socket.h>".}
## is Posix's ``bind``, because ``bind`` is a reserved word ## 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>".} 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>".} 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>".} 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>".} importc, header: "<sys/socket.h>".}
proc listen*(a1, a2: cint): cint {. proc listen*(a1: TSocketHandle, a2: cint): cint {.
importc, header: "<sys/socket.h>".} 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>".} 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 {. a5: ptr Tsockaddr, a6: ptr Tsocklen): int {.
importc, header: "<sys/socket.h>".} 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>".} 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>".} 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>".} 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 {. a6: Tsocklen): int {.
importc, header: "<sys/socket.h>".} 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>".} importc, header: "<sys/socket.h>".}
proc shutdown*(a1, a2: cint): cint {. proc shutdown*(a1: TSocketHandle, a2: cint): cint {.
importc, header: "<sys/socket.h>".} importc, header: "<sys/socket.h>".}
proc socket*(a1, a2, a3: cint): cint {. proc socket*(a1, a2, a3: cint): TSocketHandle {.
importc, header: "<sys/socket.h>".} importc, header: "<sys/socket.h>".}
proc sockatmark*(a1: cint): cint {. proc sockatmark*(a1: cint): cint {.
importc, header: "<sys/socket.h>".} importc, header: "<sys/socket.h>".}

View file

@ -89,13 +89,13 @@ import sockets, os
## getSocket(s).accept(client) ## getSocket(s).accept(client)
when defined(windows): 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: 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 type
TDelegate* = object TDelegate* = object
fd*: cint fd*: TSocketHandle
deleVal*: PObject deleVal*: PObject
handleRead*: proc (h: PObject) {.nimcall.} handleRead*: proc (h: PObject) {.nimcall.}
@ -213,6 +213,7 @@ proc asyncSockHandleRead(h: PObject) =
else: else:
PAsyncSocket(h).handleAccept(PAsyncSocket(h)) PAsyncSocket(h).handleAccept(PAsyncSocket(h))
proc close*(sock: PAsyncSocket)
proc asyncSockHandleWrite(h: PObject) = proc asyncSockHandleWrite(h: PObject) =
when defined(ssl): when defined(ssl):
if PAsyncSocket(h).socket.isSSL and not if PAsyncSocket(h).socket.isSSL and not
@ -230,6 +231,7 @@ proc asyncSockHandleWrite(h: PObject) =
else: else:
if PAsyncSocket(h).sendBuffer != "": if PAsyncSocket(h).sendBuffer != "":
let sock = PAsyncSocket(h) let sock = PAsyncSocket(h)
try:
let bytesSent = sock.socket.sendAsync(sock.sendBuffer) let bytesSent = sock.socket.sendAsync(sock.sendBuffer)
assert bytesSent > 0 assert bytesSent > 0
if bytesSent != sock.sendBuffer.len: if bytesSent != sock.sendBuffer.len:
@ -239,6 +241,9 @@ proc asyncSockHandleWrite(h: PObject) =
if PAsyncSocket(h).handleWrite != nil: if PAsyncSocket(h).handleWrite != nil:
PAsyncSocket(h).handleWrite(PAsyncSocket(h)) 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: else:
if PAsyncSocket(h).handleWrite != nil: if PAsyncSocket(h).handleWrite != nil:
PAsyncSocket(h).handleWrite(PAsyncSocket(h)) PAsyncSocket(h).handleWrite(PAsyncSocket(h))

View file

@ -12,7 +12,7 @@
const const
cb64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" cb64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
proc encode*(s: string, lineLen = 75, newLine="\13\10"): string = template encodeInternal(s: expr, lineLen: int, newLine: string): stmt {.immediate.} =
## encodes `s` into base64 representation. After `lineLen` characters, a ## encodes `s` into base64 representation. After `lineLen` characters, a
## `newline` is added. ## `newline` is added.
var total = ((len(s) + 2) div 3) * 4 var total = ((len(s) + 2) div 3) * 4
@ -60,6 +60,16 @@ proc encode*(s: string, lineLen = 75, newLine="\13\10"): string =
else: else:
assert(r == result.len) 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.} = proc decodeByte(b: char): int {.inline.} =
case b case b
of '+': result = ord('>') of '+': result = ord('>')

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"] ## assert f2 == @["yellow"]
accumulateResult(filter(seq1, pred)) 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.} = template filterIt*(seq1, pred: expr): expr {.immediate.} =
## Returns a new sequence with all the items that fulfilled the predicate. ## 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 multiplication == 495, "Multiplication is (5*(9*(11)))"
assert concatenation == "nimrodiscool" 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" echo "Finished doc tests"

View file

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

View file

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

View file

@ -98,6 +98,7 @@ type
params*: seq[string] ## Parameters of the IRC message params*: seq[string] ## Parameters of the IRC message
origin*: string ## The channel/user that this msg originated from origin*: string ## The channel/user that this msg originated from
raw*: string ## Raw IRC message raw*: string ## Raw IRC message
timestamp*: TTime ## UNIX epoch time the message was received
proc send*(irc: PIRC, message: string, sendImmediately = false) = proc send*(irc: PIRC, message: string, sendImmediately = false) =
## Sends ``message`` as a raw command. It adds ``\c\L`` for you. ## Sends ``message`` as a raw command. It adds ``\c\L`` for you.
@ -163,6 +164,7 @@ proc parseMessage(msg: string): TIRCEvent =
result.typ = EvMsg result.typ = EvMsg
result.cmd = MUnknown result.cmd = MUnknown
result.raw = msg result.raw = msg
result.timestamp = times.getTime()
var i = 0 var i = 0
# Process the prefix # Process the prefix
if msg[i] == ':': 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 # Nimrod's Runtime Library
# (c) Copyright 2012 Andreas Rumpf # (c) Copyright 2013 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -52,6 +52,10 @@ proc oidToString*(oid: TOid, str: cstring) =
inc(i) inc(i)
str[24] = '\0' str[24] = '\0'
proc `$`*(oid: TOid): string =
result = newString(25)
oidToString(oid, result)
var var
incr: int incr: int
fuzz: int32 fuzz: int32

View file

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

View file

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

View file

@ -31,6 +31,7 @@ when hostos == "solaris":
import os, parseutils import os, parseutils
from times import epochTime from times import epochTime
import unsigned
when defined(ssl): when defined(ssl):
import openssl import openssl
@ -62,7 +63,7 @@ const
type type
TSocketImpl = object ## socket type TSocketImpl = object ## socket type
fd: cint fd: TSocketHandle
case isBuffered: bool # determines whether this socket is buffered. case isBuffered: bool # determines whether this socket is buffered.
of true: of true:
buffer: array[0..BufferSize, char] buffer: array[0..BufferSize, char]
@ -82,7 +83,7 @@ type
TSocket* = ref TSocketImpl TSocket* = ref TSocketImpl
TPort* = distinct int16 ## port type TPort* = distinct uint16 ## port type
TDomain* = enum ## domain, which specifies the protocol family of the TDomain* = enum ## domain, which specifies the protocol family of the
## created socket. Other domains than those that are listed ## created socket. Other domains than those that are listed
@ -118,6 +119,10 @@ type
length*: int length*: int
addrList*: seq[string] addrList*: seq[string]
TSOBool* = enum ## Boolean socket options.
OptAcceptConn, OptBroadcast, OptDebug, OptDontRoute, OptKeepAlive,
OptOOBInline, OptReuseAddr
TRecvLineResult* = enum ## result for recvLineAsync TRecvLineResult* = enum ## result for recvLineAsync
RecvFullLine, RecvPartialLine, RecvDisconnected, RecvFail RecvFullLine, RecvPartialLine, RecvDisconnected, RecvFail
@ -126,7 +131,19 @@ type
ETimeout* = object of ESynch 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) new(result)
result.fd = fd result.fd = fd
result.isBuffered = isBuff result.isBuffered = isBuff
@ -134,15 +151,11 @@ proc newTSocket(fd: int32, isBuff: bool): TSocket =
result.currPos = 0 result.currPos = 0
result.nonblocking = false result.nonblocking = false
let
InvalidSocket*: TSocket = nil ## invalid socket
proc `==`*(a, b: TPort): bool {.borrow.} proc `==`*(a, b: TPort): bool {.borrow.}
## ``==`` for ports. ## ``==`` for ports.
proc `$`*(p: TPort): string = proc `$`*(p: TPort): string {.borrow.}
## returns the port number as a string ## returns the port number as a string
result = $ze(int16(p))
proc ntohl*(x: int32): int32 = proc ntohl*(x: int32): int32 =
## Converts 32-bit integers from network to host byte order. ## Converts 32-bit integers from network to host byte order.
@ -212,6 +225,8 @@ else:
proc socket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM, proc socket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
protocol: TProtocol = IPPROTO_TCP, buffered = true): TSocket = 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): when defined(Windows):
result = newTSocket(winlean.socket(ord(domain), ord(typ), ord(protocol)), buffered) result = newTSocket(winlean.socket(ord(domain), ord(typ), ord(protocol)), buffered)
else: else:
@ -456,7 +471,7 @@ template acceptAddrPlain(noClientRet, successRet: expr,
var sock = accept(server.fd, cast[ptr TSockAddr](addr(sockAddress)), var sock = accept(server.fd, cast[ptr TSockAddr](addr(sockAddress)),
addr(addrLen)) addr(addrLen))
if sock < 0: if sock == OSInvalidSocket:
let err = OSLastError() let err = OSLastError()
when defined(windows): when defined(windows):
if err.int32 == WSAEINPROGRESS: if err.int32 == WSAEINPROGRESS:
@ -529,7 +544,7 @@ proc acceptAddr*(server: TSocket, client: var TSocket, address: var string) {.
SSLError("Unknown error") SSLError("Unknown error")
proc setBlocking*(s: TSocket, blocking: bool) {.tags: [].} proc setBlocking*(s: TSocket, blocking: bool) {.tags: [].}
## sets blocking mode on socket ## Sets blocking mode on socket
when defined(ssl): when defined(ssl):
proc acceptAddrSSL*(server: TSocket, client: var TSocket, proc acceptAddrSSL*(server: TSocket, client: var TSocket,
@ -623,24 +638,32 @@ proc close*(socket: TSocket) =
discard SSLShutdown(socket.sslHandle) discard SSLShutdown(socket.sslHandle)
proc getServByName*(name, proto: string): TServent {.tags: [FReadIO].} = 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): when defined(Windows):
var s = winlean.getservbyname(name, proto) var s = winlean.getservbyname(name, proto)
else: else:
var s = posix.getservbyname(name, proto) 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.name = $s.s_name
result.aliases = cstringArrayToSeq(s.s_aliases) result.aliases = cstringArrayToSeq(s.s_aliases)
result.port = TPort(s.s_port) result.port = TPort(s.s_port)
result.proto = $s.s_proto result.proto = $s.s_proto
proc getServByPort*(port: TPort, proto: string): TServent {.tags: [FReadIO].} = 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): when defined(Windows):
var s = winlean.getservbyport(ze(int16(port)).cint, proto) var s = winlean.getservbyport(ze(int16(port)).cint, proto)
else: else:
var s = posix.getservbyport(ze(int16(port)).cint, proto) 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.name = $s.s_name
result.aliases = cstringArrayToSeq(s.s_aliases) result.aliases = cstringArrayToSeq(s.s_aliases)
result.port = TPort(s.s_port) result.port = TPort(s.s_port)
@ -676,7 +699,7 @@ proc getHostByAddr*(ip: string): THostEnt {.tags: [FReadIO].} =
result.length = int(s.h_length) result.length = int(s.h_length)
proc getHostByName*(name: string): THostEnt {.tags: [FReadIO].} = proc getHostByName*(name: string): THostEnt {.tags: [FReadIO].} =
## well-known gethostbyname proc. ## This function will lookup the IP address of a hostname.
when defined(Windows): when defined(Windows):
var s = winlean.gethostbyname(name) var s = winlean.gethostbyname(name)
else: else:
@ -714,6 +737,34 @@ proc setSockOptInt*(socket: TSocket, level, optname, optval: int) {.
sizeof(value).TSockLen) < 0'i32: sizeof(value).TSockLen) < 0'i32:
OSError(OSLastError()) 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), proc connect*(socket: TSocket, address: string, port = TPort(0),
af: TDomain = AF_INET) {.tags: [FReadIO].} = af: TDomain = AF_INET) {.tags: [FReadIO].} =
## Connects socket to ``address``:``port``. ``Address`` can be an IP address or a ## 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 var seconds = timeout div 1000
result.tv_sec = seconds.int32 result.tv_sec = seconds.int32
result.tv_usec = ((timeout - seconds * 1000) * 1000).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) = proc createFdSet(fd: var TFdSet, s: seq[TSocket], m: var int) =
FD_ZERO(fd) FD_ZERO(fd)
@ -1608,14 +1654,14 @@ when defined(Windows):
FIONBIO = IOC_IN.int32 or ((sizeof(int32) and IOCPARM_MASK) shl 16) or FIONBIO = IOC_IN.int32 or ((sizeof(int32) and IOCPARM_MASK) shl 16) or
(102 shl 8) or 126 (102 shl 8) or 126
proc ioctlsocket(s: TWinSocket, cmd: clong, proc ioctlsocket(s: TSocketHandle, cmd: clong,
argptr: ptr clong): cint {. argptr: ptr clong): cint {.
stdcall, importc:"ioctlsocket", dynlib: "ws2_32.dll".} stdcall, importc:"ioctlsocket", dynlib: "ws2_32.dll".}
proc setBlocking(s: TSocket, blocking: bool) = proc setBlocking(s: TSocket, blocking: bool) =
when defined(Windows): when defined(Windows):
var mode = clong(ord(not blocking)) # 1 for non-blocking, 0 for blocking 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()) OSError(OSLastError())
else: # BSD sockets else: # BSD sockets
var x: int = fcntl(s.fd, F_GETFL, 0) 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 proc isSSL*(socket: TSocket): bool = return socket.isSSL
## Determines whether ``socket`` is a SSL socket. ## 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 ## Returns the socket's file descriptor
proc isBlocking*(socket: TSocket): bool = not socket.nonblocking
## Determines whether ``socket`` is blocking.
when defined(Windows): when defined(Windows):
var wsa: TWSADATA var wsa: TWSADATA
if WSAStartup(0x0101'i16, addr wsa) != 0: OSError(OSLastError()) if WSAStartup(0x0101'i16, addr wsa) != 0: OSError(OSLastError())

View file

@ -246,7 +246,8 @@ proc toSeconds(a: TTimeInfo, interval: TTimeInterval): float =
else: else:
curMonth.inc() curMonth.inc()
result += float(newinterv.days * 24 * 60 * 60) 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 += float(newinterv.seconds)
result += newinterv.miliseconds / 1000 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])) result = TRune(ord(s[i]))
when doInc: inc(i) when doInc: inc(i)
elif ord(s[i]) shr 5 == 0b110: 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 result = TRune((ord(s[i]) and (ones(5))) shl 6 or
(ord(s[i+1]) and ones(6))) (ord(s[i+1]) and ones(6)))
when doInc: inc(i, 2) when doInc: inc(i, 2)
elif ord(s[i]) shr 4 == 0b1110: elif ord(s[i]) shr 4 == 0b1110:
assert(ord(s[i+1]) shr 6 == 0b10) # assert(ord(s[i+1]) shr 6 == 0b10)
assert(ord(s[i+2]) shr 6 == 0b10) # assert(ord(s[i+2]) shr 6 == 0b10)
result = TRune((ord(s[i]) and ones(4)) shl 12 or result = TRune((ord(s[i]) and ones(4)) shl 12 or
(ord(s[i+1]) and ones(6)) shl 6 or (ord(s[i+1]) and ones(6)) shl 6 or
(ord(s[i+2]) and ones(6))) (ord(s[i+2]) and ones(6)))
when doInc: inc(i, 3) when doInc: inc(i, 3)
elif ord(s[i]) shr 3 == 0b11110: elif ord(s[i]) shr 3 == 0b11110:
assert(ord(s[i+1]) shr 6 == 0b10) # assert(ord(s[i+1]) shr 6 == 0b10)
assert(ord(s[i+2]) shr 6 == 0b10) # assert(ord(s[i+2]) shr 6 == 0b10)
assert(ord(s[i+3]) shr 6 == 0b10) # assert(ord(s[i+3]) shr 6 == 0b10)
result = TRune((ord(s[i]) and ones(3)) shl 18 or result = TRune((ord(s[i]) and ones(3)) shl 18 or
(ord(s[i+1]) and ones(6)) shl 12 or (ord(s[i+1]) and ones(6)) shl 12 or
(ord(s[i+2]) and ones(6)) shl 6 or (ord(s[i+2]) and ones(6)) shl 6 or
(ord(s[i+3]) and ones(6))) (ord(s[i+3]) and ones(6)))
when doInc: inc(i, 4) when doInc: inc(i, 4)
elif ord(s[i]) shr 2 == 0b111110: elif ord(s[i]) shr 2 == 0b111110:
assert(ord(s[i+1]) shr 6 == 0b10) # assert(ord(s[i+1]) shr 6 == 0b10)
assert(ord(s[i+2]) shr 6 == 0b10) # assert(ord(s[i+2]) shr 6 == 0b10)
assert(ord(s[i+3]) shr 6 == 0b10) # assert(ord(s[i+3]) shr 6 == 0b10)
assert(ord(s[i+4]) shr 6 == 0b10) # assert(ord(s[i+4]) shr 6 == 0b10)
result = TRune((ord(s[i]) and ones(2)) shl 24 or result = TRune((ord(s[i]) and ones(2)) shl 24 or
(ord(s[i+1]) and ones(6)) shl 18 or (ord(s[i+1]) and ones(6)) shl 18 or
(ord(s[i+2]) and ones(6)) shl 12 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))) (ord(s[i+4]) and ones(6)))
when doInc: inc(i, 5) when doInc: inc(i, 5)
elif ord(s[i]) shr 1 == 0b1111110: elif ord(s[i]) shr 1 == 0b1111110:
assert(ord(s[i+1]) shr 6 == 0b10) # assert(ord(s[i+1]) shr 6 == 0b10)
assert(ord(s[i+2]) shr 6 == 0b10) # assert(ord(s[i+2]) shr 6 == 0b10)
assert(ord(s[i+3]) shr 6 == 0b10) # assert(ord(s[i+3]) shr 6 == 0b10)
assert(ord(s[i+4]) shr 6 == 0b10) # assert(ord(s[i+4]) shr 6 == 0b10)
assert(ord(s[i+5]) shr 6 == 0b10) # assert(ord(s[i+5]) shr 6 == 0b10)
result = TRune((ord(s[i]) and ones(1)) shl 30 or result = TRune((ord(s[i]) and ones(1)) shl 30 or
(ord(s[i+1]) and ones(6)) shl 24 or (ord(s[i+1]) and ones(6)) shl 24 or
(ord(s[i+2]) and ones(6)) shl 18 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: ## a string that describes the application type. Possible values:
## "console", "gui", "lib". ## "console", "gui", "lib".
seqShallowFlag = 1 shl (sizeof(int)*8-1) seqShallowFlag = low(int)
proc compileOption*(option: string): bool {. proc compileOption*(option: string): bool {.
magic: "CompileOption", noSideEffect.} magic: "CompileOption", noSideEffect.}
@ -1795,7 +1795,7 @@ when defined(JS):
elif hostOS != "standalone": elif hostOS != "standalone":
{.push stack_trace:off, profiler:off.} {.push stack_trace:off, profiler:off.}
proc add*(x: var string, y: cstring) {.noStackFrame.} = proc add*(x: var string, y: cstring) =
var i = 0 var i = 0
while y[i] != '\0': while y[i] != '\0':
add(x, y[i]) add(x, y[i])

View file

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

View file

@ -9,68 +9,207 @@
# Atomic operations for Nimrod. # Atomic operations for Nimrod.
when (defined(gcc) or defined(llvm_gcc)) and hasThreadSupport and when (defined(gcc) or defined(llvm_gcc)) and hasThreadSupport:
not defined(windows):
proc sync_add_and_fetch(p: var int, val: int): int {. type
importc: "__sync_add_and_fetch", nodecl.} AtomMemModel* = enum
proc sync_sub_and_fetch(p: var int, val: int): int {. ATOMIC_RELAXED,
importc: "__sync_sub_and_fetch", nodecl.} ## 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: 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.} importc: "NimXadd", nodecl.}
else: else:
proc sync_add_and_fetch(p: var int, val: int): int {.inline.} = proc add_and_fetch*(p: ptr int, val: int): int {.inline.} =
inc(p, val) inc(p[], val)
result = p 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: else:
inc(memLoc, x) inc(memLoc, x)
result = memLoc result = memLoc
proc atomicDec(memLoc: var int, x: int = 1): int = proc atomicDec*(memLoc: var int, x: int = 1): int =
when hasThreadSupport: when defined(gcc) and hasThreadSupport:
when defined(sync_sub_and_fetch): when defined(atomic_sub_fetch):
result = sync_sub_and_fetch(memLoc, x) result = atomic_sub_fetch(memLoc.addr, x, ATOMIC_RELAXED)
else: else:
result = sync_add_and_fetch(memLoc, -x) result = atomic_add_fetch(memLoc.addr, -x, ATOMIC_RELAXED)
else: else:
dec(memLoc, x) dec(memLoc, x)
result = memLoc 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 # 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 # This is achieved by combining a Deutsch-Bobrow garbage collector
# together with Christoper's partial mark-sweep garbage collector. # together with Christoper's partial mark-sweep garbage collector.
# #
@ -407,12 +407,17 @@ proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
return return
add(gch.zct, res) 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 = proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer =
# generates a new object and sets its reference counter to 0 # generates a new object and sets its reference counter to 0
sysAssert(allocInv(gch.region), "rawNewObj begin")
acquire(gch) acquire(gch)
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1") gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
collectCT(gch) collectCT(gch)
sysAssert(allocInv(gch.region), "rawNewObj begin")
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell))) var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
gcAssert((cast[TAddress](res) and (MemAlign-1)) == 0, "newObj: 2") gcAssert((cast[TAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
# now it is buffered in the ZCT # 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) writeCell("growObj new cell", res)
gcTrace(ol, csZctFreed) gcTrace(ol, csZctFreed)
gcTrace(res, csAllocated) gcTrace(res, csAllocated)
when reallyDealloc: rawDealloc(gch.region, ol) when reallyDealloc:
sysAssert(allocInv(gch.region), "growObj before dealloc")
rawDealloc(gch.region, ol)
else: else:
sysAssert(ol.typ != nil, "growObj: 5") sysAssert(ol.typ != nil, "growObj: 5")
zeroMem(ol, sizeof(TCell)) zeroMem(ol, sizeof(TCell))
@ -537,7 +544,9 @@ proc freeCyclicCell(gch: var TGcHeap, c: PCell) =
prepareDealloc(c) prepareDealloc(c)
gcTrace(c, csCycFreed) gcTrace(c, csCycFreed)
when logGC: writeCell("cycle collector dealloc cell", c) 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: else:
gcAssert(c.typ != nil, "freeCyclicCell") gcAssert(c.typ != nil, "freeCyclicCell")
zeroMem(c, sizeof(TCell)) zeroMem(c, sizeof(TCell))
@ -910,7 +919,9 @@ proc collectZCT(gch: var TGcHeap): bool =
# access invalid memory. This is done by prepareDealloc(): # access invalid memory. This is done by prepareDealloc():
prepareDealloc(c) prepareDealloc(c)
forAllChildren(c, waZctDecRef) forAllChildren(c, waZctDecRef)
when reallyDealloc: rawDealloc(gch.region, c) when reallyDealloc:
sysAssert(allocInv(gch.region), "collectZCT: rawDealloc")
rawDealloc(gch.region, c)
else: else:
sysAssert(c.typ != nil, "collectZCT 2") sysAssert(c.typ != nil, "collectZCT 2")
zeroMem(c, sizeof(TCell)) zeroMem(c, sizeof(TCell))

View file

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

View file

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

View file

@ -334,6 +334,9 @@ const
proc WSAGetLastError*(): cint {.importc: "WSAGetLastError", dynlib: ws2dll.} proc WSAGetLastError*(): cint {.importc: "WSAGetLastError", dynlib: ws2dll.}
type
TSocketHandle* = distinct int
type type
TWSAData* {.pure, final, importc: "WSADATA", header: "Winsock2.h".} = object TWSAData* {.pure, final, importc: "WSADATA", header: "Winsock2.h".} = object
wVersion, wHighVersion: int16 wVersion, wHighVersion: int16
@ -390,11 +393,9 @@ type
h_length*: int16 h_length*: int16
h_addr_list*: cstringArray h_addr_list*: cstringArray
TWinSocket* = cint
TFdSet* {.pure, final.} = object TFdSet* {.pure, final.} = object
fd_count*: cint # unsigned fd_count*: cint # unsigned
fd_array*: array[0..FD_SETSIZE-1, TWinSocket] fd_array*: array[0..FD_SETSIZE-1, TSocketHandle]
TTimeval* {.pure, final.} = object TTimeval* {.pure, final.} = object
tv_sec*, tv_usec*: int32 tv_sec*, tv_usec*: int32
@ -413,6 +414,22 @@ type
var var
SOMAXCONN* {.importc, header: "Winsock2.h".}: cint 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 {. proc getservbyname*(name, proto: cstring): ptr TServent {.
stdcall, importc: "getservbyname", dynlib: ws2dll.} 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 {. proc gethostbyname*(name: cstring): ptr THostEnt {.
stdcall, importc: "gethostbyname", dynlib: ws2dll.} stdcall, importc: "gethostbyname", dynlib: ws2dll.}
proc socket*(af, typ, protocol: cint): TWinSocket {. proc socket*(af, typ, protocol: cint): TSocketHandle {.
stdcall, importc: "socket", dynlib: ws2dll.} stdcall, importc: "socket", dynlib: ws2dll.}
proc closesocket*(s: TWinSocket): cint {. proc closesocket*(s: TSocketHandle): cint {.
stdcall, importc: "closesocket", dynlib: ws2dll.} 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.} 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.} 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.} stdcall, importc: "connect", dynlib: ws2dll.}
proc getsockname*(s: TWinSocket, name: ptr TSockAddr, proc getsockname*(s: TSocketHandle, name: ptr TSockAddr,
namelen: ptr TSockLen): cint {. namelen: ptr TSockLen): cint {.
stdcall, importc: "getsockname", dynlib: ws2dll.} 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 {. optlen: ptr TSockLen): cint {.
stdcall, importc: "getsockopt", dynlib: ws2dll.} 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 {. optlen: TSockLen): cint {.
stdcall, importc: "setsockopt", dynlib: ws2dll.} stdcall, importc: "setsockopt", dynlib: ws2dll.}
proc listen*(s: TWinSocket, backlog: cint): cint {. proc listen*(s: TSocketHandle, backlog: cint): cint {.
stdcall, importc: "listen", dynlib: ws2dll.} 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.} 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 {. fromm: ptr TSockAddr, fromlen: ptr Tsocklen): cint {.
stdcall, importc: "recvfrom", dynlib: ws2dll.} stdcall, importc: "recvfrom", dynlib: ws2dll.}
proc select*(nfds: cint, readfds, writefds, exceptfds: ptr TFdSet, proc select*(nfds: cint, readfds, writefds, exceptfds: ptr TFdSet,
timeout: ptr TTimeval): cint {. timeout: ptr TTimeval): cint {.
stdcall, importc: "select", dynlib: ws2dll.} 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.} 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 {. to: ptr TSockAddr, tolen: Tsocklen): cint {.
stdcall, importc: "sendto", dynlib: ws2dll.} stdcall, importc: "sendto", dynlib: ws2dll.}
proc shutdown*(s: TWinSocket, how: cint): cint {. proc shutdown*(s: TSocketHandle, how: cint): cint {.
stdcall, importc: "shutdown", dynlib: ws2dll.} stdcall, importc: "shutdown", dynlib: ws2dll.}
proc getnameinfo*(a1: ptr Tsockaddr, a2: Tsocklen, proc getnameinfo*(a1: ptr Tsockaddr, a2: Tsocklen,
@ -475,13 +492,13 @@ proc getnameinfo*(a1: ptr Tsockaddr, a2: Tsocklen,
proc inet_addr*(cp: cstring): int32 {. proc inet_addr*(cp: cstring): int32 {.
stdcall, importc: "inet_addr", dynlib: ws2dll.} 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.} 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 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: if FDSet.fd_count < FD_SETSIZE:
FDSet.fd_array[int(FDSet.fd_count)] = Socket FDSet.fd_array[int(FDSet.fd_count)] = Socket
inc(FDSet.fd_count) inc(FDSet.fd_count)

View file

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

View file

@ -45,6 +45,7 @@ when defined(WINDOWS):
const const
DLLSSLName = "(ssleay32|libssl32).dll" DLLSSLName = "(ssleay32|libssl32).dll"
DLLUtilName = "libeay32.dll" DLLUtilName = "libeay32.dll"
from winlean import TSocketHandle
else: else:
const const
versions = "(|.1.0.0|.0.9.9|.0.9.8|.0.9.7|.0.9.6|.0.9.5|.0.9.4)" 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 const
DLLSSLName = "libssl.so" & versions DLLSSLName = "libssl.so" & versions
DLLUtilName = "libcrypto.so" & versions DLLUtilName = "libcrypto.so" & versions
from posix import TSocketHandle
type type
SslStruct {.final, pure.} = object 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, proc SSL_CTX_check_private_key*(ctx: PSSL_CTX): cInt{.cdecl, dynlib: DLLSSLName,
importc.} 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_shutdown*(ssl: PSSL): cInt{.cdecl, dynlib: DLLSSLName, importc.}
proc SSL_connect*(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? # _Xmbtowc?
# _Xwctomb? # _Xwctomb?
# #
when defined(MACROS): #when defined(MACROS):
proc ConnectionNumber*(dpy: PDisplay): cint proc ConnectionNumber*(dpy: PDisplay): cint
proc RootWindow*(dpy: PDisplay, scr: cint): TWindow proc RootWindow*(dpy: PDisplay, scr: cint): TWindow
proc DefaultScreen*(dpy: PDisplay): cint proc DefaultScreen*(dpy: PDisplay): cint
proc DefaultRootWindow*(dpy: PDisplay): TWindow proc DefaultRootWindow*(dpy: PDisplay): TWindow
proc DefaultVisual*(dpy: PDisplay, scr: cint): PVisual proc DefaultVisual*(dpy: PDisplay, scr: cint): PVisual
proc DefaultGC*(dpy: PDisplay, scr: cint): TGC proc DefaultGC*(dpy: PDisplay, scr: cint): TGC
proc BlackPixel*(dpy: PDisplay, scr: cint): culong proc BlackPixel*(dpy: PDisplay, scr: cint): culong
proc WhitePixel*(dpy: PDisplay, scr: cint): culong proc WhitePixel*(dpy: PDisplay, scr: cint): culong
proc QLength*(dpy: PDisplay): cint proc QLength*(dpy: PDisplay): cint
proc DisplayWidth*(dpy: PDisplay, scr: cint): cint proc DisplayWidth*(dpy: PDisplay, scr: cint): cint
proc DisplayHeight*(dpy: PDisplay, scr: cint): cint proc DisplayHeight*(dpy: PDisplay, scr: cint): cint
proc DisplayWidthMM*(dpy: PDisplay, scr: cint): cint proc DisplayWidthMM*(dpy: PDisplay, scr: cint): cint
proc DisplayHeightMM*(dpy: PDisplay, scr: cint): cint proc DisplayHeightMM*(dpy: PDisplay, scr: cint): cint
proc DisplayPlanes*(dpy: PDisplay, scr: cint): cint proc DisplayPlanes*(dpy: PDisplay, scr: cint): cint
proc DisplayCells*(dpy: PDisplay, scr: cint): cint proc DisplayCells*(dpy: PDisplay, scr: cint): cint
proc ScreenCount*(dpy: PDisplay): cint proc ScreenCount*(dpy: PDisplay): cint
proc ServerVendor*(dpy: PDisplay): cstring proc ServerVendor*(dpy: PDisplay): cstring
proc ProtocolVersion*(dpy: PDisplay): cint proc ProtocolVersion*(dpy: PDisplay): cint
proc ProtocolRevision*(dpy: PDisplay): cint proc ProtocolRevision*(dpy: PDisplay): cint
proc VendorRelease*(dpy: PDisplay): cint proc VendorRelease*(dpy: PDisplay): cint
proc DisplayString*(dpy: PDisplay): cstring proc DisplayString*(dpy: PDisplay): cstring
proc DefaultDepth*(dpy: PDisplay, scr: cint): cint proc DefaultDepth*(dpy: PDisplay, scr: cint): cint
proc DefaultColormap*(dpy: PDisplay, scr: cint): TColormap proc DefaultColormap*(dpy: PDisplay, scr: cint): TColormap
proc BitmapUnit*(dpy: PDisplay): cint proc BitmapUnit*(dpy: PDisplay): cint
proc BitmapBitOrder*(dpy: PDisplay): cint proc BitmapBitOrder*(dpy: PDisplay): cint
proc BitmapPad*(dpy: PDisplay): cint proc BitmapPad*(dpy: PDisplay): cint
proc ImageByteOrder*(dpy: PDisplay): cint proc ImageByteOrder*(dpy: PDisplay): cint
proc NextRequest*(dpy: PDisplay): culong proc NextRequest*(dpy: PDisplay): culong
proc LastKnownRequestProcessed*(dpy: PDisplay): culong proc LastKnownRequestProcessed*(dpy: PDisplay): culong
proc ScreenOfDisplay*(dpy: PDisplay, scr: cint): PScreen proc ScreenOfDisplay*(dpy: PDisplay, scr: cint): PScreen
proc DefaultScreenOfDisplay*(dpy: PDisplay): PScreen proc DefaultScreenOfDisplay*(dpy: PDisplay): PScreen
proc DisplayOfScreen*(s: PScreen): PDisplay proc DisplayOfScreen*(s: PScreen): PDisplay
proc RootWindowOfScreen*(s: PScreen): TWindow proc RootWindowOfScreen*(s: PScreen): TWindow
proc BlackPixelOfScreen*(s: PScreen): culong proc BlackPixelOfScreen*(s: PScreen): culong
proc WhitePixelOfScreen*(s: PScreen): culong proc WhitePixelOfScreen*(s: PScreen): culong
proc DefaultColormapOfScreen*(s: PScreen): TColormap proc DefaultColormapOfScreen*(s: PScreen): TColormap
proc DefaultDepthOfScreen*(s: PScreen): cint proc DefaultDepthOfScreen*(s: PScreen): cint
proc DefaultGCOfScreen*(s: PScreen): TGC proc DefaultGCOfScreen*(s: PScreen): TGC
proc DefaultVisualOfScreen*(s: PScreen): PVisual proc DefaultVisualOfScreen*(s: PScreen): PVisual
proc WidthOfScreen*(s: PScreen): cint proc WidthOfScreen*(s: PScreen): cint
proc HeightOfScreen*(s: PScreen): cint proc HeightOfScreen*(s: PScreen): cint
proc WidthMMOfScreen*(s: PScreen): cint proc WidthMMOfScreen*(s: PScreen): cint
proc HeightMMOfScreen*(s: PScreen): cint proc HeightMMOfScreen*(s: PScreen): cint
proc PlanesOfScreen*(s: PScreen): cint proc PlanesOfScreen*(s: PScreen): cint
proc CellsOfScreen*(s: PScreen): cint proc CellsOfScreen*(s: PScreen): cint
proc MinCmapsOfScreen*(s: PScreen): cint proc MinCmapsOfScreen*(s: PScreen): cint
proc MaxCmapsOfScreen*(s: PScreen): cint proc MaxCmapsOfScreen*(s: PScreen): cint
proc DoesSaveUnders*(s: PScreen): TBool proc DoesSaveUnders*(s: PScreen): TBool
proc DoesBackingStore*(s: PScreen): cint proc DoesBackingStore*(s: PScreen): cint
proc EventMaskOfScreen*(s: PScreen): clong proc EventMaskOfScreen*(s: PScreen): clong
proc XAllocID*(dpy: PDisplay): TXID proc XAllocID*(dpy: PDisplay): TXID
# implementation # implementation
when defined(MACROS): #when defined(MACROS):
proc ConnectionNumber(dpy: PDisplay): cint = template privDisp : expr = cast[PXPrivDisplay](dpy)
ConnectionNumber = (PXPrivDisplay(dpy))[] .fd
proc RootWindow(dpy: PDisplay, scr: cint): TWindow = proc ConnectionNumber(dpy: PDisplay): cint =
RootWindow = (ScreenOfDisplay(dpy, scr))[] .root privDisp.fd
proc DefaultScreen(dpy: PDisplay): cint = proc RootWindow(dpy: PDisplay, scr: cint): TWindow =
DefaultScreen = (PXPrivDisplay(dpy))[] .default_screen ScreenOfDisplay(dpy, scr).root
proc DefaultRootWindow(dpy: PDisplay): TWindow = proc DefaultScreen(dpy: PDisplay): cint =
DefaultRootWindow = (ScreenOfDisplay(dpy, DefaultScreen(dpy)))[] .root privDisp.default_screen
proc DefaultVisual(dpy: PDisplay, scr: cint): PVisual = proc DefaultRootWindow(dpy: PDisplay): TWindow =
DefaultVisual = (ScreenOfDisplay(dpy, scr))[] .root_visual ScreenOfDisplay(dpy, DefaultScreen(dpy)).root
proc DefaultGC(dpy: PDisplay, scr: cint): TGC = proc DefaultVisual(dpy: PDisplay, scr: cint): PVisual =
DefaultGC = (ScreenOfDisplay(dpy, scr))[] .default_gc ScreenOfDisplay(dpy, scr).root_visual
proc BlackPixel(dpy: PDisplay, scr: cint): culong = proc DefaultGC(dpy: PDisplay, scr: cint): TGC =
BlackPixel = (ScreenOfDisplay(dpy, scr))[] .black_pixel ScreenOfDisplay(dpy, scr).default_gc
proc WhitePixel(dpy: PDisplay, scr: cint): culong = proc BlackPixel(dpy: PDisplay, scr: cint): culong =
WhitePixel = (ScreenOfDisplay(dpy, scr))[] .white_pixel ScreenOfDisplay(dpy, scr).black_pixel
proc QLength(dpy: PDisplay): cint = proc WhitePixel(dpy: PDisplay, scr: cint): culong =
QLength = (PXPrivDisplay(dpy))[] .qlen ScreenOfDisplay(dpy, scr).white_pixel
proc DisplayWidth(dpy: PDisplay, scr: cint): cint = proc QLength(dpy: PDisplay): cint =
DisplayWidth = (ScreenOfDisplay(dpy, scr))[] .width privDisp.qlen
proc DisplayHeight(dpy: PDisplay, scr: cint): cint = proc DisplayWidth(dpy: PDisplay, scr: cint): cint =
DisplayHeight = (ScreenOfDisplay(dpy, scr))[] .height ScreenOfDisplay(dpy, scr).width
proc DisplayWidthMM(dpy: PDisplay, scr: cint): cint = proc DisplayHeight(dpy: PDisplay, scr: cint): cint =
DisplayWidthMM = (ScreenOfDisplay(dpy, scr))[] .mwidth ScreenOfDisplay(dpy, scr).height
proc DisplayHeightMM(dpy: PDisplay, scr: cint): cint = proc DisplayWidthMM(dpy: PDisplay, scr: cint): cint =
DisplayHeightMM = (ScreenOfDisplay(dpy, scr))[] .mheight ScreenOfDisplay(dpy, scr).mwidth
proc DisplayPlanes(dpy: PDisplay, scr: cint): cint = proc DisplayHeightMM(dpy: PDisplay, scr: cint): cint =
DisplayPlanes = (ScreenOfDisplay(dpy, scr))[] .root_depth ScreenOfDisplay(dpy, scr).mheight
proc DisplayCells(dpy: PDisplay, scr: cint): cint = proc DisplayPlanes(dpy: PDisplay, scr: cint): cint =
DisplayCells = (DefaultVisual(dpy, scr))[] .map_entries ScreenOfDisplay(dpy, scr).root_depth
proc ScreenCount(dpy: PDisplay): cint = proc DisplayCells(dpy: PDisplay, scr: cint): cint =
ScreenCount = (PXPrivDisplay(dpy))[] .nscreens DefaultVisual(dpy, scr).map_entries
proc ServerVendor(dpy: PDisplay): cstring = proc ScreenCount(dpy: PDisplay): cint =
ServerVendor = (PXPrivDisplay(dpy))[] .vendor privDisp.nscreens
proc ProtocolVersion(dpy: PDisplay): cint = proc ServerVendor(dpy: PDisplay): cstring =
ProtocolVersion = (PXPrivDisplay(dpy))[] .proto_major_version privDisp.vendor
proc ProtocolRevision(dpy: PDisplay): cint = proc ProtocolVersion(dpy: PDisplay): cint =
ProtocolRevision = (PXPrivDisplay(dpy))[] .proto_minor_version privDisp.proto_major_version
proc VendorRelease(dpy: PDisplay): cint = proc ProtocolRevision(dpy: PDisplay): cint =
VendorRelease = (PXPrivDisplay(dpy))[] .release privDisp.proto_minor_version
proc DisplayString(dpy: PDisplay): cstring = proc VendorRelease(dpy: PDisplay): cint =
DisplayString = (PXPrivDisplay(dpy))[] .display_name privDisp.release
proc DefaultDepth(dpy: PDisplay, scr: cint): cint = proc DisplayString(dpy: PDisplay): cstring =
DefaultDepth = (ScreenOfDisplay(dpy, scr))[] .root_depth privDisp.display_name
proc DefaultColormap(dpy: PDisplay, scr: cint): TColormap = proc DefaultDepth(dpy: PDisplay, scr: cint): cint =
DefaultColormap = (ScreenOfDisplay(dpy, scr))[] .cmap ScreenOfDisplay(dpy, scr).root_depth
proc BitmapUnit(dpy: PDisplay): cint = proc DefaultColormap(dpy: PDisplay, scr: cint): TColormap =
BitmapUnit = (PXPrivDisplay(dpy))[] .bitmap_unit ScreenOfDisplay(dpy, scr).cmap
proc BitmapBitOrder(dpy: PDisplay): cint = proc BitmapUnit(dpy: PDisplay): cint =
BitmapBitOrder = (PXPrivDisplay(dpy))[] .bitmap_bit_order privDisp.bitmap_unit
proc BitmapPad(dpy: PDisplay): cint = proc BitmapBitOrder(dpy: PDisplay): cint =
BitmapPad = (PXPrivDisplay(dpy))[] .bitmap_pad privDisp.bitmap_bit_order
proc ImageByteOrder(dpy: PDisplay): cint = proc BitmapPad(dpy: PDisplay): cint =
ImageByteOrder = (PXPrivDisplay(dpy))[] .byte_order privDisp.bitmap_pad
proc NextRequest(dpy: PDisplay): culong = proc ImageByteOrder(dpy: PDisplay): cint =
NextRequest = ((PXPrivDisplay(dpy))[] .request) + 1 privDisp.byte_order
proc LastKnownRequestProcessed(dpy: PDisplay): culong = import unsigned
LastKnownRequestProcessed = (PXPrivDisplay(dpy))[] .last_request_read proc NextRequest(dpy: PDisplay): culong =
privDisp.request + 1.culong
proc ScreenOfDisplay(dpy: PDisplay, scr: cint): PScreen = proc LastKnownRequestProcessed(dpy: PDisplay): culong =
ScreenOfDisplay = addr((((PXPrivDisplay(dpy))[] .screens)[scr])) privDisp.last_request_read
proc DefaultScreenOfDisplay(dpy: PDisplay): PScreen = # from fowltek/pointer_arithm, required for ScreenOfDisplay()
DefaultScreenOfDisplay = ScreenOfDisplay(dpy, DefaultScreen(dpy)) 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 DisplayOfScreen(s: PScreen): PDisplay = proc DefaultScreenOfDisplay(dpy: PDisplay): PScreen =
DisplayOfScreen = s[] .display ScreenOfDisplay(dpy, DefaultScreen(dpy))
proc RootWindowOfScreen(s: PScreen): TWindow = proc DisplayOfScreen(s: PScreen): PDisplay =
RootWindowOfScreen = s[] .root s.display
proc BlackPixelOfScreen(s: PScreen): culong = proc RootWindowOfScreen(s: PScreen): TWindow =
BlackPixelOfScreen = s[] .black_pixel s.root
proc WhitePixelOfScreen(s: PScreen): culong = proc BlackPixelOfScreen(s: PScreen): culong =
WhitePixelOfScreen = s[] .white_pixel s.black_pixel
proc DefaultColormapOfScreen(s: PScreen): TColormap = proc WhitePixelOfScreen(s: PScreen): culong =
DefaultColormapOfScreen = s[] .cmap s.white_pixel
proc DefaultDepthOfScreen(s: PScreen): cint = proc DefaultColormapOfScreen(s: PScreen): TColormap =
DefaultDepthOfScreen = s[] .root_depth s.cmap
proc DefaultGCOfScreen(s: PScreen): TGC = proc DefaultDepthOfScreen(s: PScreen): cint =
DefaultGCOfScreen = s[] .default_gc s.root_depth
proc DefaultVisualOfScreen(s: PScreen): PVisual = proc DefaultGCOfScreen(s: PScreen): TGC =
DefaultVisualOfScreen = s[] .root_visual s.default_gc
proc WidthOfScreen(s: PScreen): cint = proc DefaultVisualOfScreen(s: PScreen): PVisual =
WidthOfScreen = s[] .width s.root_visual
proc HeightOfScreen(s: PScreen): cint = proc WidthOfScreen(s: PScreen): cint =
HeightOfScreen = s[] .height s.width
proc WidthMMOfScreen(s: PScreen): cint = proc HeightOfScreen(s: PScreen): cint =
WidthMMOfScreen = s[] .mwidth s.height
proc HeightMMOfScreen(s: PScreen): cint = proc WidthMMOfScreen(s: PScreen): cint =
HeightMMOfScreen = s[] .mheight s.mwidth
proc PlanesOfScreen(s: PScreen): cint = proc HeightMMOfScreen(s: PScreen): cint =
PlanesOfScreen = s[] .root_depth s.mheight
proc CellsOfScreen(s: PScreen): cint = proc PlanesOfScreen(s: PScreen): cint =
CellsOfScreen = (DefaultVisualOfScreen(s))[] .map_entries s.root_depth
proc MinCmapsOfScreen(s: PScreen): cint = proc CellsOfScreen(s: PScreen): cint =
MinCmapsOfScreen = s[] .min_maps DefaultVisualOfScreen(s).map_entries
proc MaxCmapsOfScreen(s: PScreen): cint = proc MinCmapsOfScreen(s: PScreen): cint =
MaxCmapsOfScreen = s[] .max_maps s.min_maps
proc DoesSaveUnders(s: PScreen): TBool = proc MaxCmapsOfScreen(s: PScreen): cint =
DoesSaveUnders = s[] .save_unders s.max_maps
proc DoesBackingStore(s: PScreen): cint = proc DoesSaveUnders(s: PScreen): TBool =
DoesBackingStore = s[] .backing_store s.save_unders
proc EventMaskOfScreen(s: PScreen): clong = proc DoesBackingStore(s: PScreen): cint =
EventMaskOfScreen = s[] .root_input_mask s.backing_store
proc XAllocID(dpy: PDisplay): TXID = proc EventMaskOfScreen(s: PScreen): clong =
XAllocID = (PXPrivDisplay(dpy))[] .resource_alloc(dpy) s.root_input_mask
proc XAllocID(dpy: PDisplay): TXID =
privDisp.resource_alloc(dpy)

View file

@ -1,6 +1,6 @@
import import
x, xlib, keysym x, xlib, keysym, unsigned
#const #const
# libX11* = "libX11.so" # libX11* = "libX11.so"
@ -356,57 +356,57 @@ proc XWMGeometry*(para1: PDisplay, para2: cint, para3: cstring, para4: cstring,
dynlib: libX11, importc.} dynlib: libX11, importc.}
proc XXorRegion*(para1: TRegion, para2: TRegion, para3: TRegion): cint{.cdecl, proc XXorRegion*(para1: TRegion, para2: TRegion, para3: TRegion): cint{.cdecl,
dynlib: libX11, importc.} dynlib: libX11, importc.}
when defined(MACROS): #when defined(MACROS):
proc XDestroyImage*(ximage: PXImage): cint proc XDestroyImage*(ximage: PXImage): cint
proc XGetPixel*(ximage: PXImage, x, y: cint): culong proc XGetPixel*(ximage: PXImage, x, y: cint): culong
proc XPutPixel*(ximage: PXImage, x, y: cint, pixel: culong): cint proc XPutPixel*(ximage: PXImage, x, y: cint, pixel: culong): cint
proc XSubImage*(ximage: PXImage, x, y: cint, width, height: cuint): PXImage proc XSubImage*(ximage: PXImage, x, y: cint, width, height: cuint): PXImage
proc XAddPixel*(ximage: PXImage, value: clong): cint proc XAddPixel*(ximage: PXImage, value: clong): cint
proc IsKeypadKey*(keysym: TKeySym): bool proc IsKeypadKey*(keysym: TKeySym): bool
proc IsPrivateKeypadKey*(keysym: TKeySym): bool proc IsPrivateKeypadKey*(keysym: TKeySym): bool
proc IsCursorKey*(keysym: TKeySym): bool proc IsCursorKey*(keysym: TKeySym): bool
proc IsPFKey*(keysym: TKeySym): bool proc IsPFKey*(keysym: TKeySym): bool
proc IsFunctionKey*(keysym: TKeySym): bool proc IsFunctionKey*(keysym: TKeySym): bool
proc IsMiscFunctionKey*(keysym: TKeySym): bool proc IsMiscFunctionKey*(keysym: TKeySym): bool
proc IsModifierKey*(keysym: TKeySym): bool proc IsModifierKey*(keysym: TKeySym): bool
#function XUniqueContext : TXContext; #function XUniqueContext : TXContext;
#function XStringToContext(_string : Pchar) : TXContext; #function XStringToContext(_string : Pchar) : TXContext;
# implementation # implementation
when defined(MACROS): #when defined(MACROS):
proc XDestroyImage(ximage: PXImage): cint = proc XDestroyImage(ximage: PXImage): cint =
XDestroyImage = ximage[] .f.destroy_image(ximage) ximage.f.destroy_image(ximage)
proc XGetPixel(ximage: PXImage, x, y: cint): culong = proc XGetPixel(ximage: PXImage, x, y: cint): culong =
XGetPixel = ximage[] .f.get_pixel(ximage, x, y) ximage.f.get_pixel(ximage, x, y)
proc XPutPixel(ximage: PXImage, x, y: cint, pixel: culong): cint = proc XPutPixel(ximage: PXImage, x, y: cint, pixel: culong): cint =
XPutPixel = ximage[] .f.put_pixel(ximage, x, y, pixel) ximage.f.put_pixel(ximage, x, y, pixel)
proc XSubImage(ximage: PXImage, x, y: cint, width, height: cuint): PXImage = proc XSubImage(ximage: PXImage, x, y: cint, width, height: cuint): PXImage =
XSubImage = ximage[] .f.sub_image(ximage, x, y, width, height) ximage.f.sub_image(ximage, x, y, width, height)
proc XAddPixel(ximage: PXImage, value: clong): cint = proc XAddPixel(ximage: PXImage, value: clong): cint =
XAddPixel = ximage[] .f.add_pixel(ximage, value) ximage.f.add_pixel(ximage, value)
proc IsKeypadKey(keysym: TKeySym): bool = proc IsKeypadKey(keysym: TKeySym): bool =
IsKeypadKey = (keysym >= XK_KP_Space) and (keysym <= XK_KP_Equal) (keysym >= XK_KP_Space) and (keysym <= XK_KP_Equal)
proc IsPrivateKeypadKey(keysym: TKeySym): bool = proc IsPrivateKeypadKey(keysym: TKeySym): bool =
IsPrivateKeypadKey = (keysym >= 0x11000000) and (keysym <= 0x1100FFFF) (keysym >= 0x11000000.TKeySym) and (keysym <= 0x1100FFFF.TKeySym)
proc IsCursorKey(keysym: TKeySym): bool = proc IsCursorKey(keysym: TKeySym): bool =
IsCursorKey = (keysym >= XK_Home) and (keysym < XK_Select) (keysym >= XK_Home) and (keysym < XK_Select)
proc IsPFKey(keysym: TKeySym): bool = proc IsPFKey(keysym: TKeySym): bool =
IsPFKey = (keysym >= XK_KP_F1) and (keysym <= XK_KP_F4) (keysym >= XK_KP_F1) and (keysym <= XK_KP_F4)
proc IsFunctionKey(keysym: TKeySym): bool = proc IsFunctionKey(keysym: TKeySym): bool =
IsFunctionKey = (keysym >= XK_F1) and (keysym <= XK_F35) (keysym >= XK_F1) and (keysym <= XK_F35)
proc IsMiscFunctionKey(keysym: TKeySym): bool = proc IsMiscFunctionKey(keysym: TKeySym): bool =
IsMiscFunctionKey = (keysym >= XK_Select) and (keysym <= XK_Break) (keysym >= XK_Select) and (keysym <= XK_Break)
proc IsModifierKey(keysym: TKeySym): bool = proc IsModifierKey(keysym: TKeySym): bool =
IsModifierKey = ((keysym >= XK_Shift_L) And (keysym <= XK_Hyper_R)) Or ((keysym >= XK_Shift_L) And (keysym <= XK_Hyper_R)) Or
(keysym == XK_Mode_switch) Or (keysym == XK_Num_Lock) (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, proc uncompress*(dest: pbytef, destLen: puLongf, source: pbytef,
sourceLen: uLong): cint{.cdecl, dynlib: libz, sourceLen: uLong): cint{.cdecl, dynlib: libz,
importc: "uncompress".} importc: "uncompress".}
proc compressBound*(sourceLen: uLong): uLong {.cdecl, dynlib: libz, importc.}
proc gzopen*(path: cstring, mode: cstring): gzFile{.cdecl, dynlib: libz, proc gzopen*(path: cstring, mode: cstring): gzFile{.cdecl, dynlib: libz,
importc: "gzopen".} importc: "gzopen".}
proc gzdopen*(fd: int32, mode: cstring): gzFile{.cdecl, dynlib: libz, 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). 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 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. currently be built for.
The compiler currently supports the following platform and architecture 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``. instead of ``build.sh``.
## Getting help ## Getting help
A [forum](http://forum.nimrod-code.org/) is available if you have any questions, A [forum](http://forum.nimrod-lang.org/) is available if you have any
and you can also get help in the IRC channel questions, and you can also get help in the IRC channel on
on [Freenode](irc://irc.freenode.net/nimrod) in #nimrod. [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 ## License
The compiler and the standard library are licensed under the MIT 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). 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 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. currently be built for.
The compiler currently supports the following platform and architecture 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``. instead of ``build.sh``.
## Getting help ## Getting help
A [forum](http://forum.nimrod-code.org/) is available if you have any questions, A [forum](http://forum.nimrod-lang.org/) is available if you have any
and you can also get help in the IRC channel questions, and you can also get help in the IRC channel on
on [Freenode](irc://irc.freenode.net/nimrod) in #nimrod. [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 ## License
The compiler and the standard library are licensed under the MIT 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 var nimrodVar = 89
{.emit: """fprintf(stdout, "%d\n", cvariable + (int)`nimrodVar`);""".} {.emit: """printf("%d\n", cvariable + (int)`nimrodVar`);""".}
embedsC() embedsC()

View file

@ -10,6 +10,10 @@ type
TBar[T; I: expr[int]] = object TBar[T; I: expr[int]] = object
data: array[I, T] 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) = proc takeFoo(x: TFoo) =
echo "abracadabra" echo "abracadabra"
echo TFoo.Val echo TFoo.Val
@ -20,3 +24,8 @@ takeFoo(x)
var y: TBar[float, 4] var y: TBar[float, 4]
echo high(y.data) 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" myos="linux"
LINK_FLAGS="$LINK_FLAGS -ldl -lm" LINK_FLAGS="$LINK_FLAGS -ldl -lm"
;; ;;
*freebsd* ) *freebsd* | *dragonfly* )
myos="freebsd" myos="freebsd"
LINK_FLAGS="$LINK_FLAGS -lm" LINK_FLAGS="$LINK_FLAGS -lm"
;; ;;