diff options
Diffstat (limited to 'compiler')
-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 |
15 files changed, 363 insertions, 142 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 = |