bugfixes for generics; new threads implementation still broken

This commit is contained in:
Araq
2011-09-20 00:56:48 +02:00
parent dc3ace4f37
commit fd62116f6e
19 changed files with 260 additions and 126 deletions

View File

@@ -279,8 +279,8 @@ type
TTypeFlags* = set[TTypeFlag]
TSymKind* = enum # the different symbols (start with the prefix sk);
# order is important for the documentation generator!
TSymKind* = enum # the different symbols (start with the prefix sk);
# order is important for the documentation generator!
skUnknown, # unknown symbol: used for parsing assembler blocks
# and first phase symbol lookup in generics
skConditional, # symbol for the preprocessor (may become obsolete)
@@ -848,6 +848,10 @@ proc initNodeTable(x: var TNodeTable) =
proc sonsLen(n: PType): int =
if isNil(n.sons): result = 0
else: result = len(n.sons)
proc len*(n: PType): int =
if isNil(n.sons): result = 0
else: result = len(n.sons)
proc newSons(father: PType, length: int) =
if isNil(father.sons): father.sons = @[]

View File

@@ -46,7 +46,6 @@ proc StrTableContains*(t: TStrTable, n: PSym): bool
proc StrTableAdd*(t: var TStrTable, n: PSym)
proc StrTableGet*(t: TStrTable, name: PIdent): PSym
# the iterator scheme:
type
TTabIter*{.final.} = object # consider all fields here private
h*: THash # current hash
@@ -749,6 +748,10 @@ proc IdTablePut(t: var TIdTable, key: PIdObj, val: PObject) =
IdTableRawInsert(t.data, key, val)
inc(t.counter)
iterator IdTablePairs*(t: TIdTable): tuple[key: PIdObj, val: PObject] =
for i in 0 .. high(t.data):
if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
proc writeIdNodeTable(t: TIdNodeTable) =
nil

View File

@@ -49,6 +49,13 @@ proc ProcessCmdLine(pass: TCmdLinePass, command, filename: var string) =
if optRun notin gGlobalOptions and arguments != "":
rawMessage(errArgsNeedRunOption, [])
proc prependCurDir(f: string): string =
when defined(unix):
if os.isAbsolute(f): result = f
else: result = "./" & f
else:
result = f
proc HandleCmdLine() =
var start = epochTime()
if paramCount() == 0:
@@ -79,11 +86,8 @@ proc HandleCmdLine() =
rawMessage(hintSuccessX, [$gLinesCompiled,
formatFloat(epochTime() - start, ffDecimal, 3)])
if optRun in gGlobalOptions:
when defined(unix):
var prog = "./" & quoteIfContainsWhite(changeFileExt(filename, ""))
else:
var prog = quoteIfContainsWhite(changeFileExt(filename, ""))
execExternalProgram(prog & ' ' & arguments)
var ex = quoteIfContainsWhite(changeFileExt(filename, "").prependCurDir)
execExternalProgram(ex & ' ' & arguments)
#GC_disableMarkAndSweep()
cmdLineInfo = newLineInfo("command line", -1, -1)

View File

@@ -53,6 +53,7 @@ const
wExtern, wImportcpp, wImportobjc}
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideEffect,
wThread}
allRoutinePragmas* = procPragmas + iteratorPragmas + lambdaPragmas
proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)
proc pragmaAsm*(c: PContext, n: PNode): char

View File

@@ -146,7 +146,7 @@ proc addCodeForGenerics(c: PContext, n: PNode) =
addSon(n, prc.ast)
lastGenericIdx = Len(generics)
proc semExprNoFlags(c: PContext, n: PNode): PNode =
proc semExprNoFlags(c: PContext, n: PNode): PNode {.procvar.} =
result = semExpr(c, n, {})
proc myOpen(module: PSym, filename: string): PPassContext =

View File

