diff options
-rw-r--r-- | compiler/aliases.nim | 182 | ||||
-rwxr-xr-x | compiler/ast.nim | 33 | ||||
-rwxr-xr-x | compiler/astalgo.nim | 24 | ||||
-rw-r--r-- | compiler/ccgcalls.nim | 92 | ||||
-rwxr-xr-x | compiler/ccgexprs.nim | 12 | ||||
-rwxr-xr-x | compiler/ccgstmts.nim | 26 | ||||
-rwxr-xr-x | compiler/cgen.nim | 29 | ||||
-rwxr-xr-x | compiler/ecmasgen.nim | 13 | ||||
-rwxr-xr-x | compiler/evals.nim | 9 | ||||
-rwxr-xr-x | compiler/pragmas.nim | 2 | ||||
-rwxr-xr-x | compiler/sem.nim | 2 | ||||
-rwxr-xr-x | compiler/semexprs.nim | 40 | ||||
-rwxr-xr-x | compiler/semfold.nim | 2 | ||||
-rw-r--r-- | compiler/semmagic.nim | 38 | ||||
-rwxr-xr-x | compiler/types.nim | 1 | ||||
-rwxr-xr-x | doc/manual.txt | 6 | ||||
-rw-r--r-- | lib/pure/actors.nim | 43 | ||||
-rwxr-xr-x | lib/system.nim | 14 | ||||
-rwxr-xr-x | lib/system/channels.nim | 5 | ||||
-rwxr-xr-x | tests/run/tpegs.nim | 74 | ||||
-rw-r--r-- | tests/run/tuserassert.nim | 1 | ||||
-rw-r--r-- | tests/specials.nim | 1 | ||||
-rw-r--r-- | tests/threads/trecursive_actor.nim | 19 | ||||
-rwxr-xr-x | todo.txt | 8 | ||||
-rwxr-xr-x | web/news.txt | 11 |
25 files changed, 486 insertions, 201 deletions
diff --git a/compiler/aliases.nim b/compiler/aliases.nim new file mode 100644 index 000000000..aa579feee --- /dev/null +++ b/compiler/aliases.nim @@ -0,0 +1,182 @@ +# +# +# The Nimrod Compiler +# (c) Copyright 2011 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Simple alias analysis for the HLO and the code generators. + +import + ast, astalgo, types, trees, intsets, msgs + +type + TAnalysisResult* = enum + arNo, arMaybe, arYes + +proc isPartOfAux(a, b: PType, marker: var TIntSet): TAnalysisResult + +proc isPartOfAux(n: PNode, b: PType, marker: var TIntSet): TAnalysisResult = + result = arNo + case n.kind + of nkRecList: + for i in countup(0, sonsLen(n) - 1): + result = isPartOfAux(n.sons[i], b, marker) + if result == arYes: return + of nkRecCase: + assert(n.sons[0].kind == nkSym) + result = isPartOfAux(n.sons[0], b, marker) + if result == arYes: return + for i in countup(1, sonsLen(n) - 1): + case n.sons[i].kind + of nkOfBranch, nkElse: + result = isPartOfAux(lastSon(n.sons[i]), b, marker) + if result == arYes: return + else: internalError("isPartOfAux(record case branch)") + of nkSym: + result = isPartOfAux(n.sym.typ, b, marker) + else: internalError(n.info, "isPartOfAux()") + +proc isPartOfAux(a, b: PType, marker: var TIntSet): TAnalysisResult = + result = arNo + if a == nil or b == nil: return + if ContainsOrIncl(marker, a.id): return + if compareTypes(a, b, dcEqIgnoreDistinct): return arYes + case a.kind + of tyObject: + result = isPartOfAux(a.sons[0], b, marker) + if result == arNo: result = isPartOfAux(a.n, b, marker) + of tyGenericInst, tyDistinct: + result = isPartOfAux(lastSon(a), b, marker) + of tyArray, tyArrayConstr, tySet, tyTuple: + for i in countup(0, sonsLen(a) - 1): + result = isPartOfAux(a.sons[i], b, marker) + if result == arYes: return + else: nil + +proc isPartOf(a, b: PType): TAnalysisResult = + ## checks iff 'a' can be part of 'b'. Iterates over VALUE types! + var marker = InitIntSet() + # watch out: parameters reversed because I'm too lazy to change the code... + result = isPartOfAux(b, a, marker) + +proc isPartOf*(a, b: PNode): TAnalysisResult = + ## checks if location `a` can be part of location `b`. We treat seqs and + ## strings as pointers because the code gen often just passes them as such. + ## + ## Note: `a` can only be part of `b`, if `a`'s type can be part of `b`'s + ## type. Since however type analysis is more expensive, we perform it only + ## if necessary. + ## + ## cases: + ## + ## YES-cases: + ## x <| x # for general trees + ## x[] <| x + ## x[i] <| x + ## x.f <| x + ## + ## NO-cases: + ## x !<| y # depending on type and symbol kind + ## x[constA] !<| x[constB] + ## x.f !<| x.g + ## x.f !<| y.f iff x !<= y + ## + ## MAYBE-cases: + ## + ## x[] ?<| y[] iff compatible type + ## + ## + ## x[] ?<| y depending on type + ## + if a.kind == b.kind: + case a.kind + of nkSym: + const varKinds = {skVar, skTemp, skProc} + # same symbol: aliasing: + if a.sym.id == b.sym.id: result = arYes + elif a.sym.kind in varKinds or b.sym.kind in varKinds: + # actually, a param could alias a var but we know that cannot happen + # here. XXX make this more generic + result = arNo + else: + # use expensive type check: + if isPartOf(a.sym.typ, b.sym.typ) != arNo: + result = arMaybe + of nkBracketExpr: + result = isPartOf(a[0], b[0]) + if len(a) >= 2 and len(b) >= 2: + # array accesses: + if result == arYes and isDeepConstExpr(a[1]) and isDeepConstExpr(b[1]): + # we know it's the same array and we have 2 constant indexes; + # if they are + var x = if a[1].kind == nkHiddenStdConv: a[1][1] else: a[1] + var y = if b[1].kind == nkHiddenStdConv: b[1][1] else: b[1] + + if SameValue(x, y): result = arYes + else: result = arNo + # else: maybe and no are accurate + else: + # pointer derefs: + if result != arYes: + if isPartOf(a.typ, b.typ) != arNo: result = arMaybe + + of nkDotExpr: + result = isPartOf(a[0], b[0]) + if result != arNo: + # if the fields are different, it's not the same location + if a[1].sym.id != b[1].sym.id: + result = arNo + + of nkHiddenDeref, nkDerefExpr: + result = isPartOf(a[0], b[0]) + # weaken because of indirection: + if result != arYes: + if isPartOf(a.typ, b.typ) != arNo: result = arMaybe + + of nkHiddenStdConv, nkHiddenSubConv, nkConv: + result = isPartOf(a[1], b[1]) + of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr: + result = isPartOf(a[0], b[0]) + else: nil + # Calls return a new location, so a default of ``arNo`` is fine. + else: + # go down recursively; this is quite demanding: + const + Ix0Kinds = {nkDotExpr, nkBracketExpr, nkObjUpConv, nkObjDownConv, + nkCheckedFieldExpr} + Ix1Kinds = {nkHiddenStdConv, nkHiddenSubConv, nkConv} + DerefKinds = {nkHiddenDeref, nkDerefExpr} + case b.kind + of Ix0Kinds: + # a* !<| b.f iff a* !<| b + result = isPartOf(a, b[0]) + + of DerefKinds: + # a* !<| b[] iff + if isPartOf(a.typ, b.typ) != arNo: + result = isPartOf(a, b[0]) + if result == arNo: result = arMaybe + + of Ix1Kinds: + # a* !<| T(b) iff a* !<| b + result = isPartOf(a, b[1]) + + of nkSym: + # b is an atom, so we have to check a: + case a.kind + of Ix0Kinds: + # a.f !<| b* iff a.f !<| b* + result = isPartOf(a[0], b) + of Ix1Kinds: + result = isPartOf(a[1], b) + + of DerefKinds: + if isPartOf(a.typ, b.typ) != arNo: + result = isPartOf(a[0], b) + if result == arNo: result = arMaybe + else: nil + else: nil + diff --git a/compiler/ast.nim b/compiler/ast.nim index 6ac7dc0de..8d1aeeb6a 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -371,7 +371,7 @@ type mFields, mFieldPairs, mAppendStrCh, mAppendStrStr, mAppendSeqElem, mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq, - mAssert, mAstToStr, mRand, + mIsPartOf, mAstToStr, mRand, mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast, mNewString, mNewStringOfCap, mReset, @@ -669,36 +669,7 @@ const # for all kind of hash tables: GrowthFactor* = 2 # must be power of 2, > 0 StartSize* = 8 # must be power of 2, > 0 -proc SameValue*(a, b: PNode): bool - # a, b are literals -proc leValue*(a, b: PNode): bool - # a <= b? a, b are literals -proc ValueToString*(a: PNode): string - -proc leValue(a, b: PNode): bool = - # a <= b? - result = false - case a.kind - of nkCharLit..nkInt64Lit: - if b.kind in {nkCharLit..nkInt64Lit}: result = a.intVal <= b.intVal - of nkFloatLit..nkFloat64Lit: - if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal <= b.floatVal - of nkStrLit..nkTripleStrLit: - if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal <= b.strVal - else: InternalError(a.info, "leValue") - -proc SameValue(a, b: PNode): bool = - result = false - case a.kind - of nkCharLit..nkInt64Lit: - if b.kind in {nkCharLit..nkInt64Lit}: result = a.intVal == b.intVal - of nkFloatLit..nkFloat64Lit: - if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal == b.floatVal - of nkStrLit..nkTripleStrLit: - if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal == b.strVal - else: InternalError(a.info, "SameValue") - -proc ValueToString(a: PNode): string = +proc ValueToString*(a: PNode): string = case a.kind of nkCharLit..nkInt64Lit: result = $(a.intVal) of nkFloatLit, nkFloat32Lit, nkFloat64Lit: result = $(a.floatVal) diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 472a8d803..94046a723 100755 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -146,6 +146,30 @@ proc IITablePut*(t: var TIITable, key, val: int) # implementation +proc SameValue*(a, b: PNode): bool = + result = false + case a.kind + of nkCharLit..nkInt64Lit: + if b.kind in {nkCharLit..nkInt64Lit}: result = a.intVal == b.intVal + of nkFloatLit..nkFloat64Lit: + if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal == b.floatVal + of nkStrLit..nkTripleStrLit: + if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal == b.strVal + else: + InternalError(a.info, "SameValue") + +proc leValue*(a, b: PNode): bool = + # a <= b? + result = false + case a.kind + of nkCharLit..nkInt64Lit: + if b.kind in {nkCharLit..nkInt64Lit}: result = a.intVal <= b.intVal + of nkFloatLit..nkFloat64Lit: + if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal <= b.floatVal + of nkStrLit..nkTripleStrLit: + if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal <= b.strVal + else: InternalError(a.info, "leValue") + proc lookupInRecord(n: PNode, field: PIdent): PSym = result = nil case n.kind diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 1c57479ae..570c931fb 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -10,16 +10,30 @@ type TAfterCallActions = tuple[p: BProc, actions: PRope] -proc fixupCall(p: BProc, t: PNode, d: var TLoc, pl: PRope) = +proc leftAppearsOnRightSide(le, ri: PNode): bool = + if le != nil: + for i in 1 .. <ri.len: + if le.isPartOf(ri[i]) != arNo: return true + +proc hasNoInit(call: PNode): bool {.inline.} = + result = call.sons[0].kind == nkSym and sfNoInit in call.sons[0].sym.flags + +proc resetLoc(p: BProc, d: var TLoc) = + zeroVar(p, d, containsGarbageCollectedRef(d.t)) + +proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, pl: PRope) = var pl = pl - var typ = t.sons[0].typ # getUniqueType() is too expensive here! + var typ = ri.sons[0].typ # getUniqueType() is too expensive here! if typ.sons[0] != nil: if isInvalidReturnType(typ.sons[0]): - if sonsLen(t) > 1: app(pl, ", ") - # beware of 'result = p(result)'. We always allocate a temporary: - if d.k in {locTemp, locNone}: - # We already got a temp. Great, special case it: + if sonsLen(ri) > 1: app(pl, ", ") + # beware of 'result = p(result)'. We may need to allocate a temporary: + if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri): + # Great, we can use 'd': if d.k == locNone: getTemp(p, typ.sons[0], d) + elif d.k notin {locExpr, locTemp} and not hasNoInit(ri): + # reset before pass as 'result' var: + resetLoc(p, d) app(pl, addrLoc(d)) app(pl, ")") app(p.s[cpsStmts], pl) @@ -117,40 +131,40 @@ proc genArgNoParam(aca: var TAfterCallActions, n: PNode): PRope = initLocExpr(aca.p, n, a) result = rdLoc(a) -proc genCall(p: BProc, t: PNode, d: var TLoc) = +proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) = var op: TLoc var aca: TAfterCallActions aca.p = p # this is a hotspot in the compiler - initLocExpr(p, t.sons[0], op) + initLocExpr(p, ri.sons[0], op) var pl = con(op.r, "(") - var typ = t.sons[0].typ # getUniqueType() is too expensive here! + var typ = ri.sons[0].typ # getUniqueType() is too expensive here! assert(typ.kind == tyProc) - var length = sonsLen(t) + var length = sonsLen(ri) for i in countup(1, length - 1): assert(sonsLen(typ) == sonsLen(typ.n)) if i < sonsLen(typ): assert(typ.n.sons[i].kind == nkSym) - app(pl, genArg(aca, t.sons[i], typ.n.sons[i].sym)) + app(pl, genArg(aca, ri.sons[i], typ.n.sons[i].sym)) else: - app(pl, genArgNoParam(aca, t.sons[i])) + app(pl, genArgNoParam(aca, ri.sons[i])) if i < length - 1: app(pl, ", ") - fixupCall(p, t, d, pl) + fixupCall(p, le, ri, d, pl) emitAfterCallActions(aca) -proc genInfixCall(p: BProc, t: PNode, d: var TLoc) = +proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) = var op, a: TLoc var aca: TAfterCallActions aca.p = p - initLocExpr(p, t.sons[0], op) + initLocExpr(p, ri.sons[0], op) var pl: PRope = nil - var typ = t.sons[0].typ # getUniqueType() is too expensive here! + var typ = ri.sons[0].typ # getUniqueType() is too expensive here! assert(typ.kind == tyProc) - var length = sonsLen(t) + var length = sonsLen(ri) assert(sonsLen(typ) == sonsLen(typ.n)) var param = typ.n.sons[1].sym - app(pl, genArg(aca, t.sons[1], param)) + app(pl, genArg(aca, ri.sons[1], param)) if skipTypes(param.typ, {tyGenericInst}).kind == tyPtr: app(pl, "->") else: app(pl, ".") @@ -160,45 +174,45 @@ proc genInfixCall(p: BProc, t: PNode, d: var TLoc) = assert(sonsLen(typ) == sonsLen(typ.n)) if i < sonsLen(typ): assert(typ.n.sons[i].kind == nkSym) - app(pl, genArg(aca, t.sons[i], typ.n.sons[i].sym)) + app(pl, genArg(aca, ri.sons[i], typ.n.sons[i].sym)) else: - app(pl, genArgNoParam(aca, t.sons[i])) + app(pl, genArgNoParam(aca, ri.sons[i])) if i < length - 1: app(pl, ", ") - fixupCall(p, t, d, pl) + fixupCall(p, le, ri, d, pl) emitAfterCallActions(aca) -proc genNamedParamCall(p: BProc, t: PNode, d: var TLoc) = +proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) = # generates a crappy ObjC call var op, a: TLoc var aca: TAfterCallActions aca.p = p - initLocExpr(p, t.sons[0], op) + initLocExpr(p, ri.sons[0], op) var pl = toRope"[" - var typ = t.sons[0].typ # getUniqueType() is too expensive here! + var typ = ri.sons[0].typ # getUniqueType() is too expensive here! assert(typ.kind == tyProc) - var length = sonsLen(t) + var length = sonsLen(ri) assert(sonsLen(typ) == sonsLen(typ.n)) if length > 1: - app(pl, genArg(aca, t.sons[1], typ.n.sons[1].sym)) + app(pl, genArg(aca, ri.sons[1], typ.n.sons[1].sym)) app(pl, " ") app(pl, op.r) if length > 2: app(pl, ": ") - app(pl, genArg(aca, t.sons[2], typ.n.sons[2].sym)) + app(pl, genArg(aca, ri.sons[2], typ.n.sons[2].sym)) for i in countup(3, length-1): assert(sonsLen(typ) == sonsLen(typ.n)) if i >= sonsLen(typ): - InternalError(t.info, "varargs for objective C method?") + InternalError(ri.info, "varargs for objective C method?") assert(typ.n.sons[i].kind == nkSym) var param = typ.n.sons[i].sym app(pl, " ") app(pl, param.name.s) app(pl, ": ") - app(pl, genArg(aca, t.sons[i], param)) + app(pl, genArg(aca, ri.sons[i], param)) if typ.sons[0] != nil: if isInvalidReturnType(typ.sons[0]): - if sonsLen(t) > 1: app(pl, " ") + if sonsLen(ri) > 1: app(pl, " ") # beware of 'result = p(result)'. We always allocate a temporary: if d.k in {locTemp, locNone}: # We already got a temp. Great, special case it: @@ -230,3 +244,21 @@ proc genNamedParamCall(p: BProc, t: PNode, d: var TLoc) = appf(p.s[cpsStmts], ";$n") emitAfterCallActions(aca) +proc genCall(p: BProc, e: PNode, d: var TLoc) = + if e.sons[0].kind == nkSym and sfInfixCall in e.sons[0].sym.flags and + e.len >= 2: + genInfixCall(p, nil, e, d) + elif e.sons[0].kind == nkSym and sfNamedParamCall in e.sons[0].sym.flags: + genNamedParamCall(p, e, d) + else: + genPrefixCall(p, nil, e, d) + +proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) = + if ri.sons[0].kind == nkSym and sfInfixCall in ri.sons[0].sym.flags and + ri.len >= 2: + genInfixCall(p, le, ri, d) + elif ri.sons[0].kind == nkSym and sfNamedParamCall in ri.sons[0].sym.flags: + genNamedParamCall(p, ri, d) + else: + genPrefixCall(p, le, ri, d) + diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 13d9637ad..ddd272fba 100755 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1378,13 +1378,6 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mCStrToStr: genDollar(p, e, d, "#cstrToNimstr($1)") of mStrToStr: expr(p, e.sons[1], d) of mEnumToStr: genRepr(p, e, d) - of mAssert: - if optAssert in p.Options: - expr(p, e.sons[1], d) - line = toRope(toLinenumber(e.info)) - filen = makeCString(ToFilename(e.info)) - appcg(p, cpsStmts, "#internalAssert($1, $2, $3);$n", - [filen, line, rdLoc(d)]) of mOf: genOf(p, e, d) of mNew: genNew(p, e) of mNewFinalize: genNewFinalize(p, e) @@ -1635,11 +1628,6 @@ proc expr(p: BProc, e: PNode, d: var TLoc) = nkCallStrLit: if e.sons[0].kind == nkSym and e.sons[0].sym.magic != mNone: genMagicExpr(p, e, d, e.sons[0].sym.magic) - elif e.sons[0].kind == nkSym and sfInfixCall in e.sons[0].sym.flags and - e.len >= 2: - genInfixCall(p, e, d) - elif e.sons[0].kind == nkSym and sfNamedParamCall in e.sons[0].sym.flags: - genNamedParamCall(p, e, d) else: genCall(p, e, d) of nkCurly: diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index a994f27f3..108d7f071 100755 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -18,16 +18,16 @@ proc genVarTuple(p: BProc, n: PNode) = if n.kind != nkVarTuple: InternalError(n.info, "genVarTuple") var L = sonsLen(n) genLineDir(p, n) - initLocExpr(p, n.sons[L - 1], tup) + initLocExpr(p, n.sons[L-1], tup) var t = tup.t - for i in countup(0, L - 3): + for i in countup(0, L-3): var v = n.sons[i].sym if sfGlobal in v.flags: assignGlobalVar(p, v) genObjectInit(p, cpsInit, v.typ, v.loc, true) - else: + else: assignLocalVar(p, v) - initVariable(p, v) + initLocalVar(p, v, immediateAsgn=true) initLoc(field, locExpr, t.sons[i], tup.s) if t.n == nil: field.r = ropef("$1.Field$2", [rdLoc(tup), toRope(i)]) @@ -37,17 +37,25 @@ proc genVarTuple(p: BProc, n: PNode) = [rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)]) putLocIntoDest(p, v.loc, field) +proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} = + if ri.kind in nkCallKinds and (ri.sons[0].kind != nkSym or + ri.sons[0].sym.magic == mNone): + genAsgnCall(p, le, ri, a) + else: + expr(p, ri, a) + proc genSingleVar(p: BProc, a: PNode) = var v = a.sons[0].sym + var immediateAsgn = a.sons[2].kind != nkEmpty if sfGlobal in v.flags: assignGlobalVar(p, v) genObjectInit(p, cpsInit, v.typ, v.loc, true) - else: + else: assignLocalVar(p, v) - initVariable(p, v) - if a.sons[2].kind != nkEmpty: + initLocalVar(p, v, immediateAsgn) + if immediateAsgn: genLineDir(p, a) - expr(p, a.sons[2], v.loc) + loadInto(p, a.sons[0], a.sons[2], v.loc) proc genVarStmt(p: BProc, n: PNode) = for i in countup(0, sonsLen(n) - 1): @@ -658,7 +666,7 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) = InitLocExpr(p, e.sons[0], a) if fastAsgn: incl(a.flags, lfNoDeepCopy) assert(a.t != nil) - expr(p, e.sons[1], a) + loadInto(p, e.sons[0], e.sons[1], a) else: asgnFieldDiscriminant(p, e) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 2018d7e6d..aa07f40aa 100755 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -14,7 +14,7 @@ import options, intsets, nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os, times, ropes, math, passes, rodread, wordrecg, treetab, cgmeth, - rodutils, renderer, idgen, cgendata, ccgmerge, semfold + rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases when options.hasTinyCBackend: import tccgen @@ -235,16 +235,17 @@ proc zeroVar(p: BProc, loc: TLoc, containsGCref: bool) = genRefAssign(p, loc, nilLoc, {afSrcIsNil}) else: appf(p.s[cpsStmts], "$1 = 0;$n", [rdLoc(loc)]) - else: + else: if containsGcref and p.WithInLoop > 0: appf(p.s[cpsInit], "memset((void*)$1, 0, sizeof($2));$n", [addrLoc(loc), rdLoc(loc)]) + genObjectInit(p, cpsInit, loc.t, loc, true) appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n", [addrLoc(loc), genTypeInfo(p.module, loc.t)]) else: appf(p.s[cpsStmts], "memset((void*)$1, 0, sizeof($2));$n", [addrLoc(loc), rdLoc(loc)]) - genObjectInit(p, cpsInit, loc.t, loc, true) + genObjectInit(p, cpsStmts, loc.t, loc, true) proc zeroTemp(p: BProc, loc: TLoc) = if skipTypes(loc.t, abstractVarRange).Kind notin @@ -259,15 +260,22 @@ proc zeroTemp(p: BProc, loc: TLoc) = else: appf(p.s[cpsStmts], "memset((void*)$1, 0, sizeof($2));$n", [addrLoc(loc), rdLoc(loc)]) + # XXX no object init necessary for temporaries? when false: appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n", [addrLoc(loc), genTypeInfo(p.module, loc.t)]) -proc initVariable(p: BProc, v: PSym) = +proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) = if sfNoInit notin v.flags: - var b = containsGarbageCollectedRef(v.typ) - if b or v.ast == nil: - zeroVar(p, v.loc, b) + # we know it is a local variable and thus on the stack! + # If ``not immediateAsgn`` it is not initialized in a binding like + # ``var v = X`` and thus we need to init it. + # If ``v`` contains a GC-ref we may pass it to ``unsureAsgnRef`` somehow + # which requires initialization. However this can really only happen if + # ``var v = X()`` gets transformed into ``X(&v)``. + # Nowadays the logic in ccgcalls deals with this case however. + if not immediateAsgn: + zeroVar(p, v.loc, containsGarbageCollectedRef(v.typ)) proc initTemp(p: BProc, tmp: var TLoc) = if containsGarbageCollectedRef(tmp.t) or isInvalidReturnType(tmp.t): @@ -534,13 +542,14 @@ proc genProcAux(m: BModule, prc: PSym) = assert(prc.ast != nil) if sfPure notin prc.flags and prc.typ.sons[0] != nil: var res = prc.ast.sons[resultPos].sym # get result symbol - if not isInvalidReturnType(prc.typ.sons[0]): + if not isInvalidReturnType(prc.typ.sons[0]): + if sfNoInit in prc.flags: incl(res.flags, sfNoInit) # declare the result symbol: assignLocalVar(p, res) assert(res.loc.r != nil) returnStmt = ropeff("return $1;$n", "ret $1$n", [rdLoc(res.loc)]) - initVariable(p, res) - else: + initLocalVar(p, res, immediateAsgn=false) + else: fillResult(res) assignParam(p, res) if skipTypes(res.typ, abstractInst).kind == tyArray: diff --git a/compiler/ecmasgen.nim b/compiler/ecmasgen.nim index 588abfc93..76d4dde89 100755 --- a/compiler/ecmasgen.nim +++ b/compiler/ecmasgen.nim @@ -720,7 +720,8 @@ proc generateHeader(p: var TProc, typ: PType): PRope = const nodeKindsNeedNoCopy = {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit, nkFloatLit..nkFloat64Lit, nkCurly, nkPar, nkStringToCString, - nkCStringToString, nkCall, nkCommand, nkHiddenCallConv, nkCallStrLit} + nkCStringToString, nkCall, nkPrefix, nkPostfix, nkInfix, + nkCommand, nkHiddenCallConv, nkCallStrLit} proc needsNoCopy(y: PNode): bool = result = (y.kind in nodeKindsNeedNoCopy) or @@ -1131,14 +1132,6 @@ proc genMagic(p: var TProc, n: PNode, r: var TCompRes) = of mLtStr: binaryExpr(p, n, r, "cmpStrings", "(cmpStrings($1, $2) < 0)") of mIsNil: unaryExpr(p, n, r, "", "$1 == null") of mEnumToStr: genRepr(p, n, r) - of mAssert: - if (optAssert in p.Options): - useMagic(p, "internalAssert") - gen(p, n.sons[1], a) - line = toRope(toLinenumber(n.info)) - filen = makeCString(ToFilename(n.info)) - appf(r.com, "if (!($3)) internalAssert($1, $2)", - [filen, line, mergeExpr(a)]) of mNew, mNewFinalize: genNew(p, n, r) of mSizeOf: r.res = toRope(getSize(n.sons[1].typ)) of mChr, mArrToSeq: gen(p, n.sons[1], r) # nothing to do @@ -1402,7 +1395,7 @@ proc gen(p: var TProc, n: PNode, r: var TCompRes) = else: r.res = toRope(f.ToStrMaxPrecision) of nkBlockExpr: genBlock(p, n, r) of nkIfExpr: genIfExpr(p, n, r) - of nkCall, nkHiddenCallConv, nkCommand, nkCallStrLit: + of nkCallKinds: if (n.sons[0].kind == nkSym) and (n.sons[0].sym.magic != mNone): genMagic(p, n, r) else: diff --git a/compiler/evals.nim b/compiler/evals.nim index fff58b7f4..2ca0f3faf 100755 --- a/compiler/evals.nim +++ b/compiler/evals.nim @@ -695,13 +695,7 @@ proc evalNewSeq(c: PEvalContext, n: PNode): PNode = for i in countup(0, L-1): a.sons[i] = getNullValue(t.sons[0], n.info) result = emptyNode - -proc evalAssert(c: PEvalContext, n: PNode): PNode = - result = evalAux(c, n.sons[1], {}) - if isSpecial(result): return - if getOrdValue(result) != 0: result = emptyNode - else: stackTrace(c, n, errAssertionFailed) - + proc evalIncl(c: PEvalContext, n: PNode): PNode = result = evalAux(c, n.sons[1], {efLValue}) if isSpecial(result): return @@ -876,7 +870,6 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode = of mOf: result = evalOf(c, n) of mSizeOf: result = raiseCannotEval(c, n) of mHigh: result = evalHigh(c, n) - of mAssert: result = evalAssert(c, n) of mExit: result = evalExit(c, n) of mNew, mNewFinalize: result = evalNew(c, n) of mNewSeq: result = evalNewSeq(c, n) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index d4ea3226d..a291d4741 100755 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -23,7 +23,7 @@ const wMagic, wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader, wCompilerProc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge, wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC, - wNoStackFrame, wError, wDiscardable} + wNoStackFrame, wError, wDiscardable, wNoInit} converterPragmas* = procPragmas methodPragmas* = procPragmas macroPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl, diff --git a/compiler/sem.nim b/compiler/sem.nim index a4a0ba1bc..d38a547c2 100755 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -14,7 +14,7 @@ import wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math, magicsys, parser, nversion, semdata, nimsets, semfold, importer, procfind, lookups, rodread, pragmas, passes, semtypinst, sigmatch, suggest, - semthreads, intsets, transf, evals, idgen + semthreads, intsets, transf, evals, idgen, aliases proc semPass*(): TPass # implementation diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 7bb6f26e0..a5093f567 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -453,6 +453,14 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) = skipTypes(t.sons[i], abstractInst).kind == tyVar: n.sons[i] = analyseIfAddressTaken(c, n.sons[i]) + +proc expectStringArg(c: PContext, n: PNode, i: int): PNode = + result = c.semAndEvalConstExpr(n.sons[i+1]) + if result.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}: + GlobalError(result.info, errStringLiteralExpected) + +include semmagic + proc semDirectCallAnalyseEffects(c: PContext, n: PNode, flags: TExprFlags): PNode = if efWantIterator in flags: @@ -520,6 +528,8 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = renderTree(n, {renderNoComments})) fixAbstractType(c, result) analyseIfAddressTakenInCall(c, result) + if result.sons[0].kind == nkSym and result.sons[0].sym.magic != mNone: + result = magicsAfterOverloadResolution(c, result, flags) proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = # this seems to be a hotspot in the compiler! @@ -530,6 +540,8 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = if result == nil: GlobalError(n.Info, errGenerated, getNotFoundError(c, n)) fixAbstractType(c, result) analyseIfAddressTakenInCall(c, result) + if result.sons[0].sym.magic != mNone: + result = magicsAfterOverloadResolution(c, result, flags) proc buildStringify(c: PContext, arg: PNode): PNode = if arg.typ != nil and skipTypes(arg.typ, abstractInst).kind == tyString: @@ -914,12 +926,6 @@ proc setMs(n: PNode, s: PSym): PNode = n.sons[0] = newSymNode(s) n.sons[0].info = n.info -proc expectStringArg(c: PContext, n: PNode, i: int): PNode = - result = c.semAndEvalConstExpr(n.sons[i+1]) - - if result.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}: - GlobalError(result.info, errStringLiteralExpected) - proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym = ## The argument to the proc should be nkCall(...) or similar ## Returns the macro/template symbol @@ -954,21 +960,6 @@ proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym, else: result = semDirectOp(c, n, flags) -proc semSlurp(c: PContext, n: PNode, flags: TExprFlags): PNode = - if sonsLen(n) == 2: - var a = expectStringArg(c, n, 0) - try: - var filename = a.strVal.FindFile - var content = readFile(filename) - result = newStrNode(nkStrLit, content) - result.typ = getSysType(tyString) - result.info = n.info - c.slurpedFiles.add(filename) - except EIO: - GlobalError(a.info, errCannotOpenFile, a.strVal) - else: - result = semDirectOp(c, n, flags) - proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = # this is a hotspot in the compiler! result = n @@ -991,14 +982,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = result = semAsgn(c, result) else: result = semDirectOp(c, n, flags) - of mSlurp: result = semSlurp(c, n, flags) of mExpandToAst: result = semExpandToAst(c, n, s, flags) - of mAstToStr: - if sonsLen(n) == 2: - result = newStrNodeT(renderTree(n[1], {renderNoComments}), n) - result.typ = getSysType(tyString) - else: - result = semDirectOp(c, n, flags) else: result = semDirectOp(c, n, flags) proc semIfExpr(c: PContext, n: PNode): PNode = diff --git a/compiler/semfold.nim b/compiler/semfold.nim index b2e2f2277..0eb05a055 100755 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -204,7 +204,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode = result = newIntNodeT(Ord( testCompileOptionArg(getStr(a), getStr(b), n.info)), n) of mNewString, mNewStringOfCap, - mExit, mInc, ast.mDec, mEcho, mAssert, mSwap, mAppendStrCh, + mExit, mInc, ast.mDec, mEcho, mSwap, mAppendStrCh, mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq, mParseExprToAst, mParseStmtToAst, mExpandToAst, mNLen..mNError, mEqRef: diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim new file mode 100644 index 000000000..696988fd3 --- /dev/null +++ b/compiler/semmagic.nim @@ -0,0 +1,38 @@ +# +# +# The Nimrod Compiler +# (c) Copyright 2011 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +# This include file implements the semantic checking for magics. + +proc semIsPartOf(c: PContext, n: PNode, flags: TExprFlags): PNode = + var r = isPartOf(n[1], n[2]) + result = newIntNodeT(ord(r), n) + +proc semSlurp(c: PContext, n: PNode, flags: TExprFlags): PNode = + assert sonsLen(n) == 2 + var a = expectStringArg(c, n, 0) + try: + var filename = a.strVal.FindFile + var content = readFile(filename) + result = newStrNode(nkStrLit, content) + result.typ = getSysType(tyString) + result.info = n.info + c.slurpedFiles.add(filename) + except EIO: + GlobalError(a.info, errCannotOpenFile, a.strVal) + +proc magicsAfterOverloadResolution(c: PContext, n: PNode, + flags: TExprFlags): PNode = + case n[0].sym.magic + of mSlurp: result = semSlurp(c, n, flags) + of mIsPartOf: result = semIsPartOf(c, n, flags) + of mAstToStr: + result = newStrNodeT(renderTree(n[1], {renderNoComments}), n) + result.typ = getSysType(tyString) + else: result = n + diff --git a/compiler/types.nim b/compiler/types.nim index 6ce4c6e48..d3f2bd1b5 100755 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1024,7 +1024,6 @@ proc computeSize(typ: PType): biggestInt = proc getReturnType*(s: PSym): PType = # Obtains the return type of a iterator/proc/macro/template assert s.kind in {skProc, skTemplate, skMacro, skIterator} - # XXX ask Zahary if this change broke something result = s.typ.sons[0] proc getSize(typ: PType): biggestInt = diff --git a/doc/manual.txt b/doc/manual.txt index 164410a68..97af7fe2a 100755 --- a/doc/manual.txt +++ b/doc/manual.txt @@ -1584,6 +1584,11 @@ The implicit initialization can be avoided for optimization reasons with the var a {.noInit.}: array [0..1023, char] +If a proc is annotated with the ``noinit`` pragma this refers to its implicit +``result`` variable: + +.. code-block:: nimrod + proc returnUndefinedValue: int {.noinit.} = nil let statement @@ -2849,6 +2854,7 @@ exported. The algorithm for compiling modules is: - compile the whole module as usual, following import statements recursively + - if there is a cycle only import the already parsed symbols (that are exported); if an unknown identifier occurs then abort diff --git a/lib/pure/actors.nim b/lib/pure/actors.nim index 2510bb8cd..c07adfd93 100644 --- a/lib/pure/actors.nim +++ b/lib/pure/actors.nim @@ -11,6 +11,8 @@ ## a channel as its inbox. This module requires the ``--threads:on`` ## command line switch. +from os import sleep + type TTask*[TIn, TOut] = object{.pure, final.} when TOut isnot void: @@ -29,7 +31,7 @@ type 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. + ## ``join`` because that also frees the actor's associated resources. result = cast[PActor[TIn, TOut]](allocShared0(sizeof(result[]))) open(result.i) createThread(result.t, action, result) @@ -42,6 +44,10 @@ proc running*[TIn, TOut](a: PActor[TIn, TOut]) = ## returns true if the actor `a` is running. result = running(a.t) +proc ready*[TIn, TOut](a: PActor[TIn, TOut]): bool = + ## returns true if the actor `a` is ready to process new messages. + result = ready(a.i) + proc join*[TIn, TOut](a: PActor[TIn, TOut]) = ## joins an actor. joinThread(a.t) @@ -111,17 +117,35 @@ proc createActorPool*[TIn, TOut](a: var TActorPool[TIn, TOut], poolSize = 4) = for i in 0 .. < a.actors.len: 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 +proc sync*[TIn, TOut](a: var TActorPool[TIn, TOut], polling=50) = + ## waits for every actor of `a` to finish with its work. Currently this is + ## implemented as polling every `polling` ms. This will change in a later + ## version, however. + while true: + var wait = false + for i in 0..high(a.actors): + if not a.actors[i].i.ready: + wait = true + break + if not wait: break + sleep(polling) + +proc terminate*[TIn, TOut](a: var TActorPool[TIn, TOut]) = + ## terminates each actor in the actor pool `a` 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].i, t) - for i in 0 .. < a.actors.len: join(a.actors[i]) + 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 +proc join*[TIn, TOut](a: var TActorPool[TIn, TOut]) = + ## short-cut for `sync` and then `terminate`. + sync(a) + terminate(a) + template setupTask = t.action = action shallowCopy(t.data, input) @@ -135,7 +159,7 @@ template schedule = return # no thread ready :-( --> send message to the thread which has the least # messages pending: - var minIdx = 0 + var minIdx = -1 var minVal = high(int) for i in 0..high(p.actors): var curr = p.actors[i].i.peek @@ -143,10 +167,13 @@ template schedule = # ok, is ready now: p.actors[i].i.send(t) return - if curr < minVal: + if curr < minVal and curr >= 0: minVal = curr minIdx = i - p.actors[minIdx].i.send(t) + if minIdx >= 0: + p.actors[minIdx].i.send(t) + else: + raise newException(EDeadThread, "cannot send message; thread died") proc spawn*[TIn, TOut](p: var TActorPool[TIn, TOut], input: TIn, action: proc (input: TIn): TOut {.thread.} diff --git a/lib/system.nim b/lib/system.nim index c7e26230a..8a99781cc 100755 --- a/lib/system.nim +++ b/lib/system.nim @@ -2071,14 +2071,24 @@ proc astToStr*[T](x: T): string {.magic: "AstToStr", noSideEffect.} ## converts the AST of `x` into a string representation. This is very useful ## for debugging. +proc raiseAssert(msg: string) {.noinline.} = + raise newException(EAssertionFailed, msg) + template assert*(cond: expr, msg = "") = ## provides a means to implement `programming by contracts`:idx: in Nimrod. ## ``assert`` evaluates expression ``cond`` and if ``cond`` is false, it ## raises an ``EAssertionFailure`` exception. However, the compiler may ## not generate any code at all for ``assert`` if it is advised to do so. ## Use ``assert`` for debugging purposes only. + bind raiseAssert when compileOption("assertions"): if not cond: - raise newException(EAssertionFailed, astToStr(cond) & ' ' & msg) - + raiseAssert(astToStr(cond) & ' ' & msg) + +template doAssert*(cond: expr, msg = "") = + ## same as `assert' but is always turned on and not affected by the + ## ``--assertions`` command line switch. + bind raiseAssert + if not cond: + raiseAssert(astToStr(cond) & ' ' & msg) diff --git a/lib/system/channels.nim b/lib/system/channels.nim index fe93d6840..47fa5b2e5 100755 --- a/lib/system/channels.nim +++ b/lib/system/channels.nim @@ -222,11 +222,14 @@ proc recv*[TMsg](c: var TChannel[TMsg]): TMsg = llRecv(q, addr(result), cast[PNimType](getTypeInfo(result))) proc peek*[TMsg](c: var TChannel[TMsg]): int = - ## returns the current number of messages in the channel `c`. + ## returns the current number of messages in the channel `c`. Returns -1 + ## if the channel has been closed. var q = cast[PRawChannel](addr(c)) if q.mask != ChannelDeadMask: lockChannel(q): result = q.count + else: + result = -1 proc open*[TMsg](c: var TChannel[TMsg]) = ## opens a channel `c` for inter thread communication. diff --git a/tests/run/tpegs.nim b/tests/run/tpegs.nim index 64c547b24..8fe302073 100755 --- a/tests/run/tpegs.nim +++ b/tests/run/tpegs.nim @@ -1669,25 +1669,25 @@ proc escapePeg*(s: string): string = if inQuote: result.add('\'') when isMainModule: - assert escapePeg("abc''def'") == r"'abc'\x27\x27'def'\x27" - #assert match("(a b c)", peg"'(' @ ')'") - assert match("W_HI_Le", peg"\y 'while'") - assert(not match("W_HI_L", peg"\y 'while'")) - assert(not match("W_HI_Le", peg"\y v'while'")) - assert match("W_HI_Le", peg"y'while'") + doAssert escapePeg("abc''def'") == r"'abc'\x27\x27'def'\x27" + #doAssert match("(a b c)", peg"'(' @ ')'") + doAssert match("W_HI_Le", peg"\y 'while'") + doAssert(not match("W_HI_L", peg"\y 'while'")) + doAssert(not match("W_HI_Le", peg"\y v'while'")) + doAssert match("W_HI_Le", peg"y'while'") - assert($ +digits == $peg"\d+") - assert "0158787".match(peg"\d+") - assert "ABC 0232".match(peg"\w+\s+\d+") - assert "ABC".match(peg"\d+ / \w+") + doAssert($ +digits == $peg"\d+") + doAssert "0158787".match(peg"\d+") + doAssert "ABC 0232".match(peg"\w+\s+\d+") + doAssert "ABC".match(peg"\d+ / \w+") for word in split("00232this02939is39an22example111", peg"\d+"): writeln(stdout, word) - assert matchLen("key", ident) == 3 + doAssert matchLen("key", ident) == 3 var pattern = sequence(ident, *whitespace, term('='), *whitespace, ident) - assert matchLen("key1= cal9", pattern) == 11 + doAssert matchLen("key1= cal9", pattern) == 11 var ws = newNonTerminal("ws", 1, 1) ws.rule = *whitespace @@ -1698,24 +1698,24 @@ when isMainModule: var c: TCaptures var s = "a+b + c +d+e+f" - assert rawMatch(s, expr.rule, 0, c) == len(s) + doAssert rawMatch(s, expr.rule, 0, c) == len(s) var a = "" for i in 0..c.ml-1: a.add(substr(s, c.matches[i][0], c.matches[i][1])) - assert a == "abcdef" + doAssert a == "abcdef" #echo expr.rule #const filename = "lib/devel/peg/grammar.txt" #var grammar = parsePeg(newFileStream(filename, fmRead), filename) #echo "a <- [abc]*?".match(grammar) - assert find("_____abc_______", term("abc"), 2) == 5 - assert match("_______ana", peg"A <- 'ana' / . A") - assert match("abcs%%%", peg"A <- ..A / .A / '%'") + doAssert find("_____abc_______", term("abc"), 2) == 5 + doAssert match("_______ana", peg"A <- 'ana' / . A") + doAssert match("abcs%%%", peg"A <- ..A / .A / '%'") if "abc" =~ peg"{'a'}'bc' 'xyz' / {\ident}": - assert matches[0] == "abc" + doAssert matches[0] == "abc" else: - assert false + doAssert false var g2 = peg"""S <- A B / C D A <- 'a'+ @@ -1723,44 +1723,44 @@ when isMainModule: C <- 'c'+ D <- 'd'+ """ - assert($g2 == "((A B) / (C D))") - assert match("cccccdddddd", g2) - assert("var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2") == + doAssert($g2 == "((A B) / (C D))") + doAssert match("cccccdddddd", g2) + doAssert("var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2") == "var1<-keykey; var2<-key2key2") - assert "var1=key; var2=key2".endsWith(peg"{\ident}'='{\ident}") + doAssert "var1=key; var2=key2".endsWith(peg"{\ident}'='{\ident}") if "aaaaaa" =~ peg"'aa' !. / ({'a'})+": - assert matches[0] == "a" + doAssert matches[0] == "a" else: - assert false + doAssert false var matches: array[0..5, string] if match("abcdefg", peg"c {d} ef {g}", matches, 2): - assert matches[0] == "d" - assert matches[1] == "g" + doAssert matches[0] == "d" + doAssert matches[1] == "g" else: - assert false + doAssert false for x in findAll("abcdef", peg"{.}", 3): echo x if "f(a, b)" =~ peg"{[0-9]+} / ({\ident} '(' {@} ')')": - assert matches[0] == "f" - assert matches[1] == "a, b" + doAssert matches[0] == "f" + doAssert matches[1] == "a, b" else: - assert false + doAssert false - assert match("eine übersicht und außerdem", peg"(\letter \white*)+") + doAssert match("eine übersicht und außerdem", peg"(\letter \white*)+") # ß is not a lower cased letter?! - assert match("eine übersicht und auerdem", peg"(\lower \white*)+") - assert match("EINE ÜBERSICHT UND AUSSERDEM", peg"(\upper \white*)+") - assert(not match("456678", peg"(\letter)+")) + doAssert match("eine übersicht und auerdem", peg"(\lower \white*)+") + doAssert match("EINE ÜBERSICHT UND AUSSERDEM", peg"(\upper \white*)+") + doAssert(not match("456678", peg"(\letter)+")) - assert("var1 = key; var2 = key2".replacef( + doAssert("var1 = key; var2 = key2".replacef( peg"\skip(\s*) {\ident}'='{\ident}", "$1<-$2$2") == "var1<-keykey;var2<-key2key2") - assert match("prefix/start", peg"^start$", 7) + doAssert match("prefix/start", peg"^start$", 7) # tricky test to check for false aliasing: block: diff --git a/tests/run/tuserassert.nim b/tests/run/tuserassert.nim index 958da2fe1..cf12c4e8b 100644 --- a/tests/run/tuserassert.nim +++ b/tests/run/tuserassert.nim @@ -5,7 +5,6 @@ discard """ template myAssert(cond: expr) = when rand(3) < 2: let c = cond.astToStr - {.warning: "code activated: " & c.} if not cond: echo c, "ugh" diff --git a/tests/specials.nim b/tests/specials.nim index 1f3013e90..a1aa1bc5a 100644 --- a/tests/specials.nim +++ b/tests/specials.nim @@ -118,6 +118,7 @@ proc runThreadTests(r: var TResults, options: string) = test "tactors" test "threadex" + test "trecursive_actor" #test "threadring" #test "tthreadanalysis" #test "tthreadsort" diff --git a/tests/threads/trecursive_actor.nim b/tests/threads/trecursive_actor.nim new file mode 100644 index 000000000..e2774704c --- /dev/null +++ b/tests/threads/trecursive_actor.nim @@ -0,0 +1,19 @@ +discard """ + outputsub: "0" +""" + +import actors + +var + a: TActorPool[int, void] +createActorPool(a) + +proc task(i: int) {.thread.} = + echo i + if i != 0: a.spawn (i-1, task) + +# count from 9 till 0 and check 0 is somewhere in the output +a.spawn(9, task) +a.join() + + diff --git a/todo.txt b/todo.txt index 0ff5967c0..33dc52bf9 100755 --- a/todo.txt +++ b/todo.txt @@ -1,7 +1,9 @@ version 0.8.14 ============== -- find a proper bugfix for C compilers optimizing away stack roots +- implement a proper bugfix for C compilers optimizing away stack roots + +- cleanup file path handling in the compiler - warning for implicit openArray -> varargs convention - implement explicit varargs; **but** ``len(varargs)`` problem remains! --> solve by implicit conversion from varargs to openarray @@ -36,9 +38,6 @@ version 0.9.0 Bugs ---- - bug: generic assign still buggy - - Optimization: If we use a temporary for the result anyway the code gen - should make use of this fact to generate better code... - - 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: @@ -124,7 +123,6 @@ Low priority need to recompile clients; er ... what about templates, macros or anything that has inlining semantics? - codegen should use "NIM_CAST" macro and respect aliasing rules for GCC -- remove unused mAssert magic Version 2 ========= diff --git a/web/news.txt b/web/news.txt index b4c76cdc3..22e0377c5 100755 --- a/web/news.txt +++ b/web/news.txt @@ -29,7 +29,7 @@ Changes affecting backwards compatibility ``os.iterOverEnvironment``, ``os.pcDirectory``, ``os.pcLinkToDirectory``, ``os.SplitPath``, ``os.extractDir``, ``os.SplitFilename``, ``os.extractFileTrunk``, ``os.extractFileExt``, ``osproc.executeProcess``, - ``osproc.executeCommand``. + ``osproc.executeCommand``. - Removed deprecated ``parseopt.init``, ``parseopt.getRestOfCommandLine``. - Moved ``strutils.validEmailAddress`` to ``matchers.validEmailAddress``. - The pointer dereference operator ``^`` has been removed, so that ``^`` @@ -53,8 +53,8 @@ Changes affecting backwards compatibility because they should not be used directly anymore. Wrapper procs have been created that should be used instead. - ``export`` is now a keyword. -- ``assert`` is now implemented in pure Nimrod; it's easy to implement your - own assertion schemes now. +- ``assert`` is now implemented in pure Nimrod as a template; it's easy + to implement your own assertion templates with ``system.astToStr``. Language Additions @@ -112,6 +112,7 @@ Compiler Additions - Added ``--import:file`` and ``--include:file`` configuration options for specifying modules that will be automatically imported/incluced. - ``nimrod i`` can now optionally be given a module to execute. +- The compiler now performs a simple aliases analysis to generate better code. Library Additions @@ -128,7 +129,7 @@ Library Additions - Added ``system.program_result``. - Added ``xmltree.innerText``. - Added ``os.isAbsolute``, ``os.dynLibFormat``, ``os.isRootDir``, - ``os.parentDirs``. + ``os.parentDirs``. - Added ``parseutils.interpolatedFragments``. - Added ``macros.treeRepr``, ``macros.lispRepr``, ``macros.dumpTree``, ``macros.dumpLisp``, ``macros.parseExpr``, ``macros.parseStmt``, @@ -142,7 +143,7 @@ Library Additions and ``exec`` on Posix systems. Define the symbol ``useFork`` to revert to the old implementation. - Added ``intsets.assign``. -- Added ``system.astToStr`` and ``system.rand``. +- Added ``system.astToStr`` and ``system.rand``, ``system.doAssert``. 2011-07-10 Version 0.8.12 released |