bugfixes for generics; new threads implementation still broken

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

View file

@ -279,8 +279,8 @@ type
TTypeFlags* = set[TTypeFlag] TTypeFlags* = set[TTypeFlag]
TSymKind* = enum # the different symbols (start with the prefix sk); TSymKind* = enum # the different symbols (start with the prefix sk);
# order is important for the documentation generator! # order is important for the documentation generator!
skUnknown, # unknown symbol: used for parsing assembler blocks skUnknown, # unknown symbol: used for parsing assembler blocks
# and first phase symbol lookup in generics # and first phase symbol lookup in generics
skConditional, # symbol for the preprocessor (may become obsolete) skConditional, # symbol for the preprocessor (may become obsolete)
@ -848,6 +848,10 @@ proc initNodeTable(x: var TNodeTable) =
proc sonsLen(n: PType): int = proc sonsLen(n: PType): int =
if isNil(n.sons): result = 0 if isNil(n.sons): result = 0
else: result = len(n.sons) 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) = proc newSons(father: PType, length: int) =
if isNil(father.sons): father.sons = @[] 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 StrTableAdd*(t: var TStrTable, n: PSym)
proc StrTableGet*(t: TStrTable, name: PIdent): PSym proc StrTableGet*(t: TStrTable, name: PIdent): PSym
# the iterator scheme:
type type
TTabIter*{.final.} = object # consider all fields here private TTabIter*{.final.} = object # consider all fields here private
h*: THash # current hash h*: THash # current hash
@ -749,6 +748,10 @@ proc IdTablePut(t: var TIdTable, key: PIdObj, val: PObject) =
IdTableRawInsert(t.data, key, val) IdTableRawInsert(t.data, key, val)
inc(t.counter) 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) = proc writeIdNodeTable(t: TIdNodeTable) =
nil nil

View file

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

View file

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

View file

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

View file

@ -1178,9 +1178,10 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
else: else:
#liMessage(n.info, warnUser, renderTree(n)); #liMessage(n.info, warnUser, renderTree(n));
result = semIndirectOp(c, n, flags) 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) result = semDirectOp(c, n, flags)
else: else:
result = semIndirectOp(c, n, flags) result = semIndirectOp(c, n, flags)
of nkMacroStmt: of nkMacroStmt:
result = semMacroStmt(c, n) result = semMacroStmt(c, n)

View file

@ -29,6 +29,10 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
break break
if t.kind == tyGenericParam: if t.kind == tyGenericParam:
InternalError(a.info, "instantiateGenericParamList: " & q.name.s) 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 s.typ = t
addDecl(c, s) addDecl(c, s)
entry.concreteTypes[i] = t entry.concreteTypes[i] = t
@ -94,6 +98,14 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
closeScope(c.tab) closeScope(c.tab)
popInfoContext() 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, proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
info: TLineInfo): PSym = info: TLineInfo): PSym =
# generates an instantiated proc # generates an instantiated proc
@ -133,7 +145,10 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
var oldPrc = GenericCacheGet(c, entry) var oldPrc = GenericCacheGet(c, entry)
if oldPrc == nil: if oldPrc == nil:
generics.add(entry) generics.add(entry)
if n.sons[pragmasPos].kind != nkEmpty:
pragma(c, result, n.sons[pragmasPos], allRoutinePragmas)
instantiateBody(c, n, result) instantiateBody(c, n, result)
sideEffectsCheck(c, result)
else: else:
result = oldPrc result = oldPrc
popInfoContext() popInfoContext()

View file

@ -554,13 +554,6 @@ proc semBorrow(c: PContext, n: PNode, s: PSym) =
n.sons[codePos] = newSymNode(b) n.sons[codePos] = newSymNode(b)
else: else:
LocalError(n.info, errNoSymbolToBorrowFromFound) 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) = proc addResult(c: PContext, t: PType, info: TLineInfo) =
if t != nil: 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.n, newSymNode(field))
addSon(result, typ) 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, proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags): PSym = allowed: TSymFlags): PSym =
# identifier with visibility # identifier with visibility
@ -489,7 +472,6 @@ proc addTypeVarsOfGenericBody(c: PContext, t: PType, genericParams: PNode,
if ContainsOrIncl(cl, t.id): return if ContainsOrIncl(cl, t.id): return
case t.kind case t.kind
of tyGenericBody: of tyGenericBody:
#debug(t)
result = newTypeS(tyGenericInvokation, c) result = newTypeS(tyGenericInvokation, c)
addSon(result, t) addSon(result, t)
for i in countup(0, sonsLen(t) - 2): 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(genericParams, newSymNode(s))
addSon(result, t.sons[i]) addSon(result, t.sons[i])
of tyGenericInst: of tyGenericInst:
#debug(t)
var L = sonsLen(t) - 1 var L = sonsLen(t) - 1
t.sons[L] = addTypeVarsOfGenericBody(c, t.sons[L], genericParams, cl) t.sons[L] = addTypeVarsOfGenericBody(c, t.sons[L], genericParams, cl)
of tyGenericInvokation: of tyGenericInvokation:
#debug(t)
for i in countup(1, sonsLen(t) - 1): for i in countup(1, sonsLen(t) - 1):
t.sons[i] = addTypeVarsOfGenericBody(c, t.sons[i], genericParams, cl) t.sons[i] = addTypeVarsOfGenericBody(c, t.sons[i], genericParams, cl)
else: else:
@ -520,7 +500,6 @@ proc paramType(c: PContext, n, genericParams: PNode, cl: var TIntSet): PType =
result = semTypeNode(c, n, nil) result = semTypeNode(c, n, nil)
if genericParams != nil and sonsLen(genericParams) == 0: if genericParams != nil and sonsLen(genericParams) == 0:
result = addTypeVarsOfGenericBody(c, result, genericParams, cl) result = addTypeVarsOfGenericBody(c, result, genericParams, cl)
#if result.kind == tyGenericInvokation: debug(result)
proc semProcTypeNode(c: PContext, n, genericParams: PNode, proc semProcTypeNode(c: PContext, n, genericParams: PNode,
prev: PType): PType = prev: PType): PType =
@ -546,6 +525,9 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
var length = sonsLen(a) var length = sonsLen(a)
if a.sons[length-2].kind != nkEmpty: if a.sons[length-2].kind != nkEmpty:
typ = paramType(c, a.sons[length-2], genericParams, cl) typ = paramType(c, a.sons[length-2], genericParams, cl)
#if matchType(typ, [(tyVar, 0)], tyGenericInvokation):
# debug a.sons[length-2][0][1]
else: else:
typ = nil typ = nil
if a.sons[length-1].kind != nkEmpty: 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: # and def.typ != nil and def.typ.kind != tyNone:
# example code that triggers it: # example code that triggers it:
# proc sort[T](cmp: proc(a, b: T): int = cmp) # proc sort[T](cmp: proc(a, b: T): int = cmp)
def = fitNode(c, typ, def) if not containsGenericType(typ):
else: def = fitNode(c, typ, def)
else:
def = ast.emptyNode def = ast.emptyNode
if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
for j in countup(0, length-3): for j in countup(0, length-3):
@ -578,6 +561,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
if skipTypes(r, {tyGenericInst}).kind != tyEmpty: if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
result.sons[0] = r result.sons[0] = r
res.typ = result.sons[0] res.typ = result.sons[0]
#if matchType(result, [(tyProc, 1), (tyVar, 0)], tyGenericInvokation):
# debug result
proc semStmtListType(c: PContext, n: PNode, prev: PType): PType = proc semStmtListType(c: PContext, n: PNode, prev: PType): PType =
checkMinSonsLen(n, 1) checkMinSonsLen(n, 1)
@ -603,6 +588,50 @@ proc semBlockType(c: PContext, n: PNode, prev: PType): PType =
closeScope(c.tab) closeScope(c.tab)
Dec(c.p.nestedBlockCounter) 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 = proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
result = nil result = nil
if gCmd == cmdIdeTools: suggestExpr(c, n) 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 = proc lookupTypeVar(cl: TReplTypeVars, t: PType): PType =
result = PType(idTableGet(cl.typeMap, t)) result = PType(idTableGet(cl.typeMap, t))
if result == nil: if result == nil:
GlobalError(t.sym.info, errCannotInstantiateX, typeToString(t)) GlobalError(t.sym.info, errCannotInstantiateX, typeToString(t))
elif result.kind == tyGenericParam: elif result.kind == tyGenericParam:
InternalError(cl.info, "substitution with generic parameter") InternalError(cl.info, "substitution with generic parameter")
proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType = proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
# tyGenericInvokation[A, tyGenericInvokation[A, B]]
# is difficult to handle:
var body = t.sons[0] var body = t.sons[0]
if body.kind != tyGenericBody: InternalError(cl.info, "no generic body") if body.kind != tyGenericBody: InternalError(cl.info, "no generic body")
var header: PType = nil var header: PType = nil
for i in countup(1, sonsLen(t) - 1): when true:
var x = replaceTypeVarsT(cl, t.sons[i]) # search for some instantiation here:
if t.sons[i].kind == tyGenericParam: result = searchInstTypes(gInstTypes, t)
if header == nil: header = copyType(t, t.owner, false) if result != nil: return
header.sons[i] = x for i in countup(1, sonsLen(t) - 1):
when false: var x = t.sons[i]
var x: PType if x.kind == tyGenericParam:
if t.sons[i].kind == tyGenericParam: x = lookupTypeVar(cl, x)
x = lookupTypeVar(cl, t.sons[i])
if header == nil: header = copyType(t, t.owner, false) if header == nil: header = copyType(t, t.owner, false)
header.sons[i] = x header.sons[i] = x
else: #idTablePut(cl.typeMap, body.sons[i-1], x)
x = t.sons[i] if header != nil:
idTablePut(cl.typeMap, body.sons[i-1], x) # search again after first pass:
if header == nil: header = t result = searchInstTypes(gInstTypes, header)
result = searchInstTypes(gInstTypes, header) if result != nil: return
if result != nil: return else:
result = newType(tyGenericInst, t.sons[0].owner) header = copyType(t, t.owner, false)
for i in countup(0, sonsLen(t) - 1): # ugh need another pass for deeply recursive generic types (e.g. PActor)
# if one of the params is not concrete, we cannot do anything # we need to add the candidate here, before it's fully instantiated for
# but we already raised an error! # recursive instantions:
addSon(result, header.sons[i]) result = newType(tyGenericInst, t.sons[0].owner)
idTablePut(gInstTypes, header, result) idTablePut(gInstTypes, header, result)
var newbody = ReplaceTypeVarsT(cl, lastSon(body))
newbody.flags = newbody.flags + t.flags + body.flags for i in countup(1, sonsLen(t) - 1):
newbody.n = ReplaceTypeVarsN(cl, lastSon(body).n) var x = replaceTypeVarsT(cl, t.sons[i])
addSon(result, newbody) assert x.kind != tyGenericInvokation
#writeln(output, ropeToStr(Typetoyaml(newbody))); header.sons[i] = x
checkPartialConstructedType(cl.info, newbody) 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 = proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
result = t result = t
if t == nil: return if t == nil: return
case t.kind case t.kind
of tyGenericParam: of tyGenericParam:
result = lookupTypeVar(cl, t) result = lookupTypeVar(cl, t)
if result.kind == tyGenericInvokation:
result = handleGenericInvokation(cl, result)
of tyGenericInvokation: of tyGenericInvokation:
result = handleGenericInvokation(cl, t) result = handleGenericInvokation(cl, t)
of tyGenericBody: of tyGenericBody:
@ -151,9 +190,10 @@ proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
result.n = ReplaceTypeVarsN(cl, result.n) result.n = ReplaceTypeVarsN(cl, result.n)
if result.Kind in GenericTypes: if result.Kind in GenericTypes:
LocalError(cl.info, errCannotInstantiateX, TypeToString(t, preferName)) LocalError(cl.info, errCannotInstantiateX, TypeToString(t, preferName))
#writeln(output, ropeToStr(Typetoyaml(result))) if result.kind == tyProc and result.sons[0] != nil:
#checkConstructedType(cl.info, result) if result.sons[0].kind == tyEmpty:
result.sons[0] = nil
proc generateTypeInstance*(p: PContext, pt: TIdTable, arg: PNode, proc generateTypeInstance*(p: PContext, pt: TIdTable, arg: PNode,
t: PType): PType = t: PType): PType =
var cl: TReplTypeVars var cl: TReplTypeVars

View file

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

View file

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

View file

@ -2,6 +2,7 @@ Comex
Eric Doughty-Papassideris Eric Doughty-Papassideris
Keita Haga Keita Haga
Philippe Lhoste Philippe Lhoste
Zahary Karadjov
Mario Ray Mahardhika Mario Ray Mahardhika
Alex Mitchell Alex Mitchell
Dominik Picheta 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! 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 Types
----- -----
@ -2900,17 +2909,17 @@ structure:
Pure pragma 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 field which is used for runtime type identification is omitted. This is
necessary for binary compatibility with other compiled languages. necessary for binary compatibility with other compiled languages.
NoStackFrame pragma NoStackFrame pragma
------------------- -------------------
A proc can be marked with the `noStackFrame`:idx: pragma to tell the compiler 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. This is useful for procs that statements like ``return result;`` generated. This is useful for procs that
only consist of an assembler statement. only consist of an assembler statement.
error pragma error pragma

View file

@ -104,13 +104,17 @@ proc toAny*[T](x: var T): TAny {.inline.} =
proc kind*(x: TAny): TAnyKind {.inline.} = proc kind*(x: TAny): TAnyKind {.inline.} =
## get the type kind ## get the type kind
result = TAnyKind(ord(x.rawType.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.} = proc baseTypeKind*(x: TAny): TAnyKind {.inline.} =
## get the base type's kind; ``akNone`` is returned if `x` has no base type. ## get the base type's kind; ``akNone`` is returned if `x` has no base type.
if x.rawType.base != nil: if x.rawType.base != nil:
result = TAnyKind(ord(x.rawType.base.kind)) 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. ## returns the size of `x`'s basetype.
if x.rawType.base != nil: if x.rawType.base != nil:
result = x.rawType.base.size result = x.rawType.base.size
@ -339,8 +343,8 @@ proc getInt64*(x: TAny): int64 =
proc getBiggestInt*(x: TAny): biggestInt = proc getBiggestInt*(x: TAny): biggestInt =
## retrieve the integer value out of `x`. `x` needs to represent ## retrieve the integer value out of `x`. `x` needs to represent
## some integer, a bool, a char or an enum. The value might be ## some integer, a bool, a char, an enum or a small enough bit set.
## sign-extended to ``biggestInt``. ## The value might be sign-extended to ``biggestInt``.
var t = skipRange(x.rawtype) var t = skipRange(x.rawtype)
case t.kind case t.kind
of tyInt: result = biggestInt(cast[ptr int](x.value)[]) 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 tyInt64: result = biggestInt(cast[ptr int64](x.value)[])
of tyBool: result = biggestInt(cast[ptr bool](x.value)[]) of tyBool: result = biggestInt(cast[ptr bool](x.value)[])
of tyChar: result = biggestInt(cast[ptr char](x.value)[]) of tyChar: result = biggestInt(cast[ptr char](x.value)[])
of tyEnum: of tyEnum, tySet:
case t.size case t.size
of 1: result = ze64(cast[ptr int8](x.value)[]) of 1: result = ze64(cast[ptr int8](x.value)[])
of 2: result = ze64(cast[ptr int16](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) = proc setBiggestInt*(x: TAny, y: biggestInt) =
## sets the integer value of `x`. `x` needs to represent ## 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) var t = skipRange(x.rawtype)
case t.kind case t.kind
of tyInt: cast[ptr int](x.value)[] = int(y) 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 tyInt64: cast[ptr int64](x.value)[] = int64(y)
of tyBool: cast[ptr bool](x.value)[] = y != 0 of tyBool: cast[ptr bool](x.value)[] = y != 0
of tyChar: cast[ptr char](x.value)[] = chr(y.int) of tyChar: cast[ptr char](x.value)[] = chr(y.int)
of tyEnum: of tyEnum, tySet:
case t.size case t.size
of 1: cast[ptr int8](x.value)[] = toU8(y.int) of 1: cast[ptr int8](x.value)[] = toU8(y.int)
of 2: cast[ptr int16](x.value)[] = toU16(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] = self: PActor[TIn, TOut]){.thread.}): PActor[TIn, TOut] =
## creates an actor; that is a thread with an inbox. The caller MUST call ## 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. ## ``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) open(result.i)
createThread(result.t, action, result) 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. ## receives a task from `a`'s inbox.
result = recv(a.i) result = recv(a.i)
proc send*[TIn, TOut, X, Y](sender: PActor[X, Z], proc send*[TIn, TOut, X, Y](receiver: PActor[TIn, TOut], msg: TIn,
receiver: PActor[TIn, TOut], msg: TIn) = sender: PActor[X, Y]) =
## sends a message to `a`'s inbox. ## sends a message to `a`'s inbox.
var t: TTask[TIn, TOut] var t: TTask[TIn, TOut]
t.receiver = addr(sender.i) t.receiver = addr(sender.i)
@ -99,9 +99,9 @@ proc poolWorker[TIn, TOut](self: PActor[TIn, TOut]) {.thread.} =
var m = self.recv var m = self.recv
if m.shutDown: break if m.shutDown: break
when TOut is void: when TOut is void:
action(m.data) m.action(m.data)
else: else:
self.repy(action(m.data)) self.repy(m.action(m.data))
proc createActorPool*[TIn, TOut](a: var TActorPool[TIn, TOut], poolSize = 4) = proc createActorPool*[TIn, TOut](a: var TActorPool[TIn, TOut], poolSize = 4) =
## creates an actor pool. ## creates an actor pool.
@ -109,21 +109,20 @@ proc createActorPool*[TIn, TOut](a: var TActorPool[TIn, TOut], poolSize = 4) =
when TOut isnot void: when TOut isnot void:
open(a.outputs) open(a.outputs)
for i in 0 .. < a.actors.len: 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]) = proc join*[TIn, TOut](a: var TActorPool[TIn, TOut]) =
## waits for each actor in the actor pool `a` to finish and frees the ## waits for each actor in the actor pool `a` to finish and frees the
## resources attached to `a`. ## resources attached to `a`.
var t: TTask[TIn, TOut] var t: TTask[TIn, TOut]
t.shutdown = true 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]) for i in 0 .. < a.actors.len: join(a.actors[i])
when TOut isnot void: when TOut isnot void:
close(a.outputs) close(a.outputs)
a.actors = nil a.actors = nil
template setupTask = template setupTask =
var t: TTask[TIn, TOut]
t.action = action t.action = action
shallowCopy(t.data, input) shallowCopy(t.data, input)
@ -132,7 +131,7 @@ template schedule =
# it remains 'hot' ;-). Round-robin hurts for keeping threads hot. # it remains 'hot' ;-). Round-robin hurts for keeping threads hot.
for i in 0..high(a.actors): for i in 0..high(a.actors):
if a.actors[i].i.ready: if a.actors[i].i.ready:
a.actors[i].send(t) a.actors[i].i.send(t)
return return
# no thread ready :-( --> send message to the thread which has the least # no thread ready :-( --> send message to the thread which has the least
# messages pending: # messages pending:
@ -142,27 +141,29 @@ template schedule =
var curr = a.actors[i].i.peek var curr = a.actors[i].i.peek
if curr == 0: if curr == 0:
# ok, is ready now: # ok, is ready now:
a.actors[i].send(t) a.actors[i].i.send(t)
return return
if curr < minVal: if curr < minVal:
minVal = curr minVal = curr
minIdx = i minIdx = i
a.actors[minIdx].send(t) a.actors[minIdx].i.send(t)
proc spawn*[TIn, TOut](p: var TActorPool[TIn, TOut], proc spawn*[TIn, TOut](p: var TActorPool[TIn, TOut], input: TIn,
action: proc (input: TIn): TOut {.thread.}, action: proc (input: TIn): TOut {.thread.}
input: TIn): ptr TChannel[TOut] = ): ptr TChannel[TOut] =
## uses the actor pool to run `action` concurrently. `spawn` is guaranteed ## uses the actor pool to run ``action(input)`` concurrently.
## to not block. ## `spawn` is guaranteed to not block.
var t: TTask[TIn, TOut]
setupTask() setupTask()
result = addr(p.outputs) result = addr(p.outputs)
t.receiver = result
schedule() schedule()
proc spawn*[TIn](p: var TActorPool[TIn, void], proc spawn*[TIn](p: var TActorPool[TIn, void], input: TIn,
action: proc (input: TIn) {.thread.}, action: proc (input: TIn) {.thread.}) =
input: TIn) = ## uses the actor pool to run ``action(input)`` concurrently.
## uses the actor pool to run `action` concurrently. `spawn` is guaranteed ## `spawn` is guaranteed to not block.
## to not block. var t: TTask[TIn, void]
setupTask() setupTask()
schedule() schedule()
@ -171,7 +172,7 @@ when isMainModule:
a: TActorPool[int, void] a: TActorPool[int, void]
createActorPool(a) createActorPool(a)
for i in 0 .. < 300: for i in 0 .. < 300:
a.spawn(proc (x: int) {.thread.} = echo x) a.spawn(i, proc (x: int) {.thread.} = echo x)
when false: when false:
proc treeDepth(n: PNode): int {.thread.} = 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: if c.tok.kind == tkSymbol:
result.value = c.tok.literal result.value = c.tok.literal
else: else:
reset result
result.kind = cfgError result.kind = cfgError
result.msg = errorStr(c, "symbol expected, but found: " & c.tok.literal) result.msg = errorStr(c, "symbol expected, but found: " & c.tok.literal)
rawGetTok(c, c.tok) rawGetTok(c, c.tok)

View file

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

View file

@ -6,6 +6,11 @@ Version 0.8.14
- fix the 'const' issues - fix the 'const' issues
- test the sort implementation again - test the sort implementation again
- optional indentation for 'case' statement - optional indentation for 'case' statement
- taint mode
- const ptr/ref
- 'let x = y'
- {.error.} pragma for proc headers
version 0.9.0 version 0.9.0
============= =============
@ -27,6 +32,14 @@ Bugs
- bug: memset() without type field initialization? - bug: memset() without type field initialization?
- special case the generic assign that needs to care about case objects - 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 version 0.9.XX
============== ==============