diff options
-rw-r--r-- | compiler/ast.nim | 20 | ||||
-rw-r--r-- | compiler/ccgcalls.nim | 11 | ||||
-rw-r--r-- | compiler/guards.nim | 104 | ||||
-rw-r--r-- | compiler/lowerings.nim | 51 | ||||
-rw-r--r-- | compiler/renderer.nim | 474 | ||||
-rw-r--r-- | compiler/semparallel.nim | 4 | ||||
-rw-r--r-- | compiler/semstmts.nim | 2 | ||||
-rw-r--r-- | compiler/transf.nim | 1 | ||||
-rw-r--r-- | lib/pure/algorithm.nim | 21 | ||||
-rw-r--r-- | lib/pure/asyncdispatch.nim | 13 | ||||
-rw-r--r-- | lib/pure/asyncfile.nim | 16 | ||||
-rw-r--r-- | tests/init/tuninit2.nim | 54 | ||||
-rw-r--r-- | tests/parallel/tconvexhull.nim | 2 | ||||
-rw-r--r-- | tests/parallel/tmissing_deepcopy.nim | 40 | ||||
-rw-r--r-- | tests/parallel/tsimple_array_checks.nim | 41 | ||||
-rw-r--r-- | tests/testament/tester.nim | 6 | ||||
-rw-r--r-- | todo.txt | 1 | ||||
-rw-r--r-- | web/question.txt | 5 |
18 files changed, 533 insertions, 333 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 8448c2a8f..ab315877a 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -807,45 +807,45 @@ type lockLevel*: TLockLevel # lock level as required for deadlock checking loc*: TLoc - TPair*{.final.} = object + TPair* = object key*, val*: RootRef TPairSeq* = seq[TPair] - TTable*{.final.} = object # the same as table[PObject] of PObject + TTable* = object # the same as table[PObject] of PObject counter*: int data*: TPairSeq - TIdPair*{.final.} = object + TIdPair* = object key*: PIdObj val*: RootRef TIdPairSeq* = seq[TIdPair] - TIdTable*{.final.} = object # the same as table[PIdent] of PObject + TIdTable* = object # the same as table[PIdent] of PObject counter*: int data*: TIdPairSeq - TIdNodePair*{.final.} = object + TIdNodePair* = object key*: PIdObj val*: PNode TIdNodePairSeq* = seq[TIdNodePair] - TIdNodeTable*{.final.} = object # the same as table[PIdObj] of PNode + TIdNodeTable* = object # the same as table[PIdObj] of PNode counter*: int data*: TIdNodePairSeq - TNodePair*{.final.} = object + TNodePair* = object h*: THash # because it is expensive to compute! key*: PNode val*: int TNodePairSeq* = seq[TNodePair] - TNodeTable*{.final.} = object # the same as table[PNode] of int; + TNodeTable* = object # the same as table[PNode] of int; # nodes are compared by structure! counter*: int data*: TNodePairSeq TObjectSeq* = seq[RootRef] - TObjectSet*{.final.} = object + TObjectSet* = object counter*: int data*: TObjectSeq @@ -1318,7 +1318,7 @@ proc isGCedMem*(t: PType): bool {.inline.} = t.kind == tyProc and t.callConv == ccClosure proc propagateToOwner*(owner, elem: PType) = - const HaveTheirOwnEmpty = {tySequence, tySet} + const HaveTheirOwnEmpty = {tySequence, tySet, tyPtr, tyRef, tyProc} owner.flags = owner.flags + (elem.flags * {tfHasMeta}) if tfNotNil in elem.flags: if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvocation}: diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 200ff91e0..86f300aa0 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -135,14 +135,14 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): PRope = elif ccgIntroducedPtr(param): initLocExpr(p, n, a) result = addrLoc(a) - elif p.module.compileToCpp and param.typ.kind == tyVar and + elif p.module.compileToCpp and param.typ.kind == tyVar and n.kind == nkHiddenAddr: initLocExprSingleUse(p, n.sons[0], a) # if the proc is 'importc'ed but not 'importcpp'ed then 'var T' still # means '*T'. See posix.nim for lots of examples that do that in the wild. let callee = call.sons[0] if callee.kind == nkSym and - {sfImportC, sfInfixCall, sfCompilerProc} * callee.sym.flags == {sfImportC} and + {sfImportC, sfInfixCall, sfCompilerProc} * callee.sym.flags == {sfImportC} and {lfHeader, lfNoDecl} * callee.sym.loc.flags != {}: result = addrLoc(a) else: @@ -192,7 +192,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = var op: TLoc initLocExpr(p, ri.sons[0], op) var pl: PRope - + var typ = skipTypes(ri.sons[0].typ, abstractInst) assert(typ.kind == tyProc) var length = sonsLen(ri) @@ -204,7 +204,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = else: app(pl, genArgNoParam(p, ri.sons[i])) if i < length - 1: app(pl, ~", ") - + template genCallPattern {.dirty.} = lineF(p, cpsStmts, callPattern & ";$n", op.r, pl, pl.addComma, rawProc) @@ -339,7 +339,8 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): PRope = let typ = skipTypes(ri.sons[0].typ, abstractInst) if pat[i+1] == '+': result.app genArgNoParam(p, ri.sons[0]) result.app(~"(") - result.app genOtherArg(p, ri, 1, typ) + if 1 < ri.len: + result.app genOtherArg(p, ri, 1, typ) for k in j+1 .. < ri.len: result.app(~", ") result.app genOtherArg(p, ri, k, typ) diff --git a/compiler/guards.nim b/compiler/guards.nim index 3255364c2..b0420cb75 100644 --- a/compiler/guards.nim +++ b/compiler/guards.nim @@ -15,11 +15,11 @@ import ast, astalgo, msgs, magicsys, nimsets, trees, types, renderer, idents, const someEq = {mEqI, mEqI64, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc, mEqUntracedRef, mEqStr, mEqSet, mEqCString} - + # set excluded here as the semantics are vastly different: someLe = {mLeI, mLeI64, mLeF64, mLeU, mLeU64, mLeEnum, mLeCh, mLeB, mLePtr, mLeStr} - someLt = {mLtI, mLtI64, mLtF64, mLtU, mLtU64, mLtEnum, + someLt = {mLtI, mLtI64, mLtF64, mLtU, mLtU64, mLtEnum, mLtCh, mLtB, mLtPtr, mLtStr} someLen = {mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq} @@ -44,7 +44,7 @@ proc isLet(n: PNode): bool = if n.kind == nkSym: if n.sym.kind in {skLet, skTemp, skForVar}: result = true - elif n.sym.kind == skParam and skipTypes(n.sym.typ, + elif n.sym.kind == skParam and skipTypes(n.sym.typ, abstractInst).kind != tyVar: result = true @@ -117,7 +117,7 @@ proc neg(n: PNode): PNode = result.sons[0] = n.sons[0] result.sons[2] = n.sons[2] if t.kind == tyEnum: - var s = newNodeIT(nkCurly, n.info, n.sons[1].typ) + var s = newNodeIT(nkCurly, n.info, n.sons[1].typ) for e in t.n: let eAsNode = newIntNode(nkIntLit, e.sym.position) if not inSet(n.sons[1], eAsNode): s.add eAsNode @@ -189,13 +189,17 @@ proc zero(): PNode = nkIntLit.newIntNode(0) proc one(): PNode = nkIntLit.newIntNode(1) proc minusOne(): PNode = nkIntLit.newIntNode(-1) -proc lowBound*(x: PNode): PNode = +proc lowBound*(x: PNode): PNode = result = nkIntLit.newIntNode(firstOrd(x.typ)) result.info = x.info proc highBound*(x: PNode): PNode = - result = if x.typ.skipTypes(abstractInst).kind == tyArray: - nkIntLit.newIntNode(lastOrd(x.typ)) + let typ = x.typ.skipTypes(abstractInst) + result = if typ.kind in {tyArrayConstr, tyArray}: + nkIntLit.newIntNode(lastOrd(typ)) + elif typ.kind == tySequence and x.kind == nkSym and + x.sym.kind == skConst: + nkIntLit.newIntNode(x.sym.ast.len-1) else: opAdd.buildCall(opLen.buildCall(x), minusOne()) result.info = x.info @@ -205,21 +209,32 @@ proc reassociation(n: PNode): PNode = # (foo+5)+5 --> foo+10; same for '*' case result.getMagic of someAdd: - if result[2].isValue and + if result[2].isValue and result[1].getMagic in someAdd and result[1][2].isValue: result = opAdd.buildCall(result[1][1], result[1][2] |+| result[2]) of someMul: - if result[2].isValue and + if result[2].isValue and result[1].getMagic in someMul and result[1][2].isValue: result = opAdd.buildCall(result[1][1], result[1][2] |*| result[2]) else: discard +proc pred(n: PNode): PNode = + if n.kind in {nkCharLit..nkUInt64Lit} and n.intVal != low(BiggestInt): + result = copyNode(n) + dec result.intVal + else: + result = n + proc canon*(n: PNode): PNode = # XXX for now only the new code in 'semparallel' uses this if n.safeLen >= 1: result = shallowCopy(n) for i in 0 .. < n.len: result.sons[i] = canon(n.sons[i]) + elif n.kind == nkSym and n.sym.kind == skLet and + n.sym.ast.getMagic in (someEq + someAdd + someMul + someMin + + someMax + someHigh + {mUnaryLt} + someSub + someLen): + result = n.sym.ast.copyTree else: result = n case result.getMagic @@ -231,34 +246,40 @@ proc canon*(n: PNode): PNode = of someHigh: # high == len+(-1) result = opAdd.buildCall(opLen.buildCall(result[1]), minusOne()) - of mUnaryMinusI, mUnaryMinusI64: + of mUnaryLt: result = buildCall(opAdd, result[1], newIntNode(nkIntLit, -1)) of someSub: # x - 4 --> x + (-4) result = negate(result[1], result[2], result) of someLen: result.sons[0] = opLen.newSymNode + of someLt: + # x < y same as x <= y-1: + let y = n[2].canon + let p = pred(y) + let minus = if p != y: p else: opAdd.buildCall(y, minusOne()).canon + result = opLe.buildCall(n[1].canon, minus) else: discard result = skipConv(result) result = reassociation(result) - # most important rule: (x-4) < a.len --> x < a.len+4 + # most important rule: (x-4) <= a.len --> x <= a.len+4 case result.getMagic - of someLe, someLt: + of someLe: let x = result[1] let y = result[2] - if x.kind in nkCallKinds and x.len == 3 and x[2].isValue and + if x.kind in nkCallKinds and x.len == 3 and x[2].isValue and isLetLocation(x[1], true): case x.getMagic of someSub: - result = buildCall(result[0].sym, x[1], + result = buildCall(result[0].sym, x[1], reassociation(opAdd.buildCall(y, x[2]))) of someAdd: # Rule A: let plus = negate(y, x[2], nil).reassociation if plus != nil: result = buildCall(result[0].sym, x[1], plus) else: discard - elif y.kind in nkCallKinds and y.len == 3 and y[2].isValue and + elif y.kind in nkCallKinds and y.len == 3 and y[2].isValue and isLetLocation(y[1], true): # a.len < x-3 case y.getMagic @@ -317,7 +338,7 @@ proc usefulFact(n: PNode): PNode = of mOr: # 'or' sucks! (p.isNil or q.isNil) --> hard to do anything # with that knowledge... - # DeMorgan helps a little though: + # DeMorgan helps a little though: # not a or not b --> not (a and b) # (x == 3) or (y == 2) ---> not ( not (x==3) and not (y == 2)) # not (x != 3 and y != 2) @@ -348,11 +369,11 @@ proc addFact*(m: var TModel, n: PNode) = let n = usefulFact(n) if n != nil: m.add n -proc addFactNeg*(m: var TModel, n: PNode) = +proc addFactNeg*(m: var TModel, n: PNode) = let n = n.neg if n != nil: addFact(m, n) -proc sameTree*(a, b: PNode): bool = +proc sameTree*(a, b: PNode): bool = result = false if a == b: result = true @@ -382,8 +403,8 @@ proc invalidateFacts*(m: var TModel, n: PNode) = # 'while p != nil: f(p); p = p.next' # This is actually quite easy to do: # Re-assignments (incl. pass to a 'var' param) trigger an invalidation - # of every fact that contains 'v'. - # + # of every fact that contains 'v'. + # # if x < 4: # if y < 5 # x = unknown() @@ -402,16 +423,9 @@ proc valuesUnequal(a, b: PNode): bool = if a.isValue and b.isValue: result = not sameValue(a, b) -proc pred(n: PNode): PNode = - if n.kind in {nkCharLit..nkUInt64Lit} and n.intVal != low(BiggestInt): - result = copyNode(n) - dec result.intVal - else: - result = n - proc impliesEq(fact, eq: PNode): TImplication = let (loc, val) = if isLocation(eq.sons[1]): (1, 2) else: (2, 1) - + case fact.sons[0].sym.magic of someEq: if sameTree(fact.sons[1], eq.sons[loc]): @@ -428,12 +442,12 @@ proc impliesEq(fact, eq: PNode): TImplication = else: result = impNo of mNot, mOr, mAnd: internalError(eq.info, "impliesEq") else: discard - + proc leImpliesIn(x, c, aSet: PNode): TImplication = if c.kind in {nkCharLit..nkUInt64Lit}: # fact: x <= 4; question x in {56}? # --> true if every value <= 4 is in the set {56} - # + # var value = newIntNode(c.kind, firstOrd(x.typ)) # don't iterate too often: if c.intVal - value.intVal < 1000: @@ -449,7 +463,7 @@ proc geImpliesIn(x, c, aSet: PNode): TImplication = if c.kind in {nkCharLit..nkUInt64Lit}: # fact: x >= 4; question x in {56}? # --> true iff every value >= 4 is in the set {56} - # + # var value = newIntNode(c.kind, c.intVal) let max = lastOrd(x.typ) # don't iterate too often: @@ -568,19 +582,19 @@ proc impliesLe(fact, x, c: PNode): TImplication = # fact: x < 4; question x <= 2? --> we don't know elif sameTree(fact.sons[2], x): # fact: 3 < x; question: x <= 1 ? --> false iff 1 <= 3 - if isValue(fact.sons[1]) and isValue(c): + if isValue(fact.sons[1]) and isValue(c): if leValue(c, fact.sons[1]): result = impNo - + of someLe: if sameTree(fact.sons[1], x): if isValue(fact.sons[2]) and isValue(c): # fact: x <= 4; question x <= 56? --> true iff 4 <= 56 if leValue(fact.sons[2], c): result = impYes # fact: x <= 4; question x <= 2? --> we don't know - + elif sameTree(fact.sons[2], x): # fact: 3 <= x; question: x <= 2 ? --> false iff 2 < 3 - if isValue(fact.sons[1]) and isValue(c): + if isValue(fact.sons[1]) and isValue(c): if leValue(c, fact.sons[1].pred): result = impNo of mNot, mOr, mAnd: internalError(x.info, "impliesLe") @@ -614,7 +628,7 @@ proc factImplies(fact, prop: PNode): TImplication = # it's provably wrong if every value > 4 is in the set {56} # That's because we compute the implication and 'a -> not b' cannot # be treated the same as 'not a -> b' - + # (not a) -> b compute as not (a -> b) ??? # == not a or not b == not (a and b) let arg = fact.sons[1] @@ -635,7 +649,7 @@ proc factImplies(fact, prop: PNode): TImplication = if result != impUnknown: return result return factImplies(fact.sons[2], prop) else: discard - + case prop.sons[0].sym.magic of mNot: result = ~fact.factImplies(prop.sons[1]) of mIsNil: result = impliesIsNil(fact, prop) @@ -671,6 +685,7 @@ proc pleViaModel(model: TModel; aa, bb: PNode): TImplication proc ple(m: TModel; a, b: PNode): TImplication = template `<=?`(a,b): expr = ple(m,a,b) == impYes + # 0 <= 3 if a.isValue and b.isValue: return if leValue(a, b): impYes else: impNo @@ -744,16 +759,21 @@ proc pleViaModelRec(m: var TModel; a, b: PNode): TImplication = # mark as used: m[i] = nil if ple(m, a, x) == impYes: - if ple(m, y, b) == impYes: return impYes + if ple(m, y, b) == impYes: + return impYes #if pleViaModelRec(m, y, b): return impYes # fact: 16 <= i # x y # question: i <= 15? no! result = impliesLe(fact, a, b) - if result != impUnknown: return result - if sameTree(y, a): - result = ple(m, b, x) - if result != impUnknown: return result + if result != impUnknown: + return result + when false: + # given: x <= y; y==a; x <= a this means: a <= b if x <= b + if sameTree(y, a): + result = ple(m, b, x) + if result != impUnknown: + return result proc pleViaModel(model: TModel; aa, bb: PNode): TImplication = # compute replacements: diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index 0f670ae7a..a51ca9ed6 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -23,7 +23,7 @@ proc newTupleAccess*(tup: PNode, i: int): PNode = lit.intVal = i addSon(result, lit) -proc addVar*(father, v: PNode) = +proc addVar*(father, v: PNode) = var vpart = newNodeI(nkIdentDefs, v.info, 3) vpart.sons[0] = v vpart.sons[1] = ast.emptyNode @@ -53,7 +53,7 @@ proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode = let tempAsNode = newSymNode(temp) v.addVar(tempAsNode) result.add(v) - + result.add newAsgnStmt(tempAsNode, value) for i in 0 .. n.len-3: if n.sons[i].kind == nkSym: v.addVar(n.sons[i]) @@ -70,7 +70,7 @@ proc rawAddField*(obj: PType; field: PSym) = field.position = sonsLen(obj.n) addSon(obj.n, newSymNode(field)) -proc rawIndirectAccess*(a: PNode; field: PSym; info: TLineInfo): PNode = +proc rawIndirectAccess*(a: PNode; field: PSym; info: TLineInfo): PNode = # returns a[].field as a node assert field.kind == skField var deref = newNodeI(nkHiddenDeref, info) @@ -109,7 +109,7 @@ proc newDotExpr(obj, b: PSym): PNode = addSon(result, newSymNode(field)) result.typ = field.typ -proc indirectAccess*(a: PNode, b: string, info: TLineInfo): PNode = +proc indirectAccess*(a: PNode, b: string, info: TLineInfo): PNode = # returns a[].b as a node var deref = newNodeI(nkHiddenDeref, info) deref.typ = a.typ.skipTypes(abstractInst).sons[0] @@ -144,7 +144,7 @@ proc getFieldFromObj*(t: PType; v: PSym): PSym = if t == nil: break t = t.skipTypes(abstractInst) -proc indirectAccess*(a: PNode, b: PSym, info: TLineInfo): PNode = +proc indirectAccess*(a: PNode, b: PSym, info: TLineInfo): PNode = # returns a[].b as a node result = indirectAccess(a, b.name.s & $b.id, info) @@ -158,11 +158,11 @@ proc genAddrOf*(n: PNode): PNode = result.typ.rawAddSon(n.typ) proc genDeref*(n: PNode): PNode = - result = newNodeIT(nkHiddenDeref, n.info, + result = newNodeIT(nkHiddenDeref, n.info, n.typ.skipTypes(abstractInst).sons[0]) result.add n -proc callCodegenProc*(name: string, arg1: PNode; +proc callCodegenProc*(name: string, arg1: PNode; arg2, arg3: PNode = nil): PNode = result = newNodeI(nkCall, arg1.info) let sym = magicsys.getCompilerProc(name) @@ -203,6 +203,17 @@ proc flowVarKind(t: PType): TFlowVarKind = elif containsGarbageCollectedRef(t): fvInvalid else: fvBlob +proc typeNeedsNoDeepCopy(t: PType): bool = + var t = t.skipTypes(abstractInst) + # for the tconvexhull example (and others) we're a bit lax here and pretend + # seqs and strings are *by value* only and 'shallow' doesn't exist! + if t.kind == tyString: return true + # note that seq[T] is fine, but 'var seq[T]' is not, so we need to skip 'var' + # for the stricter check and likewise we can skip 'seq' for a less + # strict check: + if t.kind in {tyVar, tySequence}: t = t.sons[0] + result = not containsGarbageCollectedRef(t) + proc addLocalVar(varSection, varInit: PNode; owner: PSym; typ: PType; v: PNode; useShallowCopy=false): PSym = result = newSym(skTemp, getIdent(genPrefix), owner, varSection.info) @@ -215,7 +226,7 @@ proc addLocalVar(varSection, varInit: PNode; owner: PSym; typ: PType; vpart.sons[2] = if varInit.isNil: v else: ast.emptyNode varSection.add vpart if varInit != nil: - if useShallowCopy: + if useShallowCopy and typeNeedsNoDeepCopy(typ): varInit.add newFastAsgnStmt(newSymNode(result), v) else: let deepCopyCall = newNodeI(nkCall, varInit.info, 3) @@ -236,10 +247,10 @@ proc f_wrapper(thread, args) = fv.owner = thread # optional nimArgsPassingDone() # signal parent that the work is done - # + # args.fv.blob = f(a, b, ...) nimFlowVarSignal(args.fv) - + # - or - f(a, b, ...) barrierLeave(args.barrier) # for parallel statement @@ -261,7 +272,7 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym; var threadLocalBarrier: PSym if barrier != nil: var varSection2 = newNodeI(nkVarSection, barrier.info) - threadLocalBarrier = addLocalVar(varSection2, nil, argsParam.owner, + threadLocalBarrier = addLocalVar(varSection2, nil, argsParam.owner, barrier.typ, barrier) body.add varSection2 body.add callCodegenProc("barrierEnter", threadLocalBarrier.newSymNode) @@ -285,7 +296,7 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym; elif fv != nil: let fk = fv.typ.sons[1].flowVarKind if fk == fvInvalid: - localError(f.info, "cannot create a flowVar of type: " & + localError(f.info, "cannot create a flowVar of type: " & typeToString(fv.typ.sons[1])) body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode, if fk == fvGC: "data" else: "blob", fv.info), call) @@ -330,8 +341,8 @@ proc createCastExpr(argsParam: PSym; objType: PType): PNode = result.typ = newType(tyPtr, objType.owner) result.typ.rawAddSon(objType) -proc setupArgsForConcurrency(n: PNode; objType: PType; scratchObj: PSym, - castExpr, call, +proc setupArgsForConcurrency(n: PNode; objType: PType; scratchObj: PSym, + castExpr, call, varSection, varInit, result: PNode) = let formals = n[0].typ.n let tmpName = getIdent(genPrefix) @@ -385,7 +396,7 @@ proc genHigh(n: PNode): PNode = result.sons[1] = n proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym; - castExpr, call, + castExpr, call, varSection, varInit, result: PNode) = let formals = n[0].typ.n let tmpName = getIdent(genPrefix) @@ -409,7 +420,7 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym; var fieldB = newSym(skField, tmpName, objType.owner, n.info) fieldB.typ = getSysType(tyInt) objType.addField(fieldB) - + if getMagic(n) == mSlice: let a = genAddrOf(n[1]) field.typ = a.typ @@ -464,7 +475,7 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym; useShallowCopy=true) call.add(threadLocal.newSymNode) -proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType; +proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType; barrier, dest: PNode = nil): PNode = # if 'barrier' != nil, then it is in a 'parallel' section and we # generate quite different code @@ -530,10 +541,10 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType; var varSection = newNodeI(nkVarSection, n.info) var varInit = newNodeI(nkStmtList, n.info) if barrier.isNil: - setupArgsForConcurrency(n, objType, scratchObj, castExpr, call, + setupArgsForConcurrency(n, objType, scratchObj, castExpr, call, varSection, varInit, result) else: - setupArgsForParallelism(n, objType, scratchObj, castExpr, call, + setupArgsForParallelism(n, objType, scratchObj, castExpr, call, varSection, varInit, result) var barrierAsExpr: PNode = nil @@ -566,7 +577,7 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType; fvAsExpr = indirectAccess(castExpr, field, n.info) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), genAddrOf(dest)) - let wrapper = createWrapperProc(fn, threadParam, argsParam, + let wrapper = createWrapperProc(fn, threadParam, argsParam, varSection, varInit, call, barrierAsExpr, fvAsExpr, spawnKind) result.add callCodegenProc("nimSpawn", wrapper.newSymNode, diff --git a/compiler/renderer.nim b/compiler/renderer.nim index ccf3837ed..689bf23c8 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -9,20 +9,20 @@ # This module implements the renderer of the standard Nim representation. -import +import lexer, options, idents, strutils, ast, msgs, lists -type - TRenderFlag* = enum - renderNone, renderNoBody, renderNoComments, renderDocComments, +type + TRenderFlag* = enum + renderNone, renderNoBody, renderNoComments, renderDocComments, renderNoPragmas, renderIds, renderNoProcDefs TRenderFlags* = set[TRenderFlag] - TRenderTok*{.final.} = object + TRenderTok*{.final.} = object kind*: TTokType length*: int16 TRenderTokSeq* = seq[TRenderTok] - TSrcGen*{.final.} = object + TSrcGen*{.final.} = object indent*: int lineLen*: int pos*: int # current position for iteration over the buffer @@ -41,6 +41,8 @@ proc renderModule*(n: PNode, filename: string, renderFlags: TRenderFlags = {}) proc renderTree*(n: PNode, renderFlags: TRenderFlags = {}): string proc initTokRender*(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {}) proc getNextTok*(r: var TSrcGen, kind: var TTokType, literal: var string) + +proc `$`*(n: PNode): string = n.renderTree # implementation # We render the source code in a two phases: The first # determines how long the subtree will likely be, the second @@ -65,13 +67,13 @@ proc renderDefinitionName*(s: PSym, noQuotes = false): string = else: result = '`' & x & '`' -const +const IndentWidth = 2 longIndentWid = 4 MaxLineLen = 80 LineCommentColumn = 30 -proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) = +proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) = g.comStack = @[] g.tokens = @[] g.indent = 0 @@ -83,67 +85,67 @@ proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) = g.pendingNL = -1 g.checkAnon = false -proc addTok(g: var TSrcGen, kind: TTokType, s: string) = +proc addTok(g: var TSrcGen, kind: TTokType, s: string) = var length = len(g.tokens) setLen(g.tokens, length + 1) g.tokens[length].kind = kind g.tokens[length].length = int16(len(s)) add(g.buf, s) -proc addPendingNL(g: var TSrcGen) = - if g.pendingNL >= 0: +proc addPendingNL(g: var TSrcGen) = + if g.pendingNL >= 0: addTok(g, tkSpaces, "\n" & spaces(g.pendingNL)) g.lineLen = g.pendingNL g.pendingNL = - 1 -proc putNL(g: var TSrcGen, indent: int) = +proc putNL(g: var TSrcGen, indent: int) = if g.pendingNL >= 0: addPendingNL(g) else: addTok(g, tkSpaces, "\n") g.pendingNL = indent g.lineLen = indent -proc putNL(g: var TSrcGen) = +proc putNL(g: var TSrcGen) = putNL(g, g.indent) -proc optNL(g: var TSrcGen, indent: int) = +proc optNL(g: var TSrcGen, indent: int) = g.pendingNL = indent g.lineLen = indent # BUGFIX - -proc optNL(g: var TSrcGen) = + +proc optNL(g: var TSrcGen) = optNL(g, g.indent) -proc indentNL(g: var TSrcGen) = +proc indentNL(g: var TSrcGen) = inc(g.indent, IndentWidth) g.pendingNL = g.indent g.lineLen = g.indent -proc dedent(g: var TSrcGen) = +proc dedent(g: var TSrcGen) = dec(g.indent, IndentWidth) assert(g.indent >= 0) - if g.pendingNL > IndentWidth: + if g.pendingNL > IndentWidth: dec(g.pendingNL, IndentWidth) dec(g.lineLen, IndentWidth) -proc put(g: var TSrcGen, kind: TTokType, s: string) = +proc put(g: var TSrcGen, kind: TTokType, s: string) = addPendingNL(g) - if len(s) > 0: + if len(s) > 0: addTok(g, kind, s) inc(g.lineLen, len(s)) -proc putLong(g: var TSrcGen, kind: TTokType, s: string, lineLen: int) = +proc putLong(g: var TSrcGen, kind: TTokType, s: string, lineLen: int) = # use this for tokens over multiple lines. addPendingNL(g) addTok(g, kind, s) g.lineLen = lineLen -proc toNimChar(c: char): string = +proc toNimChar(c: char): string = case c of '\0': result = "\\0" of '\x01'..'\x1F', '\x80'..'\xFF': result = "\\x" & strutils.toHex(ord(c), 2) of '\'', '\"', '\\': result = '\\' & c else: result = c & "" - -proc makeNimString(s: string): string = + +proc makeNimString(s: string): string = result = "\"" for i in countup(0, len(s)-1): add(result, toNimChar(s[i])) add(result, '\"') @@ -174,7 +176,7 @@ proc putComment(g: var TSrcGen, s: string) = add(com, s[i]) inc(i) comIndent = 0 - while s[i] == ' ': + while s[i] == ' ': add(com, s[i]) inc(i) inc(comIndent) @@ -187,109 +189,109 @@ proc putComment(g: var TSrcGen, s: string) = # compute length of the following word: var j = i while s[j] > ' ': inc(j) - if not isCode and (g.lineLen + (j - i) > MaxLineLen): + if not isCode and (g.lineLen + (j - i) > MaxLineLen): put(g, tkComment, com) optNL(g, ind) com = '#' & spaces(comIndent) - while s[i] > ' ': + while s[i] > ' ': add(com, s[i]) inc(i) put(g, tkComment, com) optNL(g) -proc maxLineLength(s: string): int = +proc maxLineLength(s: string): int = if s.isNil: return 0 var i = 0 var lineLen = 0 while true: case s[i] - of '\0': - break - of '\x0D': + of '\0': + break + of '\x0D': inc(i) if s[i] == '\x0A': inc(i) result = max(result, lineLen) lineLen = 0 - of '\x0A': + of '\x0A': inc(i) result = max(result, lineLen) lineLen = 0 - else: + else: inc(lineLen) inc(i) -proc putRawStr(g: var TSrcGen, kind: TTokType, s: string) = +proc putRawStr(g: var TSrcGen, kind: TTokType, s: string) = var i = 0 var hi = len(s) - 1 var str = "" - while i <= hi: + while i <= hi: case s[i] - of '\x0D': + of '\x0D': put(g, kind, str) str = "" inc(i) if (i <= hi) and (s[i] == '\x0A'): inc(i) optNL(g, 0) - of '\x0A': + of '\x0A': put(g, kind, str) str = "" inc(i) optNL(g, 0) - else: + else: add(str, s[i]) inc(i) put(g, kind, str) -proc containsNL(s: string): bool = - for i in countup(0, len(s) - 1): +proc containsNL(s: string): bool = + for i in countup(0, len(s) - 1): case s[i] - of '\x0D', '\x0A': + of '\x0D', '\x0A': return true - else: + else: discard result = false -proc pushCom(g: var TSrcGen, n: PNode) = +proc pushCom(g: var TSrcGen, n: PNode) = var length = len(g.comStack) setLen(g.comStack, length + 1) g.comStack[length] = n -proc popAllComs(g: var TSrcGen) = +proc popAllComs(g: var TSrcGen) = setLen(g.comStack, 0) -proc popCom(g: var TSrcGen) = +proc popCom(g: var TSrcGen) = setLen(g.comStack, len(g.comStack) - 1) -const +const Space = " " -proc shouldRenderComment(g: var TSrcGen, n: PNode): bool = +proc shouldRenderComment(g: var TSrcGen, n: PNode): bool = result = false - if n.comment != nil: + if n.comment != nil: result = (renderNoComments notin g.flags) or (renderDocComments in g.flags) and startsWith(n.comment, "##") - -proc gcom(g: var TSrcGen, n: PNode) = + +proc gcom(g: var TSrcGen, n: PNode) = assert(n != nil) - if shouldRenderComment(g, n): + if shouldRenderComment(g, n): if (g.pendingNL < 0) and (len(g.buf) > 0) and (g.buf[len(g.buf)-1] != ' '): - put(g, tkSpaces, Space) + put(g, tkSpaces, Space) # Before long comments we cannot make sure that a newline is generated, # because this might be wrong. But it is no problem in practice. if (g.pendingNL < 0) and (len(g.buf) > 0) and - (g.lineLen < LineCommentColumn): + (g.lineLen < LineCommentColumn): var ml = maxLineLength(n.comment) - if ml + LineCommentColumn <= MaxLineLen: + if ml + LineCommentColumn <= MaxLineLen: put(g, tkSpaces, spaces(LineCommentColumn - g.lineLen)) putComment(g, n.comment) #assert(g.comStack[high(g.comStack)] = n); - -proc gcoms(g: var TSrcGen) = + +proc gcoms(g: var TSrcGen) = for i in countup(0, high(g.comStack)): gcom(g, g.comStack[i]) popAllComs(g) proc lsub(n: PNode): int proc litAux(n: PNode, x: BiggestInt, size: int): string = - proc skip(t: PType): PType = + proc skip(t: PType): PType = result = t while result.kind in {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal, tyConst, tyMutable}: @@ -299,20 +301,20 @@ proc litAux(n: PNode, x: BiggestInt, size: int): string = # we need a slow linear search because of enums with holes: for e in items(enumfields): if e.sym.position == x: return e.sym.name.s - + if nfBase2 in n.flags: result = "0b" & toBin(x, size * 8) elif nfBase8 in n.flags: result = "0o" & toOct(x, size * 3) elif nfBase16 in n.flags: result = "0x" & toHex(x, size * 2) else: result = $x -proc ulitAux(n: PNode, x: BiggestInt, size: int): string = +proc ulitAux(n: PNode, x: BiggestInt, size: int): string = if nfBase2 in n.flags: result = "0b" & toBin(x, size * 8) elif nfBase8 in n.flags: result = "0o" & toOct(x, size * 3) elif nfBase16 in n.flags: result = "0x" & toHex(x, size * 2) else: result = $x # XXX proper unsigned output! - -proc atom(n: PNode): string = + +proc atom(n: PNode): string = var f: float32 case n.kind of nkEmpty: result = "" @@ -335,49 +337,49 @@ proc atom(n: PNode): string = of nkFloatLit: if n.flags * {nfBase2, nfBase8, nfBase16} == {}: result = $(n.floatVal) else: result = litAux(n, (cast[PInt64](addr(n.floatVal)))[] , 8) - of nkFloat32Lit: - if n.flags * {nfBase2, nfBase8, nfBase16} == {}: + of nkFloat32Lit: + if n.flags * {nfBase2, nfBase8, nfBase16} == {}: result = $n.floatVal & "\'f32" - else: + else: f = n.floatVal.float32 result = litAux(n, (cast[PInt32](addr(f)))[], 4) & "\'f32" - of nkFloat64Lit: - if n.flags * {nfBase2, nfBase8, nfBase16} == {}: + of nkFloat64Lit: + if n.flags * {nfBase2, nfBase8, nfBase16} == {}: result = $n.floatVal & "\'f64" - else: + else: result = litAux(n, (cast[PInt64](addr(n.floatVal)))[], 8) & "\'f64" of nkNilLit: result = "nil" - of nkType: + of nkType: if (n.typ != nil) and (n.typ.sym != nil): result = n.typ.sym.name.s else: result = "[type node]" - else: + else: internalError("rnimsyn.atom " & $n.kind) result = "" - -proc lcomma(n: PNode, start: int = 0, theEnd: int = - 1): int = + +proc lcomma(n: PNode, start: int = 0, theEnd: int = - 1): int = assert(theEnd < 0) result = 0 - for i in countup(start, sonsLen(n) + theEnd): + for i in countup(start, sonsLen(n) + theEnd): inc(result, lsub(n.sons[i])) inc(result, 2) # for ``, `` - if result > 0: + if result > 0: dec(result, 2) # last does not get a comma! - -proc lsons(n: PNode, start: int = 0, theEnd: int = - 1): int = + +proc lsons(n: PNode, start: int = 0, theEnd: int = - 1): int = assert(theEnd < 0) result = 0 for i in countup(start, sonsLen(n) + theEnd): inc(result, lsub(n.sons[i])) - -proc lsub(n: PNode): int = + +proc lsub(n: PNode): int = # computes the length of a tree if isNil(n): return 0 if n.comment != nil: return MaxLineLen + 1 case n.kind of nkEmpty: result = 0 - of nkTripleStrLit: + of nkTripleStrLit: if containsNL(n.strVal): result = MaxLineLen + 1 else: result = len(atom(n)) - of succ(nkEmpty)..pred(nkTripleStrLit), succ(nkTripleStrLit)..nkNilLit: + of succ(nkEmpty)..pred(nkTripleStrLit), succ(nkTripleStrLit)..nkNilLit: result = len(atom(n)) of nkCall, nkBracketExpr, nkCurlyExpr, nkConv, nkPattern, nkObjConstr: result = lsub(n.sons[0]) + lcomma(n, 1) + 2 @@ -392,7 +394,7 @@ proc lsub(n: PNode): int = of nkArgList: result = lcomma(n) of nkTableConstr: result = if n.len > 0: lcomma(n) + 2 else: len("{:}") - of nkClosedSymChoice, nkOpenSymChoice: + of nkClosedSymChoice, nkOpenSymChoice: result = lsons(n) + len("()") + sonsLen(n) - 1 of nkTupleTy: result = lcomma(n) + len("tuple[]") of nkTupleClassTy: result = len("tuple") @@ -403,7 +405,7 @@ proc lsub(n: PNode): int = of nkCheckedFieldExpr: result = lsub(n.sons[0]) of nkLambda: result = lsons(n) + len("proc__=_") of nkDo: result = lsons(n) + len("do__:_") - of nkConstDef, nkIdentDefs: + of nkConstDef, nkIdentDefs: result = lcomma(n, 0, - 3) var L = sonsLen(n) if n.sons[L - 2].kind != nkEmpty: result = result + lsub(n.sons[L - 2]) + 2 @@ -412,7 +414,7 @@ proc lsub(n: PNode): int = of nkChckRangeF: result = len("chckRangeF") + 2 + lcomma(n) of nkChckRange64: result = len("chckRange64") + 2 + lcomma(n) of nkChckRange: result = len("chckRange") + 2 + lcomma(n) - of nkObjDownConv, nkObjUpConv, nkStringToCString, nkCStringToString: + of nkObjDownConv, nkObjUpConv, nkStringToCString, nkCStringToString: result = 2 if sonsLen(n) >= 1: result = result + lsub(n.sons[0]) result = result + lcomma(n, 1) @@ -426,7 +428,7 @@ proc lsub(n: PNode): int = of nkRange: result = lsons(n) + 2 of nkDerefExpr: result = lsub(n.sons[0]) + 2 of nkAccQuoted: result = lsons(n) + 2 - of nkIfExpr: + of nkIfExpr: result = lsub(n.sons[0].sons[0]) + lsub(n.sons[0].sons[1]) + lsons(n, 1) + len("if_:_") of nkElifExpr: result = lsons(n) + len("_elif_:_") @@ -447,13 +449,13 @@ proc lsub(n: PNode): int = of nkProcTy: result = lsons(n) + len("proc_") of nkIteratorTy: result = lsons(n) + len("iterator_") of nkSharedTy: result = lsons(n) + len("shared_") - of nkEnumTy: + of nkEnumTy: if sonsLen(n) > 0: result = lsub(n.sons[0]) + lcomma(n, 1) + len("enum_") else: result = len("enum") of nkEnumFieldDef: result = lsons(n) + 3 - of nkVarSection, nkLetSection: + of nkVarSection, nkLetSection: if sonsLen(n) > 1: result = MaxLineLen + 1 else: result = lsons(n) + len("var_") of nkReturnStmt: result = lsub(n.sons[0]) + len("return_") @@ -470,50 +472,50 @@ proc lsub(n: PNode): int = of nkElse: result = lsub(n.sons[0]) + len("else:_") of nkFinally: result = lsub(n.sons[0]) + len("finally:_") of nkGenericParams: result = lcomma(n) + 2 - of nkFormalParams: + of nkFormalParams: result = lcomma(n, 1) + 2 if n.sons[0].kind != nkEmpty: result = result + lsub(n.sons[0]) + 2 - of nkExceptBranch: + of nkExceptBranch: result = lcomma(n, 0, -2) + lsub(lastSon(n)) + len("except_:_") else: result = MaxLineLen + 1 - -proc fits(g: TSrcGen, x: int): bool = + +proc fits(g: TSrcGen, x: int): bool = result = x + g.lineLen <= MaxLineLen -type - TSubFlag = enum +type + TSubFlag = enum rfLongMode, rfNoIndent, rfInConstExpr TSubFlags = set[TSubFlag] TContext = tuple[spacing: int, flags: TSubFlags] -const +const emptyContext: TContext = (spacing: 0, flags: {}) -proc initContext(c: var TContext) = +proc initContext(c: var TContext) = c.spacing = 0 c.flags = {} proc gsub(g: var TSrcGen, n: PNode, c: TContext) -proc gsub(g: var TSrcGen, n: PNode) = +proc gsub(g: var TSrcGen, n: PNode) = var c: TContext initContext(c) gsub(g, n, c) -proc hasCom(n: PNode): bool = +proc hasCom(n: PNode): bool = result = false if n.comment != nil: return true case n.kind of nkEmpty..nkNilLit: discard - else: - for i in countup(0, sonsLen(n) - 1): + else: + for i in countup(0, sonsLen(n) - 1): if hasCom(n.sons[i]): return true - -proc putWithSpace(g: var TSrcGen, kind: TTokType, s: string) = + +proc putWithSpace(g: var TSrcGen, kind: TTokType, s: string) = put(g, kind, s) put(g, tkSpaces, Space) -proc gcommaAux(g: var TSrcGen, n: PNode, ind: int, start: int = 0, - theEnd: int = - 1, separator = tkComma) = +proc gcommaAux(g: var TSrcGen, n: PNode, ind: int, start: int = 0, + theEnd: int = - 1, separator = tkComma) = for i in countup(start, sonsLen(n) + theEnd): var c = i < sonsLen(n) + theEnd var sublen = lsub(n.sons[i]) + ord(c) @@ -523,54 +525,54 @@ proc gcommaAux(g: var TSrcGen, n: PNode, ind: int, start: int = 0, if c: if g.tokens.len > oldLen: putWithSpace(g, separator, TokTypeToStr[separator]) - if hasCom(n.sons[i]): + if hasCom(n.sons[i]): gcoms(g) optNL(g, ind) -proc gcomma(g: var TSrcGen, n: PNode, c: TContext, start: int = 0, - theEnd: int = - 1) = +proc gcomma(g: var TSrcGen, n: PNode, c: TContext, start: int = 0, + theEnd: int = - 1) = var ind: int - if rfInConstExpr in c.flags: + if rfInConstExpr in c.flags: ind = g.indent + IndentWidth - else: + else: ind = g.lineLen if ind > MaxLineLen div 2: ind = g.indent + longIndentWid gcommaAux(g, n, ind, start, theEnd) -proc gcomma(g: var TSrcGen, n: PNode, start: int = 0, theEnd: int = - 1) = +proc gcomma(g: var TSrcGen, n: PNode, start: int = 0, theEnd: int = - 1) = var ind = g.lineLen if ind > MaxLineLen div 2: ind = g.indent + longIndentWid gcommaAux(g, n, ind, start, theEnd) -proc gsemicolon(g: var TSrcGen, n: PNode, start: int = 0, theEnd: int = - 1) = +proc gsemicolon(g: var TSrcGen, n: PNode, start: int = 0, theEnd: int = - 1) = var ind = g.lineLen if ind > MaxLineLen div 2: ind = g.indent + longIndentWid gcommaAux(g, n, ind, start, theEnd, tkSemiColon) -proc gsons(g: var TSrcGen, n: PNode, c: TContext, start: int = 0, - theEnd: int = - 1) = +proc gsons(g: var TSrcGen, n: PNode, c: TContext, start: int = 0, + theEnd: int = - 1) = for i in countup(start, sonsLen(n) + theEnd): gsub(g, n.sons[i], c) -proc gsection(g: var TSrcGen, n: PNode, c: TContext, kind: TTokType, - k: string) = +proc gsection(g: var TSrcGen, n: PNode, c: TContext, kind: TTokType, + k: string) = if sonsLen(n) == 0: return # empty var sections are possible putWithSpace(g, kind, k) gcoms(g) indentNL(g) - for i in countup(0, sonsLen(n) - 1): + for i in countup(0, sonsLen(n) - 1): optNL(g) gsub(g, n.sons[i], c) gcoms(g) dedent(g) -proc longMode(n: PNode, start: int = 0, theEnd: int = - 1): bool = +proc longMode(n: PNode, start: int = 0, theEnd: int = - 1): bool = result = n.comment != nil - if not result: + if not result: # check further - for i in countup(start, sonsLen(n) + theEnd): - if (lsub(n.sons[i]) > MaxLineLen): + for i in countup(start, sonsLen(n) + theEnd): + if (lsub(n.sons[i]) > MaxLineLen): result = true - break + break proc gstmts(g: var TSrcGen, n: PNode, c: TContext, doIndent=true) = if n.kind == nkEmpty: return @@ -590,33 +592,33 @@ proc gstmts(g: var TSrcGen, n: PNode, c: TContext, doIndent=true) = gcoms(g) optNL(g) if rfLongMode in c.flags: dedent(g) - -proc gif(g: var TSrcGen, n: PNode) = + +proc gif(g: var TSrcGen, n: PNode) = var c: TContext gsub(g, n.sons[0].sons[0]) initContext(c) putWithSpace(g, tkColon, ":") - if longMode(n) or (lsub(n.sons[0].sons[1]) + g.lineLen > MaxLineLen): + if longMode(n) or (lsub(n.sons[0].sons[1]) + g.lineLen > MaxLineLen): incl(c.flags, rfLongMode) gcoms(g) # a good place for comments gstmts(g, n.sons[0].sons[1], c) var length = sonsLen(n) - for i in countup(1, length - 1): + for i in countup(1, length - 1): optNL(g) gsub(g, n.sons[i], c) -proc gwhile(g: var TSrcGen, n: PNode) = +proc gwhile(g: var TSrcGen, n: PNode) = var c: TContext putWithSpace(g, tkWhile, "while") gsub(g, n.sons[0]) putWithSpace(g, tkColon, ":") initContext(c) - if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen): + if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen): incl(c.flags, rfLongMode) gcoms(g) # a good place for comments gstmts(g, n.sons[1], c) -proc gpattern(g: var TSrcGen, n: PNode) = +proc gpattern(g: var TSrcGen, n: PNode) = var c: TContext put(g, tkCurlyLe, "{") initContext(c) @@ -626,7 +628,7 @@ proc gpattern(g: var TSrcGen, n: PNode) = gstmts(g, n, c) put(g, tkCurlyRi, "}") -proc gpragmaBlock(g: var TSrcGen, n: PNode) = +proc gpragmaBlock(g: var TSrcGen, n: PNode) = var c: TContext gsub(g, n.sons[0]) putWithSpace(g, tkColon, ":") @@ -636,25 +638,25 @@ proc gpragmaBlock(g: var TSrcGen, n: PNode) = gcoms(g) # a good place for comments gstmts(g, n.sons[1], c) -proc gtry(g: var TSrcGen, n: PNode) = +proc gtry(g: var TSrcGen, n: PNode) = var c: TContext put(g, tkTry, "try") putWithSpace(g, tkColon, ":") initContext(c) - if longMode(n) or (lsub(n.sons[0]) + g.lineLen > MaxLineLen): + if longMode(n) or (lsub(n.sons[0]) + g.lineLen > MaxLineLen): incl(c.flags, rfLongMode) gcoms(g) # a good place for comments gstmts(g, n.sons[0], c) gsons(g, n, c, 1) -proc gfor(g: var TSrcGen, n: PNode) = +proc gfor(g: var TSrcGen, n: PNode) = var c: TContext var length = sonsLen(n) putWithSpace(g, tkFor, "for") initContext(c) if longMode(n) or (lsub(n.sons[length - 1]) + lsub(n.sons[length - 2]) + 6 + g.lineLen > - MaxLineLen): + MaxLineLen): incl(c.flags, rfLongMode) gcomma(g, n, c, 0, - 3) put(g, tkSpaces, Space) @@ -664,17 +666,17 @@ proc gfor(g: var TSrcGen, n: PNode) = gcoms(g) gstmts(g, n.sons[length - 1], c) -proc gmacro(g: var TSrcGen, n: PNode) = +proc gmacro(g: var TSrcGen, n: PNode) = var c: TContext initContext(c) gsub(g, n.sons[0]) putWithSpace(g, tkColon, ":") - if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen): + if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen): incl(c.flags, rfLongMode) gcoms(g) gsons(g, n, c, 1) -proc gcase(g: var TSrcGen, n: PNode) = +proc gcase(g: var TSrcGen, n: PNode) = var c: TContext initContext(c) var length = sonsLen(n) @@ -685,18 +687,18 @@ proc gcase(g: var TSrcGen, n: PNode) = gcoms(g) optNL(g) gsons(g, n, c, 1, last) - if last == - 2: + if last == - 2: initContext(c) if longMode(n.sons[length - 1]): incl(c.flags, rfLongMode) gsub(g, n.sons[length - 1], c) -proc gproc(g: var TSrcGen, n: PNode) = +proc gproc(g: var TSrcGen, n: PNode) = var c: TContext if n.sons[namePos].kind == nkSym: put(g, tkSymbol, renderDefinitionName(n.sons[namePos].sym)) else: gsub(g, n.sons[namePos]) - + if n.sons[patternPos].kind != nkEmpty: gpattern(g, n.sons[patternPos]) let oldCheckAnon = g.checkAnon @@ -733,7 +735,7 @@ proc gTypeClassTy(g: var TSrcGen, n: PNode) = gstmts(g, n[3], c) dedent(g) -proc gblock(g: var TSrcGen, n: PNode) = +proc gblock(g: var TSrcGen, n: PNode) = var c: TContext initContext(c) if n.sons[0].kind != nkEmpty: @@ -742,7 +744,7 @@ proc gblock(g: var TSrcGen, n: PNode) = else: put(g, tkBlock, "block") putWithSpace(g, tkColon, ":") - if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen): + if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen): incl(c.flags, rfLongMode) gcoms(g) # XXX I don't get why this is needed here! gstmts should already handle this! @@ -750,17 +752,17 @@ proc gblock(g: var TSrcGen, n: PNode) = gstmts(g, n.sons[1], c) dedent(g) -proc gstaticStmt(g: var TSrcGen, n: PNode) = +proc gstaticStmt(g: var TSrcGen, n: PNode) = var c: TContext putWithSpace(g, tkStatic, "static") putWithSpace(g, tkColon, ":") initContext(c) - if longMode(n) or (lsub(n.sons[0]) + g.lineLen > MaxLineLen): + if longMode(n) or (lsub(n.sons[0]) + g.lineLen > MaxLineLen): incl(c.flags, rfLongMode) gcoms(g) # a good place for comments gstmts(g, n.sons[0], c) -proc gasm(g: var TSrcGen, n: PNode) = +proc gasm(g: var TSrcGen, n: PNode) = putWithSpace(g, tkAsm, "asm") gsub(g, n.sons[0]) gcoms(g) @@ -770,16 +772,16 @@ proc gident(g: var TSrcGen, n: PNode) = if g.checkAnon and n.kind == nkSym and sfAnon in n.sym.flags: return var t: TTokType var s = atom(n) - if (s[0] in lexer.SymChars): - if (n.kind == nkIdent): + if (s[0] in lexer.SymChars): + if (n.kind == nkIdent): if (n.ident.id < ord(tokKeywordLow) - ord(tkSymbol)) or - (n.ident.id > ord(tokKeywordHigh) - ord(tkSymbol)): + (n.ident.id > ord(tokKeywordHigh) - ord(tkSymbol)): t = tkSymbol - else: + else: t = TTokType(n.ident.id + ord(tkSymbol)) - else: + else: t = tkSymbol - else: + else: t = tkOpr put(g, t, s) if n.kind == nkSym and renderIds in g.flags: put(g, tkIntLit, $n.sym.id) @@ -789,12 +791,12 @@ proc doParamsAux(g: var TSrcGen, params: PNode) = put(g, tkParLe, "(") gsemicolon(g, params, 1) put(g, tkParRi, ")") - - if params.sons[0].kind != nkEmpty: + + if params.sons[0].kind != nkEmpty: putWithSpace(g, tkOpr, "->") gsub(g, params.sons[0]) -proc gsub(g: var TSrcGen, n: PNode, c: TContext) = +proc gsub(g: var TSrcGen, n: PNode, c: TContext) = if isNil(n): return var a: TContext @@ -827,14 +829,14 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = put(g, tkParLe, "(") gcomma(g, n, 1) put(g, tkParRi, ")") - of nkCallStrLit: + of nkCallStrLit: gsub(g, n.sons[0]) - if n.sons[1].kind == nkRStrLit: + if n.sons[1].kind == nkRStrLit: put(g, tkRStrLit, '\"' & replace(n[1].strVal, "\"", "\"\"") & '\"') - else: + else: gsub(g, n.sons[1]) of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: gsub(g, n.sons[1]) - of nkCast: + of nkCast: put(g, tkCast, "cast") put(g, tkBracketLe, "[") gsub(g, n.sons[0]) @@ -842,7 +844,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = put(g, tkParLe, "(") gsub(g, n.sons[1]) put(g, tkParRi, ")") - of nkAddr: + of nkAddr: put(g, tkAddr, "addr") put(g, tkParLe, "(") gsub(g, n.sons[0]) @@ -851,7 +853,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = put(g, tkStatic, "static") put(g, tkSpaces, Space) gsub(g, n.sons[0]) - of nkBracketExpr: + of nkBracketExpr: gsub(g, n.sons[0]) put(g, tkBracketLe, "[") gcomma(g, n, 1) @@ -861,41 +863,41 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = put(g, tkCurlyLe, "{") gcomma(g, n, 1) put(g, tkCurlyRi, "}") - of nkPragmaExpr: + of nkPragmaExpr: gsub(g, n.sons[0]) gcomma(g, n, 1) - of nkCommand: + of nkCommand: gsub(g, n.sons[0]) put(g, tkSpaces, Space) gcomma(g, n, 1) - of nkExprEqExpr, nkAsgn, nkFastAsgn: + of nkExprEqExpr, nkAsgn, nkFastAsgn: gsub(g, n.sons[0]) put(g, tkSpaces, Space) putWithSpace(g, tkEquals, "=") gsub(g, n.sons[1]) - of nkChckRangeF: + of nkChckRangeF: put(g, tkSymbol, "chckRangeF") put(g, tkParLe, "(") gcomma(g, n) put(g, tkParRi, ")") - of nkChckRange64: + of nkChckRange64: put(g, tkSymbol, "chckRange64") put(g, tkParLe, "(") gcomma(g, n) put(g, tkParRi, ")") - of nkChckRange: + of nkChckRange: put(g, tkSymbol, "chckRange") put(g, tkParLe, "(") gcomma(g, n) put(g, tkParRi, ")") - of nkObjDownConv, nkObjUpConv, nkStringToCString, nkCStringToString: + of nkObjDownConv, nkObjUpConv, nkStringToCString, nkCStringToString: if sonsLen(n) >= 1: gsub(g, n.sons[0]) put(g, tkParLe, "(") gcomma(g, n, 1) put(g, tkParRi, ")") of nkClosedSymChoice, nkOpenSymChoice: put(g, tkParLe, "(") - for i in countup(0, sonsLen(n) - 1): + for i in countup(0, sonsLen(n) - 1): if i > 0: put(g, tkOpr, "|") if n.sons[i].kind == nkSym: let s = n[i].sym @@ -906,11 +908,11 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = else: gsub(g, n.sons[i], c) put(g, tkParRi, if n.kind == nkOpenSymChoice: "|...)" else: ")") - of nkPar, nkClosure: + of nkPar, nkClosure: put(g, tkParLe, "(") gcomma(g, n, c) put(g, tkParRi, ")") - of nkCurly: + of nkCurly: put(g, tkCurlyLe, "{") gcomma(g, n, c) put(g, tkCurlyRi, "}") @@ -925,14 +927,14 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = put(g, tkBracketLe, "[") gcomma(g, n, c) put(g, tkBracketRi, "]") - of nkDotExpr: + of nkDotExpr: gsub(g, n.sons[0]) put(g, tkDot, ".") gsub(g, n.sons[1]) - of nkBind: + of nkBind: putWithSpace(g, tkBind, "bind") gsub(g, n.sons[0]) - of nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref: + of nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref: gsub(g, n.sons[0]) of nkLambda: putWithSpace(g, tkProc, "proc") @@ -950,34 +952,34 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = of nkConstDef, nkIdentDefs: gcomma(g, n, 0, -3) var L = sonsLen(n) - if L >= 2 and n.sons[L - 2].kind != nkEmpty: + if L >= 2 and n.sons[L - 2].kind != nkEmpty: putWithSpace(g, tkColon, ":") gsub(g, n.sons[L - 2]) - if L >= 1 and n.sons[L - 1].kind != nkEmpty: + if L >= 1 and n.sons[L - 1].kind != nkEmpty: put(g, tkSpaces, Space) putWithSpace(g, tkEquals, "=") gsub(g, n.sons[L - 1], c) - of nkVarTuple: + of nkVarTuple: put(g, tkParLe, "(") gcomma(g, n, 0, -3) put(g, tkParRi, ")") put(g, tkSpaces, Space) putWithSpace(g, tkEquals, "=") gsub(g, lastSon(n), c) - of nkExprColonExpr: + of nkExprColonExpr: gsub(g, n.sons[0]) putWithSpace(g, tkColon, ":") gsub(g, n.sons[1]) - of nkInfix: + of nkInfix: gsub(g, n.sons[1]) put(g, tkSpaces, Space) gsub(g, n.sons[0]) # binary operator - if not fits(g, lsub(n.sons[2]) + lsub(n.sons[0]) + 1): + if not fits(g, lsub(n.sons[2]) + lsub(n.sons[0]) + 1): optNL(g, g.indent + longIndentWid) - else: + else: put(g, tkSpaces, Space) gsub(g, n.sons[2]) - of nkPrefix: + of nkPrefix: gsub(g, n.sons[0]) if n.len > 1: put(g, tkSpaces, Space) @@ -987,10 +989,10 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = put(g, tkParRi, ")") else: gsub(g, n.sons[1]) - of nkPostfix: + of nkPostfix: gsub(g, n.sons[1]) gsub(g, n.sons[0]) - of nkRange: + of nkRange: gsub(g, n.sons[0]) put(g, tkDotDot, "..") gsub(g, n.sons[1]) @@ -1004,43 +1006,43 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = put(g, tkSpaces, Space) gsub(g, n.sons[i]) put(g, tkAccent, "`") - of nkIfExpr: + of nkIfExpr: putWithSpace(g, tkIf, "if") gsub(g, n.sons[0].sons[0]) putWithSpace(g, tkColon, ":") gsub(g, n.sons[0].sons[1]) gsons(g, n, emptyContext, 1) - of nkElifExpr: + of nkElifExpr: putWithSpace(g, tkElif, " elif") gsub(g, n.sons[0]) putWithSpace(g, tkColon, ":") gsub(g, n.sons[1]) - of nkElseExpr: + of nkElseExpr: put(g, tkElse, " else") putWithSpace(g, tkColon, ":") gsub(g, n.sons[0]) of nkTypeOfExpr: putWithSpace(g, tkType, "type") if n.len > 0: gsub(g, n.sons[0]) - of nkRefTy: + of nkRefTy: if sonsLen(n) > 0: putWithSpace(g, tkRef, "ref") gsub(g, n.sons[0]) else: put(g, tkRef, "ref") - of nkPtrTy: + of nkPtrTy: if sonsLen(n) > 0: putWithSpace(g, tkPtr, "ptr") gsub(g, n.sons[0]) else: put(g, tkPtr, "ptr") - of nkVarTy: + of nkVarTy: if sonsLen(n) > 0: putWithSpace(g, tkVar, "var") gsub(g, n.sons[0]) else: put(g, tkVar, "var") - of nkDistinctTy: + of nkDistinctTy: if n.len > 0: putWithSpace(g, tkDistinct, "distinct") gsub(g, n.sons[0]) @@ -1052,14 +1054,14 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = gcomma(g, n[1]) else: put(g, tkDistinct, "distinct") - of nkTypeDef: + of nkTypeDef: gsub(g, n.sons[0]) gsub(g, n.sons[1]) put(g, tkSpaces, Space) - if n.sons[2].kind != nkEmpty: + if n.sons[2].kind != nkEmpty: putWithSpace(g, tkEquals, "=") gsub(g, n.sons[2]) - of nkObjectTy: + of nkObjectTy: if sonsLen(n) > 0: putWithSpace(g, tkObject, "object") gsub(g, n.sons[0]) @@ -1068,18 +1070,18 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = gsub(g, n.sons[2]) else: put(g, tkObject, "object") - of nkRecList: + of nkRecList: indentNL(g) - for i in countup(0, sonsLen(n) - 1): + for i in countup(0, sonsLen(n) - 1): optNL(g) gsub(g, n.sons[i], c) gcoms(g) dedent(g) putNL(g) - of nkOfInherit: + of nkOfInherit: putWithSpace(g, tkOf, "of") gsub(g, n.sons[0]) - of nkProcTy: + of nkProcTy: if sonsLen(n) > 0: putWithSpace(g, tkProc, "proc") gsub(g, n.sons[0]) @@ -1098,7 +1100,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = put(g, tkBracketLe, "[") if n.len > 0: gsub(g, n.sons[0]) - put(g, tkBracketRi, "]") + put(g, tkBracketRi, "]") of nkEnumTy: if sonsLen(n) > 0: putWithSpace(g, tkEnum, "enum") @@ -1110,16 +1112,16 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = dedent(g) else: put(g, tkEnum, "enum") - of nkEnumFieldDef: + of nkEnumFieldDef: gsub(g, n.sons[0]) put(g, tkSpaces, Space) putWithSpace(g, tkEquals, "=") gsub(g, n.sons[1]) of nkStmtList, nkStmtListExpr, nkStmtListType: gstmts(g, n, emptyContext) - of nkIfStmt: + of nkIfStmt: putWithSpace(g, tkIf, "if") gif(g, n) - of nkWhen, nkRecWhen: + of nkWhen, nkRecWhen: putWithSpace(g, tkWhen, "when") gif(g, n) of nkWhileStmt: gwhile(g, n) @@ -1130,27 +1132,27 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = of nkBlockStmt, nkBlockExpr: gblock(g, n) of nkStaticStmt: gstaticStmt(g, n) of nkAsmStmt: gasm(g, n) - of nkProcDef: + of nkProcDef: if renderNoProcDefs notin g.flags: putWithSpace(g, tkProc, "proc") gproc(g, n) of nkConverterDef: if renderNoProcDefs notin g.flags: putWithSpace(g, tkConverter, "converter") gproc(g, n) - of nkMethodDef: + of nkMethodDef: if renderNoProcDefs notin g.flags: putWithSpace(g, tkMethod, "method") gproc(g, n) - of nkIteratorDef: + of nkIteratorDef: if renderNoProcDefs notin g.flags: putWithSpace(g, tkIterator, "iterator") gproc(g, n) - of nkMacroDef: + of nkMacroDef: if renderNoProcDefs notin g.flags: putWithSpace(g, tkMacro, "macro") gproc(g, n) - of nkTemplateDef: + of nkTemplateDef: if renderNoProcDefs notin g.flags: putWithSpace(g, tkTemplate, "template") gproc(g, n) - of nkTypeSection: + of nkTypeSection: gsection(g, n, emptyContext, tkType, "type") - of nkConstSection: + of nkConstSection: initContext(a) incl(a.flags, rfInConstExpr) gsection(g, n, a, tkConst, "const") @@ -1159,32 +1161,32 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = if L == 0: return if n.kind == nkVarSection: putWithSpace(g, tkVar, "var") else: putWithSpace(g, tkLet, "let") - if L > 1: + if L > 1: gcoms(g) indentNL(g) - for i in countup(0, L - 1): + for i in countup(0, L - 1): optNL(g) gsub(g, n.sons[i]) gcoms(g) dedent(g) - else: + else: gsub(g, n.sons[0]) - of nkReturnStmt: + of nkReturnStmt: putWithSpace(g, tkReturn, "return") gsub(g, n.sons[0]) - of nkRaiseStmt: + of nkRaiseStmt: putWithSpace(g, tkRaise, "raise") gsub(g, n.sons[0]) - of nkYieldStmt: + of nkYieldStmt: putWithSpace(g, tkYield, "yield") gsub(g, n.sons[0]) - of nkDiscardStmt: + of nkDiscardStmt: putWithSpace(g, tkDiscard, "discard") gsub(g, n.sons[0]) - of nkBreakStmt: + of nkBreakStmt: putWithSpace(g, tkBreak, "break") gsub(g, n.sons[0]) - of nkContinueStmt: + of nkContinueStmt: putWithSpace(g, tkContinue, "continue") gsub(g, n.sons[0]) of nkPragma: @@ -1219,24 +1221,24 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = gcommaAux(g, n, g.indent, 1) gcoms(g) putNL(g) - of nkFromStmt: + of nkFromStmt: putWithSpace(g, tkFrom, "from") gsub(g, n.sons[0]) put(g, tkSpaces, Space) putWithSpace(g, tkImport, "import") gcomma(g, n, emptyContext, 1) putNL(g) - of nkIncludeStmt: + of nkIncludeStmt: putWithSpace(g, tkInclude, "include") gcoms(g) indentNL(g) gcommaAux(g, n, g.indent) dedent(g) putNL(g) - of nkCommentStmt: + of nkCommentStmt: gcoms(g) optNL(g) - of nkOfBranch: + of nkOfBranch: optNL(g) putWithSpace(g, tkOf, "of") gcomma(g, n, c, 0, - 2) @@ -1248,50 +1250,50 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = put(g, tkSpaces, Space) putWithSpace(g, tkAs, "as") gsub(g, n.sons[1]) - of nkBindStmt: + of nkBindStmt: putWithSpace(g, tkBind, "bind") gcomma(g, n, c) of nkMixinStmt: putWithSpace(g, tkMixin, "mixin") gcomma(g, n, c) - of nkElifBranch: + of nkElifBranch: optNL(g) putWithSpace(g, tkElif, "elif") gsub(g, n.sons[0]) putWithSpace(g, tkColon, ":") gcoms(g) gstmts(g, n.sons[1], c) - of nkElse: + of nkElse: optNL(g) put(g, tkElse, "else") putWithSpace(g, tkColon, ":") gcoms(g) gstmts(g, n.sons[0], c) - of nkFinally: + of nkFinally: optNL(g) put(g, tkFinally, "finally") putWithSpace(g, tkColon, ":") gcoms(g) gstmts(g, n.sons[0], c) - of nkExceptBranch: + of nkExceptBranch: optNL(g) putWithSpace(g, tkExcept, "except") gcomma(g, n, 0, - 2) putWithSpace(g, tkColon, ":") gcoms(g) gstmts(g, lastSon(n), c) - of nkGenericParams: + of nkGenericParams: put(g, tkBracketLe, "[") gcomma(g, n) put(g, tkBracketRi, "]") - of nkFormalParams: + of nkFormalParams: put(g, tkParLe, "(") gsemicolon(g, n, 1) put(g, tkParRi, ")") - if n.sons[0].kind != nkEmpty: + if n.sons[0].kind != nkEmpty: putWithSpace(g, tkColon, ":") gsub(g, n.sons[0]) - of nkTupleTy: + of nkTupleTy: put(g, tkTuple, "tuple") put(g, tkBracketLe, "[") gcomma(g, n) @@ -1309,17 +1311,17 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = gsons(g, n, c) of nkTypeClassTy: gTypeClassTy(g, n) - else: - #nkNone, nkExplicitTypeListCall: + else: + #nkNone, nkExplicitTypeListCall: internalError(n.info, "rnimsyn.gsub(" & $n.kind & ')') -proc renderTree(n: PNode, renderFlags: TRenderFlags = {}): string = +proc renderTree(n: PNode, renderFlags: TRenderFlags = {}): string = var g: TSrcGen initSrcGen(g, renderFlags) gsub(g, n) result = g.buf -proc renderModule(n: PNode, filename: string, +proc renderModule(n: PNode, filename: string, renderFlags: TRenderFlags = {}) = var f: File @@ -1339,18 +1341,18 @@ proc renderModule(n: PNode, filename: string, write(f, g.buf) close(f) else: - rawMessage(errCannotOpenFile, filename) + rawMessage(errCannotOpenFile, filename) -proc initTokRender(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {}) = +proc initTokRender(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {}) = initSrcGen(r, renderFlags) gsub(r, n) -proc getNextTok(r: var TSrcGen, kind: var TTokType, literal: var string) = - if r.idx < len(r.tokens): +proc getNextTok(r: var TSrcGen, kind: var TTokType, literal: var string) = + if r.idx < len(r.tokens): kind = r.tokens[r.idx].kind var length = r.tokens[r.idx].length.int literal = substr(r.buf, r.pos, r.pos + length - 1) inc(r.pos, length) inc(r.idx) - else: + else: kind = tkEof diff --git a/compiler/semparallel.nim b/compiler/semparallel.nim index a914832de..6572a7f49 100644 --- a/compiler/semparallel.nim +++ b/compiler/semparallel.nim @@ -37,7 +37,7 @@ is valid, but spawn f(a[i]) spawn f(a[i]) inc i -is not! However, +is not! However, spawn f(a[i]) if guard: inc i spawn f(a[i]) @@ -460,7 +460,7 @@ proc liftParallel*(owner: PSym; n: PNode): PNode = # - detect used slices # - detect used arguments #echo "PAR ", renderTree(n) - + var a = initAnalysisCtx() let body = n.lastSon analyse(a, body) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index db0b9b67f..19514263f 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -410,7 +410,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = let shadowed = findShadowedVar(c, v) if shadowed != nil: shadowed.flags.incl(sfShadowed) - if shadowed.kind == skResult: + if shadowed.kind == skResult and sfGenSym notin v.flags: message(a.info, warnResultShadowed) # a shadowed variable is an error unless it appears on the right # side of the '=': diff --git a/compiler/transf.nim b/compiler/transf.nim index e5e3bbe63..7e56f09dc 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -152,6 +152,7 @@ proc transformVarSection(c: PTransf, v: PNode): PTransNode = defs[0] = newSymNode(newVar).PTransNode defs[1] = it.sons[1].PTransNode defs[2] = transform(c, it.sons[2]) + newVar.ast = defs[2].PNode result[i] = defs else: if it.kind != nkVarTuple: diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 05fcc9584..08d224dfd 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -196,7 +196,7 @@ proc sorted*[T](a: openArray[T], cmp: proc(x, y: T): int {.closure.}, result[i] = a[i] sort(result, cmp, order) -template sortByIt*(seq1, op: expr): expr = +template sortedByIt*(seq1, op: expr): expr = ## Convenience template around the ``sorted`` proc to reduce typing. ## ## The template injects the ``it`` variable which you can use directly in an @@ -204,10 +204,23 @@ template sortByIt*(seq1, op: expr): expr = ## ## .. code-block:: nim ## - ## var users: seq[tuple[id: int, name: string]] = - ## @[(0, "Smith"), (1, "Pratt"), (2, "Sparrow")] + ## type Person = tuple[name: string, age: int] + ## var + ## p1: Person = (name: "p1", age: 60) + ## p2: Person = (name: "p2", age: 20) + ## p3: Person = (name: "p3", age: 30) + ## p4: Person = (name: "p4", age: 30) ## - ## echo users.sortByIt(it.name) + ## people = @[p1,p2,p4,p3] + ## + ## echo people.sortedByIt(it.name) + ## + ## Because the underlying ``cmp()`` is defined for tuples you can do + ## a nested sort like in the following example: + ## + ## .. code-block:: nim + ## + ## echo people.sortedByIt((it.age, it.name)) ## var result {.gensym.} = sorted(seq1, proc(x, y: type(seq1[0])): int = var it {.inject.} = x diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index bf905ed49..a8caf809e 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -1323,14 +1323,25 @@ macro async*(prc: stmt): stmt {.immediate.} = newLit(prc[0].getName)))) # Get type from return type of this proc # -> iterator nameIter(): FutureBase {.closure.} = + # -> {.push warning[resultshadowed]: off.} # -> var result: T + # -> {.pop.} # -> <proc_body> # -> complete(retFuture, result) var iteratorNameSym = genSym(nskIterator, $prc[0].getName & "Iter") var procBody = prc[6].processBody(retFutureSym, subtypeIsVoid, nil) if not subtypeIsVoid: - procBody.insert(0, newNimNode(nnkVarSection, prc[6]).add( + procBody.insert(0, newNimNode(nnkPragma).add(newIdentNode("push"), + newNimNode(nnkExprColonExpr).add(newNimNode(nnkBracketExpr).add( + newIdentNode("warning"), newIdentNode("resultshadowed")), + newIdentNode("off")))) # -> {.push warning[resultshadowed]: off.} + + procBody.insert(1, newNimNode(nnkVarSection, prc[6]).add( newIdentDefs(newIdentNode("result"), returnType[1]))) # -> var result: T + + procBody.insert(2, newNimNode(nnkPragma).add( + newIdentNode("pop"))) # -> {.pop.}) + procBody.add( newCall(newIdentNode("complete"), retFutureSym, newIdentNode("result"))) # -> complete(retFuture, result) diff --git a/lib/pure/asyncfile.nim b/lib/pure/asyncfile.nim index 844c2ab55..25e121183 100644 --- a/lib/pure/asyncfile.nim +++ b/lib/pure/asyncfile.nim @@ -24,7 +24,7 @@ import asyncdispatch, os -when defined(windows): +when defined(windows) or defined(nimdoc): import winlean else: import posix @@ -34,7 +34,7 @@ type fd: TAsyncFd offset: int64 -when defined(windows): +when defined(windows) or defined(nimdoc): proc getDesiredAccess(mode: FileMode): int32 = case mode of fmRead: @@ -70,7 +70,7 @@ else: proc getFileSize(f: AsyncFile): int64 = ## Retrieves the specified file's size. - when defined(windows): + when defined(windows) or defined(nimdoc): var high: DWord let low = getFileSize(f.fd.THandle, addr high) if low == INVALID_FILE_SIZE: @@ -81,7 +81,7 @@ proc openAsync*(filename: string, mode = fmRead): AsyncFile = ## Opens a file specified by the path in ``filename`` using ## the specified ``mode`` asynchronously. new result - when defined(windows): + when defined(windows) or defined(nimdoc): let flags = FILE_FLAG_OVERLAPPED or FILE_ATTRIBUTE_NORMAL let desiredAccess = getDesiredAccess(mode) let creationDisposition = getCreationDisposition(mode, filename) @@ -120,7 +120,7 @@ proc read*(f: AsyncFile, size: int): Future[string] = ## returned. var retFuture = newFuture[string]("asyncfile.read") - when defined(windows): + when defined(windows) or defined(nimdoc): var buffer = alloc0(size) var ol = PCustomOverlapped() @@ -224,7 +224,7 @@ proc setFilePos*(f: AsyncFile, pos: int64) = ## Sets the position of the file pointer that is used for read/write ## operations. The file's first byte has the index zero. f.offset = pos - when not defined(windows): + when not defined(windows) and not defined(nimdoc): let ret = lseek(f.fd.cint, pos, SEEK_SET) if ret == -1: raiseOSError(osLastError()) @@ -245,7 +245,7 @@ proc write*(f: AsyncFile, data: string): Future[void] = ## specified file. var retFuture = newFuture[void]("asyncfile.write") var copy = data - when defined(windows): + when defined(windows) or defined(nimdoc): var buffer = alloc0(data.len) copyMem(buffer, addr copy[0], data.len) @@ -316,7 +316,7 @@ proc write*(f: AsyncFile, data: string): Future[void] = proc close*(f: AsyncFile) = ## Closes the file specified. - when defined(windows): + when defined(windows) or defined(nimdoc): if not closeHandle(f.fd.THandle).bool: raiseOSError(osLastError()) else: diff --git a/tests/init/tuninit2.nim b/tests/init/tuninit2.nim new file mode 100644 index 000000000..950895c02 --- /dev/null +++ b/tests/init/tuninit2.nim @@ -0,0 +1,54 @@ +# bug #2316 + +type + EventType = enum + QuitEvent = 5 + AppMain* = ref object of RootObj + width: int + height: int + title: string + running: bool + event_type: EventType + App* = ref object of AppMain + draw_proc: proc(app: AppMain): void {.closure.} + events_proc: proc(app: AppMain): void {.closure.} + update_proc: proc(app: AppMain, dt: float): void {.closure.} + load_proc: proc(app: AppMain): void {.closure.} + + +proc initApp*(t: string, w, h: int): App = + App(width: w, height: h, title: t, event_type: EventType.QuitEvent) + + +method getTitle*(self: AppMain): string = self.title +method getWidth*(self: AppMain): int = self.width +method getHeight*(self: AppMain): int = self.height + + +method draw*(self: App, draw: proc(app: AppMain)): void = + self.draw_proc = draw + +method load*(self: App, load: proc(a: AppMain)): void = + self.load_proc = load + +method events*(self: App, events: proc(app: AppMain)): void = + self.events_proc = events + +method update*(self: App, update: proc(app: AppMain, delta: float)): void = + self.update_proc = update + +method run*(self: App): void = discard + +var mygame = initApp("Example", 800, 600) + +mygame.load(proc(app: AppMain): void = + echo app.getTitle() + echo app.getWidth() + echo app.getHeight() +) + +mygame.events(proc(app: AppMain): void = + discard +) + +mygame.run() diff --git a/tests/parallel/tconvexhull.nim b/tests/parallel/tconvexhull.nim index d7e4f7716..dffe5339b 100644 --- a/tests/parallel/tconvexhull.nim +++ b/tests/parallel/tconvexhull.nim @@ -6,7 +6,7 @@ true true true''' -ccodeCheck: "!'deepcopy('" +ccodeCheck: "\\i ! @'deepCopy(' .*" """ # parallel convex hull for Nim bigbreak diff --git a/tests/parallel/tmissing_deepcopy.nim b/tests/parallel/tmissing_deepcopy.nim new file mode 100644 index 000000000..53481e4df --- /dev/null +++ b/tests/parallel/tmissing_deepcopy.nim @@ -0,0 +1,40 @@ +discard """ + ccodeCheck: "\\i @'deepCopy(' .*" +""" + +# bug #2286 + +import threadPool + +type + Person = ref object + name: string + friend: Person + +var + people: seq[Person] = @[] + +proc newPerson(name:string): Person = + result.new() + result.name = name + +proc greet(p:Person) = + p.friend.name &= "-MUT" # this line crashes the program + echo "Person {", + " name:", p.name, "(", cast[int](addr p.name),"),", + " friend:", p.friend.name, "(", cast[int](addr p.friend.name),") }" + +proc setup = + for i in 0 .. <20: + people.add newPerson("Person" & $(i + 1)) + for i in 0 .. <20: + people[i].friend = people[19-i] + +proc update = + parallel: + for i in 0 .. people.high: + spawn people[i].greet() + +when isMainModule: + setup() + update() diff --git a/tests/parallel/tsimple_array_checks.nim b/tests/parallel/tsimple_array_checks.nim new file mode 100644 index 000000000..9874d3299 --- /dev/null +++ b/tests/parallel/tsimple_array_checks.nim @@ -0,0 +1,41 @@ +# bug #2287 + +import threadPool + +# If `nums` is an array instead of seq, +# NONE of the iteration ways below work (including high / len-1) +let nums = @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + +proc log(n:int) = + echo n + +proc main = + parallel: + for n in nums: # Error: cannot prove: i <= len(nums) + -1 + spawn log(n) + #for i in 0 .. <nums.len: # Error: cannot prove: i <= len(nums) + -1 + #for i in 0 .. nums.len-1: # WORKS! + #for i in 0 .. <nums.len: # WORKS! + # spawn log(nums[i]) + +# Array needs explicit size to work, probably related to issue #2287 +#const a: array[0..5, int] = [1,2,3,4,5,6] + +#const a = [1,2,3,4,5,6] # Doesn't work +const a = @[1,2,3,4,5,6] # Doesn't work +proc f(n: int) = echo "Hello ", n + +proc maino = + parallel: + # while loop doesn't work: + var i = 0 + while i < a.high: + #for i in countup(0, a.high-1, 2): + spawn f(a[i]) + spawn f(a[i+1]) + i += 2 + +maino() # Doesn't work outside a proc + +when isMainModule: + main() diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim index 54ab67d85..7cf902704 100644 --- a/tests/testament/tester.nim +++ b/tests/testament/tester.nim @@ -148,7 +148,11 @@ proc codegenCheck(test: TTest, check: string, given: var TSpec) = let genFile = generatedFile(path, name, test.target) echo genFile let contents = readFile(genFile).string - if contents.find(check.peg) < 0: + if check[0] == '\\': + # little hack to get 'match' support: + if not contents.match(check.peg): + given.err = reCodegenFailure + elif contents.find(check.peg) < 0: given.err = reCodegenFailure except ValueError: given.err = reInvalidPeg diff --git a/todo.txt b/todo.txt index 69674f019..47180aaf1 100644 --- a/todo.txt +++ b/todo.txt @@ -54,6 +54,7 @@ Bugs - VM: ptr/ref T cannot work in general - scopes are still broken for generic instantiation! - blocks can "export" an identifier but the CCG generates {} for them ... +- ConcreteTypes in a 'case' means we don't check for duplicated case branches version 0.9.x diff --git a/web/question.txt b/web/question.txt index 28c7ece14..0733a2455 100644 --- a/web/question.txt +++ b/web/question.txt @@ -105,12 +105,13 @@ General FAQ -------------------------- - Nim IDE: https://github.com/nim-lang/Aporia - - Emacs: https://github.com/Tass/nim-mode + - Emacs: https://github.com/reactormonk/nim-mode - Vim: https://github.com/zah/nimrod.vim/ - Scite: Included - - Gedit: The `Aporia .lang file <https://github.com/nim-lang/Aporia/blob/master/share/gtksourceview-2.0/language-specs/nimrod.lang>`_ + - Gedit: The `Aporia .lang file <https://github.com/nim-lang/Aporia/blob/master/share/gtksourceview-2.0/language-specs/nim.lang>`_ - jEdit: https://github.com/exhu/nimrod-misc/tree/master/jedit - TextMate: Available in bundle installer (`Repository <https://github.com/textmate/nim.tmbundle>`_) + - Sublime Text: Available via Package Control (`Repository <https://github.com/Varriount/NimLime>`_) .. container:: standout |