diff options
Diffstat (limited to 'compiler')
38 files changed, 596 insertions, 241 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index ac917346f..0cc4daf22 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -292,6 +292,8 @@ const sfNoForward* = sfRegister # forward declarations are not required (per module) + sfReorder* = sfForward + # reordering pass is enabled sfCompileToCpp* = sfInfixCall # compile the module as C++ code sfCompileToObjc* = sfNamedParamCall # compile the module as Objective-C code diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 0ec16710f..f5c793d29 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -744,14 +744,17 @@ proc genTupleElem(p: BProc, e: PNode, d: var TLoc) = addf(r, ".Field$1", [rope(i)]) putIntoDest(p, d, tupType.sons[i], r, a.s) -proc lookupFieldAgain(p: BProc, ty: PType; field: PSym; r: var Rope): PSym = +proc lookupFieldAgain(p: BProc, ty: PType; field: PSym; r: var Rope; + resTyp: ptr PType = nil): PSym = var ty = ty assert r != nil while ty != nil: ty = ty.skipTypes(skipPtrs) assert(ty.kind in {tyTuple, tyObject}) result = lookupInRecord(ty.n, field.name) - if result != nil: break + if result != nil: + if resTyp != nil: resTyp[] = ty + break if not p.module.compileToCpp: add(r, ".Sup") ty = ty.sons[0] if result == nil: internalError(field.info, "genCheckedRecordField") @@ -768,8 +771,9 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) = addf(r, ".Field$1", [rope(f.position)]) putIntoDest(p, d, f.typ, r, a.s) else: - let field = lookupFieldAgain(p, ty, f, r) - if field.loc.r == nil: fillObjectFields(p.module, ty) + var rtyp: PType + let field = lookupFieldAgain(p, ty, f, r, addr rtyp) + if field.loc.r == nil and rtyp != nil: fillObjectFields(p.module, rtyp) if field.loc.r == nil: internalError(e.info, "genRecordField 3 " & typeToString(ty)) addf(r, ".$1", [field.loc.r]) putIntoDest(p, d, field.typ, r, a.s) @@ -1057,7 +1061,7 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = "$1 = ($2) #incrSeqV2(&($1)->Sup, sizeof($3));$n" else: "$1 = ($2) #incrSeqV2($1, sizeof($3));$n" - var a, b, dest: TLoc + var a, b, dest, tmpL: TLoc initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[2], b) let bt = skipTypes(e.sons[2].typ, {tyVar}) @@ -1068,9 +1072,10 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = #if bt != b.t: # echo "YES ", e.info, " new: ", typeToString(bt), " old: ", typeToString(b.t) initLoc(dest, locExpr, bt, OnHeap) - dest.r = rfmt(nil, "$1->data[$1->$2]", rdLoc(a), lenField(p)) + getIntTemp(p, tmpL) + lineCg(p, cpsStmts, "$1 = $2->$3++;$n", tmpL.r, rdLoc(a), lenField(p)) + dest.r = rfmt(nil, "$1->data[$2]", rdLoc(a), tmpL.r) genAssignment(p, dest, b, {needToCopy, afDestIsNil}) - lineCg(p, cpsStmts, "++$1->$2;$n", rdLoc(a), lenField(p)) gcUsage(e) proc genReset(p: BProc, n: PNode) = @@ -1096,9 +1101,9 @@ proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) = if a.s == OnHeap and usesNativeGC(): # use newObjRC1 as an optimization if canFormAcycle(a.t): - linefmt(p, cpsStmts, "if ($1) #nimGCunref($1);$n", a.rdLoc) + linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", a.rdLoc) else: - linefmt(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);$n", a.rdLoc) + linefmt(p, cpsStmts, "if ($1) { #nimGCunrefNoCycle($1); $1 = NIM_NIL; }$n", a.rdLoc) b.r = ropecg(p.module, "($1) #newObjRC1($2, $3)", args) linefmt(p, cpsStmts, "$1 = $2;$n", a.rdLoc, b.rdLoc) else: @@ -1126,9 +1131,9 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope) = initLoc(call, locExpr, dest.t, OnHeap) if dest.s == OnHeap and usesNativeGC(): if canFormAcycle(dest.t): - linefmt(p, cpsStmts, "if ($1) #nimGCunref($1);$n", dest.rdLoc) + linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", dest.rdLoc) else: - linefmt(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);$n", dest.rdLoc) + linefmt(p, cpsStmts, "if ($1) { #nimGCunrefNoCycle($1); $1 = NIM_NIL; }$n", dest.rdLoc) call.r = ropecg(p.module, "($1) #newSeqRC1($2, $3)", args) linefmt(p, cpsStmts, "$1 = $2;$n", dest.rdLoc, call.rdLoc) else: @@ -1170,7 +1175,10 @@ proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool = proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = #echo rendertree e, " ", e.isDeepConstExpr - if handleConstExpr(p, e, d): return + # inheritance in C++ does not allow struct initialization so + # we skip this step here: + if not p.module.compileToCpp: + if handleConstExpr(p, e, d): return var tmp: TLoc var t = e.typ.skipTypes(abstractInst) getTemp(p, t, tmp) @@ -1378,13 +1386,30 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) = useStringh(p.module) if op == mHigh: unaryExpr(p, e, d, "($1 ? (strlen($1)-1) : -1)") else: unaryExpr(p, e, d, "($1 ? strlen($1) : 0)") - of tyString, tySequence: + of tyString: if not p.module.compileToCpp: if op == mHigh: unaryExpr(p, e, d, "($1 ? ($1->Sup.len-1) : -1)") else: unaryExpr(p, e, d, "($1 ? $1->Sup.len : 0)") else: if op == mHigh: unaryExpr(p, e, d, "($1 ? ($1->len-1) : -1)") else: unaryExpr(p, e, d, "($1 ? $1->len : 0)") + of tySequence: + var a, tmp: TLoc + initLocExpr(p, e[1], a) + getIntTemp(p, tmp) + var frmt: FormatStr + if not p.module.compileToCpp: + if op == mHigh: + frmt = "$1 = ($2 ? ($2->Sup.len-1) : -1);$n" + else: + frmt = "$1 = ($2 ? $2->Sup.len : 0);$n" + else: + if op == mHigh: + frmt = "$1 = ($2 ? ($2->len-1) : -1);$n" + else: + frmt = "$1 = ($2 ? $2->len : 0);$n" + lineCg(p, cpsStmts, frmt, tmp.r, rdLoc(a)) + putIntoDest(p, d, e.typ, tmp.r) of tyArray: # YYY: length(sideeffect) is optimized away incorrectly? if op == mHigh: putIntoDest(p, d, e.typ, rope(lastOrd(typ))) @@ -1742,11 +1767,23 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mOrd: genOrd(p, e, d) of mLengthArray, mHigh, mLengthStr, mLengthSeq, mLengthOpenArray: genArrayLen(p, e, d, op) - of mXLenStr, mXLenSeq: + of mXLenStr: if not p.module.compileToCpp: unaryExpr(p, e, d, "($1->Sup.len)") else: unaryExpr(p, e, d, "$1->len") + of mXLenSeq: + # see 'taddhigh.nim' for why we need to use a temporary here: + var a, tmp: TLoc + initLocExpr(p, e[1], a) + getIntTemp(p, tmp) + var frmt: FormatStr + if not p.module.compileToCpp: + frmt = "$1 = $2->Sup.len;$n" + else: + frmt = "$1 = $2->len;$n" + lineCg(p, cpsStmts, frmt, tmp.r, rdLoc(a)) + putIntoDest(p, d, e.typ, tmp.r) of mGCref: unaryStmt(p, e, d, "#nimGCref($1);$n") of mGCunref: unaryStmt(p, e, d, "#nimGCunref($1);$n") of mSetLengthStr: genSetLengthStr(p, e, d) @@ -2123,17 +2160,19 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = # See tests/run/tcnstseq3 for an example that would fail otherwise. genAsgn(p, n, fastAsgn=p.prc != nil) of nkDiscardStmt: - if n.sons[0].kind != nkEmpty: + let ex = n[0] + if ex.kind != nkEmpty: genLineDir(p, n) var a: TLoc - if n[0].kind in nkCallKinds: + if ex.kind in nkCallKinds and (ex[0].kind != nkSym or + ex[0].sym.magic == mNone): # bug #6037: do not assign to a temp in C++ mode: incl a.flags, lfSingleUse - genCall(p, n[0], a) + genCall(p, ex, a) if lfSingleUse notin a.flags: line(p, cpsStmts, a.r & ";" & tnl) else: - initLocExpr(p, n.sons[0], a) + initLocExpr(p, ex, a) of nkAsmStmt: genAsmStmt(p, n) of nkTryStmt: if p.module.compileToCpp and optNoCppExceptions notin gGlobalOptions: @@ -2201,20 +2240,22 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope = else: globalError(info, "cannot create null element for: " & $t.kind) -proc getNullValueAux(p: BProc; obj, cons: PNode, result: var Rope) = +proc getNullValueAux(p: BProc; t: PType; obj, cons: PNode, result: var Rope; count: var int) = case obj.kind of nkRecList: - for i in countup(0, sonsLen(obj) - 1): getNullValueAux(p, obj.sons[i], cons, result) + for i in countup(0, sonsLen(obj) - 1): + getNullValueAux(p, t, obj.sons[i], cons, result, count) of nkRecCase: - getNullValueAux(p, obj.sons[0], cons, result) + getNullValueAux(p, t, obj.sons[0], cons, result, count) for i in countup(1, sonsLen(obj) - 1): - getNullValueAux(p, lastSon(obj.sons[i]), cons, result) + getNullValueAux(p, t, lastSon(obj.sons[i]), cons, result, count) of nkSym: - if not result.isNil: result.add ", " + if count > 0: result.add ", " + inc count let field = obj.sym for i in 1..<cons.len: if cons[i].kind == nkExprColonExpr: - if cons[i][0].sym.name == field.name: + if cons[i][0].sym.name.id == field.name.id: result.add genConstExpr(p, cons[i][1]) return elif i == field.position: @@ -2225,14 +2266,32 @@ proc getNullValueAux(p: BProc; obj, cons: PNode, result: var Rope) = else: localError(cons.info, "cannot create null element for: " & $obj) +proc getNullValueAuxT(p: BProc; orig, t: PType; obj, cons: PNode, result: var Rope; count: var int) = + var base = t.sons[0] + let oldRes = result + if not p.module.compileToCpp: result.add "{" + let oldcount = count + if base != nil: + base = skipTypes(base, skipPtrs) + getNullValueAuxT(p, orig, base, base.n, cons, result, count) + elif not isObjLackingTypeField(t) and not p.module.compileToCpp: + addf(result, "$1", [genTypeInfo(p.module, orig)]) + inc count + getNullValueAux(p, t, obj, cons, result, count) + # do not emit '{}' as that is not valid C: + if oldcount == count: result = oldres + elif not p.module.compileToCpp: result.add "}" + proc genConstObjConstr(p: BProc; n: PNode): Rope = - var length = sonsLen(n) result = nil let t = n.typ.skipTypes(abstractInst) - if not isObjLackingTypeField(t) and not p.module.compileToCpp: - addf(result, "{$1}", [genTypeInfo(p.module, t)]) - getNullValueAux(p, t.n, n, result) - result = "{$1}$n" % [result] + var count = 0 + #if not isObjLackingTypeField(t) and not p.module.compileToCpp: + # addf(result, "{$1}", [genTypeInfo(p.module, t)]) + # inc count + getNullValueAuxT(p, t, t, t.n, n, result, count) + if p.module.compileToCpp: + result = "{$1}$n" % [result] proc genConstSimpleList(p: BProc, n: PNode): Rope = var length = sonsLen(n) @@ -2279,6 +2338,15 @@ proc genConstExpr(p: BProc, n: PNode): Rope = var t = skipTypes(n.typ, abstractInst) if t.kind == tySequence: result = genConstSeq(p, n, n.typ) + elif t.kind == tyProc and t.callConv == ccClosure and not n.sons.isNil and + n.sons[0].kind == nkNilLit and n.sons[1].kind == nkNilLit: + # this hack fixes issue that nkNilLit is expanded to {NIM_NIL,NIM_NIL} + # this behaviour is needed since closure_var = nil must be + # expanded to {NIM_NIL,NIM_NIL} + # in VM closures are initialized with nkPar(nkNilLit, nkNilLit) + # leading to duplicate code like this: + # "{NIM_NIL,NIM_NIL}, {NIM_NIL,NIM_NIL}" + result = ~"{NIM_NIL,NIM_NIL}" else: result = genConstSimpleList(p, n) of nkObjConstr: diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 378951d9d..8796dd729 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -164,11 +164,11 @@ proc genBreakState(p: BProc, n: PNode) = if n.sons[0].kind == nkClosure: # XXX this produces quite inefficient code! initLocExpr(p, n.sons[0].sons[1], a) - lineF(p, cpsStmts, "if (((NI*) $1)[0] < 0) break;$n", [rdLoc(a)]) + lineF(p, cpsStmts, "if (((NI*) $1)[1] < 0) break;$n", [rdLoc(a)]) else: initLocExpr(p, n.sons[0], a) - # the environment is guaranteed to contain the 'state' field at offset 0: - lineF(p, cpsStmts, "if ((((NI*) $1.ClE_0)[0]) < 0) break;$n", [rdLoc(a)]) + # the environment is guaranteed to contain the 'state' field at offset 1: + lineF(p, cpsStmts, "if ((((NI*) $1.ClE_0)[1]) < 0) break;$n", [rdLoc(a)]) # lineF(p, cpsStmts, "if (($1) < 0) break;$n", [rdLoc(a)]) proc genVarPrototypeAux(m: BModule, sym: PSym) diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim index 982f88cbd..fa228ff04 100644 --- a/compiler/ccgtrav.nim +++ b/compiler/ccgtrav.nim @@ -72,10 +72,16 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: Rope, typ: PType) = let arraySize = lengthOrd(typ.sons[0]) var i: TLoc getTemp(p, getSysType(tyInt), i) + let oldCode = p.s(cpsStmts) linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n", i.r, arraySize.rope) + let oldLen = p.s(cpsStmts).len genTraverseProc(c, rfmt(nil, "$1[$2]", accessor, i.r), typ.sons[1]) - lineF(p, cpsStmts, "}$n", []) + if p.s(cpsStmts).len == oldLen: + # do not emit dummy long loops for faster debug builds: + p.s(cpsStmts) = oldCode + else: + lineF(p, cpsStmts, "}$n", []) of tyObject: for i in countup(0, sonsLen(typ) - 1): var x = typ.sons[i] @@ -99,10 +105,16 @@ proc genTraverseProcSeq(c: var TTraversalClosure, accessor: Rope, typ: PType) = assert typ.kind == tySequence var i: TLoc getTemp(p, getSysType(tyInt), i) + let oldCode = p.s(cpsStmts) lineF(p, cpsStmts, "for ($1 = 0; $1 < $2->$3; $1++) {$n", [i.r, accessor, rope(if c.p.module.compileToCpp: "len" else: "Sup.len")]) + let oldLen = p.s(cpsStmts).len genTraverseProc(c, "$1->data[$2]" % [accessor, i.r], typ.sons[0]) - lineF(p, cpsStmts, "}$n", []) + if p.s(cpsStmts).len == oldLen: + # do not emit dummy long loops for faster debug builds: + p.s(cpsStmts) = oldCode + else: + lineF(p, cpsStmts, "}$n", []) proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash; reason: TTypeInfoReason): Rope = diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 0c81ca814..35d73aac0 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -12,6 +12,7 @@ # ------------------------- Name Mangling -------------------------------- import sighashes +from lowerings import createObj proc isKeyword(w: PIdent): bool = # Nim and C++ share some keywords @@ -122,10 +123,11 @@ const proc typeName(typ: PType): Rope = let typ = typ.skipTypes(irrelevantForBackend) - result = if typ.sym != nil and typ.kind in {tyObject, tyEnum}: - typ.sym.name.s.mangle.rope - else: - ~"TY" + result = + if typ.sym != nil and typ.kind in {tyObject, tyEnum}: + rope($typ.kind & '_' & typ.sym.name.s.mangle) + else: + rope($typ.kind) proc getTypeName(m: BModule; typ: PType; sig: SigHash): Rope = var t = typ @@ -335,6 +337,7 @@ proc getTypePre(m: BModule, typ: PType; sig: SigHash): Rope = if result == nil: result = cacheGetType(m.typeCache, sig) proc structOrUnion(t: PType): Rope = + let t = t.skipTypes({tyAlias}) (if tfUnion in t.flags: rope("union") else: rope("struct")) proc getForwardStructFormat(m: BModule): string = @@ -473,11 +476,14 @@ proc genRecordFieldsAux(m: BModule, n: PNode, if tfPacked notin rectype.flags: add(unionBody, "struct {") else: - addf(unionBody, CC[cCompiler].structStmtFmt, - [rope"struct", nil, rope(CC[cCompiler].packedPragma)]) - add(unionBody, "{") + if hasAttribute in CC[cCompiler].props: + add(unionBody, "struct __attribute__((__packed__)){" ) + else: + addf(unionBody, "#pragma pack(1)$nstruct{", []) add(unionBody, a) addf(unionBody, "} $1;$n", [sname]) + if tfPacked in rectype.flags and hasAttribute notin CC[cCompiler].props: + addf(unionBody, "#pragma pack(pop)$n", []) else: add(unionBody, genRecordFieldsAux(m, k, ae, rectype, check)) else: internalError("genRecordFieldsAux(record case branch)") @@ -524,12 +530,16 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope, # declare the record: var hasField = false - var attribute: Rope = - if tfPacked in typ.flags: rope(CC[cCompiler].packedPragma) - else: nil + if tfPacked in typ.flags: + if hasAttribute in CC[cCompiler].props: + result = structOrUnion(typ) & " __attribute__((__packed__))" + else: + result = "#pragma pack(1)" & tnl & structOrUnion(typ) + else: + result = structOrUnion(typ) - result = ropecg(m, CC[cCompiler].structStmtFmt, - [structOrUnion(typ), name, attribute]) + result.add " " + result.add name if typ.kind == tyObject: @@ -537,7 +547,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope, if (typ.sym != nil and sfPure in typ.sym.flags) or tfFinal in typ.flags: appcg(m, result, " {$n", []) else: - appcg(m, result, " {$n#TNimType* m_type;$n", [name, attribute]) + appcg(m, result, " {$n#TNimType* m_type;$n", []) hasField = true elif m.compileToCpp: appcg(m, result, " : public $1 {$n", @@ -556,6 +566,8 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope, else: add(result, desc) add(result, "};" & tnl) + if tfPacked in typ.flags and hasAttribute notin CC[cCompiler].props: + result.add "#pragma pack(pop)" & tnl proc getTupleDesc(m: BModule, typ: PType, name: Rope, check: var IntSet): Rope = @@ -787,7 +799,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = add(m.s[cfsTypes], recdesc) elif tfIncompleteStruct notin t.flags: addAbiCheck(m, t, result) of tySet: - result = getTypeName(m, t.lastSon, hashType t.lastSon) & "_Set" + result = $t.kind & '_' & getTypeName(m, t.lastSon, hashType t.lastSon) m.typeCache[sig] = result if not isImportedType(t): let s = int(getSize(t)) @@ -1083,7 +1095,8 @@ proc fakeClosureType(owner: PSym): PType = result = newType(tyTuple, owner) result.rawAddSon(newType(tyPointer, owner)) var r = newType(tyRef, owner) - r.rawAddSon(newType(tyTuple, owner)) + let obj = createObj(owner, owner.info, final=false) + r.rawAddSon(obj) result.rawAddSon(r) type diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 3797a92c2..b618837c7 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -209,7 +209,7 @@ proc genLineDir(p: BProc, t: PNode) = if ({optStackTrace, optEndb} * p.options == {optStackTrace, optEndb}) and (p.prc == nil or sfPure notin p.prc.flags): if freshLineInfo(p, tt.info): - linefmt(p, cpsStmts, "#endb($1, $2);$n", + linefmt(p, cpsStmts, "#endb($1, $2);$N", line.rope, makeCString(toFilename(tt.info))) elif ({optLineTrace, optStackTrace} * p.options == {optLineTrace, optStackTrace}) and @@ -345,6 +345,15 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) = result.flags = {} constructLoc(p, result, not needsInit) +proc getIntTemp(p: BProc, result: var TLoc) = + inc(p.labels) + result.r = "T" & rope(p.labels) & "_" + linefmt(p, cpsLocals, "NI $1;$n", result.r) + result.k = locTemp + result.s = OnStack + result.t = getSysType(tyInt) + result.flags = {} + proc initGCFrame(p: BProc): Rope = if p.gcFrameId > 0: result = "struct {$1} GCFRAME_;$n" % [p.gcFrameType] @@ -385,7 +394,8 @@ proc assignLocalVar(p: BProc, s: PSym) = #assert(s.loc.k == locNone) # not yet assigned # this need not be fulfilled for inline procs; they are regenerated # for each module that uses them! - let decl = localVarDecl(p, s) & ";" & tnl + let nl = if optLineDir in gOptions: "" else: tnl + let decl = localVarDecl(p, s) & ";" & nl line(p, cpsLocals, decl) localDebugInfo(p, s) @@ -618,11 +628,11 @@ proc initFrame(p: BProc, procname, filename: Rope): Rope = discard cgsym(p.module, "nimFrame") if p.maxFrameLen > 0: discard cgsym(p.module, "VarSlot") - result = rfmt(nil, "\tnimfrs_($1, $2, $3, $4)$N", + result = rfmt(nil, "\tnimfrs_($1, $2, $3, $4);$n", procname, filename, p.maxFrameLen.rope, p.blocks[0].frameLen.rope) else: - result = rfmt(nil, "\tnimfr_($1, $2)$N", procname, filename) + result = rfmt(nil, "\tnimfr_($1, $2);$n", procname, filename) proc deinitFrame(p: BProc): Rope = result = rfmt(p.module, "\t#popFrame();$n") @@ -1302,6 +1312,7 @@ proc myProcess(b: PPassContext, n: PNode): PNode = if b == nil or passes.skipCodegen(n): return var m = BModule(b) m.initProc.options = initProcOptions(m) + softRnl = if optLineDir in gOptions: noRnl else: rnl genStmts(m.initProc, n) proc finishModule(m: BModule) = diff --git a/compiler/commands.nim b/compiler/commands.nim index 22e4b5a2c..9781a8af4 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -207,7 +207,7 @@ proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool = of "generational": result = gSelectedGC == gcGenerational of "go": result = gSelectedGC == gcGo of "none": result = gSelectedGC == gcNone - of "stack": result = gSelectedGC == gcStack + of "stack", "regions": result = gSelectedGC == gcRegions else: localError(info, errNoneBoehmRefcExpectedButXFound, arg) of "opt": case arg.normalize @@ -429,9 +429,9 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "none": gSelectedGC = gcNone defineSymbol("nogc") - of "stack": - gSelectedGC= gcStack - defineSymbol("gcstack") + of "stack", "regions": + gSelectedGC= gcRegions + defineSymbol("gcregions") else: localError(info, errNoneBoehmRefcExpectedButXFound, arg) of "warnings", "w": if processOnOffSwitchOrList({optWarns}, arg, pass, info): listWarnings() @@ -454,6 +454,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "native", "gdb": incl(gGlobalOptions, optCDebug) gOptions = gOptions + {optLineDir} - {optEndb} + defineSymbol("nimTypeNames", nil) # type names are used in gdb pretty printing undefSymbol("endb") else: localError(info, "expected endb|gdb but found " & arg) diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index a4f47ac72..dc97e3648 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -41,7 +41,10 @@ proc isDefined*(symbol: string): bool = result = targetOS in {osLinux, osMorphos, osSkyos, osIrix, osPalmos, osQnx, osAtari, osAix, osHaiku, osVxWorks, osSolaris, osNetbsd, - osFreebsd, osOpenbsd, osDragonfly, osMacosx} + osFreebsd, osOpenbsd, osDragonfly, osMacosx, + osAndroid} + of "linux": + result = targetOS in {osLinux, osAndroid} of "bsd": result = targetOS in {osNetbsd, osFreebsd, osOpenbsd, osDragonfly} of "emulatedthreadvars": diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 26dd889ce..3f4f7b164 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -462,12 +462,14 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) = var path = n.info.toFullPath if path.startsWith(cwd): path = path[cwd.len+1 .. ^1].replace('\\', '/') - var commit = getConfigVar("git.commit") - if commit.len == 0: commit = "master" - dispA(seeSrcRope, "$1", "", [ropeFormatNamedVars(docItemSeeSrc, - ["path", "line", "url", "commit"], [rope path, - rope($n.info.line), rope getConfigVar("git.url"), - rope commit])]) + let gitUrl = getConfigVar("git.url") + if gitUrl.len > 0: + var commit = getConfigVar("git.commit") + if commit.len == 0: commit = "master" + dispA(seeSrcRope, "$1", "", [ropeFormatNamedVars(docItemSeeSrc, + ["path", "line", "url", "commit"], [rope path, + rope($n.info.line), rope gitUrl, + rope commit])]) add(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"), ["name", "header", "desc", "itemID", "header_plain", "itemSym", diff --git a/compiler/evalffi.nim b/compiler/evalffi.nim index 987cfaf42..6789df87d 100644 --- a/compiler/evalffi.nim +++ b/compiler/evalffi.nim @@ -104,9 +104,9 @@ proc mapCallConv(cc: TCallingConvention, info: TLineInfo): TABI = else: globalError(info, "cannot map calling convention to FFI") -template rd(T, p: expr): expr {.immediate.} = (cast[ptr T](p))[] -template wr(T, p, v: expr) {.immediate.} = (cast[ptr T](p))[] = v -template `+!`(x, y: expr): expr {.immediate.} = +template rd(T, p: untyped): untyped = (cast[ptr T](p))[] +template wr(T, p, v: untyped): untyped = (cast[ptr T](p))[] = v +template `+!`(x, y: untyped): untyped = cast[pointer](cast[ByteAddress](x) + y) proc packSize(v: PNode, typ: PType): int = @@ -171,7 +171,7 @@ const maxPackDepth = 20 var packRecCheck = 0 proc pack(v: PNode, typ: PType, res: pointer) = - template awr(T, v: expr) {.immediate, dirty.} = + template awr(T, v: untyped): untyped = wr(T, res, v) case typ.kind @@ -302,7 +302,7 @@ proc canonNodeKind(k: TNodeKind): TNodeKind = else: result = k proc unpack(x: pointer, typ: PType, n: PNode): PNode = - template aw(k, v, field: expr) {.immediate, dirty.} = + template aw(k, v, field: untyped): untyped = if n.isNil: result = newNode(k) result.typ = typ @@ -326,9 +326,9 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode = result.kind = nkNilLit result.typ = typ - template awi(kind, v: expr) {.immediate, dirty.} = aw(kind, v, intVal) - template awf(kind, v: expr) {.immediate, dirty.} = aw(kind, v, floatVal) - template aws(kind, v: expr) {.immediate, dirty.} = aw(kind, v, strVal) + template awi(kind, v: untyped): untyped = aw(kind, v, intVal) + template awf(kind, v: untyped): untyped = aw(kind, v, floatVal) + template aws(kind, v: untyped): untyped = aw(kind, v, strVal) case typ.kind of tyBool: awi(nkIntLit, rd(bool, x).ord) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index ca4f621e4..c47e4fb9a 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -53,7 +53,6 @@ type # used on some platforms asmStmtFrmt: string, # format of ASM statement structStmtFmt: string, # Format for struct statement - packedPragma: string, # Attribute/pragma to make struct packed (1-byte aligned) props: TInfoCCProps] # properties of the C compiler @@ -86,7 +85,6 @@ compiler gcc: pic: "-fPIC", asmStmtFrmt: "asm($1);$n", structStmtFmt: "$1 $3 $2 ", # struct|union [packed] $name - packedPragma: "__attribute__((__packed__))", props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm, hasAttribute}) @@ -129,7 +127,6 @@ compiler vcc: pic: "", asmStmtFrmt: "__asm{$n$1$n}$n", structStmtFmt: "$3$n$1 $2", - packedPragma: "#pragma pack(1)", props: {hasCpp, hasAssume, hasDeclspec}) # Intel C/C++ Compiler @@ -166,7 +163,6 @@ compiler lcc: pic: "", asmStmtFrmt: "_asm{$n$1$n}$n", structStmtFmt: "$1 $2", - packedPragma: "", # XXX: not supported yet props: {}) # Borland C Compiler @@ -191,7 +187,6 @@ compiler bcc: pic: "", asmStmtFrmt: "__asm{$n$1$n}$n", structStmtFmt: "$1 $2", - packedPragma: "", # XXX: not supported yet props: {hasCpp}) # Digital Mars C Compiler @@ -216,7 +211,6 @@ compiler dmc: pic: "", asmStmtFrmt: "__asm{$n$1$n}$n", structStmtFmt: "$3$n$1 $2", - packedPragma: "#pragma pack(1)", props: {hasCpp}) # Watcom C Compiler @@ -241,7 +235,6 @@ compiler wcc: pic: "", asmStmtFrmt: "__asm{$n$1$n}$n", structStmtFmt: "$1 $2", - packedPragma: "", # XXX: not supported yet props: {hasCpp}) # Tiny C Compiler @@ -266,7 +259,6 @@ compiler tcc: pic: "", asmStmtFrmt: "__asm{$n$1$n}$n", structStmtFmt: "$1 $2", - packedPragma: "", # XXX: not supported yet props: {hasSwitchRange, hasComputedGoto}) # Pelles C Compiler @@ -292,7 +284,6 @@ compiler pcc: pic: "", asmStmtFrmt: "__asm{$n$1$n}$n", structStmtFmt: "$1 $2", - packedPragma: "", # XXX: not supported yet props: {}) # Your C Compiler @@ -317,7 +308,6 @@ compiler ucc: pic: "", asmStmtFrmt: "__asm{$n$1$n}$n", structStmtFmt: "$1 $2", - packedPragma: "", # XXX: not supported yet props: {}) const @@ -687,11 +677,14 @@ proc getLinkCmd(projectfile, objfiles: string): string = exefile = quoteShell(exefile) let linkOptions = getLinkOptions() & " " & getConfigVar(cCompiler, ".options.linker") + var linkTmpl = getConfigVar(cCompiler, ".linkTmpl") + if linkTmpl.len == 0: + linkTmpl = CC[cCompiler].linkTmpl result = quoteShell(result % ["builddll", builddll, "buildgui", buildgui, "options", linkOptions, "objfiles", objfiles, "exefile", exefile, "nim", getPrefixDir(), "lib", libpath]) result.add ' ' - addf(result, CC[cCompiler].linkTmpl, ["builddll", builddll, + addf(result, linkTmpl, ["builddll", builddll, "buildgui", buildgui, "options", linkOptions, "objfiles", objfiles, "exefile", exefile, "nim", quoteShell(getPrefixDir()), diff --git a/compiler/installer.ini b/compiler/installer.ini index 8cc89da9f..8052121bf 100644 --- a/compiler/installer.ini +++ b/compiler/installer.ini @@ -6,7 +6,7 @@ Name: "Nim" Version: "$version" Platforms: """ windows: i386;amd64 - linux: i386;amd64;powerpc64;arm;sparc;mips;mipsel;powerpc;powerpc64el;arm64 + linux: i386;amd64;powerpc64;arm;sparc;mips;mipsel;mips64;mips64el;powerpc;powerpc64el;arm64 macosx: i386;amd64;powerpc64 solaris: i386;amd64;sparc;sparc64 freebsd: i386;amd64 @@ -14,6 +14,7 @@ Platforms: """ openbsd: i386;amd64 dragonfly: i386;amd64 haiku: i386;amd64 + android: i386;arm;arm64 """ Authors: "Andreas Rumpf" @@ -47,7 +48,7 @@ Start: "doc/html/overview.html" [Other] -Files: "readme.txt;copying.txt" +Files: "readme.txt;copying.txt;install.txt" Files: "makefile" Files: "koch.nim" Files: "install_nimble.nims" diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 46766cfcf..73e6a9948 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -2340,7 +2340,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = of nkPragma: genPragma(p, n) of nkProcDef, nkMethodDef, nkConverterDef: var s = n.sons[namePos].sym - if sfExportc in s.flags and compilingLib: + if {sfExportc, sfCompilerProc} * s.flags == {sfExportc}: genSym(p, n.sons[namePos], r) r.res = nil of nkGotoState, nkState: diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index cd2ccfe53..986d8c716 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -142,7 +142,7 @@ proc createStateField(iter: PSym): PSym = proc createEnvObj(owner: PSym; info: TLineInfo): PType = # YYY meh, just add the state field for every closure for now, it's too # hard to figure out if it comes from a closure iterator: - result = createObj(owner, info) + result = createObj(owner, info, final=false) rawAddField(result, createStateField(owner)) proc getIterResult(iter: PSym): PSym = diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index 4bd54603d..ce76b63a4 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -109,17 +109,19 @@ proc lowerSwap*(n: PNode; owner: PSym): PNode = result.add newFastAsgnStmt(n[1], n[2]) result.add newFastAsgnStmt(n[2], tempAsNode) -proc createObj*(owner: PSym, info: TLineInfo): PType = +proc createObj*(owner: PSym, info: TLineInfo; final=true): PType = result = newType(tyObject, owner) - rawAddSon(result, nil) - incl result.flags, tfFinal + if final: + rawAddSon(result, nil) + incl result.flags, tfFinal + else: + rawAddSon(result, getCompilerProc("RootObj").typ) result.n = newNodeI(nkRecList, info) - when true: - let s = newSym(skType, getIdent("Env_" & info.toFilename), - owner, info) - incl s.flags, sfAnon - s.typ = result - result.sym = s + let s = newSym(skType, getIdent("Env_" & info.toFilename), + owner, info) + incl s.flags, sfAnon + s.typ = result + result.sym = s proc rawAddField*(obj: PType; field: PSym) = assert field.kind == skField diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 5f4a0caf1..4a1166f51 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -746,7 +746,7 @@ proc toFileLine*(info: TLineInfo): string {.inline.} = result = info.toFilename & ":" & $info.line proc toFileLineCol*(info: TLineInfo): string {.inline.} = - result = info.toFilename & "(" & $info.line & "," & $info.col & ")" + result = info.toFilename & "(" & $info.line & ", " & $info.col & ")" proc `$`*(info: TLineInfo): string = toFileLineCol(info) diff --git a/compiler/nimblecmd.nim b/compiler/nimblecmd.nim index 5e6d843de..8042644b0 100644 --- a/compiler/nimblecmd.nim +++ b/compiler/nimblecmd.nim @@ -9,7 +9,7 @@ ## Implements some helper procs for Nimble (Nim's package manager) support. -import parseutils, strutils, strtabs, os, options, msgs +import parseutils, strutils, strtabs, os, options, msgs, sequtils proc addPath*(path: string, info: TLineInfo) = if not options.searchPaths.contains(path): @@ -21,51 +21,76 @@ proc versionSplitPos(s: string): int = while result > 1 and s[result] != '-': dec result if s[result] != '-': result = s.len -const - latest = "" - -proc `<.`(a, b: string): bool = - # wether a has a smaller version than b: - if a == latest: return true - elif b == latest: return false - var i = 0 - var j = 0 - var verA = 0 - var verB = 0 - while true: - let ii = parseInt(a, verA, i) - let jj = parseInt(b, verB, j) - if ii <= 0 or jj <= 0: - # if A has no number and B has but A has no number whatsoever ("#head"), - # A is preferred: - if ii > 0 and jj <= 0 and j == 0: return true - if ii <= 0 and jj > 0 and i == 0: return false - # if A has no number left, but B has, B is preferred: 0.8 vs 0.8.3 - return jj > 0 - if verA < verB: return true - elif verA > verB: return false - # else: same version number; continue: - inc i, ii - inc j, jj - if a[i] == '.': inc i - if b[j] == '.': inc j +type + Version = distinct string + +proc `$`(ver: Version): string {.borrow.} + +proc newVersion(ver: string): Version = + doAssert(ver.len == 0 or ver[0] in {'#', '\0'} + Digits, + "Wrong version: " & ver) + return Version(ver) + +proc isSpecial(ver: Version): bool = + return ($ver).len > 0 and ($ver)[0] == '#' + +proc `<`(ver: Version, ver2: Version): bool = + ## This is synced from Nimble's version module. + + # Handling for special versions such as "#head" or "#branch". + if ver.isSpecial or ver2.isSpecial: + if ver2.isSpecial and ($ver2).normalize == "#head": + return ($ver).normalize != "#head" + + if not ver2.isSpecial: + # `#aa111 < 1.1` + return ($ver).normalize != "#head" + + # Handling for normal versions such as "0.1.0" or "1.0". + var sVer = string(ver).split('.') + var sVer2 = string(ver2).split('.') + for i in 0..max(sVer.len, sVer2.len)-1: + var sVerI = 0 + if i < sVer.len: + discard parseInt(sVer[i], sVerI) + var sVerI2 = 0 + if i < sVer2.len: + discard parseInt(sVer2[i], sVerI2) + if sVerI < sVerI2: + return true + elif sVerI == sVerI2: + discard + else: + return false proc addPackage(packages: StringTableRef, p: string) = let x = versionSplitPos(p) let name = p.substr(0, x-1) - let version = if x < p.len: p.substr(x+1) else: "" - if packages.getOrDefault(name) <. version: - packages[name] = version + let version = newVersion(if x < p.len: p.substr(x+1) else: "") + if packages.getOrDefault(name).newVersion < version or + (not packages.hasKey(name)): + packages[name] = $version iterator chosen(packages: StringTableRef): string = for key, val in pairs(packages): - let res = if val == latest: key else: key & '-' & val + let res = if val.len == 0: key else: key & '-' & val yield res proc addNimblePath(p: string, info: TLineInfo) = - if not contains(options.searchPaths, p): - message(info, hintPath, p) - options.lazyPaths.insert(p, 0) + var path = p + let nimbleLinks = toSeq(walkPattern(p / "*.nimble-link")) + if nimbleLinks.len > 0: + # If the user has more than one .nimble-link file then... we just ignore it. + # Spec for these files is available in Nimble's readme: + # https://github.com/nim-lang/nimble#nimble-link + let nimbleLinkLines = readFile(nimbleLinks[0]).splitLines() + path = nimbleLinkLines[1] + if not path.isAbsolute(): + path = p / path + + if not contains(options.searchPaths, path): + message(info, hintPath, path) + options.lazyPaths.insert(path, 0) proc addPathRec(dir: string, info: TLineInfo) = var packages = newStringTable(modeStyleInsensitive) @@ -82,7 +107,17 @@ proc nimblePath*(path: string, info: TLineInfo) = addNimblePath(path, info) when isMainModule: + proc v(s: string): Version = s.newVersion + # #head is special in the sense that it's assumed to always be newest. + doAssert v"1.0" < v"#head" + doAssert v"1.0" < v"1.1" + doAssert v"1.0.1" < v"1.1" + doAssert v"1" < v"1.1" + doAssert v"#aaaqwe" < v"1.1" # We cannot assume that a branch is newer. + doAssert v"#a111" < v"#head" + var rr = newStringTable() + addPackage rr, "irc-#a111" addPackage rr, "irc-#head" addPackage rr, "irc-0.1.0" addPackage rr, "irc" @@ -93,5 +128,6 @@ when isMainModule: addPackage rr, "ab-0.1" addPackage rr, "justone" - for p in rr.chosen: - echo p + doAssert toSeq(rr.chosen) == + @["irc-#head", "another-0.1", "ab-0.1.3", "justone"] + diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index 808159b8f..c19b41af1 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -152,7 +152,7 @@ proc confTok(L: var TLexer, tok: var TToken; config: ConfigRef) = parseDirective(L, tok, config) # else: give the token to the parser proc checkSymbol(L: TLexer, tok: TToken) = - if tok.tokType notin {tkSymbol..pred(tkIntLit), tkStrLit..tkTripleStrLit}: + if tok.tokType notin {tkSymbol..tkInt64Lit, tkStrLit..tkTripleStrLit}: lexMessage(L, errIdentifierExpected, tokToStr(tok)) proc parseAssignment(L: var TLexer, tok: var TToken; config: ConfigRef) = diff --git a/compiler/options.nim b/compiler/options.nim index bf1b04c2c..40d56aea5 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -94,7 +94,7 @@ type cmdRun # run the project via TCC backend TStringSeq* = seq[string] TGCMode* = enum # the selected GC - gcNone, gcBoehm, gcGo, gcStack, gcMarkAndSweep, gcRefc, + gcNone, gcBoehm, gcGo, gcRegions, gcMarkAndSweep, gcRefc, gcV2, gcGenerational IdeCmd* = enum @@ -291,8 +291,8 @@ proc pathSubs*(p, config: string): string = "projectpath", options.gProjectPath, "projectdir", options.gProjectPath, "nimcache", getNimcacheDir()]) - if '~' in result: - result = result.replace("~", home) + if "~/" in result: + result = result.replace("~/", home & '/') proc toGeneratedFile*(path, ext: string): string = ## converts "/home/a/mymodule.nim", "rod" to "/home/a/nimcache/mymodule.rod" diff --git a/compiler/parser.nim b/compiler/parser.nim index 3cd1e4d92..253716247 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -685,6 +685,11 @@ proc namedParams(p: var TParser, callee: PNode, # progress guaranteed exprColonEqExprListAux(p, endTok, result) +proc commandParam(p: var TParser): PNode = + result = parseExpr(p) + if p.tok.tokType == tkDo: + result = postExprBlocks(p, result) + proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode = #| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks? #| | doBlocks @@ -733,7 +738,7 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode = when true: # progress NOT guaranteed p.hasProgress = false - addSon result, parseExpr(p) + addSon result, commandParam(p) if not p.hasProgress: break else: while p.tok.tokType != tkEof: @@ -1253,14 +1258,12 @@ proc parseExprStmt(p: var TParser): PNode = while true: getTok(p) optInd(p, result) - var e = parseExpr(p) - addSon(result, e) + addSon(result, commandParam(p)) if p.tok.tokType != tkComma: break elif p.tok.indent < 0 and isExprStart(p): result = newNode(nkCommand, a.info, @[a]) while true: - var e = parseExpr(p) - addSon(result, e) + addSon(result, commandParam(p)) if p.tok.tokType != tkComma: break getTok(p) optInd(p, result) diff --git a/compiler/passes.nim b/compiler/passes.nim index 7966ee88d..bf6ce1a0a 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -13,7 +13,7 @@ import strutils, options, ast, astalgo, llstream, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math, magicsys, nversion, - nimsets, syntaxes, times, rodread, idgen, modulegraphs + nimsets, syntaxes, times, rodread, idgen, modulegraphs, reorder type TPassContext* = object of RootObj # the pass's context @@ -202,7 +202,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream, if graph.stopCompile(): break var n = parseTopLevelStmt(p) if n.kind == nkEmpty: break - if sfNoForward in module.flags: + if {sfNoForward, sfReorder} * module.flags != {}: # read everything, no streaming possible var sl = newNodeI(nkStmtList, n.info) sl.add n @@ -210,6 +210,8 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream, var n = parseTopLevelStmt(p) if n.kind == nkEmpty: break sl.add n + if sfReorder in module.flags: + sl = reorder sl discard processTopLevelStmt(sl, a) break elif not processTopLevelStmt(n, a): break diff --git a/compiler/platform.nim b/compiler/platform.nim index eb0aca186..01ddba23e 100644 --- a/compiler/platform.nim +++ b/compiler/platform.nim @@ -21,8 +21,8 @@ type # conditionals to condsyms (end of module). osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris, osIrix, osNetbsd, osFreebsd, osOpenbsd, osDragonfly, osAix, osPalmos, osQnx, - osAmiga, osAtari, osNetware, osMacos, osMacosx, osHaiku, osVxworks, osGenode - osJS, osNimrodVM, osStandalone + osAmiga, osAtari, osNetware, osMacos, osMacosx, osHaiku, osAndroid, osVxworks + osGenode, osJS, osNimrodVM, osStandalone type TInfoOSProp* = enum @@ -143,6 +143,10 @@ const objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", props: {ospNeedsPIC, ospPosix, ospLacksThreadVars}), + (name: "Android", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", + objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", + scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", + props: {ospNeedsPIC, ospPosix}), (name: "VxWorks", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", objExt: ".o", newLine: "\x0A", pathSep: ";", dirSep: "\\", scriptExt: ".sh", curDir: ".", exeExt: ".vxe", extSep: ".", @@ -171,7 +175,8 @@ type # alias conditionals to condsyms (end of module). cpuNone, cpuI386, cpuM68k, cpuAlpha, cpuPowerpc, cpuPowerpc64, cpuPowerpc64el, cpuSparc, cpuVm, cpuIa64, cpuAmd64, cpuMips, cpuMipsel, - cpuArm, cpuArm64, cpuJS, cpuNimrodVM, cpuAVR, cpuMSP430, cpuSparc64 + cpuArm, cpuArm64, cpuJS, cpuNimrodVM, cpuAVR, cpuMSP430, cpuSparc64, + cpuMips64, cpuMips64el type TEndian* = enum @@ -200,7 +205,9 @@ const (name: "nimrodvm", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32), (name: "avr", intSize: 16, endian: littleEndian, floatSize: 32, bit: 16), (name: "msp430", intSize: 16, endian: littleEndian, floatSize: 32, bit: 16), - (name: "sparc64", intSize: 64, endian: bigEndian, floatSize: 64, bit: 64)] + (name: "sparc64", intSize: 64, endian: bigEndian, floatSize: 64, bit: 64), + (name: "mips64", intSize: 64, endian: bigEndian, floatSize: 64, bit: 64), + (name: "mips64el", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64)] var targetCPU*, hostCPU*: TSystemCPU diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 7e1db5b29..bc3771700 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -45,7 +45,7 @@ const wFatal, wDefine, wUndef, wCompile, wLink, wLinksys, wPure, wPush, wPop, wBreakpoint, wWatchPoint, wPassl, wPassc, wDeadCodeElim, wDeprecated, wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll, - wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto, + wLinearScanEnd, wPatterns, wEffects, wNoForward, wReorder, wComputedGoto, wInjectStmt, wDeprecated, wExperimental, wThis} lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl, wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader, @@ -210,9 +210,9 @@ proc pragmaDeadCodeElim(c: PContext, n: PNode) = if isTurnedOn(c, n): incl(c.module.flags, sfDeadCodeElim) else: excl(c.module.flags, sfDeadCodeElim) -proc pragmaNoForward(c: PContext, n: PNode) = - if isTurnedOn(c, n): incl(c.module.flags, sfNoForward) - else: excl(c.module.flags, sfNoForward) +proc pragmaNoForward(c: PContext, n: PNode; flag=sfNoForward) = + if isTurnedOn(c, n): incl(c.module.flags, flag) + else: excl(c.module.flags, flag) proc processCallConv(c: PContext, n: PNode) = if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent): @@ -726,6 +726,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, incl(sym.flags, sfThread) of wDeadCodeElim: pragmaDeadCodeElim(c, it) of wNoForward: pragmaNoForward(c, it) + of wReorder: pragmaNoForward(c, it, sfReorder) of wMagic: processMagic(c, it, sym) of wCompileTime: noVal(it) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 7d9536625..220693f68 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -1327,7 +1327,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = if n.hasExplicitParams: put(g, tkBracketLe, "[") - gcomma(g, n) + gsemicolon(g, n) put(g, tkBracketRi, "]") of nkFormalParams: put(g, tkParLe, "(") diff --git a/compiler/reorder.nim b/compiler/reorder.nim new file mode 100644 index 000000000..a9ad1fd97 --- /dev/null +++ b/compiler/reorder.nim @@ -0,0 +1,102 @@ + +import intsets, tables, ast, idents, renderer + +const + nfTempMark = nfTransf + nfPermMark = nfNoRewrite + +proc accQuoted(n: PNode): PIdent = + var id = "" + for i in 0 .. <n.len: + let x = n[i] + case x.kind + of nkIdent: id.add(x.ident.s) + of nkSym: id.add(x.sym.name.s) + else: discard + result = getIdent(id) + +proc addDecl(n: PNode; declares: var IntSet) = + case n.kind + of nkPostfix: addDecl(n[1], declares) + of nkPragmaExpr: addDecl(n[0], declares) + of nkIdent: + declares.incl n.ident.id + of nkSym: + declares.incl n.sym.name.id + of nkAccQuoted: + declares.incl accQuoted(n).id + else: discard + +proc computeDeps(n: PNode, declares, uses: var IntSet; topLevel: bool) = + template deps(n) = computeDeps(n, declares, uses, false) + template decl(n) = + if topLevel: addDecl(n, declares) + case n.kind + of procDefs: + decl(n[0]) + for i in 1..bodyPos: deps(n[i]) + of nkLetSection, nkVarSection, nkUsingStmt: + for a in n: + if a.kind in {nkIdentDefs, nkVarTuple}: + for j in countup(0, a.len-3): decl(a[j]) + for j in a.len-2..a.len-1: deps(a[j]) + of nkConstSection, nkTypeSection: + for a in n: + if a.len >= 3: + decl(a[0]) + for i in 1..<a.len: deps(a[i]) + of nkIdent: uses.incl n.ident.id + of nkSym: uses.incl n.sym.name.id + of nkAccQuoted: uses.incl accQuoted(n).id + of nkOpenSymChoice, nkClosedSymChoice: + uses.incl n.sons[0].sym.name.id + of nkStmtList, nkStmtListExpr, nkWhenStmt, nkElifBranch, nkElse: + for i in 0..<len(n): computeDeps(n[i], declares, uses, topLevel) + else: + for i in 0..<safeLen(n): deps(n[i]) + +proc visit(i: int; all, res: PNode; deps: var seq[(IntSet, IntSet)]): bool = + let n = all[i] + if nfTempMark in n.flags: + # not a DAG! + return true + if nfPermMark notin n.flags: + incl n.flags, nfTempMark + var uses = deps[i][1] + for j in 0..<all.len: + if j != i: + let declares = deps[j][0] + for d in declares: + if uses.contains(d): + let oldLen = res.len + if visit(j, all, res, deps): + result = true + # rollback what we did, it turned out to be a dependency that caused + # trouble: + for k in oldLen..<res.len: + res.sons[k].flags = res.sons[k].flags - {nfPermMark, nfTempMark} + if oldLen != res.len: res.sons.setLen oldLen + break + n.flags = n.flags + {nfPermMark} - {nfTempMark} + res.add n + +proc reorder*(n: PNode): PNode = + result = newNodeI(nkStmtList, n.info) + var deps = newSeq[(IntSet, IntSet)](n.len) + for i in 0..<n.len: + deps[i][0] = initIntSet() + deps[i][1] = initIntSet() + computeDeps(n[i], deps[i][0], deps[i][1], true) + + for i in 0 .. n.len-1: + discard visit(i, n, result, deps) + for i in 0..<result.len: + result.sons[i].flags = result.sons[i].flags - {nfTempMark, nfPermMark} + when false: + # reverse the result: + let L = result.len-1 + for i in 0 .. result.len div 2: + result.sons[i].flags = result.sons[i].flags - {nfTempMark, nfPermMark} + result.sons[L - i].flags = result.sons[L - i].flags - {nfTempMark, nfPermMark} + swap(result.sons[i], result.sons[L - i]) + #echo result diff --git a/compiler/ropes.nim b/compiler/ropes.nim index d84b59f78..358ce8a53 100644 --- a/compiler/ropes.nim +++ b/compiler/ropes.nim @@ -228,6 +228,7 @@ proc prepend*(a: var Rope, b: string) = a = b & a var rnl* = tnl.newRope softRnl* = tnl.newRope + noRnl* = "".newRope proc `%`*(frmt: FormatStr, args: openArray[Rope]): Rope = var i = 0 diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 5f48e2fc5..74b074f61 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -47,11 +47,9 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = #raiseRecoverableError("") result = errorNode(c, n) if result.typ == nil or result.typ == enforceVoidContext: - if n.kind != nkStmtList: - # we cannot check for 'void' in macros ... - localError(n.info, errExprXHasNoType, - renderTree(result, {renderNoComments})) - result.typ = errorType(c) + localError(n.info, errExprXHasNoType, + renderTree(result, {renderNoComments})) + result.typ = errorType(c) else: if efNoProcvarCheck notin flags: semProcvarCheck(c, result) if result.typ.kind == tyVar: result = newDeref(result) @@ -276,41 +274,6 @@ proc semSizeof(c: PContext, n: PNode): PNode = n.typ = getSysType(tyInt) result = n -proc semOf(c: PContext, n: PNode): PNode = - if sonsLen(n) == 3: - n.sons[1] = semExprWithType(c, n.sons[1]) - n.sons[2] = semExprWithType(c, n.sons[2], {efDetermineType}) - #restoreOldStyleType(n.sons[1]) - #restoreOldStyleType(n.sons[2]) - let a = skipTypes(n.sons[1].typ, abstractPtrs) - let b = skipTypes(n.sons[2].typ, abstractPtrs) - let x = skipTypes(n.sons[1].typ, abstractPtrs-{tyTypeDesc}) - let y = skipTypes(n.sons[2].typ, abstractPtrs-{tyTypeDesc}) - - if x.kind == tyTypeDesc or y.kind != tyTypeDesc: - localError(n.info, errXExpectsObjectTypes, "of") - elif b.kind != tyObject or a.kind != tyObject: - localError(n.info, errXExpectsObjectTypes, "of") - else: - let diff = inheritanceDiff(a, b) - # | returns: 0 iff `a` == `b` - # | returns: -x iff `a` is the x'th direct superclass of `b` - # | returns: +x iff `a` is the x'th direct subclass of `b` - # | returns: `maxint` iff `a` and `b` are not compatible at all - if diff <= 0: - # optimize to true: - message(n.info, hintConditionAlwaysTrue, renderTree(n)) - result = newIntNode(nkIntLit, 1) - result.info = n.info - result.typ = getSysType(tyBool) - return result - elif diff == high(int): - localError(n.info, errXcanNeverBeOfThisSubtype, typeToString(a)) - else: - localError(n.info, errXExpectsTwoArguments, "of") - n.typ = getSysType(tyBool) - result = n - proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode = internalAssert n.sonsLen == 3 and n[1].typ != nil and n[1].typ.kind == tyTypeDesc and @@ -1121,9 +1084,11 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = if ty.n != nil and ty.n.kind == nkRecList: let field = lookupInRecord(ty.n, i) if field != nil: - n.typ = newTypeWithSons(c, tyFieldAccessor, @[ty, field.typ]) - n.typ.n = copyTree(n) + n.typ = makeTypeDesc(c, field.typ) return n + #n.typ = newTypeWithSons(c, tyFieldAccessor, @[ty, field.typ]) + #n.typ.n = copyTree(n) + #return n else: tryReadingGenericParam(ty) return @@ -1490,6 +1455,9 @@ proc semYieldVarResult(c: PContext, n: PNode, restype: PType) = var t = skipTypes(restype, {tyGenericInst, tyAlias}) case t.kind of tyVar: + if n.sons[0].kind in {nkHiddenStdConv, nkHiddenSubConv}: + n.sons[0] = n.sons[0].sons[1] + n.sons[0] = takeImplicitAddr(c, n.sons[0]) of tyTuple: for i in 0.. <t.sonsLen: @@ -1829,11 +1797,11 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = of mDefined: result = semDefined(c, setMs(n, s), false) of mDefinedInScope: result = semDefined(c, setMs(n, s), true) of mCompiles: result = semCompiles(c, setMs(n, s), flags) - of mLow: result = semLowHigh(c, setMs(n, s), mLow) - of mHigh: result = semLowHigh(c, setMs(n, s), mHigh) + #of mLow: result = semLowHigh(c, setMs(n, s), mLow) + #of mHigh: result = semLowHigh(c, setMs(n, s), mHigh) of mSizeOf: result = semSizeof(c, setMs(n, s)) of mIs: result = semIs(c, setMs(n, s), flags) - of mOf: result = semOf(c, setMs(n, s)) + #of mOf: result = semOf(c, setMs(n, s)) of mShallowCopy: result = semShallowCopy(c, n, flags) of mExpandToAst: result = semExpandToAst(c, n, s, flags) of mQuoteAst: result = semQuoteAst(c, n) @@ -2207,9 +2175,14 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = message(n.info, warnDeprecated, "bind") result = semExpr(c, n.sons[0], flags) of nkTypeOfExpr, nkTupleTy, nkTupleClassTy, nkRefTy..nkEnumTy, nkStaticTy: + if c.matchedConcept != nil and n.len == 1: + let modifier = n.modifierTypeKindOfNode + if modifier != tyNone: + var baseType = semExpr(c, n[0]).typ.skipTypes({tyTypeDesc}) + result.typ = c.makeTypeDesc(c.newTypeWithSons(modifier, @[baseType])) + return var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc}) result.typ = makeTypeDesc(c, typ) - #result = symNodeFromType(c, typ, n.info) of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: # check if it is an expression macro: checkMinSonsLen(n, 1) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index c664f735c..8b3d9c014 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -200,6 +200,41 @@ proc isStrangeArray(t: PType): bool = let t = t.skipTypes(abstractInst) result = t.kind == tyArray and t.firstOrd != 0 +proc semOf(c: PContext, n: PNode): PNode = + if sonsLen(n) == 3: + n.sons[1] = semExprWithType(c, n.sons[1]) + n.sons[2] = semExprWithType(c, n.sons[2], {efDetermineType}) + #restoreOldStyleType(n.sons[1]) + #restoreOldStyleType(n.sons[2]) + let a = skipTypes(n.sons[1].typ, abstractPtrs) + let b = skipTypes(n.sons[2].typ, abstractPtrs) + let x = skipTypes(n.sons[1].typ, abstractPtrs-{tyTypeDesc}) + let y = skipTypes(n.sons[2].typ, abstractPtrs-{tyTypeDesc}) + + if x.kind == tyTypeDesc or y.kind != tyTypeDesc: + localError(n.info, errXExpectsObjectTypes, "of") + elif b.kind != tyObject or a.kind != tyObject: + localError(n.info, errXExpectsObjectTypes, "of") + else: + let diff = inheritanceDiff(a, b) + # | returns: 0 iff `a` == `b` + # | returns: -x iff `a` is the x'th direct superclass of `b` + # | returns: +x iff `a` is the x'th direct subclass of `b` + # | returns: `maxint` iff `a` and `b` are not compatible at all + if diff <= 0: + # optimize to true: + message(n.info, hintConditionAlwaysTrue, renderTree(n)) + result = newIntNode(nkIntLit, 1) + result.info = n.info + result.typ = getSysType(tyBool) + return result + elif diff == high(int): + localError(n.info, errXcanNeverBeOfThisSubtype, typeToString(a)) + else: + localError(n.info, errXExpectsTwoArguments, "of") + n.typ = getSysType(tyBool) + result = n + proc magicsAfterOverloadResolution(c: PContext, n: PNode, flags: TExprFlags): PNode = case n[0].sym.magic @@ -219,6 +254,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, result.typ = getSysType(tyString) of mInstantiationInfo: result = semInstantiationInfo(c, n) of mOrd: result = semOrd(c, n) + of mOf: result = semOf(c, n) of mHigh, mLow: result = semLowHigh(c, n, n[0].sym.magic) of mShallowCopy: result = semShallowCopy(c, n, flags) of mNBindSym: result = semBindSym(c, n) diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index f4c225526..b331d05a1 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -44,7 +44,9 @@ proc locateFieldInInitExpr(field: PSym, initExpr: PNode): PNode = let fieldId = field.name.id for i in 1 .. <initExpr.len: let assignment = initExpr[i] - internalAssert assignment.kind == nkExprColonExpr + if assignment.kind != nkExprColonExpr: + localError(initExpr.info, "incorrect object construction syntax") + continue if fieldId == considerQuotedIdent(assignment[0]).id: return assignment @@ -278,6 +280,9 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = for i in 1.. <result.len: let field = result[i] if nfSem notin field.flags: + if field.kind != nkExprColonExpr: + localError(n.info, "incorrect object construction syntax") + continue let id = considerQuotedIdent(field[0]) # This node was not processed. There are two possible reasons: # 1) It was shadowed by a field with the same name on the left diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 5ac2e678a..8ad8a6288 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -12,14 +12,14 @@ discard """ hygienic templates: - template `||` (a, b: expr): expr = + template `||` (a, b: untyped): untyped = let aa = a if aa: aa else: b var a, b: T - a || b || a + echo a || b || a Each evaluation context has to be different and we need to perform some form of preliminary symbol lookup in template definitions. Hygiene is diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index de71f1632..a7c9244cc 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1202,6 +1202,15 @@ proc freshType(res, prev: PType): PType {.inline.} = else: result = res +template modifierTypeKindOfNode(n: PNode): TTypeKind = + case n.kind + of nkVarTy: tyVar + of nkRefTy: tyRef + of nkPtrTy: tyPtr + of nkStaticTy: tyStatic + of nkTypeOfExpr: tyTypeDesc + else: tyNone + proc semTypeClass(c: PContext, n: PNode, prev: PType): PType = # if n.sonsLen == 0: return newConstraint(c, tyTypeClass) if nfBase2 in n.flags: @@ -1227,13 +1236,7 @@ proc semTypeClass(c: PContext, n: PNode, prev: PType): PType = dummyName: PNode dummyType: PType - let modifier = case param.kind - of nkVarTy: tyVar - of nkRefTy: tyRef - of nkPtrTy: tyPtr - of nkStaticTy: tyStatic - of nkTypeOfExpr: tyTypeDesc - else: tyNone + let modifier = param.modifierTypeKindOfNode if modifier != tyNone: dummyName = param[0] @@ -1509,9 +1512,26 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = dec c.inTypeContext proc setMagicType(m: PSym, kind: TTypeKind, size: int) = + # source : https://en.wikipedia.org/wiki/Data_structure_alignment#x86 m.typ.kind = kind - m.typ.align = size.int16 m.typ.size = size + # this usually works for most basic types + # Assuming that since ARM, ARM64 don't support unaligned access + # data is aligned to type size + m.typ.align = size.int16 + + # FIXME: proper support for clongdouble should be added. + # long double size can be 8, 10, 12, 16 bytes depending on platform & compiler + if targetCPU == cpuI386 and size == 8: + #on Linux/BSD i386, double are aligned to 4bytes (except with -malign-double) + if kind in {tyFloat64, tyFloat} and + targetOS in {osLinux, osAndroid, osNetbsd, osFreebsd, osOpenbsd, osDragonfly}: + m.typ.align = 4 + # on i386, all known compiler, 64bits ints are aligned to 4bytes (except with -malign-double) + elif kind in {tyInt, tyUInt, tyInt64, tyUInt64}: + m.typ.align = 4 + else: + discard proc processMagicType(c: PContext, m: PSym) = case m.magic diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 6084e11c0..41596f05c 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -297,7 +297,9 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1; n.sons[i].typ = arg.typ n.sons[i].sons[1] = arg else: - if arg.typ.isNil and arg.kind notin {nkStmtList, nkDo}: + if arg.typ.isNil and arg.kind notin {nkStmtList, nkDo, nkElse, + nkOfBranch, nkElifBranch, + nkExceptBranch}: arg = c.semOperand(c, n.sons[i]) n.sons[i] = arg if arg.typ != nil and arg.typ.kind == tyError: return diff --git a/compiler/testability.nim b/compiler/testability.nim deleted file mode 100644 index 4587a5344..000000000 --- a/compiler/testability.nim +++ /dev/null @@ -1,5 +0,0 @@ -template tests*(body: stmt) {.immediate.} = - when defined(selftest): - when not declared(unittest): import unittest - body - diff --git a/compiler/vm.nim b/compiler/vm.nim index b8e6467b5..93cf66c05 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -409,6 +409,28 @@ proc recSetFlagIsRef(arg: PNode) = for i in 0 ..< arg.safeLen: arg.sons[i].recSetFlagIsRef +proc setLenSeq(c: PCtx; node: PNode; newLen: int; info: TLineInfo) = + # FIXME: this doesn't attempt to solve incomplete + # support of tyPtr, tyRef in VM. + let typ = node.typ.skipTypes(abstractInst+{tyRange}-{tyTypeDesc}) + let typeEntry = typ.sons[0].skipTypes(abstractInst+{tyRange}-{tyTypeDesc}) + let typeKind = case typeEntry.kind + of tyUInt..tyUInt64: nkUIntLit + of tyRange, tyEnum, tyBool, tyChar, tyInt..tyInt64: nkIntLit + of tyFloat..tyFloat128: nkFloatLit + of tyString: nkStrLit + of tyObject: nkObjConstr + of tySequence: nkNilLit + of tyProc, tyTuple: nkPar + else: nkEmpty + + let oldLen = node.len + setLen(node.sons, newLen) + if oldLen < newLen: + # TODO: This is still not correct for tyPtr, tyRef default value + for i in oldLen .. <newLen: + node.sons[i] = newNodeI(typeKind, info) + proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = var pc = start var tos = tos @@ -1118,14 +1140,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = decodeB(rkNode) let newLen = regs[rb].intVal.int if regs[ra].node.isNil: stackTrace(c, tos, pc, errNilAccess) - else: - let oldLen = regs[ra].node.len - setLen(regs[ra].node.sons, newLen) - if oldLen < newLen: - # XXX This is still not entirely correct - # set to default value: - for i in oldLen .. <newLen: - regs[ra].node.sons[i] = newNodeI(nkEmpty, c.debug[pc]) + else: c.setLenSeq(regs[ra].node, newLen, c.debug[pc]) of opcReset: internalError(c.debug[pc], "too implement") of opcNarrowS: @@ -1307,12 +1322,24 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = ensureKind(rkNode) if c.callsite != nil: regs[ra].node = c.callsite else: stackTrace(c, tos, pc, errFieldXNotFound, "callsite") - of opcNLineInfo: + of opcNGetFile: decodeB(rkNode) let n = regs[rb].node - createStr regs[ra] - regs[ra].node.strVal = n.info.toFileLineCol - regs[ra].node.info = c.debug[pc] + regs[ra].node = newStrNode(nkStrLit, n.info.toFilename) + regs[ra].node.info = n.info + regs[ra].node.typ = n.typ + of opcNGetLine: + decodeB(rkNode) + let n = regs[rb].node + regs[ra].node = newIntNode(nkIntLit, n.info.line) + regs[ra].node.info = n.info + regs[ra].node.typ = n.typ + of opcNGetColumn: + decodeB(rkNode) + let n = regs[rb].node + regs[ra].node = newIntNode(nkIntLit, n.info.col) + regs[ra].node.info = n.info + regs[ra].node.typ = n.typ of opcEqIdent: decodeBC(rkInt) if regs[rb].node.kind == nkIdent and regs[rc].node.kind == nkIdent: @@ -1471,6 +1498,17 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = createStrKeepNode(regs[ra]) if regs[ra].node.strVal.isNil: regs[ra].node.strVal = newStringOfCap(1000) storeAny(regs[ra].node.strVal, typ, regs[rb].regToNode) + of opcToNarrowInt: + decodeBC(rkInt) + let mask = (1'i64 shl rc) - 1 # 0xFF + let signbit = 1'i64 shl (rc - 1) # 0x80 + let toggle = mask - signbit # 0x7F + # algorithm: -((i8 and 0xFF) xor 0x7F) + 0x7F + # mask off higher bits. + # uses two's complement to sign-extend integer. + # reajust integer into desired range. + regs[ra].intVal = -((regs[rb].intVal and mask) xor toggle) + toggle + inc pc proc execute(c: PCtx, start: int): PNode = diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 263ec8378..7e1309e0a 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -98,7 +98,7 @@ type opcNError, opcNWarning, opcNHint, - opcNLineInfo, + opcNGetLine, opcNGetColumn, opcNGetFile, opcEqIdent, opcStrToIdent, opcIdentToStr, @@ -136,7 +136,8 @@ type opcNBindSym, opcSetType, # dest.typ = types[Bx] opcTypeTrait, - opcMarshalLoad, opcMarshalStore + opcMarshalLoad, opcMarshalStore, + opcToNarrowInt TBlock* = object label*: PSym diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index b2b1ec92b..b9bbba551 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -224,12 +224,13 @@ proc mapTypeToAstX(t: PType; info: TLineInfo; result.add copyTree(c) of tyTuple: if inst: - result = newNodeX(nkTupleTy) # only named tuples have a node, unnamed tuples don't if t.n.isNil: + result = newNodeX(nkPar) for subType in t.sons: result.add mapTypeToAst(subType, info) else: + result = newNodeX(nkTupleTy) for s in t.n.sons: result.add newIdentDefs(s) else: diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index ba89f88d4..dbb8c9dcd 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -656,16 +656,17 @@ proc genNarrow(c: PCtx; n: PNode; dest: TDest) = let t = skipTypes(n.typ, abstractVar-{tyTypeDesc}) # uint is uint64 in the VM, we we only need to mask the result for # other unsigned types: - if t.kind in {tyUInt8..tyUInt32}: + if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and t.size < 8): c.gABC(n, opcNarrowU, dest, TRegister(t.size*8)) - elif t.kind in {tyInt8..tyInt32}: + elif t.kind in {tyInt8..tyInt32} or (t.kind == tyInt and t.size < 8): c.gABC(n, opcNarrowS, dest, TRegister(t.size*8)) proc genNarrowU(c: PCtx; n: PNode; dest: TDest) = let t = skipTypes(n.typ, abstractVar-{tyTypeDesc}) # uint is uint64 in the VM, we we only need to mask the result for # other unsigned types: - if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32}: + if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32} or + (t.kind in {tyUInt, tyInt} and t.size < 8): c.gABC(n, opcNarrowU, dest, TRegister(t.size*8)) proc genBinaryABCnarrow(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) = @@ -875,11 +876,25 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = of mBitnotI: genUnaryABC(c, n, dest, opcBitnotInt) genNarrowU(c, n, dest) - of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, - mToU8, mToU16, mToU32, mToFloat, mToBiggestFloat, mToInt, + of mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr: genConv(c, n, n.sons[1], dest) + of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64: + #genNarrowU modified + let t = skipTypes(n.sons[1].typ, abstractVar-{tyTypeDesc}) + let tmp = c.genx(n.sons[1]) + c.gABC(n, opcNarrowU, tmp, TRegister(t.size*8)) + # assign result to dest register + if dest < 0: dest = c.getTemp(n.typ) + c.gABC(n, opcAsgnInt, dest, tmp) + c.freeTemp(tmp) + of mToU8, mToU16, mToU32: + let t = skipTypes(n.typ, abstractVar-{tyTypeDesc}) + var tmp = c.genx(n.sons[1]) + if dest < 0: dest = c.getTemp(n.typ) + c.gABC(n, opcToNarrowInt, dest, tmp, TRegister(t.size*8)) + c.freeTemp(tmp) of mEqStr, mEqCString: genBinaryABC(c, n, dest, opcEqStr) of mLeStr: genBinaryABC(c, n, dest, opcLeStr) of mLtStr: genBinaryABC(c, n, dest, opcLtStr) @@ -1071,7 +1086,16 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = of mEqIdent: genBinaryABC(c, n, dest, opcEqIdent) of mEqNimrodNode: genBinaryABC(c, n, dest, opcEqNimrodNode) of mSameNodeType: genBinaryABC(c, n, dest, opcSameNodeType) - of mNLineInfo: genUnaryABC(c, n, dest, opcNLineInfo) + of mNLineInfo: + case n[0].sym.name.s + of "getFile": + genUnaryABC(c, n, dest, opcNGetFile) + of "getLine": + genUnaryABC(c, n, dest, opcNGetLine) + of "getColumn": + genUnaryABC(c, n, dest, opcNGetColumn) + else: + internalAssert false of mNHint: unused(n, dest) genUnaryStmt(c, n, opcNHint) diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 98fd912d8..773ab8ff5 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -55,7 +55,7 @@ type wFloatchecks, wNanChecks, wInfChecks, wAssertions, wPatterns, wWarnings, wHints, wOptimization, wRaises, wWrites, wReads, wSize, wEffects, wTags, - wDeadCodeElim, wSafecode, wNoForward, wNoRewrite, + wDeadCodeElim, wSafecode, wNoForward, wReorder, wNoRewrite, wPragma, wCompileTime, wNoInit, wPassc, wPassl, wBorrow, wDiscardable, @@ -143,7 +143,7 @@ const "assertions", "patterns", "warnings", "hints", "optimization", "raises", "writes", "reads", "size", "effects", "tags", - "deadcodeelim", "safecode", "noforward", "norewrite", + "deadcodeelim", "safecode", "noforward", "reorder", "norewrite", "pragma", "compiletime", "noinit", "passc", "passl", "borrow", "discardable", "fieldchecks", |