diff options
-rwxr-xr-x | compiler/ast.nim | 8 | ||||
-rwxr-xr-x | compiler/astalgo.nim | 5 | ||||
-rwxr-xr-x | compiler/nimrod.nim | 14 | ||||
-rwxr-xr-x | compiler/pragmas.nim | 1 | ||||
-rwxr-xr-x | compiler/sem.nim | 2 | ||||
-rwxr-xr-x | compiler/semexprs.nim | 5 | ||||
-rwxr-xr-x | compiler/seminst.nim | 15 | ||||
-rwxr-xr-x | compiler/semstmts.nim | 7 | ||||
-rwxr-xr-x | compiler/semtypes.nim | 75 | ||||
-rwxr-xr-x | compiler/semtypinst.nim | 100 | ||||
-rwxr-xr-x | compiler/sigmatch.nim | 13 | ||||
-rwxr-xr-x | compiler/types.nim | 26 | ||||
-rwxr-xr-x | contributors.txt | 1 | ||||
-rwxr-xr-x | doc/manual.txt | 27 | ||||
-rwxr-xr-x | lib/core/typeinfo.nim | 16 | ||||
-rw-r--r-- | lib/pure/actors.nim | 45 | ||||
-rwxr-xr-x | lib/pure/parsecfg.nim | 1 | ||||
-rwxr-xr-x | lib/system/threads.nim | 8 | ||||
-rwxr-xr-x | todo.txt | 13 |
19 files changed, 258 insertions, 124 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index e9bf532b1..bb9803830 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -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 = @[] diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 08b502af7..17875d524 100755 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -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 diff --git a/compiler/nimrod.nim b/compiler/nimrod.nim index 5c91329cd..3a910cfad 100755 --- a/compiler/nimrod.nim +++ b/compiler/nimrod.nim @@ -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) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index d5cbae4ab..039474266 100755 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -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 diff --git a/compiler/sem.nim b/compiler/sem.nim index 5d2e1069f..c0ea23d2e 100755 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -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 = diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index d116ede2e..f86a4f60d 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -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) diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 87f988ed9..d53d33898 100755 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -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() diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index c37706f3a..ce870a3ad 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -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: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 7cdb32c79..9ff7ea27f 100755 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -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) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 41ec8ddac..88697dc85 100755 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -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) + 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 + #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 - when false: - var x: PType + 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: - x = lookupTypeVar(cl, t.sons[i]) 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) + 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 diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 9acf83a46..1e93385d9 100755 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -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: diff --git a/compiler/types.nim b/compiler/types.nim index 692b7f61b..d8d0caf35 100755 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -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) diff --git a/contributors.txt b/contributors.txt index 37978dc3f..e51914e26 100755 --- a/contributors.txt +++ b/contributors.txt @@ -2,6 +2,7 @@ Comex Eric Doughty-Papassideris Keita Haga Philippe Lhoste +Zahary Karadjov Mario Ray Mahardhika Alex Mitchell Dominik Picheta diff --git a/doc/manual.txt b/doc/manual.txt index f9a0b5dfc..2002a2461 100755 --- a/doc/manual.txt +++ b/doc/manual.txt @@ -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 diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim index 32042695d..b5e9e1a0f 100755 --- a/lib/core/typeinfo.nim +++ b/lib/core/typeinfo.nim @@ -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) diff --git a/lib/pure/actors.nim b/lib/pure/actors.nim index 285e3241d..4576cb602 100644 --- a/lib/pure/actors.nim +++ b/lib/pure/actors.nim @@ -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.} = diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim index 67644e156..3e85a9ee6 100755 --- a/lib/pure/parsecfg.nim +++ b/lib/pure/parsecfg.nim @@ -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) diff --git a/lib/system/threads.nim b/lib/system/threads.nim index 2079762f8..9fbea2e1a 100755 --- a/lib/system/threads.nim +++ b/lib/system/threads.nim @@ -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() diff --git a/todo.txt b/todo.txt index ad80e4812..d8f0ac65a 100755 --- a/todo.txt +++ b/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 ============== |