diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ast.nim | 3 | ||||
-rw-r--r-- | compiler/ccgexprs.nim | 61 | ||||
-rw-r--r-- | compiler/ccgstmts.nim | 9 | ||||
-rw-r--r-- | compiler/ccgtypes.nim | 10 | ||||
-rw-r--r-- | compiler/cgen.nim | 30 | ||||
-rw-r--r-- | compiler/cgendata.nim | 2 | ||||
-rw-r--r-- | compiler/cgmeth.nim | 9 | ||||
-rw-r--r-- | compiler/extccomp.nim | 37 | ||||
-rw-r--r-- | compiler/jsgen.nim | 37 | ||||
-rw-r--r-- | compiler/jstypes.nim | 2 | ||||
-rw-r--r-- | compiler/lowerings.nim | 68 | ||||
-rw-r--r-- | compiler/nimblecmd.nim | 41 | ||||
-rw-r--r-- | compiler/options.nim | 3 | ||||
-rw-r--r-- | compiler/parser.nim | 5 | ||||
-rw-r--r-- | compiler/semexprs.nim | 6 | ||||
-rw-r--r-- | compiler/sempass2.nim | 6 | ||||
-rw-r--r-- | compiler/trees.nim | 2 | ||||
-rw-r--r-- | compiler/vm.nim | 10 | ||||
-rw-r--r-- | compiler/vmdeps.nim | 7 |
19 files changed, 241 insertions, 107 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 5b68e9712..487b5d1a7 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -741,6 +741,8 @@ type OnUnknown, # location is unknown (stack, heap or static) OnStatic, # in a static section OnStack, # location is on hardware stack + OnStackShadowDup, # location is on the stack but also replicated + # on the shadow stack OnHeap # location is on heap or global # (reference counting needed) TLocFlags* = set[TLocFlag] @@ -750,6 +752,7 @@ type flags*: TLocFlags # location's flags t*: PType # type of location r*: Rope # rope value of location (code generators) + dup*: Rope # duplicated location for precise stack scans # ---------------- end of backend information ------------------------------ diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index f981f9595..b32f4b66b 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -132,32 +132,12 @@ proc genSetNode(p: BProc, n: PNode): Rope = else: result = genRawSetData(cs, size) -proc getStorageLoc(n: PNode): TStorageLoc = - case n.kind - of nkSym: - case n.sym.kind - of skParam, skTemp: - result = OnStack - of skVar, skForVar, skResult, skLet: - if sfGlobal in n.sym.flags: result = OnHeap - else: result = OnStack - of skConst: - if sfGlobal in n.sym.flags: result = OnHeap - else: result = OnUnknown - else: result = OnUnknown - of nkDerefExpr, nkHiddenDeref: - case n.sons[0].typ.kind - of tyVar: result = OnUnknown - of tyPtr: result = OnStack - of tyRef: result = OnHeap - else: internalError(n.info, "getStorageLoc") - of nkBracketExpr, nkDotExpr, nkObjDownConv, nkObjUpConv: - result = getStorageLoc(n.sons[0]) - else: result = OnUnknown - proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = if dest.s == OnStack or not usesNativeGC(): linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src)) + elif dest.s == OnStackShadowDup: + linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src)) + linefmt(p, cpsStmts, "$1 = $2;$n", dupLoc(dest), rdLoc(src)) elif dest.s == OnHeap: # location is on heap # now the writer barrier is inlined for performance: @@ -184,6 +164,8 @@ proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = else: linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, $2);$n", addrLoc(dest), rdLoc(src)) + if preciseStack(): + linefmt(p, cpsStmts, "$1 = $2;$n", dupLoc(dest), rdLoc(src)) proc asgnComplexity(n: PNode): int = if n != nil: @@ -241,7 +223,7 @@ proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags, proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = # Consider: - # type TMyFastString {.shallow.} = string + # type MyFastString {.shallow.} = string # Due to the implementation of pragmas this would end up to set the # tfShallow flag for the built-in string type too! So we check only # here for this flag, where it is reasonably safe to do so @@ -259,6 +241,9 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = else: linefmt(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n", addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)) + if dest.s == OnStackShadowDup: + linefmt(p, cpsStmts, "#genericAssignDup((void*)&$1, (void*)$2, $3);$n", + dupLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)) proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = # This function replaces all other methods for generating @@ -277,12 +262,17 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = else: linefmt(p, cpsStmts, "#genericSeqAssign($1, $2, $3);$n", addrLoc(dest), rdLoc(src), genTypeInfo(p.module, dest.t)) + if dest.s == OnStackShadowDup: + linefmt(p, cpsStmts, "$1 = $2;$n", dest.dupLoc, dest.rdLoc) of tyString: if needToCopy notin flags and src.s != OnStatic: genRefAssign(p, dest, src, flags) else: if dest.s == OnStack or not usesNativeGC(): linefmt(p, cpsStmts, "$1 = #copyString($2);$n", dest.rdLoc, src.rdLoc) + elif dest.s == OnStackShadowDup: + linefmt(p, cpsStmts, "$1 = #copyString($2);$n", dest.rdLoc, src.rdLoc) + linefmt(p, cpsStmts, "$1 = $2;$n", dest.dupLoc, dest.rdLoc) elif dest.s == OnHeap: # we use a temporary to care for the dreaded self assignment: var tmp: TLoc @@ -293,6 +283,8 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = else: linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, #copyString($2));$n", addrLoc(dest), rdLoc(src)) + if preciseStack(): + linefmt(p, cpsStmts, "$1 = $2;$n", dest.dupLoc, dest.rdLoc) of tyProc: if needsComplexAssignment(dest.t): # optimize closure assignment: @@ -738,6 +730,9 @@ proc genTupleElem(p: BProc, e: PNode, d: var TLoc) = else: internalError(e.info, "genTupleElem") addf(r, ".Field$1", [rope(i)]) putIntoDest(p, d, tupType.sons[i], r, a.s) + if a.s == OnStackShadowDup: + d.s = OnStackShadowDup + d.dup = ropef("$1[$2]", a.dup, ithRefInTuple(tupType, i)) proc lookupFieldAgain(p: BProc, ty: PType; field: PSym; r: var Rope): PSym = var ty = ty @@ -762,12 +757,18 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) = # so we use Field$i addf(r, ".Field$1", [rope(f.position)]) putIntoDest(p, d, f.typ, r, a.s) + if a.s == OnStackShadowDup: + d.s = OnStackShadowDup + d.dup = ropef("$1[$2]", a.dup, ithRefInTuple(ty, f.position)) else: let field = lookupFieldAgain(p, ty, f, r) if field.loc.r == nil: fillObjectFields(p.module, ty) 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) + if a.s == OnStackShadowDup and field.loc.dup != nil: + d.s = OnStackShadowDup + d.dup = ropef("$1.$2", a.dup, field.loc.dup) #d.s = a.s proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc) @@ -819,6 +820,9 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) = genFieldCheck(p, e, r, field, ty) add(r, rfmt(nil, ".$1", field.loc.r)) putIntoDest(p, d, field.typ, r, a.s) + if a.s == OnStackShadowDup and field.loc.dup != nil: + d.s = OnStackShadowDup + d.dup = ropef("$1.$2", a.dup, field.loc.dup) else: genRecordField(p, e.sons[0], d) @@ -846,6 +850,9 @@ proc genArrayElem(p: BProc, x, y: PNode, d: var TLoc) = d.inheritLocation(a) putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)), rfmt(nil, "$1[($2)- $3]", rdLoc(a), rdCharLoc(b), first), a.s) + if a.s == OnStackShadowDup: + d.s = OnStackShadowDup + d.dup = ropef("$1[($2)- $3]", a.dup, rdCharLoc(b), first) proc genCStringElem(p: BProc, x, y: PNode, d: var TLoc) = var a, b: TLoc @@ -866,6 +873,9 @@ proc genOpenArrayElem(p: BProc, x, y: PNode, d: var TLoc) = if d.k == locNone: d.s = a.s putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)), rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.s) + if a.s == OnStackShadowDup: + d.s = OnStackShadowDup + d.dup = ropef("$1[$2]", a.dup, rdCharLoc(b)) proc genSeqElem(p: BProc, x, y: PNode, d: var TLoc) = var a, b: TLoc @@ -1170,6 +1180,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = var t = e.typ.skipTypes(abstractInst) getTemp(p, t, tmp) let isRef = t.kind == tyRef + let stck = stackPlacement(t) var r = rdLoc(tmp) if isRef: rawGenNew(p, tmp, nil) @@ -1193,7 +1204,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = add(tmp2.r, field.loc.r) tmp2.k = locTemp tmp2.t = field.loc.t - tmp2.s = if isRef: OnHeap else: OnStack + tmp2.s = if isRef: OnHeap else: stck expr(p, it.sons[1], tmp2) if d.k == locNone: diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index cc925b150..1bb26c48d 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -332,7 +332,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) = var alreadyPoppedCnt = p.inExceptBlock for i in countup(1, howManyTrys): - if not p.module.compileToCpp: + if not p.module.compileToCpp or optNoCppExceptions in gGlobalOptions: # Pop safe points generated by try if alreadyPoppedCnt > 0: dec alreadyPoppedCnt @@ -354,7 +354,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) = for i in countdown(howManyTrys-1, 0): p.nestedTryStmts.add(stack[i]) - if not p.module.compileToCpp: + if not p.module.compileToCpp or optNoCppExceptions in gGlobalOptions: # Pop exceptions that was handled by the # except-blocks we are in for i in countdown(howManyExcepts-1, 0): @@ -803,6 +803,8 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = endBlock(p, ropecg(p.module, "} catch (NimException& $1) {$n", [exc])) if optStackTrace in p.options: linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR_);$n") + if p.gcFrameLen > 0: + linefmt(p, cpsStmts, "#setGcFrame((#GcFrameBase*)&GCF_);$n") inc p.inExceptBlock var i = 1 var catchAllPresent = false @@ -911,6 +913,9 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) = linefmt(p, cpsStmts, "#popSafePoint();$n") if optStackTrace in p.options: linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR_);$n") + if p.gcFrameLen > 0: + linefmt(p, cpsStmts, "#setGcFrame((#GcFrameBase*)&GCF_);$n") + inc p.inExceptBlock var i = 1 while (i < length) and (t.sons[i].kind == nkExceptBranch): diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 5e4bcfe97..f26854824 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -282,7 +282,7 @@ proc ccgIntroducedPtr(s: PSym): bool = proc fillResult(param: PSym) = fillLoc(param.loc, locParam, param.typ, ~"Result", - OnStack) + stackPlacement(param.typ)) if mapReturnType(param.typ) != ctArray and isInvalidReturnType(param.typ): incl(param.loc.flags, lfIndirect) param.loc.s = OnUnknown @@ -376,9 +376,9 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope = result = getTypeDescAux(m, t, check) proc paramStorageLoc(param: PSym): TStorageLoc = - if param.typ.skipTypes({tyVar, tyTypeDesc}).kind notin { - tyArray, tyOpenArray, tyVarargs}: - result = OnStack + let t = param.typ.skipTypes({tyVar, tyTypeDesc}) + if t.kind notin {tyArray, tyOpenArray, tyVarargs}: + result = stackPlacement(t) else: result = OnUnknown @@ -988,7 +988,7 @@ proc genObjectInfo(m: BModule, typ, origType: PType, name: Rope) = if typ.kind == tyObject: genTypeInfoAux(m, typ, origType, name) else: genTypeInfoAuxBase(m, typ, origType, name, rope("0")) var tmp = getNimNode(m) - if not isImportedCppType(typ): + if not isImportedType(typ): genObjectFields(m, typ, origType, typ.n, tmp) addf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, tmp]) var t = typ.sons[0] diff --git a/compiler/cgen.nim b/compiler/cgen.nim index fd15d0793..c9b047a49 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -244,6 +244,10 @@ proc addrLoc(a: TLoc): Rope = if lfIndirect notin a.flags and mapType(a.t) != ctArray: result = "(&" & result & ")" +proc dupLoc(a: TLoc): Rope = + result = a.dup + assert result != nil + proc rdCharLoc(a: TLoc): Rope = # read a location that may need a char-cast: result = rdLoc(a) @@ -288,12 +292,13 @@ proc resetLoc(p: BProc, loc: var TLoc) = if not isComplexValueType(typ): if containsGcRef: var nilLoc: TLoc - initLoc(nilLoc, locTemp, loc.t, OnStack) + initLoc(nilLoc, locTemp, loc.t, stackPlacement(typ)) nilLoc.r = rope("NIM_NIL") genRefAssign(p, loc, nilLoc, {afSrcIsNil}) else: linefmt(p, cpsStmts, "$1 = 0;$n", rdLoc(loc)) else: + # XXX use stackPlacement here? if optNilCheck in p.options: linefmt(p, cpsStmts, "#chckNil((void*)$1);$n", addrLoc(loc)) if loc.s != OnStack: @@ -343,17 +348,21 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) = linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r) result.k = locTemp result.t = t - result.s = OnStack + result.s = stackPlacement(t) result.flags = {} constructLoc(p, result, not needsInit) proc initGCFrame(p: BProc): Rope = - if p.gcFrameId > 0: result = "struct {$1} GCFRAME_;$n" % [p.gcFrameType] + if p.gcFrameLen > 0: + result = ropegc(p.module, """ + struct {#GcFrameBase b_; $1} GCF_;$n + GCF_.b_.L=$2;$n + #pushGcFrame((GcFrameBase*)&GCF_);$n""" % [ + p.gcFrameType, rope(p.gcFrameLen)]) proc deinitGCFrame(p: BProc): Rope = - if p.gcFrameId > 0: - result = ropecg(p.module, - "if (((NU)&GCFRAME_) < 4096) #nimGCFrame(&GCFRAME_);$n") + if p.gcFrameLen > 0: + result = ropecg(p.module, "#popGcFrame();$n") proc localDebugInfo(p: BProc, s: PSym) = if {optStackTrace, optEndb} * p.options != {optStackTrace, optEndb}: return @@ -370,7 +379,7 @@ proc localDebugInfo(p: BProc, s: PSym) = proc localVarDecl(p: BProc; s: PSym): Rope = if s.loc.k == locNone: - fillLoc(s.loc, locLocalVar, s.typ, mangleLocalName(p, s), OnStack) + fillLoc(s.loc, locLocalVar, s.typ, mangleLocalName(p, s), stackPlacement(s.typ)) if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy) result = getTypeDesc(p.module, s.typ) if s.constraint.isNil: @@ -1315,8 +1324,11 @@ proc shouldRecompile(code: Rope, cfile: Cfile): bool = if optForceFullMake notin gGlobalOptions: if not equalsFile(code, cfile.cname): if isDefined("nimdiff"): - copyFile(cfile.cname, cfile.cname & ".backup") - echo "diff ", cfile.cname, ".backup ", cfile.cname + if fileExists(cfile.cname): + copyFile(cfile.cname, cfile.cname & ".backup") + echo "diff ", cfile.cname, ".backup ", cfile.cname + else: + echo "new file ", cfile.cname writeRope(code, cfile.cname) return if existsFile(cfile.obj) and os.fileNewer(cfile.obj, cfile.cname): diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index be087095f..2f927c83e 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -90,7 +90,7 @@ type splitDecls*: int # > 0 if we are in some context for C++ that # requires 'T x = T()' to become 'T x; x = T()' # (yes, C++ is weird like that) - gcFrameId*: Natural # for the GC stack marking + gcFrameLen*: int # the number of slots in the GC-Frame gcFrameType*: Rope # the struct {} we put the GC markers into sigConflicts*: CountTable[string] diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index e14306e56..1165ec932 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -233,6 +233,12 @@ proc genDispatcher(methods: TSymSeq, relevantCols: IntSet): PSym = var disp = newNodeI(nkIfStmt, base.info) var ands = getSysSym("and") var iss = getSysSym("of") + for col in countup(1, paramLen - 1): + if contains(relevantCols, col): + let param = base.typ.n.sons[col].sym + if param.typ.skipTypes(abstractInst).kind in {tyRef, tyPtr}: + addSon(nilchecks, newTree(nkCall, + newSymNode(getCompilerProc"chckNilDisp"), newSymNode(param))) for meth in countup(0, high(methods)): var curr = methods[meth] # generate condition: var cond: PNode = nil @@ -242,9 +248,6 @@ proc genDispatcher(methods: TSymSeq, relevantCols: IntSet): PSym = addSon(isn, newSymNode(iss)) let param = base.typ.n.sons[col].sym addSon(isn, newSymNode(param)) - if param.typ.skipTypes(abstractInst).kind in {tyRef, tyPtr}: - addSon(nilchecks, newTree(nkCall, - newSymNode(getCompilerProc"chckNilDisp"), newSymNode(param))) addSon(isn, newNodeIT(nkType, base.info, curr.typ.sons[col])) if cond != nil: var a = newNodeIT(nkCall, base.info, getSysType(tyBool)) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 1af113be6..ca4f621e4 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -697,6 +697,17 @@ proc getLinkCmd(projectfile, objfiles: string): string = "nim", quoteShell(getPrefixDir()), "lib", quoteShell(libpath)]) +template tryExceptOSErrorMessage(errorPrefix: string = "", body: untyped): typed = + try: + body + except OSError: + let ose = (ref OSError)(getCurrentException()) + if errorPrefix.len > 0: + rawMessage(errGenerated, errorPrefix & " " & ose.msg & " " & $ose.errorCode) + else: + rawMessage(errExecutionOfProgramFailed, ose.msg & " " & $ose.errorCode) + raise + proc callCCompiler*(projectfile: string) = var linkCmd: string @@ -721,17 +732,20 @@ proc callCCompiler*(projectfile: string) = var res = 0 if gNumberOfProcessors <= 1: for i in countup(0, high(cmds)): - res = execWithEcho(cmds[i]) + tryExceptOSErrorMessage("invocation of external compiler program failed."): + res = execWithEcho(cmds[i]) if res != 0: rawMessage(errExecutionOfProgramFailed, cmds[i]) - elif optListCmd in gGlobalOptions or gVerbosity > 1: - res = execProcesses(cmds, {poEchoCmd, poStdErrToStdOut, poUsePath, poParentStreams}, - gNumberOfProcessors, afterRunEvent=runCb) - elif gVerbosity == 1: - res = execProcesses(cmds, {poStdErrToStdOut, poUsePath, poParentStreams}, - gNumberOfProcessors, prettyCb, afterRunEvent=runCb) else: - res = execProcesses(cmds, {poStdErrToStdOut, poUsePath, poParentStreams}, - gNumberOfProcessors, afterRunEvent=runCb) + tryExceptOSErrorMessage("invocation of external compiler program failed."): + if optListCmd in gGlobalOptions or gVerbosity > 1: + res = execProcesses(cmds, {poEchoCmd, poStdErrToStdOut, poUsePath, poParentStreams}, + gNumberOfProcessors, afterRunEvent=runCb) + elif gVerbosity == 1: + res = execProcesses(cmds, {poStdErrToStdOut, poUsePath, poParentStreams}, + gNumberOfProcessors, prettyCb, afterRunEvent=runCb) + else: + res = execProcesses(cmds, {poStdErrToStdOut, poUsePath, poParentStreams}, + gNumberOfProcessors, afterRunEvent=runCb) if res != 0: if gNumberOfProcessors <= 1: rawMessage(errExecutionOfProgramFailed, cmds.join()) @@ -749,8 +763,9 @@ proc callCCompiler*(projectfile: string) = linkCmd = getLinkCmd(projectfile, objfiles) if optCompileOnly notin gGlobalOptions: - execExternalProgram(linkCmd, - if optListCmd in gGlobalOptions or gVerbosity > 1: hintExecuting else: hintLinking) + tryExceptOSErrorMessage("invocation of external linker program failed."): + execExternalProgram(linkCmd, + if optListCmd in gGlobalOptions or gVerbosity > 1: hintExecuting else: hintLinking) else: linkCmd = "" if optGenScript in gGlobalOptions: diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 0016a8492..ee35356c9 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -434,22 +434,23 @@ proc binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) = proc unsignedTrimmerJS(size: BiggestInt): Rope = case size - of 1: rope"& 0xff" - of 2: rope"& 0xffff" - of 4: rope">>> 0" - else: rope"" + of 1: rope"& 0xff" + of 2: rope"& 0xffff" + of 4: rope">>> 0" + else: rope"" proc unsignedTrimmerPHP(size: BiggestInt): Rope = case size - of 1: rope"& 0xff" - of 2: rope"& 0xffff" - of 4: rope"& 0xffffffff" - else: rope"" + of 1: rope"& 0xff" + of 2: rope"& 0xffff" + of 4: rope"& 0xffffffff" + else: rope"" template unsignedTrimmer(size: BiggestInt): Rope = size.unsignedTrimmerJS | size.unsignedTrimmerPHP -proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string, reassign: bool = false) = +proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string, + reassign = false) = var x, y: TCompRes gen(p, n.sons[1], x) gen(p, n.sons[2], y) @@ -1633,11 +1634,11 @@ proc genReprAux(p: PProc, n: PNode, r: var TCompRes, magic: string, typ: Rope = gen(p, n.sons[1], a) if magic == "reprAny": - # the pointer argument in reprAny is expandend to + # the pointer argument in reprAny is expandend to # (pointedto, pointer), so we need to fill it if a.address.isNil: add(r.res, a.res) - add(r.res, ", null") + add(r.res, ", null") else: add(r.res, "$1, $2" % [a.address, a.res]) else: @@ -1670,7 +1671,7 @@ proc genRepr(p: PProc, n: PNode, r: var TCompRes) = genReprAux(p, n, r, "reprSet", genTypeInfo(p, t)) of tyEmpty, tyVoid: localError(n.info, "'repr' doesn't support 'void' type") - of tyPointer: + of tyPointer: genReprAux(p, n, r, "reprPointer") of tyOpenArray, tyVarargs: genReprAux(p, n, r, "reprJSONStringify") @@ -1863,8 +1864,8 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) = var a, b: TCompRes - useMagic(p, "SetConstr") - r.res = rope("SetConstr(") + useMagic(p, "setConstr") + r.res = rope("setConstr(") r.kind = resExpr for i in countup(0, sonsLen(n) - 1): if i > 0: add(r.res, ", ") @@ -1877,6 +1878,12 @@ proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) = gen(p, it, a) add(r.res, a.res) add(r.res, ")") + # emit better code for constant sets: + if p.target == targetJS and isDeepConstExpr(n): + inc(p.g.unique) + let tmp = rope("ConstSet") & rope(p.g.unique) + addf(p.g.constants, "var $1 = $2;$n", [tmp, r.res]) + r.res = tmp proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) = var a: TCompRes @@ -2128,6 +2135,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = else: r.res = rope(f.toStrMaxPrecision) r.kind = resExpr of nkCallKinds: + if isEmptyType(n.typ): genLineDir(p, n) if (n.sons[0].kind == nkSym) and (n.sons[0].sym.magic != mNone): genMagic(p, n, r) elif n.sons[0].kind == nkSym and sfInfixCall in n.sons[0].sym.flags and @@ -2264,7 +2272,6 @@ proc myProcess(b: PPassContext, n: PNode): PNode = genModule(p, n) add(p.g.code, p.locals) add(p.g.code, p.body) - globals.unique = p.unique proc wholeCode(graph: ModuleGraph; m: BModule): Rope = for prc in globals.forwarded: diff --git a/compiler/jstypes.nim b/compiler/jstypes.nim index f49bd7668..ae30861e7 100644 --- a/compiler/jstypes.nim +++ b/compiler/jstypes.nim @@ -59,7 +59,7 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope = u = rope(lengthOrd(field.typ)) else: internalError(n.info, "genObjectFields(nkRecCase)") if result != nil: add(result, ", " & tnl) - addf(result, "[SetConstr($1), $2]", + addf(result, "[setConstr($1), $2]", [u, genObjectFields(p, typ, lastSon(b))]) result = ("{kind: 3, offset: \"$1\", len: $3, " & "typ: $2, name: $4, sons: [$5]}") % [ diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index 245cc5f61..4bd54603d 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -74,9 +74,9 @@ proc lowerTupleUnpackingForAsgn*(n: PNode; owner: PSym): PNode = let value = n.lastSon result = newNodeI(nkStmtList, n.info) - var temp = newSym(skTemp, getIdent(genPrefix), owner, value.info) + var temp = newSym(skLet, getIdent("_"), owner, value.info) var v = newNodeI(nkLetSection, value.info) - let tempAsNode = newIdentNode(getIdent(genPrefix & $temp.id), value.info) + let tempAsNode = newSymNode(temp) #newIdentNode(getIdent(genPrefix & $temp.id), value.info) var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3) vpart.sons[0] = tempAsNode @@ -115,7 +115,7 @@ proc createObj*(owner: PSym, info: TLineInfo): PType = incl result.flags, tfFinal result.n = newNodeI(nkRecList, info) when true: - let s = newSym(skType, getIdent("Env_" & info.toFilename & "_" & $info.line), + let s = newSym(skType, getIdent("Env_" & info.toFilename), owner, info) incl s.flags, sfAnon s.typ = result @@ -137,10 +137,32 @@ proc rawIndirectAccess*(a: PNode; field: PSym; info: TLineInfo): PNode = addSon(result, newSymNode(field)) result.typ = field.typ +proc lookupInRecord(n: PNode, id: int): PSym = + result = nil + case n.kind + of nkRecList: + for i in countup(0, sonsLen(n) - 1): + result = lookupInRecord(n.sons[i], id) + if result != nil: return + of nkRecCase: + if n.sons[0].kind != nkSym: return + result = lookupInRecord(n.sons[0], id) + if result != nil: return + for i in countup(1, sonsLen(n) - 1): + case n.sons[i].kind + of nkOfBranch, nkElse: + result = lookupInRecord(lastSon(n.sons[i]), id) + if result != nil: return + else: discard + of nkSym: + if n.sym.id == -abs(id): result = n.sym + else: discard + proc addField*(obj: PType; s: PSym) = # because of 'gensym' support, we have to mangle the name with its ID. # This is hacky but the clean solution is much more complex than it looks. - var field = newSym(skField, getIdent(s.name.s & $s.id), s.owner, s.info) + var field = newSym(skField, getIdent(s.name.s & $obj.n.len), s.owner, s.info) + field.id = -s.id let t = skipIntLit(s.typ) field.typ = t assert t.kind != tyStmt @@ -148,9 +170,9 @@ proc addField*(obj: PType; s: PSym) = addSon(obj.n, newSymNode(field)) proc addUniqueField*(obj: PType; s: PSym) = - let fieldName = getIdent(s.name.s & $s.id) - if lookupInRecord(obj.n, fieldName) == nil: - var field = newSym(skField, fieldName, s.owner, s.info) + if lookupInRecord(obj.n, s.id) == nil: + var field = newSym(skField, getIdent(s.name.s & $obj.n.len), s.owner, s.info) + field.id = -s.id let t = skipIntLit(s.typ) field.typ = t assert t.kind != tyStmt @@ -159,13 +181,36 @@ proc addUniqueField*(obj: PType; s: PSym) = proc newDotExpr(obj, b: PSym): PNode = result = newNodeI(nkDotExpr, obj.info) - let field = getSymFromList(obj.typ.n, getIdent(b.name.s & $b.id)) + let field = lookupInRecord(obj.typ.n, b.id) assert field != nil, b.name.s addSon(result, newSymNode(obj)) addSon(result, newSymNode(field)) result.typ = field.typ -proc indirectAccess*(a: PNode, b: string, info: TLineInfo): PNode = +proc indirectAccess*(a: PNode, b: int, info: TLineInfo): PNode = + # returns a[].b as a node + var deref = newNodeI(nkHiddenDeref, info) + deref.typ = a.typ.skipTypes(abstractInst).sons[0] + var t = deref.typ.skipTypes(abstractInst) + var field: PSym + while true: + assert t.kind == tyObject + field = lookupInRecord(t.n, b) + if field != nil: break + t = t.sons[0] + if t == nil: break + t = t.skipTypes(skipPtrs) + #if field == nil: + # echo "FIELD ", b + # debug deref.typ + internalAssert field != nil + addSon(deref, a) + result = newNodeI(nkDotExpr, info) + addSon(result, deref) + addSon(result, newSymNode(field)) + result.typ = field.typ + +proc indirectAccess(a: PNode, b: string, info: TLineInfo): PNode = # returns a[].b as a node var deref = newNodeI(nkHiddenDeref, info) deref.typ = a.typ.skipTypes(abstractInst).sons[0] @@ -191,11 +236,10 @@ proc indirectAccess*(a: PNode, b: string, info: TLineInfo): PNode = proc getFieldFromObj*(t: PType; v: PSym): PSym = assert v.kind != skField - let fieldName = getIdent(v.name.s & $v.id) var t = t while true: assert t.kind == tyObject - result = getSymFromList(t.n, fieldName) + result = lookupInRecord(t.n, v.id) if result != nil: break t = t.sons[0] if t == nil: break @@ -203,7 +247,7 @@ proc getFieldFromObj*(t: PType; v: PSym): PSym = proc indirectAccess*(a: PNode, b: PSym, info: TLineInfo): PNode = # returns a[].b as a node - result = indirectAccess(a, b.name.s & $b.id, info) + result = indirectAccess(a, b.id, info) proc indirectAccess*(a, b: PSym, info: TLineInfo): PNode = result = indirectAccess(newSymNode(a), b, info) diff --git a/compiler/nimblecmd.nim b/compiler/nimblecmd.nim index e6466fc24..5e6d843de 100644 --- a/compiler/nimblecmd.nim +++ b/compiler/nimblecmd.nim @@ -17,15 +17,17 @@ proc addPath*(path: string, info: TLineInfo) = proc versionSplitPos(s: string): int = result = s.len-2 - while result > 1 and s[result] in {'0'..'9', '.'}: dec result + #while result > 1 and s[result] in {'0'..'9', '.'}: dec result + while result > 1 and s[result] != '-': dec result if s[result] != '-': result = s.len const - latest = "head" + latest = "" proc `<.`(a, b: string): bool = # wether a has a smaller version than b: - if a == latest: return false + if a == latest: return true + elif b == latest: return false var i = 0 var j = 0 var verA = 0 @@ -33,8 +35,13 @@ proc `<.`(a, b: string): bool = while true: let ii = parseInt(a, verA, i) let jj = parseInt(b, verB, j) - # if A has no number left, but B has, B is preferred: 0.8 vs 0.8.3 - if ii <= 0 or jj <= 0: return jj > 0 + 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: @@ -46,12 +53,9 @@ proc `<.`(a, b: string): bool = proc addPackage(packages: StringTableRef, p: string) = let x = versionSplitPos(p) let name = p.substr(0, x-1) - if x < p.len: - let version = p.substr(x+1) - if packages.getOrDefault(name) <. version: - packages[name] = version - else: - packages[name] = latest + let version = if x < p.len: p.substr(x+1) else: "" + if packages.getOrDefault(name) <. version: + packages[name] = version iterator chosen(packages: StringTableRef): string = for key, val in pairs(packages): @@ -76,3 +80,18 @@ proc addPathRec(dir: string, info: TLineInfo) = proc nimblePath*(path: string, info: TLineInfo) = addPathRec(path, info) addNimblePath(path, info) + +when isMainModule: + var rr = newStringTable() + addPackage rr, "irc-#head" + addPackage rr, "irc-0.1.0" + addPackage rr, "irc" + addPackage rr, "another" + addPackage rr, "another-0.1" + + addPackage rr, "ab-0.1.3" + addPackage rr, "ab-0.1" + addPackage rr, "justone" + + for p in rr.chosen: + echo p diff --git a/compiler/options.nim b/compiler/options.nim index c4a57f41c..3e681c8d1 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -140,12 +140,13 @@ var gEvalExpr* = "" # expression for idetools --eval gLastCmdTime*: float # when caas is enabled, we measure each command gListFullPaths*: bool - isServing*: bool = false + gPreciseStack*: bool = false gNoNimblePath* = false gExperimentalMode*: bool proc importantComments*(): bool {.inline.} = gCmd in {cmdDoc, cmdIdeTools} proc usesNativeGC*(): bool {.inline.} = gSelectedGC >= gcRefc +template preciseStack*(): bool = gPreciseStack template compilationCachePresent*: untyped = {optCaasEnabled, optSymbolFiles} * gGlobalOptions != {} diff --git a/compiler/parser.nim b/compiler/parser.nim index e4c04c0f7..e2d17b455 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1246,10 +1246,7 @@ proc parseExprStmt(p: var TParser): PNode = addSon(result, e) if p.tok.tokType != tkComma: break elif p.tok.indent < 0 and isExprStart(p): - if a.kind == nkCommand: - result = a - else: - result = newNode(nkCommand, a.info, @[a]) + result = newNode(nkCommand, a.info, @[a]) while true: var e = parseExpr(p) addSon(result, e) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 4baef5385..8ff5fdd9c 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1269,7 +1269,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = result.typ = makeTypeDesc(c, semTypeNode(c, n, nil)) #result = symNodeFromType(c, semTypeNode(c, n, nil), n.info) of tyTuple: - checkSonsLen(n, 2) + if n.len != 2: return nil n.sons[0] = makeDeref(n.sons[0]) c.p.bracketExpr = n.sons[0] # [] operator for tuples requires constant expression: @@ -1279,9 +1279,9 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = var idx = getOrdValue(n.sons[1]) if idx >= 0 and idx < sonsLen(arr): n.typ = arr.sons[int(idx)] else: localError(n.info, errInvalidIndexValueForTuple) + result = n else: - localError(n.info, errIndexTypesDoNotMatch) - result = n + result = nil else: let s = if n.sons[0].kind == nkSym: n.sons[0].sym elif n[0].kind in nkSymChoices: n.sons[0][0].sym diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 88c05faa4..96bdc6cba 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -517,7 +517,7 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) = proc procVarcheck(n: PNode) = if n.kind in nkSymChoices: for x in n: procVarCheck(x) - elif n.kind == nkSym and n.sym.magic != mNone: + elif n.kind == nkSym and n.sym.magic != mNone and n.sym.kind in routineKinds: localError(n.info, errXCannotBePassedToProcVar, n.sym.name.s) proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) = @@ -783,6 +783,10 @@ proc track(tracked: PEffects, n: PNode) = notNilCheck(tracked, last, child.sons[i].typ) # since 'var (a, b): T = ()' is not even allowed, there is always type # inference for (a, b) and thus no nil checking is necessary. + of nkConstSection: + for child in n: + let last = lastSon(child) + track(tracked, last) of nkCaseStmt: trackCase(tracked, n) of nkWhen, nkIfStmt, nkIfExpr: trackIf(tracked, n) of nkBlockStmt, nkBlockExpr: trackBlock(tracked, n.sons[1]) diff --git a/compiler/trees.nim b/compiler/trees.nim index 424fba14c..8f0af89d3 100644 --- a/compiler/trees.nim +++ b/compiler/trees.nim @@ -96,7 +96,7 @@ proc isDeepConstExpr*(n: PNode): bool = result = true of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv: result = isDeepConstExpr(n.sons[1]) - of nkCurly, nkBracket, nkPar, nkObjConstr, nkClosure: + of nkCurly, nkBracket, nkPar, nkObjConstr, nkClosure, nkRange: for i in ord(n.kind == nkObjConstr) .. <n.len: if not isDeepConstExpr(n.sons[i]): return false if n.typ.isNil: result = true diff --git a/compiler/vm.nim b/compiler/vm.nim index 14800fb13..043506e62 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1657,8 +1657,16 @@ proc evalMacroCall*(module: PSym; cache: IdentCache, n, nOrig: PNode, for i in 0 .. <gp.len: if sfImmediate notin sym.flags: let idx = sym.typ.len + i - tos.slots[idx] = setupMacroParam(n.sons[idx], gp[i].sym.typ) + if idx < n.len: + tos.slots[idx] = setupMacroParam(n.sons[idx], gp[i].sym.typ) + else: + dec(evalMacroCounter) + c.callsite = nil + localError(n.info, "expected " & $gp.len & + " generic parameter(s)") elif gp[i].sym.typ.kind in {tyStatic, tyTypeDesc}: + dec(evalMacroCounter) + c.callsite = nil globalError(n.info, "static[T] or typedesc nor supported for .immediate macros") # temporary storage: #for i in L .. <maxSlots: tos.slots[i] = newNode(nkEmpty) diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index 8c7388643..b2b1ec92b 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -175,7 +175,12 @@ proc mapTypeToAstX(t: PType; info: TLineInfo; result.add mapTypeToAst(t.sons[i], info) else: result = mapTypeToAstX(t.lastSon, info, inst, allowRecursion) - of tyGenericBody, tyOrdinal: + of tyGenericBody: + if inst: + result = mapTypeToAstX(t.lastSon, info, inst, true) + else: + result = mapTypeToAst(t.lastSon, info) + of tyOrdinal: result = mapTypeToAst(t.lastSon, info) of tyDistinct: if inst: |