@@ -1178,9 +1178,10 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
else:
#liMessage(n.info, warnUser, renderTree(n));
result = semIndirectOp(c, n, flags)
elif n.sons[0].kind == nkSymChoice:
elif n.sons[0].kind == nkSymChoice or n[0].kind == nkBracketExpr and
n[0][0].kind == nkSymChoice:
result = semDirectOp(c, n, flags)
else:
else:
result = semIndirectOp(c, n, flags)
of nkMacroStmt:
result = semMacroStmt(c, n)

View File

@@ -29,6 +29,10 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
break
if t.kind == tyGenericParam:
InternalError(a.info, "instantiateGenericParamList: " & q.name.s)
elif t.kind == tyGenericInvokation:
#t = instGenericContainer(c, a, t)
t = generateTypeInstance(c, pt, a, t)
#t = ReplaceTypeVarsT(cl, t)
s.typ = t
addDecl(c, s)
entry.concreteTypes[i] = t
@@ -94,6 +98,14 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
closeScope(c.tab)
popInfoContext()
proc sideEffectsCheck(c: PContext, s: PSym) =
if {sfNoSideEffect, sfSideEffect} * s.flags ==
{sfNoSideEffect, sfSideEffect}:
LocalError(s.info, errXhasSideEffects, s.name.s)
elif sfThread in s.flags and semthreads.needsGlobalAnalysis() and
s.ast.sons[genericParamsPos].kind == nkEmpty:
c.threadEntries.add(s)
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
info: TLineInfo): PSym =
# generates an instantiated proc
@@ -133,7 +145,10 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
var oldPrc = GenericCacheGet(c, entry)
if oldPrc == nil:
generics.add(entry)
if n.sons[pragmasPos].kind != nkEmpty:
pragma(c, result, n.sons[pragmasPos], allRoutinePragmas)
instantiateBody(c, n, result)
sideEffectsCheck(c, result)
else:
result = oldPrc
popInfoContext()

View File

@@ -554,13 +554,6 @@ proc semBorrow(c: PContext, n: PNode, s: PSym) =
n.sons[codePos] = newSymNode(b)
else:
LocalError(n.info, errNoSymbolToBorrowFromFound)
proc sideEffectsCheck(c: PContext, s: PSym) =
if {sfNoSideEffect, sfSideEffect} * s.flags ==
{sfNoSideEffect, sfSideEffect}:
LocalError(s.info, errXhasSideEffects, s.name.s)
elif sfThread in s.flags and semthreads.needsGlobalAnalysis():
c.threadEntries.add(s)
proc addResult(c: PContext, t: PType, info: TLineInfo) =
if t != nil:

View File

