basic thread support; still broken on Windows; untested on Mac OS X
This commit is contained in:
parent
0f743e0183
commit
66cfc851a1
17 changed files with 521 additions and 127 deletions
250
lib/core/macros.nim
Executable file
250
lib/core/macros.nim
Executable file
|
|
@ -0,0 +1,250 @@
|
|||
#
|
||||
#
|
||||
# Nimrod's Runtime Library
|
||||
# (c) Copyright 2009 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
|
||||
## This module contains the interface to the compiler's abstract syntax
|
||||
## tree (`AST`:idx:). Macros operate on this tree.
|
||||
|
||||
## .. include:: ../doc/astspec.txt
|
||||
|
||||
#[[[cog
|
||||
#def toEnum(name, elems):
|
||||
# body = ""
|
||||
# counter = 0
|
||||
# for e in elems:
|
||||
# if counter % 4 == 0: p = "\n "
|
||||
# else: p = ""
|
||||
# body = body + p + 'n' + e + ', '
|
||||
# counter = counter + 1
|
||||
#
|
||||
# return (" TNimrod%s* = enum%s\n TNim%ss* = set[TNimrod%s]\n" %
|
||||
# (name, body[:-2], name, name))
|
||||
#
|
||||
#enums = eval(open("data/ast.yml").read())
|
||||
#cog.out("type\n")
|
||||
#for key, val in enums.items():
|
||||
# if key[-4:] == "Flag": continue
|
||||
# cog.out(toEnum(key, val))
|
||||
#]]]
|
||||
type
|
||||
TNimrodNodeKind* = enum
|
||||
nnkNone, nnkEmpty, nnkIdent, nnkSym,
|
||||
nnkType, nnkCharLit, nnkIntLit, nnkInt8Lit,
|
||||
nnkInt16Lit, nnkInt32Lit, nnkInt64Lit, nnkFloatLit,
|
||||
nnkFloat32Lit, nnkFloat64Lit, nnkStrLit, nnkRStrLit,
|
||||
nnkTripleStrLit, nnkMetaNode, nnkNilLit, nnkDotCall,
|
||||
nnkCommand, nnkCall, nnkCallStrLit, nnkExprEqExpr,
|
||||
nnkExprColonExpr, nnkIdentDefs, nnkVarTuple, nnkInfix,
|
||||
nnkPrefix, nnkPostfix, nnkPar, nnkCurly,
|
||||
nnkBracket, nnkBracketExpr, nnkPragmaExpr, nnkRange,
|
||||
nnkDotExpr, nnkCheckedFieldExpr, nnkDerefExpr, nnkIfExpr,
|
||||
nnkElifExpr, nnkElseExpr, nnkLambda, nnkAccQuoted,
|
||||
nnkTableConstr, nnkBind, nnkSymChoice, nnkHiddenStdConv,
|
||||
nnkHiddenSubConv, nnkHiddenCallConv, nnkConv, nnkCast,
|
||||
nnkAddr, nnkHiddenAddr, nnkHiddenDeref, nnkObjDownConv,
|
||||
nnkObjUpConv, nnkChckRangeF, nnkChckRange64, nnkChckRange,
|
||||
nnkStringToCString, nnkCStringToString, nnkPassAsOpenArray, nnkAsgn,
|
||||
nnkFastAsgn, nnkGenericParams, nnkFormalParams, nnkOfInherit,
|
||||
nnkModule, nnkProcDef, nnkMethodDef, nnkConverterDef,
|
||||
nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch,
|
||||
nnkElifBranch, nnkExceptBranch, nnkElse, nnkMacroStmt,
|
||||
nnkAsmStmt, nnkPragma, nnkIfStmt, nnkWhenStmt,
|
||||
nnkForStmt, nnkWhileStmt, nnkCaseStmt, nnkVarSection,
|
||||
nnkConstSection, nnkConstDef, nnkTypeSection, nnkTypeDef,
|
||||
nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt,
|
||||
nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt,
|
||||
nnkDiscardStmt, nnkStmtList, nnkImportStmt, nnkFromStmt,
|
||||
nnkIncludeStmt, nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr,
|
||||
nnkStmtListType, nnkBlockType, nnkTypeOfExpr, nnkObjectTy,
|
||||
nnkTupleTy, nnkRecList, nnkRecCase, nnkRecWhen,
|
||||
nnkRefTy, nnkPtrTy, nnkVarTy, nnkDistinctTy,
|
||||
nnkProcTy, nnkEnumTy, nnkEnumFieldDef, nnkReturnToken
|
||||
TNimNodeKinds* = set[TNimrodNodeKind]
|
||||
TNimrodTypeKind* = enum
|
||||
ntyNone, ntyBool, ntyChar, ntyEmpty,
|
||||
ntyArrayConstr, ntyNil, ntyExpr, ntyStmt,
|
||||
ntyTypeDesc, ntyGenericInvokation, ntyGenericBody, ntyGenericInst,
|
||||
ntyGenericParam, ntyDistinct, ntyEnum, ntyOrdinal,
|
||||
ntyArray, ntyObject, ntyTuple, ntySet,
|
||||
ntyRange, ntyPtr, ntyRef, ntyVar,
|
||||
ntySequence, ntyProc, ntyPointer, ntyOpenArray,
|
||||
ntyString, ntyCString, ntyForward, ntyInt,
|
||||
ntyInt8, ntyInt16, ntyInt32, ntyInt64,
|
||||
ntyFloat, ntyFloat32, ntyFloat64, ntyFloat128
|
||||
TNimTypeKinds* = set[TNimrodTypeKind]
|
||||
TNimrodSymKind* = enum
|
||||
nskUnknown, nskConditional, nskDynLib, nskParam,
|
||||
nskGenericParam, nskTemp, nskType, nskConst,
|
||||
nskVar, nskProc, nskMethod, nskIterator,
|
||||
nskConverter, nskMacro, nskTemplate, nskField,
|
||||
nskEnumField, nskForVar, nskModule, nskLabel,
|
||||
nskStub
|
||||
TNimSymKinds* = set[TNimrodSymKind]
|
||||
#[[[end]]]
|
||||
|
||||
type
|
||||
TNimrodIdent* = object of TObject
|
||||
## represents a Nimrod identifier in the AST
|
||||
|
||||
TNimrodSymbol {.final.} = object # hidden
|
||||
TNimrodType {.final.} = object # hidden
|
||||
|
||||
PNimrodType* {.compilerproc.} = ref TNimrodType
|
||||
## represents a Nimrod type in the compiler; currently this is not very
|
||||
## useful as there is no API to deal with Nimrod types.
|
||||
|
||||
PNimrodSymbol* {.compilerproc.} = ref TNimrodSymbol
|
||||
## represents a Nimrod *symbol* in the compiler; a *symbol* is a looked-up
|
||||
## *ident*.
|
||||
|
||||
PNimrodNode* = expr
|
||||
## represents a Nimrod AST node. Macros operate on this type.
|
||||
|
||||
# Nodes should be reference counted to make the `copy` operation very fast!
|
||||
# However, this is difficult to achieve: modify(n[0][1]) should propagate to
|
||||
# its father. How to do this without back references? Hm, BS, it works without
|
||||
# them.
|
||||
|
||||
proc `[]`* (n: PNimrodNode, i: int): PNimrodNode {.magic: "NChild".}
|
||||
## get `n`'s `i`'th child.
|
||||
|
||||
proc `[]=`* (n: PNimrodNode, i: int, child: PNimrodNode) {.magic: "NSetChild".}
|
||||
## set `n`'s `i`'th child to `child`.
|
||||
|
||||
proc `!` *(s: string): TNimrodIdent {.magic: "StrToIdent".}
|
||||
## constructs an identifier from the string `s`
|
||||
|
||||
proc `$`*(i: TNimrodIdent): string {.magic: "IdentToStr".}
|
||||
## converts a Nimrod identifier to a string
|
||||
|
||||
proc `==`* (a, b: TNimrodIdent): bool {.magic: "EqIdent", noSideEffect.}
|
||||
## compares two Nimrod identifiers
|
||||
|
||||
proc `==`* (a, b: PNimrodNode): bool {.magic: "EqNimrodNode", noSideEffect.}
|
||||
## compares two Nimrod nodes
|
||||
|
||||
proc len*(n: PNimrodNode): int {.magic: "NLen".}
|
||||
## returns the number of children of `n`.
|
||||
|
||||
proc add*(father, child: PNimrodNode) {.magic: "NAdd".}
|
||||
## adds the `child` to the `father` node
|
||||
|
||||
proc add*(father: PNimrodNode, children: openArray[PNimrodNode]) {.
|
||||
magic: "NAddMultiple".}
|
||||
## adds each child of `children` to the `father` node
|
||||
|
||||
proc del*(father: PNimrodNode, idx = 0, n = 1) {.magic: "NDel".}
|
||||
## deletes `n` children of `father` starting at index `idx`.
|
||||
|
||||
proc kind*(n: PNimrodNode): TNimrodNodeKind {.magic: "NKind".}
|
||||
## returns the `kind` of the node `n`.
|
||||
|
||||
proc intVal*(n: PNimrodNode): biggestInt {.magic: "NIntVal".}
|
||||
proc floatVal*(n: PNimrodNode): biggestFloat {.magic: "NFloatVal".}
|
||||
proc symbol*(n: PNimrodNode): PNimrodSymbol {.magic: "NSymbol".}
|
||||
proc ident*(n: PNimrodNode): TNimrodIdent {.magic: "NIdent".}
|
||||
proc typ*(n: PNimrodNode): PNimrodType {.magic: "NGetType".}
|
||||
proc strVal*(n: PNimrodNode): string {.magic: "NStrVal".}
|
||||
|
||||
proc `intVal=`*(n: PNimrodNode, val: biggestInt) {.magic: "NSetIntVal".}
|
||||
proc `floatVal=`*(n: PNimrodNode, val: biggestFloat) {.magic: "NSetFloatVal".}
|
||||
proc `symbol=`*(n: PNimrodNode, val: PNimrodSymbol) {.magic: "NSetSymbol".}
|
||||
proc `ident=`*(n: PNimrodNode, val: TNimrodIdent) {.magic: "NSetIdent".}
|
||||
proc `typ=`*(n: PNimrodNode, typ: PNimrodType) {.magic: "NSetType".}
|
||||
proc `strVal=`*(n: PNimrodNode, val: string) {.magic: "NSetStrVal".}
|
||||
|
||||
proc newNimNode*(kind: TNimrodNodeKind,
|
||||
n: PNimrodNode=nil): PNimrodNode {.magic: "NNewNimNode".}
|
||||
|
||||
proc copyNimNode*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimNode".}
|
||||
proc copyNimTree*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimTree".}
|
||||
|
||||
proc error*(msg: string) {.magic: "NError".}
|
||||
## writes an error message at compile time
|
||||
|
||||
proc warning*(msg: string) {.magic: "NWarning".}
|
||||
## writes a warning message at compile time
|
||||
|
||||
proc hint*(msg: string) {.magic: "NHint".}
|
||||
## writes a hint message at compile time
|
||||
|
||||
proc newStrLitNode*(s: string): PNimrodNode {.compileTime.} =
|
||||
## creates a string literal node from `s`
|
||||
result = newNimNode(nnkStrLit)
|
||||
result.strVal = s
|
||||
|
||||
proc newIntLitNode*(i: biggestInt): PNimrodNode {.compileTime.} =
|
||||
## creates a int literal node from `i`
|
||||
result = newNimNode(nnkIntLit)
|
||||
result.intVal = i
|
||||
|
||||
proc newFloatLitNode*(f: biggestFloat): PNimrodNode {.compileTime.} =
|
||||
## creates a float literal node from `f`
|
||||
result = newNimNode(nnkFloatLit)
|
||||
result.floatVal = f
|
||||
|
||||
proc newIdentNode*(i: TNimrodIdent): PNimrodNode {.compileTime.} =
|
||||
## creates an identifier node from `i`
|
||||
result = newNimNode(nnkIdent)
|
||||
result.ident = i
|
||||
|
||||
proc newIdentNode*(i: string): PNimrodNode {.compileTime.} =
|
||||
## creates an identifier node from `i`
|
||||
result = newNimNode(nnkIdent)
|
||||
result.ident = !i
|
||||
|
||||
proc toStrLit*(n: PNimrodNode): PNimrodNode {.compileTime.} =
|
||||
## converts the AST `n` to the concrete Nimrod code and wraps that
|
||||
## in a string literal node
|
||||
return newStrLitNode(repr(n))
|
||||
|
||||
proc expectKind*(n: PNimrodNode, k: TNimrodNodeKind) {.compileTime.} =
|
||||
## checks that `n` is of kind `k`. If this is not the case,
|
||||
## compilation aborts with an error message. This is useful for writing
|
||||
## macros that check the AST that is passed to them.
|
||||
if n.kind != k: error("macro expects a node of kind: " & repr(k))
|
||||
|
||||
proc expectMinLen*(n: PNimrodNode, min: int) {.compileTime.} =
|
||||
## checks that `n` has at least `min` children. If this is not the case,
|
||||
## compilation aborts with an error message. This is useful for writing
|
||||
## macros that check its number of arguments.
|
||||
if n.len < min: error("macro expects a node with " & $min & " children")
|
||||
|
||||
proc expectLen*(n: PNimrodNode, len: int) {.compileTime.} =
|
||||
## checks that `n` has exactly `len` children. If this is not the case,
|
||||
## compilation aborts with an error message. This is useful for writing
|
||||
## macros that check its number of arguments.
|
||||
if n.len != len: error("macro expects a node with " & $len & " children")
|
||||
|
||||
proc newCall*(theProc: TNimrodIdent,
|
||||
args: openArray[PNimrodNode]): PNimrodNode {.compileTime.} =
|
||||
## produces a new call node. `theProc` is the proc that is called with
|
||||
## the arguments ``args[0..]``.
|
||||
result = newNimNode(nnkCall)
|
||||
result.add(newIdentNode(theProc))
|
||||
result.add(args)
|
||||
|
||||
proc newCall*(theProc: string,
|
||||
args: openArray[PNimrodNode]): PNimrodNode {.compileTime.} =
|
||||
## produces a new call node. `theProc` is the proc that is called with
|
||||
## the arguments ``args[0..]``.
|
||||
result = newNimNode(nnkCall)
|
||||
result.add(newIdentNode(theProc))
|
||||
result.add(args)
|
||||
|
||||
proc nestList*(theProc: TNimrodIdent,
|
||||
x: PNimrodNode): PNimrodNode {.compileTime.} =
|
||||
## nests the list `x` into a tree of call expressions:
|
||||
## ``[a, b, c]`` is transformed into ``theProc(a, theProc(c, d))``
|
||||
var L = x.len
|
||||
result = newCall(theProc, x[L-2], x[L-1])
|
||||
var a = result
|
||||
for i in countdown(L-3, 0):
|
||||
a = newCall(theProc, x[i], copyNimTree(a))
|
||||
|
||||
259
lib/core/marshal.nim
Normal file
259
lib/core/marshal.nim
Normal file
|
|
@ -0,0 +1,259 @@
|
|||
#
|
||||
#
|
||||
# Nimrod's Runtime Library
|
||||
# (c) Copyright 2011 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This module contains procs for serialization and deseralization of
|
||||
## arbitrary Nimrod data structures. XXX This is not implemented yet!
|
||||
|
||||
import streams
|
||||
|
||||
proc load*[T](s: PStream, data: var T) {.magic: "Load".}
|
||||
## loads `data` from the stream `s`. Raises `EIO` in case of an error.
|
||||
|
||||
proc store*[T](s: PStream, data: T) {.magic: "Store".}
|
||||
## stores `data` into the stream `s`. Raises `EIO` in case of an error.
|
||||
|
||||
|
||||
proc reprInt(x: int64): string {.compilerproc.} = return $x
|
||||
proc reprFloat(x: float): string {.compilerproc.} = return $x
|
||||
|
||||
proc reprPointer(x: pointer): string {.compilerproc.} =
|
||||
var buf: array [0..59, char]
|
||||
c_sprintf(buf, "%p", x)
|
||||
return $buf
|
||||
|
||||
proc reprStrAux(result: var string, s: string) =
|
||||
if cast[pointer](s) == nil:
|
||||
add result, "nil"
|
||||
return
|
||||
add result, reprPointer(cast[pointer](s)) & "\""
|
||||
for c in items(s):
|
||||
case c
|
||||
of '"': add result, "\\\""
|
||||
of '\\': add result, "\\\\" # BUGFIX: forgotten
|
||||
of '\10': add result, "\\10\"\n\"" # " \n " # better readability
|
||||
of '\128' .. '\255', '\0'..'\9', '\11'..'\31':
|
||||
add result, "\\" & reprInt(ord(c))
|
||||
else: result.add(c)
|
||||
add result, "\""
|
||||
|
||||
proc reprStr(s: string): string {.compilerRtl.} =
|
||||
result = ""
|
||||
reprStrAux(result, s)
|
||||
|
||||
proc reprBool(x: bool): string {.compilerRtl.} =
|
||||
if x: result = "true"
|
||||
else: result = "false"
|
||||
|
||||
proc reprChar(x: char): string {.compilerRtl.} =
|
||||
result = "\'"
|
||||
case x
|
||||
of '"': add result, "\\\""
|
||||
of '\\': add result, "\\\\"
|
||||
of '\128' .. '\255', '\0'..'\31': add result, "\\" & reprInt(ord(x))
|
||||
else: add result, x
|
||||
add result, "\'"
|
||||
|
||||
proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} =
|
||||
if e <% typ.node.len: # BUGFIX
|
||||
result = $typ.node.sons[e].name
|
||||
else:
|
||||
result = $e & " (invalid data!)"
|
||||
|
||||
type
|
||||
pbyteArray = ptr array[0.. 0xffff, byte]
|
||||
|
||||
proc addSetElem(result: var string, elem: int, typ: PNimType) =
|
||||
case typ.kind
|
||||
of tyEnum: add result, reprEnum(elem, typ)
|
||||
of tyBool: add result, reprBool(bool(elem))
|
||||
of tyChar: add result, reprChar(chr(elem))
|
||||
of tyRange: addSetElem(result, elem, typ.base)
|
||||
of tyInt..tyInt64: add result, reprInt(elem)
|
||||
else: # data corrupt --> inform the user
|
||||
add result, " (invalid data!)"
|
||||
|
||||
proc reprSetAux(result: var string, p: pointer, typ: PNimType) =
|
||||
# "typ.slots.len" field is for sets the "first" field
|
||||
var elemCounter = 0 # we need this flag for adding the comma at
|
||||
# the right places
|
||||
add result, "{"
|
||||
var u: int64
|
||||
case typ.size
|
||||
of 1: u = ze64(cast[ptr int8](p)^)
|
||||
of 2: u = ze64(cast[ptr int16](p)^)
|
||||
of 4: u = ze64(cast[ptr int32](p)^)
|
||||
of 8: u = cast[ptr int64](p)^
|
||||
else:
|
||||
var a = cast[pbyteArray](p)
|
||||
for i in 0 .. typ.size*8-1:
|
||||
if (ze(a[i div 8]) and (1 shl (i mod 8))) != 0:
|
||||
if elemCounter > 0: add result, ", "
|
||||
addSetElem(result, i+typ.node.len, typ.base)
|
||||
inc(elemCounter)
|
||||
if typ.size <= 8:
|
||||
for i in 0..sizeof(int64)*8-1:
|
||||
if (u and (1 shl i)) != 0:
|
||||
if elemCounter > 0: add result, ", "
|
||||
addSetElem(result, i+typ.node.len, typ.base)
|
||||
inc(elemCounter)
|
||||
add result, "}"
|
||||
|
||||
proc reprSet(p: pointer, typ: PNimType): string {.compilerRtl.} =
|
||||
result = ""
|
||||
reprSetAux(result, p, typ)
|
||||
|
||||
type
|
||||
TReprClosure {.final.} = object # we cannot use a global variable here
|
||||
# as this wouldn't be thread-safe
|
||||
marked: TCellSet
|
||||
recdepth: int # do not recurse endless
|
||||
indent: int # indentation
|
||||
|
||||
when not defined(useNimRtl):
|
||||
proc initReprClosure(cl: var TReprClosure) =
|
||||
Init(cl.marked)
|
||||
cl.recdepth = -1 # default is to display everything!
|
||||
cl.indent = 0
|
||||
|
||||
proc deinitReprClosure(cl: var TReprClosure) =
|
||||
Deinit(cl.marked)
|
||||
|
||||
proc reprBreak(result: var string, cl: TReprClosure) =
|
||||
add result, "\n"
|
||||
for i in 0..cl.indent-1: add result, ' '
|
||||
|
||||
proc reprAux(result: var string, p: pointer, typ: PNimType,
|
||||
cl: var TReprClosure)
|
||||
|
||||
proc reprArray(result: var string, p: pointer, typ: PNimType,
|
||||
cl: var TReprClosure) =
|
||||
add result, "["
|
||||
var bs = typ.base.size
|
||||
for i in 0..typ.size div bs - 1:
|
||||
if i > 0: add result, ", "
|
||||
reprAux(result, cast[pointer](cast[TAddress](p) + i*bs), typ.base, cl)
|
||||
add result, "]"
|
||||
|
||||
proc reprSequence(result: var string, p: pointer, typ: PNimType,
|
||||
cl: var TReprClosure) =
|
||||
if p == nil:
|
||||
add result, "nil"
|
||||
return
|
||||
result.add(reprPointer(p) & "[")
|
||||
var bs = typ.base.size
|
||||
for i in 0..cast[PGenericSeq](p).len-1:
|
||||
if i > 0: add result, ", "
|
||||
reprAux(result, cast[pointer](cast[TAddress](p) + GenericSeqSize + i*bs),
|
||||
typ.Base, cl)
|
||||
add result, "]"
|
||||
|
||||
proc reprRecordAux(result: var string, p: pointer, n: ptr TNimNode,
|
||||
cl: var TReprClosure) =
|
||||
case n.kind
|
||||
of nkNone: assert(false)
|
||||
of nkSlot:
|
||||
add result, $n.name
|
||||
add result, " = "
|
||||
reprAux(result, cast[pointer](cast[TAddress](p) + n.offset), n.typ, cl)
|
||||
of nkList:
|
||||
for i in 0..n.len-1:
|
||||
if i > 0: add result, ",\n"
|
||||
reprRecordAux(result, p, n.sons[i], cl)
|
||||
of nkCase:
|
||||
var m = selectBranch(p, n)
|
||||
reprAux(result, cast[pointer](cast[TAddress](p) + n.offset), n.typ, cl)
|
||||
if m != nil: reprRecordAux(result, p, m, cl)
|
||||
|
||||
proc reprRecord(result: var string, p: pointer, typ: PNimType,
|
||||
cl: var TReprClosure) =
|
||||
add result, "["
|
||||
reprRecordAux(result, p, typ.node, cl)
|
||||
add result, "]"
|
||||
|
||||
proc reprRef(result: var string, p: pointer, typ: PNimType,
|
||||
cl: var TReprClosure) =
|
||||
# we know that p is not nil here:
|
||||
when defined(boehmGC) or defined(nogc):
|
||||
var cell = cast[PCell](p)
|
||||
else:
|
||||
var cell = usrToCell(p)
|
||||
add result, "ref " & reprPointer(p)
|
||||
if cell notin cl.marked:
|
||||
# only the address is shown:
|
||||
incl(cl.marked, cell)
|
||||
add result, " --> "
|
||||
reprAux(result, p, typ.base, cl)
|
||||
|
||||
proc reprAux(result: var string, p: pointer, typ: PNimType,
|
||||
cl: var TReprClosure) =
|
||||
if cl.recdepth == 0:
|
||||
add result, "..."
|
||||
return
|
||||
dec(cl.recdepth)
|
||||
case typ.kind
|
||||
of tySet: reprSetAux(result, p, typ)
|
||||
of tyArray: reprArray(result, p, typ, cl)
|
||||
of tyTuple, tyPureObject: reprRecord(result, p, typ, cl)
|
||||
of tyObject:
|
||||
var t = cast[ptr PNimType](p)^
|
||||
reprRecord(result, p, t, cl)
|
||||
of tyRef, tyPtr:
|
||||
assert(p != nil)
|
||||
if cast[ppointer](p)^ == nil: add result, "nil"
|
||||
else: reprRef(result, cast[ppointer](p)^, typ, cl)
|
||||
of tySequence:
|
||||
reprSequence(result, cast[ppointer](p)^, typ, cl)
|
||||
of tyInt: add result, $(cast[ptr int](p)^)
|
||||
of tyInt8: add result, $int(cast[ptr Int8](p)^)
|
||||
of tyInt16: add result, $int(cast[ptr Int16](p)^)
|
||||
of tyInt32: add result, $int(cast[ptr Int32](p)^)
|
||||
of tyInt64: add result, $(cast[ptr Int64](p)^)
|
||||
of tyFloat: add result, $(cast[ptr float](p)^)
|
||||
of tyFloat32: add result, $(cast[ptr float32](p)^)
|
||||
of tyFloat64: add result, $(cast[ptr float64](p)^)
|
||||
of tyEnum: add result, reprEnum(cast[ptr int](p)^, typ)
|
||||
of tyBool: add result, reprBool(cast[ptr bool](p)^)
|
||||
of tyChar: add result, reprChar(cast[ptr char](p)^)
|
||||
of tyString: reprStrAux(result, cast[ptr string](p)^)
|
||||
of tyCString: reprStrAux(result, $(cast[ptr cstring](p)^))
|
||||
of tyRange: reprAux(result, p, typ.base, cl)
|
||||
of tyProc, tyPointer:
|
||||
if cast[ppointer](p)^ == nil: add result, "nil"
|
||||
else: add result, reprPointer(cast[ppointer](p)^)
|
||||
else:
|
||||
add result, "(invalid data!)"
|
||||
inc(cl.recdepth)
|
||||
|
||||
proc reprOpenArray(p: pointer, length: int, elemtyp: PNimType): string {.
|
||||
compilerRtl.} =
|
||||
var
|
||||
cl: TReprClosure
|
||||
initReprClosure(cl)
|
||||
result = "["
|
||||
var bs = elemtyp.size
|
||||
for i in 0..length - 1:
|
||||
if i > 0: add result, ", "
|
||||
reprAux(result, cast[pointer](cast[TAddress](p) + i*bs), elemtyp, cl)
|
||||
add result, "]"
|
||||
deinitReprClosure(cl)
|
||||
|
||||
when not defined(useNimRtl):
|
||||
proc reprAny(p: pointer, typ: PNimType): string =
|
||||
var
|
||||
cl: TReprClosure
|
||||
initReprClosure(cl)
|
||||
result = ""
|
||||
if typ.kind in {tyObject, tyPureObject, tyTuple, tyArray, tySet}:
|
||||
reprAux(result, p, typ, cl)
|
||||
else:
|
||||
var p = p
|
||||
reprAux(result, addr(p), typ, cl)
|
||||
add result, "\n"
|
||||
deinitReprClosure(cl)
|
||||
|
||||
174
lib/core/threads.nim
Normal file
174
lib/core/threads.nim
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
#
|
||||
#
|
||||
# Nimrod's Runtime Library
|
||||
# (c) Copyright 2011 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Basic thread support for Nimrod. Note that Nimrod's default GC is still
|
||||
## single-threaded. This means that either your threads should not allocate
|
||||
## GC'ed memory, or you should compile with ``--gc:none`` or ``--gc:boehm``.
|
||||
##
|
||||
## Example:
|
||||
##
|
||||
## .. code-block:: nimrod
|
||||
##
|
||||
## var
|
||||
## thr: array [0..4, TThread]
|
||||
## L: TLock
|
||||
##
|
||||
## proc threadFunc(c: pointer) {.procvar.} =
|
||||
## for i in 0..9:
|
||||
## Aquire(L) # lock stdout
|
||||
## echo i
|
||||
## Release(L)
|
||||
##
|
||||
## InitLock(L)
|
||||
##
|
||||
## for i in 0..high(thr):
|
||||
## createThread(thr[i], threadFunc)
|
||||
## for i in 0..high(thr):
|
||||
## joinThread(thr[i])
|
||||
|
||||
|
||||
# We jump through some hops here to ensure that Nimrod thread procs can have
|
||||
# the Nimrod calling convention. This is needed because thread procs are
|
||||
# ``stdcall`` on Windows and ``noconv`` on UNIX. Alternative would be to just
|
||||
# use ``stdcall`` since it is mapped to ``noconv`` on UNIX anyway. However,
|
||||
# the current approach will likely result in less problems later when we have
|
||||
# GC'ed closures in Nimrod.
|
||||
|
||||
type
|
||||
TThreadProc* = proc (closure: pointer) ## Standard Nimrod thread proc.
|
||||
TThreadProcClosure {.pure, final.} = object
|
||||
fn: TThreadProc
|
||||
data: pointer
|
||||
|
||||
when defined(Windows):
|
||||
type
|
||||
THandle = int
|
||||
TSysThread = THandle
|
||||
TSysLock {.final, pure.} = object # CRITICAL_SECTION in WinApi
|
||||
DebugInfo: pointer
|
||||
LockCount: int32
|
||||
RecursionCount: int32
|
||||
OwningThread: int
|
||||
LockSemaphore: int
|
||||
Reserved: int32
|
||||
|
||||
TWinThreadProc = proc (x: pointer): int32 {.stdcall.}
|
||||
|
||||
TLock* = TSysLock ## Standard Nimrod Lock type.
|
||||
|
||||
proc InitLock*(L: var TLock) {.stdcall,
|
||||
dynlib: "kernel32", importc: "InitializeCriticalSection".}
|
||||
## Initializes the lock `L`.
|
||||
|
||||
proc Aquire*(L: var TLock) {.stdcall,
|
||||
dynlib: "kernel32", importc: "EnterCriticalSection".}
|
||||
## Aquires the lock `L`.
|
||||
|
||||
proc Release*(L: var TLock) {.stdcall,
|
||||
dynlib: "kernel32", importc: "LeaveCriticalSection".}
|
||||
## Releases the lock `L`.
|
||||
|
||||
proc CreateThread(lpThreadAttributes: Pointer, dwStackSize: int32,
|
||||
lpStartAddress: TWinThreadProc,
|
||||
lpParameter: Pointer,
|
||||
dwCreationFlags: int32, lpThreadId: var int32): THandle {.
|
||||
stdcall, dynlib: "kernel32", importc: "CreateThread".}
|
||||
|
||||
when false:
|
||||
proc winSuspendThread(hThread: TSysThread): int32 {.
|
||||
stdcall, dynlib: "kernel32", importc: "SuspendThread".}
|
||||
|
||||
proc winResumeThread(hThread: TSysThread): int32 {.
|
||||
stdcall, dynlib: "kernel32", importc: "ResumeThread".}
|
||||
|
||||
proc WaitForMultipleObjects(nCount: int32,
|
||||
lpHandles: ptr array[0..10, THandle],
|
||||
bWaitAll: int32,
|
||||
dwMilliseconds: int32): int32 {.
|
||||
stdcall, dynlib: "kernel32", importc: "WaitForMultipleObjects".}
|
||||
|
||||
proc WaitForSingleObject(hHandle: THANDLE, dwMilliseconds: int32): int32 {.
|
||||
stdcall, dynlib: "kernel32", importc: "WaitForSingleObject".}
|
||||
|
||||
proc TerminateThread(hThread: THandle, dwExitCode: int32): int32 {.
|
||||
stdcall, dynlib: "kernel32", importc: "TerminateThread".}
|
||||
|
||||
proc threadProcWrapper(closure: pointer): int32 {.stdcall.} =
|
||||
var c = cast[ptr TThreadProcClosure](closure)
|
||||
c.fn(c.data)
|
||||
# implicitely return 0
|
||||
|
||||
else:
|
||||
type
|
||||
TSysLock {.importc: "pthread_mutex_t", header: "<sys/types.h>".} = int
|
||||
TSysThread {.importc: "pthread_t", header: "<sys/types.h>".} = int
|
||||
|
||||
TLock* = TSysLock
|
||||
|
||||
proc InitLockAux(L: var TSysLock, attr: pointer = nil) {.
|
||||
importc: "pthread_mutex_init", header: "<pthread.h>".}
|
||||
|
||||
proc InitLock*(L: var TLock) {.inline.} =
|
||||
InitLockAux(L)
|
||||
proc Aquire*(L: var TLock) {.
|
||||
importc: "pthread_mutex_lock", header: "<pthread.h>".}
|
||||
proc Release*(L: var TLock) {.
|
||||
importc: "pthread_mutex_unlock", header: "<pthread.h>".}
|
||||
|
||||
proc pthread_create(a1: var TSysThread, a2: ptr int,
|
||||
a3: proc (x: pointer) {.noconv.},
|
||||
a4: pointer): cint {.importc: "pthread_create",
|
||||
header: "<pthread.h>".}
|
||||
proc pthread_join(a1: TSysThread, a2: ptr pointer): cint {.
|
||||
importc, header: "<pthread.h>".}
|
||||
|
||||
proc pthread_cancel(a1: TSysThread): cint {.
|
||||
importc: "pthread_cancel", header: "<pthread.h>".}
|
||||
|
||||
proc threadProcWrapper(closure: pointer) {.noconv.} =
|
||||
var c = cast[ptr TThreadProcClosure](closure)
|
||||
c.fn(c.data)
|
||||
|
||||
{.passL: "-pthread".}
|
||||
{.passC: "-pthread".}
|
||||
|
||||
type
|
||||
TThread* = object of TObject ## Nimrod thread.
|
||||
sys: TSysThread
|
||||
c: TThreadProcClosure
|
||||
|
||||
|
||||
proc createThread*(t: var TThread, tp: TThreadProc,
|
||||
closure: pointer = nil) =
|
||||
## creates a new thread `t` and starts its execution. Entry point is the
|
||||
## proc `tp`. `closure` is passed to `tp`.
|
||||
t.c.data = closure
|
||||
t.c.fn = tp
|
||||
when defined(windows):
|
||||
var dummyThreadId: int32
|
||||
t.sys = CreateThread(nil, 0'i32, threadProcWrapper, addr(t.c), 0'i32,
|
||||
dummyThreadId)
|
||||
else:
|
||||
discard pthread_create(t.sys, nil, threadProcWrapper, addr(t.c))
|
||||
|
||||
proc joinThread*(t: TThread) =
|
||||
## waits for the thread `t` until it has terminated.
|
||||
when defined(windows):
|
||||
discard WaitForSingleObject(t.sys, -1'i32)
|
||||
else:
|
||||
discard pthread_join(t.sys, nil)
|
||||
|
||||
proc destroyThread*(t: var TThread) =
|
||||
## forces the thread `t` to terminate. This is potentially dangerous if
|
||||
## you don't have full control over `t` and its aquired ressources.
|
||||
when defined(windows):
|
||||
discard TerminateThread(t.sys, 1'i32)
|
||||
else:
|
||||
discard pthread_cancel(t.sys)
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue