mirror of
https://github.com/nim-lang/Nim.git
synced 2026-02-14 23:33:28 +00:00
bugfixes for generics; new threads implementation still broken
This commit is contained in:
@@ -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 = @[]
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -2,6 +2,7 @@ Comex
|
||||
Eric Doughty-Papassideris
|
||||
Keita Haga
|
||||
Philippe Lhoste
|
||||
Zahary Karadjov
|
||||
Mario Ray Mahardhika
|
||||
Alex Mitchell
|
||||
Dominik Picheta
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.} =
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
13
todo.txt
13
todo.txt
@@ -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
|
||||
==============
|
||||
|
||||
Reference in New Issue
Block a user