@@ -216,23 +216,6 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
addSon(result.n, newSymNode(field))
addSon(result, typ)
proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
if s.typ == nil or s.typ.kind != tyGenericBody:
GlobalError(n.info, errCannotInstantiateX, s.name.s)
result = newOrPrevType(tyGenericInvokation, prev, c)
if s.typ.containerID == 0: InternalError(n.info, "semtypes.semGeneric")
if sonsLen(n) != sonsLen(s.typ):
GlobalError(n.info, errWrongNumberOfArguments)
addSon(result, s.typ)
var isConcrete = true # iterate over arguments:
for i in countup(1, sonsLen(n)-1):
var elem = semTypeNode(c, n.sons[i], nil)
if elem.kind in {tyGenericParam, tyGenericInvokation}: isConcrete = false
addSon(result, elem)
if isConcrete:
if s.ast == nil: GlobalError(n.info, errCannotInstantiateX, s.name.s)
result = instGenericContainer(c, n, result)
proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags): PSym =
# identifier with visibility
@@ -489,7 +472,6 @@ proc addTypeVarsOfGenericBody(c: PContext, t: PType, genericParams: PNode,
if ContainsOrIncl(cl, t.id): return
case t.kind
of tyGenericBody:
#debug(t)
result = newTypeS(tyGenericInvokation, c)
addSon(result, t)
for i in countup(0, sonsLen(t) - 2):
@@ -505,11 +487,9 @@ proc addTypeVarsOfGenericBody(c: PContext, t: PType, genericParams: PNode,
addSon(genericParams, newSymNode(s))
addSon(result, t.sons[i])
of tyGenericInst:
#debug(t)
var L = sonsLen(t) - 1
t.sons[L] = addTypeVarsOfGenericBody(c, t.sons[L], genericParams, cl)
of tyGenericInvokation:
#debug(t)
for i in countup(1, sonsLen(t) - 1):
t.sons[i] = addTypeVarsOfGenericBody(c, t.sons[i], genericParams, cl)
else:
@@ -520,7 +500,6 @@ proc paramType(c: PContext, n, genericParams: PNode, cl: var TIntSet): PType =
result = semTypeNode(c, n, nil)
if genericParams != nil and sonsLen(genericParams) == 0:
result = addTypeVarsOfGenericBody(c, result, genericParams, cl)
#if result.kind == tyGenericInvokation: debug(result)
proc semProcTypeNode(c: PContext, n, genericParams: PNode,
prev: PType): PType =
@@ -546,6 +525,9 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
var length = sonsLen(a)
if a.sons[length-2].kind != nkEmpty:
typ = paramType(c, a.sons[length-2], genericParams, cl)
#if matchType(typ, [(tyVar, 0)], tyGenericInvokation):
# debug a.sons[length-2][0][1]
else:
typ = nil
if a.sons[length-1].kind != nkEmpty:
@@ -557,8 +539,9 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
# and def.typ != nil and def.typ.kind != tyNone:
# example code that triggers it:
# proc sort[T](cmp: proc(a, b: T): int = cmp)
def = fitNode(c, typ, def)
else:
if not containsGenericType(typ):
def = fitNode(c, typ, def)
else:
def = ast.emptyNode
if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
for j in countup(0, length-3):
@@ -578,6 +561,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
result.sons[0] = r
res.typ = result.sons[0]
#if matchType(result, [(tyProc, 1), (tyVar, 0)], tyGenericInvokation):
# debug result
proc semStmtListType(c: PContext, n: PNode, prev: PType): PType =
checkMinSonsLen(n, 1)
@@ -603,6 +588,50 @@ proc semBlockType(c: PContext, n: PNode, prev: PType): PType =
closeScope(c.tab)
Dec(c.p.nestedBlockCounter)
proc semGenericParamInInvokation(c: PContext, n: PNode): PType =
# XXX hack 1022 for generics ... would have been nice if the compiler had
# been designed with them in mind from start ...
when false:
if n.kind == nkSym:
# for generics we need to lookup the type var again:
var s = SymtabGet(c.Tab, n.sym.name)
if s != nil:
if s.kind == skType and s.typ != nil:
var t = n.sym.typ
echo "came here"
return t
else:
echo "s is crap:"
debug(s)
else:
echo "s is nil!!!!"
result = semTypeNode(c, n, nil)
proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
if s.typ == nil or s.typ.kind != tyGenericBody:
GlobalError(n.info, errCannotInstantiateX, s.name.s)
result = newOrPrevType(tyGenericInvokation, prev, c)
if s.typ.containerID == 0: InternalError(n.info, "semtypes.semGeneric")
if sonsLen(n) != sonsLen(s.typ):
GlobalError(n.info, errWrongNumberOfArguments)
addSon(result, s.typ)
var isConcrete = true # iterate over arguments:
for i in countup(1, sonsLen(n)-1):
var elem = semGenericParamInInvokation(c, n.sons[i])
if containsGenericType(elem): isConcrete = false
#if elem.kind in {tyGenericParam, tyGenericInvokation}: isConcrete = false
addSon(result, elem)
if isConcrete:
if s.ast == nil: GlobalError(n.info, errCannotInstantiateX, s.name.s)
result = instGenericContainer(c, n, result)
proc FixupRemainingGenericInvokations(c: PContext, n: PNode,
typ: PType): PType =
if typ.kind == tyGenericInvokation:
nil
else:
result = typ
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
result = nil
if gCmd == cmdIdeTools: suggestExpr(c, n)

View File

@@ -92,51 +92,90 @@ proc ReplaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
proc lookupTypeVar(cl: TReplTypeVars, t: PType): PType =
result = PType(idTableGet(cl.typeMap, t))
if result == nil:
if result == nil:
GlobalError(t.sym.info, errCannotInstantiateX, typeToString(t))
elif result.kind == tyGenericParam:
InternalError(cl.info, "substitution with generic parameter")
proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
# tyGenericInvokation[A, tyGenericInvokation[A, B]]
# is difficult to handle:
var body = t.sons[0]
if body.kind != tyGenericBody: InternalError(cl.info, "no generic body")
var header: PType = nil
for i in countup(1, sonsLen(t) - 1):
var x = replaceTypeVarsT(cl, t.sons[i])
if t.sons[i].kind == tyGenericParam:
if header == nil: header = copyType(t, t.owner, false)
header.sons[i] = x
when false:
var x: PType
if t.sons[i].kind == tyGenericParam:
x = lookupTypeVar(cl, t.sons[i])
when true:
# search for some instantiation here:
result = searchInstTypes(gInstTypes, t)
if result != nil: return
for i in countup(1, sonsLen(t) - 1):
var x = t.sons[i]
if x.kind == tyGenericParam:
x = lookupTypeVar(cl, x)
if header == nil: header = copyType(t, t.owner, false)
header.sons[i] = x
else:
x = t.sons[i]
idTablePut(cl.typeMap, body.sons[i-1], x)
if header == nil: header = t
result = searchInstTypes(gInstTypes, header)
if result != nil: return
result = newType(tyGenericInst, t.sons[0].owner)
for i in countup(0, sonsLen(t) - 1):
# if one of the params is not concrete, we cannot do anything
# but we already raised an error!
addSon(result, header.sons[i])
idTablePut(gInstTypes, header, result)
var newbody = ReplaceTypeVarsT(cl, lastSon(body))
newbody.flags = newbody.flags + t.flags + body.flags
newbody.n = ReplaceTypeVarsN(cl, lastSon(body).n)
addSon(result, newbody)
#writeln(output, ropeToStr(Typetoyaml(newbody)));
checkPartialConstructedType(cl.info, newbody)
#idTablePut(cl.typeMap, body.sons[i-1], x)
if header != nil:
# search again after first pass:
result = searchInstTypes(gInstTypes, header)
if result != nil: return
else:
header = copyType(t, t.owner, false)
# ugh need another pass for deeply recursive generic types (e.g. PActor)
# we need to add the candidate here, before it's fully instantiated for
# recursive instantions:
result = newType(tyGenericInst, t.sons[0].owner)
idTablePut(gInstTypes, header, result)
for i in countup(1, sonsLen(t) - 1):
var x = replaceTypeVarsT(cl, t.sons[i])
assert x.kind != tyGenericInvokation
header.sons[i] = x
idTablePut(cl.typeMap, body.sons[i-1], x)
for i in countup(0, sonsLen(t) - 1):
# if one of the params is not concrete, we cannot do anything
# but we already raised an error!
addSon(result, header.sons[i])
var newbody = ReplaceTypeVarsT(cl, lastSon(body))
newbody.flags = newbody.flags + t.flags + body.flags
result.flags = result.flags + newbody.flags
newbody.callConv = body.callConv
newbody.n = ReplaceTypeVarsN(cl, lastSon(body).n)
addSon(result, newbody)
checkPartialConstructedType(cl.info, newbody)
else:
for i in countup(1, sonsLen(t) - 1):
if PType(idTableGet(cl.typeMap, t.sons[i])) == nil: debug(t)
var x = replaceTypeVarsT(cl, t.sons[i])
if t.sons[i].kind == tyGenericParam:
if header == nil: header = copyType(t, t.owner, false)
header.sons[i] = x
assert x.kind != tyGenericInvokation
idTablePut(cl.typeMap, body.sons[i-1], x)
if header == nil: header = t
result = searchInstTypes(gInstTypes, header)
if result != nil: return
result = newType(tyGenericInst, t.sons[0].owner)
for i in countup(0, sonsLen(t) - 1):
# if one of the params is not concrete, we cannot do anything
# but we already raised an error!
addSon(result, header.sons[i])
idTablePut(gInstTypes, header, result)
var newbody = ReplaceTypeVarsT(cl, lastSon(body))
newbody.flags = newbody.flags + t.flags + body.flags
newbody.n = ReplaceTypeVarsN(cl, lastSon(body).n)
addSon(result, newbody)
checkPartialConstructedType(cl.info, newbody)
proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
result = t
if t == nil: return
case t.kind
of tyGenericParam:
of tyGenericParam:
result = lookupTypeVar(cl, t)
if result.kind == tyGenericInvokation:
result = handleGenericInvokation(cl, result)
of tyGenericInvokation:
result = handleGenericInvokation(cl, t)
of tyGenericBody:
@@ -151,9 +190,10 @@ proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
result.n = ReplaceTypeVarsN(cl, result.n)
if result.Kind in GenericTypes:
LocalError(cl.info, errCannotInstantiateX, TypeToString(t, preferName))
#writeln(output, ropeToStr(Typetoyaml(result)))
#checkConstructedType(cl.info, result)
if result.kind == tyProc and result.sons[0] != nil:
if result.sons[0].kind == tyEmpty:
result.sons[0] = nil
proc generateTypeInstance*(p: PContext, pt: TIdTable, arg: PNode,
t: PType): PType =
var cl: TReplTypeVars

View File

@@ -137,6 +137,8 @@ proc concreteType(mapping: TIdTable, t: PType): PType =
# example code that triggers it:
# proc sort[T](cmp: proc(a, b: T): int = cmp)
if result.kind != tyGenericParam: break
of tyGenericInvokation:
assert false
else:
result = t # Note: empty is valid here
@@ -388,8 +390,10 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
of tyGenericInvokation:
assert(f.sons[0].kind == tyGenericBody)
if a.kind == tyGenericInvokation:
InternalError("typeRel: tyGenericInvokation -> tyGenericInvokation")
if (a.kind == tyGenericInst):
#InternalError("typeRel: tyGenericInvokation -> tyGenericInvokation")
# simply no match for now:
nil
elif a.kind == tyGenericInst:
if (f.sons[0].containerID == a.sons[0].containerID) and
(sonsLen(a) - 1 == sonsLen(f)):
assert(a.sons[0].kind == tyGenericBody)
@@ -404,7 +408,7 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
# we steal the generic parameters from the tyGenericBody:
for i in countup(1, sonsLen(f) - 1):
var x = PType(idTableGet(mapping, f.sons[0].sons[i - 1]))
if x == nil or x.kind == tyGenericParam:
if x == nil or x.kind in {tyGenericInvokation, tyGenericParam}:
InternalError("wrong instantiated type!")
idTablePut(mapping, f.sons[i], x)
of tyGenericParam:
@@ -413,8 +417,7 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
if sonsLen(f) == 0:
# no constraints
var concrete = concreteType(mapping, a)
if concrete != nil:
#MessageOut('putting: ' + f.sym.name.s);
if concrete != nil:
idTablePut(mapping, f, concrete)
result = isGeneric
else:

View File

@@ -728,7 +728,16 @@ proc typeAllowedNode(marker: var TIntSet, n: PNode, kind: TSymKind): bool =
else:
for i in countup(0, sonsLen(n) - 1):
result = typeAllowedNode(marker, n.sons[i], kind)
if not result: return
if not result: break
proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
last: TTypeKind): bool =
var a = a
for k, i in pattern.items:
if a.kind != k: return false
if i >= a.sonslen or a.sons[i] == nil: return false
a = a.sons[i]
result = a.kind == last
proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
assert(kind in {skVar, skConst, skParam, skResult})
@@ -751,13 +760,14 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
of tyProc:
for i in countup(1, sonsLen(t) - 1):
result = typeAllowedAux(marker, t.sons[i], skParam)
if not result: return
if t.sons[0] != nil: result = typeAllowedAux(marker, t.sons[0], skResult)
if not result: break
if result and t.sons[0] != nil:
result = typeAllowedAux(marker, t.sons[0], skResult)
of tyExpr, tyStmt, tyTypeDesc:
result = true
of tyGenericBody, tyGenericParam, tyForward, tyNone, tyGenericInvokation:
result = false #InternalError('shit found');
of tyEmpty, tyNil:
of tyEmpty, tyNil:
result = kind == skConst
of tyString, tyBool, tyChar, tyEnum, tyInt..tyFloat128, tyCString, tyPointer:
result = true
@@ -781,13 +791,13 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
of tyArrayConstr, tyTuple, tySet:
for i in countup(0, sonsLen(t) - 1):
result = typeAllowedAux(marker, t.sons[i], kind)
if not result: return
if not result: break
of tyObject:
for i in countup(0, sonsLen(t) - 1):
result = typeAllowedAux(marker, t.sons[i], skVar)
if not result: return
if t.n != nil: result = typeAllowedNode(marker, t.n, skVar)
if not result: break
if result and t.n != nil: result = typeAllowedNode(marker, t.n, skVar)
proc typeAllowed(t: PType, kind: TSymKind): bool =
var marker = InitIntSet()
result = typeAllowedAux(marker, t, kind)

View File

@@ -2,6 +2,7 @@ Comex
Eric Doughty-Papassideris
Keita Haga
Philippe Lhoste
Zahary Karadjov
Mario Ray Mahardhika
Alex Mitchell
Dominik Picheta

View File

@@ -433,6 +433,15 @@ have no side-effect can be used in constant expressions too:
constEval = contains("abc", 'b') # computed at compile time!
The rules for compile-time computability are:
1. Literals are compile-time computable.
2. Procedure calls of the form ``p(X)`` are compile-time computable if
``p`` is a proc without side-effects (see the `noSideEffect pragma`_
for details) and if ``X`` is a (possibly empty) list of compile-time
computable arguments.
Types
-----
@@ -2900,17 +2909,17 @@ structure:
Pure pragma
-----------
An object type can be marked with the `pure`:idx: pragma so that its type
An object type can be marked with the `pure`:idx: pragma so that its type
field which is used for runtime type identification is omitted. This is
necessary for binary compatibility with other compiled languages.
NoStackFrame pragma
-------------------
A proc can be marked with the `noStackFrame`:idx: pragma to tell the compiler
it should not generate a stack frame for the proc. There are also no exit
statements like ``return result;`` generated. This is useful for procs that
only consist of an assembler statement.
NoStackFrame pragma
-------------------
A proc can be marked with the `noStackFrame`:idx: pragma to tell the compiler
it should not generate a stack frame for the proc. There are also no exit
statements like ``return result;`` generated. This is useful for procs that
only consist of an assembler statement.
error pragma

View File

@@ -104,13 +104,17 @@ proc toAny*[T](x: var T): TAny {.inline.} =
proc kind*(x: TAny): TAnyKind {.inline.} =
## get the type kind
result = TAnyKind(ord(x.rawType.kind))
proc size*(x: TAny): int {.inline.} =
## returns the size of `x`'s type.
result = x.rawType.size
proc baseTypeKind*(x: TAny): TAnyKind {.inline.} =
## get the base type's kind; ``akNone`` is returned if `x` has no base type.
if x.rawType.base != nil:
result = TAnyKind(ord(x.rawType.base.kind))
proc baseTypeSize*(x: TAny): int =
proc baseTypeSize*(x: TAny): int {.inline.} =
## returns the size of `x`'s basetype.
if x.rawType.base != nil:
result = x.rawType.base.size
@@ -339,8 +343,8 @@ proc getInt64*(x: TAny): int64 =
proc getBiggestInt*(x: TAny): biggestInt =
## retrieve the integer value out of `x`. `x` needs to represent
## some integer, a bool, a char or an enum. The value might be
## sign-extended to ``biggestInt``.
## some integer, a bool, a char, an enum or a small enough bit set.
## The value might be sign-extended to ``biggestInt``.
var t = skipRange(x.rawtype)
case t.kind
of tyInt: result = biggestInt(cast[ptr int](x.value)[])
@@ -350,7 +354,7 @@ proc getBiggestInt*(x: TAny): biggestInt =
of tyInt64: result = biggestInt(cast[ptr int64](x.value)[])
of tyBool: result = biggestInt(cast[ptr bool](x.value)[])
of tyChar: result = biggestInt(cast[ptr char](x.value)[])
of tyEnum:
of tyEnum, tySet:
case t.size
of 1: result = ze64(cast[ptr int8](x.value)[])
of 2: result = ze64(cast[ptr int16](x.value)[])
@@ -361,7 +365,7 @@ proc getBiggestInt*(x: TAny): biggestInt =
proc setBiggestInt*(x: TAny, y: biggestInt) =
## sets the integer value of `x`. `x` needs to represent
## some integer, a bool, a char or an enum.
## some integer, a bool, a char, an enum or a small enough bit set.
var t = skipRange(x.rawtype)
case t.kind
of tyInt: cast[ptr int](x.value)[] = int(y)
@@ -371,7 +375,7 @@ proc setBiggestInt*(x: TAny, y: biggestInt) =
of tyInt64: cast[ptr int64](x.value)[] = int64(y)
of tyBool: cast[ptr bool](x.value)[] = y != 0
of tyChar: cast[ptr char](x.value)[] = chr(y.int)
of tyEnum:
of tyEnum, tySet:
case t.size
of 1: cast[ptr int8](x.value)[] = toU8(y.int)
of 2: cast[ptr int16](x.value)[] = toU16(y.int)

View File

@@ -30,7 +30,7 @@ proc spawn*[TIn, TOut](action: proc(
self: PActor[TIn, TOut]){.thread.}): PActor[TIn, TOut] =
## creates an actor; that is a thread with an inbox. The caller MUST call
## ``join`` because that also frees the associated resources with the actor.
result = allocShared0(sizeof(result[]))
result = cast[PActor[TIn, TOut]](allocShared0(sizeof(result[])))
open(result.i)
createThread(result.t, action, result)
@@ -52,8 +52,8 @@ proc recv*[TIn, TOut](a: PActor[TIn, TOut]): TTask[TIn, TOut] =
## receives a task from `a`'s inbox.
result = recv(a.i)
proc send*[TIn, TOut, X, Y](sender: PActor[X, Z],
receiver: PActor[TIn, TOut], msg: TIn) =
proc send*[TIn, TOut, X, Y](receiver: PActor[TIn, TOut], msg: TIn,
sender: PActor[X, Y]) =
## sends a message to `a`'s inbox.
var t: TTask[TIn, TOut]
t.receiver = addr(sender.i)
@@ -99,9 +99,9 @@ proc poolWorker[TIn, TOut](self: PActor[TIn, TOut]) {.thread.} =
var m = self.recv
if m.shutDown: break
when TOut is void:
action(m.data)
m.action(m.data)
else:
self.repy(action(m.data))
self.repy(m.action(m.data))
proc createActorPool*[TIn, TOut](a: var TActorPool[TIn, TOut], poolSize = 4) =
## creates an actor pool.
@@ -109,21 +109,20 @@ proc createActorPool*[TIn, TOut](a: var TActorPool[TIn, TOut], poolSize = 4) =
when TOut isnot void:
open(a.outputs)
for i in 0 .. < a.actors.len:
a.actors[i] = spawn(poolWorker)
a.actors[i] = spawn(poolWorker[TIn, TOut])
proc join*[TIn, TOut](a: var TActorPool[TIn, TOut]) =
## waits for each actor in the actor pool `a` to finish and frees the
## resources attached to `a`.
var t: TTask[TIn, TOut]
t.shutdown = true
for i in 0 .. < a.actors.len: send(a.actors[i], t)
for i in 0 .. < a.actors.len: send(a.actors[i].i, t)
for i in 0 .. < a.actors.len: join(a.actors[i])
when TOut isnot void:
close(a.outputs)
a.actors = nil
template setupTask =
var t: TTask[TIn, TOut]
t.action = action
shallowCopy(t.data, input)
@@ -132,7 +131,7 @@ template schedule =
# it remains 'hot' ;-). Round-robin hurts for keeping threads hot.
for i in 0..high(a.actors):
if a.actors[i].i.ready:
a.actors[i].send(t)
a.actors[i].i.send(t)
return
# no thread ready :-( --> send message to the thread which has the least
# messages pending:
@@ -142,27 +141,29 @@ template schedule =
var curr = a.actors[i].i.peek
if curr == 0:
# ok, is ready now:
a.actors[i].send(t)
a.actors[i].i.send(t)
return
if curr < minVal:
minVal = curr
minIdx = i
a.actors[minIdx].send(t)
a.actors[minIdx].i.send(t)
proc spawn*[TIn, TOut](p: var TActorPool[TIn, TOut],
action: proc (input: TIn): TOut {.thread.},
input: TIn): ptr TChannel[TOut] =
## uses the actor pool to run `action` concurrently. `spawn` is guaranteed
## to not block.
proc spawn*[TIn, TOut](p: var TActorPool[TIn, TOut], input: TIn,
action: proc (input: TIn): TOut {.thread.}
): ptr TChannel[TOut] =
## uses the actor pool to run ``action(input)`` concurrently.
## `spawn` is guaranteed to not block.
var t: TTask[TIn, TOut]
setupTask()
result = addr(p.outputs)
t.receiver = result
schedule()
proc spawn*[TIn](p: var TActorPool[TIn, void],
action: proc (input: TIn) {.thread.},
input: TIn) =
## uses the actor pool to run `action` concurrently. `spawn` is guaranteed
## to not block.
proc spawn*[TIn](p: var TActorPool[TIn, void], input: TIn,
action: proc (input: TIn) {.thread.}) =
## uses the actor pool to run ``action(input)`` concurrently.
## `spawn` is guaranteed to not block.
var t: TTask[TIn, void]
setupTask()
schedule()
@@ -171,7 +172,7 @@ when isMainModule:
a: TActorPool[int, void]
createActorPool(a)
for i in 0 .. < 300:
a.spawn(proc (x: int) {.thread.} = echo x)
a.spawn(i, proc (x: int) {.thread.} = echo x)
when false:
proc treeDepth(n: PNode): int {.thread.} =

View File

@@ -323,6 +323,7 @@ proc getKeyValPair(c: var TCfgParser, kind: TCfgEventKind): TCfgEvent =
if c.tok.kind == tkSymbol:
result.value = c.tok.literal
else:
reset result
result.kind = cfgError
result.msg = errorStr(c, "symbol expected, but found: " & c.tok.literal)
rawGetTok(c, c.tok)

View File

@@ -252,8 +252,10 @@ type
object of TGcThread ## Nimrod thread. A thread is a heavy object (~14K)
## that **must not** be part of a message! Use
## a ``TThreadId`` for that.
dataFn: proc (m: TArg)
when TArg isnot void:
when TArg is void:
dataFn: proc ()
else:
dataFn: proc (m: TArg)
data: TArg
TThreadId*[TArg] = ptr TThread[TArg] ## the current implementation uses
## a pointer as a thread ID.
@@ -273,7 +275,7 @@ template ThreadProcWrapperBody(closure: expr) =
when defined(registerThread):
t.stackBottom = addr(t)
registerThread(t)
if TArg is void: t.dataFn()
when TArg is void: t.dataFn()
else: t.dataFn(t.data)
when defined(registerThread): unregisterThread(t)
when defined(deallocOsPages): deallocOsPages()

View File

@@ -6,6 +6,11 @@ Version 0.8.14
- fix the 'const' issues
- test the sort implementation again
- optional indentation for 'case' statement
- taint mode
- const ptr/ref
- 'let x = y'
- {.error.} pragma for proc headers
version 0.9.0
=============
@@ -27,6 +32,14 @@ Bugs
- bug: memset() without type field initialization?
- special case the generic assign that needs to care about case objects
- bug: returning a tyVar does not mean it is save to return it:
proc forward[T](x: var T): var T = result = x
proc p(): var int =
var x: int
result = forward(x)
- bug: DLL generation is broken
version 0.9.XX
==============