diff --git a/compiler/ast.nim b/compiler/ast.nim index 177b5c5c7..7b6f39cbc 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -709,6 +709,7 @@ type lfSingleUse # no location yet and will only be used once TStorageLoc* = enum OnUnknown, # location is unknown (stack, heap or static) + OnStatic, # in a static section OnStack, # location is on hardware stack OnHeap # location is on heap or global # (reference counting needed) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index ba8ced52a..54063229f 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -221,7 +221,7 @@ proc optAsgnLoc(a: TLoc, t: PType, field: Rope): TLoc = proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = let newflags = - if src.k == locData: + if src.s == OnStatic: flags + {needToCopy} elif tfShallow in dest.t.flags: flags - {needToCopy} @@ -238,7 +238,7 @@ proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags, t: PNode) = if t == nil: return let newflags = - if src.k == locData: + if src.s == OnStatic: flags + {needToCopy} elif tfShallow in dest.t.flags: flags - {needToCopy} @@ -287,13 +287,13 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = of tyRef: genRefAssign(p, dest, src, flags) of tySequence: - if needToCopy notin flags and src.k != locData: + if needToCopy notin flags and src.s != OnStatic: genRefAssign(p, dest, src, flags) else: linefmt(p, cpsStmts, "#genericSeqAssign($1, $2, $3);$n", addrLoc(dest), rdLoc(src), genTypeInfo(p.module, dest.t)) of tyString: - if needToCopy notin flags and src.k != locData: + if needToCopy notin flags and src.s != OnStatic: genRefAssign(p, dest, src, flags) else: if dest.s == OnStack or not usesNativeGC(): @@ -413,7 +413,7 @@ proc putDataIntoDest(p: BProc, d: var TLoc, t: PType, r: Rope) = var a: TLoc if d.k != locNone: # need to generate an assignment here - initLoc(a, locData, t, OnUnknown) + initLoc(a, locData, t, OnStatic) a.r = r if lfNoDeepCopy in d.flags: genAssignment(p, d, a, {}) else: genAssignment(p, d, a, {needToCopy}) @@ -424,11 +424,11 @@ proc putDataIntoDest(p: BProc, d: var TLoc, t: PType, r: Rope) = d.t = t d.r = r -proc putIntoDest(p: BProc, d: var TLoc, t: PType, r: Rope) = +proc putIntoDest(p: BProc, d: var TLoc, t: PType, r: Rope; s=OnUnknown) = var a: TLoc if d.k != locNone: # need to generate an assignment here - initLoc(a, locExpr, t, OnUnknown) + initLoc(a, locExpr, t, s) a.r = r if lfNoDeepCopy in d.flags: genAssignment(p, d, a, {}) else: genAssignment(p, d, a, {needToCopy}) @@ -685,7 +685,7 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) = d.s = OnUnknown if tfVarIsPtr notin typ.flags and p.module.compileToCpp and e.kind == nkHiddenDeref: - putIntoDest(p, d, e.typ, rdLoc(a)) + putIntoDest(p, d, e.typ, rdLoc(a), a.s) return of tyPtr: d.s = OnUnknown # BUGFIX! @@ -694,7 +694,7 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) = let typ = skipTypes(a.t, abstractInst) if typ.kind == tyVar and tfVarIsPtr notin typ.flags and e.kind == nkHiddenDeref: - putIntoDest(p, d, e.typ, rdLoc(a)) + putIntoDest(p, d, e.typ, rdLoc(a), a.s) return if enforceDeref and mt == ctPtrToArray: # we lie about the type for better C interop: 'ptr array[3,T]' is @@ -702,23 +702,23 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) = # See tmissingderef. So we get rid of the deref instead. The codegen # ends up using 'memcpy' for the array assignment, # so the '&' and '*' cancel out: - putIntoDest(p, d, a.t.sons[0], rdLoc(a)) + putIntoDest(p, d, a.t.sons[0], rdLoc(a), a.s) else: - putIntoDest(p, d, e.typ, "(*$1)" % [rdLoc(a)]) + putIntoDest(p, d, e.typ, "(*$1)" % [rdLoc(a)], a.s) proc genAddr(p: BProc, e: PNode, d: var TLoc) = # careful 'addr(myptrToArray)' needs to get the ampersand: if e.sons[0].typ.skipTypes(abstractInst).kind in {tyRef, tyPtr}: var a: TLoc initLocExpr(p, e.sons[0], a) - putIntoDest(p, d, e.typ, "&" & a.r) + putIntoDest(p, d, e.typ, "&" & a.r, a.s) #Message(e.info, warnUser, "HERE NEW &") elif mapType(e.sons[0].typ) == ctArray or isCppRef(p, e.sons[0].typ): expr(p, e.sons[0], d) else: var a: TLoc initLocExpr(p, e.sons[0], a) - putIntoDest(p, d, e.typ, addrLoc(a)) + putIntoDest(p, d, e.typ, addrLoc(a), a.s) template inheritLocation(d: var TLoc, a: TLoc) = if d.k == locNone: d.s = a.s @@ -745,7 +745,7 @@ proc genTupleElem(p: BProc, e: PNode, d: var TLoc) = of nkIntLit..nkUInt64Lit: i = int(e.sons[1].intVal) else: internalError(e.info, "genTupleElem") addf(r, ".Field$1", [rope(i)]) - putIntoDest(p, d, ty.sons[i], r) + putIntoDest(p, d, ty.sons[i], r, a.s) proc genRecordField(p: BProc, e: PNode, d: var TLoc) = var a: TLoc @@ -756,7 +756,7 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) = # we found a unique tuple type which lacks field information # so we use Field$i addf(r, ".Field$1", [rope(f.position)]) - putIntoDest(p, d, f.typ, r) + putIntoDest(p, d, f.typ, r, a.s) else: var field: PSym = nil while ty != nil: @@ -769,7 +769,7 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) = if field == nil: internalError(e.info, "genRecordField 2 ") if field.loc.r == nil: internalError(e.info, "genRecordField 3") addf(r, ".$1", [field.loc.r]) - putIntoDest(p, d, field.typ, r) + putIntoDest(p, d, field.typ, r, a.s) #d.s = a.s proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc) @@ -824,7 +824,7 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) = internalError(e.info, "genCheckedRecordField") # generate the checks: genFieldCheck(p, e, r, field) add(r, rfmt(nil, ".$1", field.loc.r)) - putIntoDest(p, d, field.typ, r) + putIntoDest(p, d, field.typ, r, a.s) else: genRecordField(p, e.sons[0], d) @@ -851,7 +851,7 @@ proc genArrayElem(p: BProc, x, y: PNode, d: var TLoc) = localError(x.info, errIndexOutOfBounds) d.inheritLocation(a) putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)), - rfmt(nil, "$1[($2)- $3]", rdLoc(a), rdCharLoc(b), first)) + rfmt(nil, "$1[($2)- $3]", rdLoc(a), rdCharLoc(b), first), a.s) proc genCStringElem(p: BProc, x, y: PNode, d: var TLoc) = var a, b: TLoc @@ -860,7 +860,7 @@ proc genCStringElem(p: BProc, x, y: PNode, d: var TLoc) = var ty = skipTypes(a.t, abstractVarRange) if d.k == locNone: d.s = a.s putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)), - rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b))) + rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.s) proc genOpenArrayElem(p: BProc, x, y: PNode, d: var TLoc) = var a, b: TLoc @@ -871,7 +871,7 @@ proc genOpenArrayElem(p: BProc, x, y: PNode, d: var TLoc) = rdLoc(b), rdLoc(a)) # BUGFIX: ``>=`` and not ``>``! if d.k == locNone: d.s = a.s putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)), - rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b))) + rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.s) proc genSeqElem(p: BProc, x, y: PNode, d: var TLoc) = var a, b: TLoc @@ -894,7 +894,7 @@ proc genSeqElem(p: BProc, x, y: PNode, d: var TLoc) = if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}: a.r = rfmt(nil, "(*$1)", a.r) putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)), - rfmt(nil, "$1->data[$2]", rdLoc(a), rdCharLoc(b))) + rfmt(nil, "$1->data[$2]", rdLoc(a), rdCharLoc(b)), a.s) proc genBracketExpr(p: BProc; n: PNode; d: var TLoc) = var ty = skipTypes(n.sons[0].typ, abstractVarRange) @@ -1272,7 +1272,7 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) = r = rfmt(p.module, "(($1) && ($2))", nilCheck, genOfHelper(p, dest, r)) else: r = rfmt(p.module, "($1)", genOfHelper(p, dest, r)) - putIntoDest(p, d, getSysType(tyBool), r) + putIntoDest(p, d, getSysType(tyBool), r, a.s) proc genOf(p: BProc, n: PNode, d: var TLoc) = genOf(p, n.sons[1], n.sons[2].typ, d) @@ -1284,47 +1284,47 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) = case t.kind of tyInt..tyInt64, tyUInt..tyUInt64: putIntoDest(p, d, e.typ, - ropecg(p.module, "#reprInt((NI64)$1)", [rdLoc(a)])) + ropecg(p.module, "#reprInt((NI64)$1)", [rdLoc(a)]), a.s) of tyFloat..tyFloat128: - putIntoDest(p, d, e.typ, ropecg(p.module, "#reprFloat($1)", [rdLoc(a)])) + putIntoDest(p, d, e.typ, ropecg(p.module, "#reprFloat($1)", [rdLoc(a)]), a.s) of tyBool: - putIntoDest(p, d, e.typ, ropecg(p.module, "#reprBool($1)", [rdLoc(a)])) + putIntoDest(p, d, e.typ, ropecg(p.module, "#reprBool($1)", [rdLoc(a)]), a.s) of tyChar: - putIntoDest(p, d, e.typ, ropecg(p.module, "#reprChar($1)", [rdLoc(a)])) + putIntoDest(p, d, e.typ, ropecg(p.module, "#reprChar($1)", [rdLoc(a)]), a.s) of tyEnum, tyOrdinal: putIntoDest(p, d, e.typ, ropecg(p.module, "#reprEnum($1, $2)", [ - rdLoc(a), genTypeInfo(p.module, t)])) + rdLoc(a), genTypeInfo(p.module, t)]), a.s) of tyString: - putIntoDest(p, d, e.typ, ropecg(p.module, "#reprStr($1)", [rdLoc(a)])) + putIntoDest(p, d, e.typ, ropecg(p.module, "#reprStr($1)", [rdLoc(a)]), a.s) of tySet: putIntoDest(p, d, e.typ, ropecg(p.module, "#reprSet($1, $2)", [ - addrLoc(a), genTypeInfo(p.module, t)])) + addrLoc(a), genTypeInfo(p.module, t)]), a.s) of tyOpenArray, tyVarargs: var b: TLoc case a.t.kind of tyOpenArray, tyVarargs: - putIntoDest(p, b, e.typ, "$1, $1Len0" % [rdLoc(a)]) + putIntoDest(p, b, e.typ, "$1, $1Len0" % [rdLoc(a)], a.s) of tyString, tySequence: putIntoDest(p, b, e.typ, - "$1->data, $1->$2" % [rdLoc(a), lenField(p)]) + "$1->data, $1->$2" % [rdLoc(a), lenField(p)], a.s) of tyArray, tyArrayConstr: putIntoDest(p, b, e.typ, - "$1, $2" % [rdLoc(a), rope(lengthOrd(a.t))]) + "$1, $2" % [rdLoc(a), rope(lengthOrd(a.t))], a.s) else: internalError(e.sons[0].info, "genRepr()") putIntoDest(p, d, e.typ, ropecg(p.module, "#reprOpenArray($1, $2)", [rdLoc(b), - genTypeInfo(p.module, elemType(t))])) + genTypeInfo(p.module, elemType(t))]), a.s) of tyCString, tyArray, tyArrayConstr, tyRef, tyPtr, tyPointer, tyNil, tySequence: putIntoDest(p, d, e.typ, ropecg(p.module, "#reprAny($1, $2)", [ - rdLoc(a), genTypeInfo(p.module, t)])) + rdLoc(a), genTypeInfo(p.module, t)]), a.s) of tyEmpty: localError(e.info, "'repr' doesn't support 'void' type") else: putIntoDest(p, d, e.typ, ropecg(p.module, "#reprAny($1, $2)", - [addrLoc(a), genTypeInfo(p.module, t)])) + [addrLoc(a), genTypeInfo(p.module, t)]), a.s) gcUsage(e) proc genGetTypeInfo(p: BProc, e: PNode, d: var TLoc) = @@ -1549,13 +1549,13 @@ proc genSomeCast(p: BProc, e: PNode, d: var TLoc) = let etyp = skipTypes(e.typ, abstractRange) if etyp.kind in ValueTypes and lfIndirect notin a.flags: putIntoDest(p, d, e.typ, "(*($1*) ($2))" % - [getTypeDesc(p.module, e.typ), addrLoc(a)]) + [getTypeDesc(p.module, e.typ), addrLoc(a)], a.s) elif etyp.kind == tyProc and etyp.callConv == ccClosure: putIntoDest(p, d, e.typ, "(($1) ($2))" % - [getClosureType(p.module, etyp, clHalfWithEnv), rdCharLoc(a)]) + [getClosureType(p.module, etyp, clHalfWithEnv), rdCharLoc(a)], a.s) else: putIntoDest(p, d, e.typ, "(($1) ($2))" % - [getTypeDesc(p.module, e.typ), rdCharLoc(a)]) + [getTypeDesc(p.module, e.typ), rdCharLoc(a)], a.s) proc genCast(p: BProc, e: PNode, d: var TLoc) = const floatTypes = {tyFloat..tyFloat128} @@ -1575,7 +1575,7 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) = tmp.s = OnStack tmp.flags = {} expr(p, e.sons[1], tmp) - putIntoDest(p, d, e.typ, "LOC$#.dest" % [lbl]) + putIntoDest(p, d, e.typ, "LOC$#.dest" % [lbl], tmp.s) else: # I prefer the shorter cast version for pointer types -> generate less # C code; plus it's the right thing to do for closures: @@ -1589,13 +1589,13 @@ proc genRangeChck(p: BProc, n: PNode, d: var TLoc, magic: string) = {tyUInt..tyUInt64}: initLocExpr(p, n.sons[0], a) putIntoDest(p, d, n.typ, "(($1) ($2))" % - [getTypeDesc(p.module, dest), rdCharLoc(a)]) + [getTypeDesc(p.module, dest), rdCharLoc(a)], a.s) else: initLocExpr(p, n.sons[0], a) putIntoDest(p, d, dest, ropecg(p.module, "(($1)#$5($2, $3, $4))", [ getTypeDesc(p.module, dest), rdCharLoc(a), genLiteral(p, n.sons[1], dest), genLiteral(p, n.sons[2], dest), - rope(magic)])) + rope(magic)]), a.s) proc genConv(p: BProc, e: PNode, d: var TLoc) = let destType = e.typ.skipTypes({tyVar, tyGenericInst}) @@ -1607,13 +1607,13 @@ proc genConv(p: BProc, e: PNode, d: var TLoc) = proc convStrToCStr(p: BProc, n: PNode, d: var TLoc) = var a: TLoc initLocExpr(p, n.sons[0], a) - putIntoDest(p, d, skipTypes(n.typ, abstractVar), "$1->data" % [rdLoc(a)]) + putIntoDest(p, d, skipTypes(n.typ, abstractVar), "$1->data" % [rdLoc(a)], a.s) proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) = var a: TLoc initLocExpr(p, n.sons[0], a) putIntoDest(p, d, skipTypes(n.typ, abstractVar), - ropecg(p.module, "#cstrToNimstr($1)", [rdLoc(a)])) + ropecg(p.module, "#cstrToNimstr($1)", [rdLoc(a)]), a.s) gcUsage(n) proc genStrEquals(p: BProc, e: PNode, d: var TLoc) = @@ -1763,7 +1763,7 @@ proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool = var t = getUniqueType(n.typ) discard getTypeDesc(p.module, t) # so that any fields are initialized var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId) - fillLoc(d, locData, t, "TMP" & rope(id), OnHeap) + fillLoc(d, locData, t, "TMP" & rope(id), OnStatic) if id == gBackendId: # expression not found in the cache: inc(gBackendId) @@ -1849,7 +1849,7 @@ proc genClosure(p: BProc, n: PNode, d: var TLoc) = var tmp = "LOC" & rope(p.labels) addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n", [getTypeDesc(p.module, n.typ), tmp, genConstExpr(p, n)]) - putIntoDest(p, d, n.typ, tmp) + putIntoDest(p, d, n.typ, tmp, OnStatic) else: var tmp, a, b: TLoc initLocExpr(p, n.sons[0], a) @@ -1903,10 +1903,10 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) = r, genTypeInfo(p.module, dest)) if n.sons[0].typ.kind != tyObject: putIntoDest(p, d, n.typ, - "(($1) ($2))" % [getTypeDesc(p.module, n.typ), rdLoc(a)]) + "(($1) ($2))" % [getTypeDesc(p.module, n.typ), rdLoc(a)], a.s) else: putIntoDest(p, d, n.typ, "(*($1*) ($2))" % - [getTypeDesc(p.module, dest), addrLoc(a)]) + [getTypeDesc(p.module, dest), addrLoc(a)], a.s) proc downConv(p: BProc, n: PNode, d: var TLoc) = if p.module.compileToCpp: @@ -1938,9 +1938,9 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) = linefmt(p, cpsStmts, "$1 = &$2;$n", rdLoc(d), r) else: r = "&" & r - putIntoDest(p, d, n.typ, r) + putIntoDest(p, d, n.typ, r, a.s) else: - putIntoDest(p, d, n.typ, r) + putIntoDest(p, d, n.typ, r, a.s) proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) = var t = getUniqueType(n.typ) @@ -1955,7 +1955,7 @@ proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) = [getTypeDesc(p.module, t), tmp, genConstExpr(p, n)]) if d.k == locNone: - fillLoc(d, locData, t, tmp, OnHeap) + fillLoc(d, locData, t, tmp, OnStatic) else: putDataIntoDest(p, d, t, tmp) @@ -1982,7 +1982,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = if sfGlobal in sym.flags: genVarPrototype(p.module, sym) putLocIntoDest(p, d, sym.loc) elif isSimpleConst(sym.typ): - putIntoDest(p, d, n.typ, genLiteral(p, sym.ast, sym.typ)) + putIntoDest(p, d, n.typ, genLiteral(p, sym.ast, sym.typ), OnStatic) else: genComplexConst(p, sym, d) of skEnumField: diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 13514818e..3f88e63ee 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -760,7 +760,7 @@ proc requestConstImpl(p: BProc, sym: PSym) = var m = p.module useHeader(m, sym) if sym.loc.k == locNone: - fillLoc(sym.loc, locData, sym.typ, mangleName(sym), OnUnknown) + fillLoc(sym.loc, locData, sym.typ, mangleName(sym), OnStatic) if lfNoDecl in sym.loc.flags: return # declare implementation: var q = findPendingModule(m, sym) diff --git a/compiler/commands.nim b/compiler/commands.nim index dba117516..6b2f074e8 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -645,11 +645,18 @@ proc processSwitch*(pass: TCmdLinePass; p: OptParser) = proc processArgument*(pass: TCmdLinePass; p: OptParser; argsCount: var int): bool = if argsCount == 0: - if pass != passCmd2: options.command = p.key + # nim filename.nims is the same as "nim e filename.nims": + if p.key.endswith(".nims"): + options.command = "e" + options.gProjectName = unixToNativePath(p.key) + arguments = cmdLineRest(p) + result = true + elif pass != passCmd2: + options.command = p.key else: if pass == passCmd1: options.commandArgs.add p.key if argsCount == 1: - # support UNIX style filenames anywhere for portable build scripts: + # support UNIX style filenames everywhere for portable build scripts: options.gProjectName = unixToNativePath(p.key) arguments = cmdLineRest(p) result = true diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 297b865b2..31bd85a06 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -91,3 +91,4 @@ proc initDefines*() = defineSymbol("nimnomagic64") defineSymbol("nimvarargstyped") defineSymbol("nimtypedescfixed") + defineSymbol("nimKnowsNimvm") diff --git a/compiler/filter_tmpl.nim b/compiler/filter_tmpl.nim index d3ab1728c..21810adb9 100644 --- a/compiler/filter_tmpl.nim +++ b/compiler/filter_tmpl.nim @@ -67,9 +67,9 @@ proc parseLine(p: var TTmplParser) = keyw: string j = 0 while p.x[j] == ' ': inc(j) - if (p.x[0] == p.nimDirective) and (p.x[0 + 1] == '!'): + if p.x[0] == p.nimDirective and p.x[1] in {'?', '!'}: newLine(p) - elif (p.x[j] == p.nimDirective): + elif p.x[j] == p.nimDirective: newLine(p) inc(j) while p.x[j] == ' ': inc(j) diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 2ab43a9c9..70276a6d4 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -435,7 +435,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode = mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq, mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait, mDotDot, mNLen..mNError, mEqRef, mSlurp, mStaticExec, mNGenSym, mSpawn, - mParallel, mPlugin, mGetTypeInfo: + mParallel, mPlugin, mGetTypeInfo, mTypeOf: discard of mEqProc: result = newIntNodeT(ord( diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim index 91cfdbefd..021910544 100644 --- a/compiler/syntaxes.nim +++ b/compiler/syntaxes.nim @@ -92,10 +92,15 @@ proc parsePipe(filename: string, inputStream: PLLStream): PNode = var line = newStringOfCap(80) discard llStreamReadLine(s, line) var i = utf8Bom(line) + var linenumber = 1 if containsShebang(line, i): discard llStreamReadLine(s, line) i = 0 - if line[i] == '#' and line[i+1] == '!': + inc linenumber + if line[i] == '#' and line[i+1] in {'?', '!'}: + if line[i+1] == '!': + message(newLineInfo(filename, linenumber, 1), + warnDeprecated, "use '#?' instead; '#!'") inc(i, 2) while line[i] in Whitespace: inc(i) var q: TParser diff --git a/compiler/writetracking.nim b/compiler/writetracking.nim index 38258b07a..141b496c1 100644 --- a/compiler/writetracking.nim +++ b/compiler/writetracking.nim @@ -200,7 +200,7 @@ proc deps(w: var W; n: PNode) = proc possibleAliases(w: var W; result: var seq[ptr TSym]) = # this is an expensive fixpoint iteration. We could speed up this analysis - # by a smarter data-structure but we wait until prolifing shows us it's + # by a smarter data-structure but we wait until profiling shows us it's # expensive. Usually 'w.assignments' is small enough. var alreadySeen = initIntSet() template addNoDup(x) = diff --git a/contributors.txt b/contributors.txt index f9268974d..d54ec844a 100644 --- a/contributors.txt +++ b/contributors.txt @@ -1,4 +1,4 @@ -Comex +Comex Eric Doughty-Papassideris Simon Hafner Keita Haga @@ -6,7 +6,7 @@ Grzegorz Adam Hankiewicz Philippe Lhoste Zahary Karadjov Mario Ray Mahardhika -Alex Mitchell +Alexander Mitchell-Robinson (Amrykid) Dominik Picheta Jonathan Plona Alexander Rødseth diff --git a/doc/filelist.txt b/doc/filelist.txt index beff8f6c8..71379b40d 100644 --- a/doc/filelist.txt +++ b/doc/filelist.txt @@ -4,12 +4,12 @@ Short description of Nim's modules ============== ========================================================== Module Description ============== ========================================================== -nim main module: parses the command line and calls +nim main module: parses the command line and calls ``main.MainCommand`` main implements the top-level command dispatching nimconf implements the config file reader syntaxes dispatcher for the different parsers and filters -filter_tmpl standard template filter (``#! stdtempl``) +filter_tmpl standard template filter (``#? stdtempl``) lexbase buffer handling of the lexical analyser lexer lexical analyser parser Nim's parser diff --git a/doc/filters.txt b/doc/filters.txt index afbd61e3c..46bc6c3e5 100644 --- a/doc/filters.txt +++ b/doc/filters.txt @@ -8,9 +8,9 @@ A `Source Code Filter` transforms the input character stream to an in-memory output stream before parsing. A filter can be used to provide templating systems or preprocessors. -To use a filter for a source file the *shebang* notation is used:: +To use a filter for a source file the ``#?`` notation is used:: - #! stdtmpl(subsChar = '$', metaChar = '#') + #? stdtmpl(subsChar = '$', metaChar = '#') #proc generateXML(name, age: string): string = # result = "" @@ -20,7 +20,8 @@ To use a filter for a source file the *shebang* notation is used:: As the example shows, passing arguments to a filter can be done just like an ordinary procedure call with named or positional arguments. The -available parameters depend on the invoked filter. +available parameters depend on the invoked filter. Before version 0.12.0 of +the language ``#!`` was used instead of ``#?``. Pipe operator @@ -28,7 +29,7 @@ Pipe operator Filters can be combined with the ``|`` pipe operator:: - #! strip(startswith="<") | stdtmpl + #? strip(startswith="<") | stdtmpl #proc generateXML(name, age: string): string = # result = "" @@ -104,7 +105,7 @@ Parameters and their defaults: Example:: - #! stdtmpl | standard + #? stdtmpl | standard #proc generateHTMLPage(title, currentTab, content: string, # tabs: openArray[string]): string = # result = "" @@ -172,7 +173,7 @@ produces ``$``. The template engine is quite flexible. It is easy to produce a procedure that writes the template code directly to a file:: - #! stdtmpl(emit="f.write") | standard + #? stdtmpl(emit="f.write") | standard #proc writeHTMLPage(f: File, title, currentTab, content: string, # tabs: openArray[string]) = $title diff --git a/doc/manual/stmts.txt b/doc/manual/stmts.txt index 3fc950b4b..062c08d7c 100644 --- a/doc/manual/stmts.txt +++ b/doc/manual/stmts.txt @@ -329,8 +329,10 @@ The ``when`` statement enables conditional compilation techniques. As a special syntactic extension, the ``when`` construct is also available within ``object`` definitions. + When nimvm statement ---------------------- +-------------------- + ``nimvm`` is a special symbol, that may be used as expression of ``when nimvm`` statement to differentiate execution path between runtime and compile time. diff --git a/doc/manual/syntax.txt b/doc/manual/syntax.txt index 99af15948..c444a3995 100644 --- a/doc/manual/syntax.txt +++ b/doc/manual/syntax.txt @@ -68,13 +68,13 @@ Strong spaces ------------- The number of spaces preceding a non-keyword operator affects precedence -if the experimental parser directive ``#!strongSpaces`` is used. Indentation +if the experimental parser directive ``#?strongSpaces`` is used. Indentation is not used to determine the number of spaces. If 2 or more operators have the same number of preceding spaces the precedence table applies, so ``1 + 3 * 4`` is still parsed as ``1 + (3 * 4)``, but ``1+3 * 4`` is parsed as ``(1+3) * 4``: .. code-block:: nim - #! strongSpaces + #? strongSpaces if foo+4 * 4 == 8 and b&c | 9 ++ bar: echo "" @@ -86,7 +86,7 @@ Furthermore whether an operator is used a prefix operator is affected by the number of spaces: .. code-block:: nim - #! strongSpaces + #? strongSpaces echo $foo # is parsed as echo($foo) @@ -95,7 +95,7 @@ This also affects whether ``[]``, ``{}``, ``()`` are parsed as constructors or as accessors: .. code-block:: nim - #! strongSpaces + #? strongSpaces echo (1,2) # is parsed as echo((1,2)) diff --git a/doc/nims.txt b/doc/nims.txt index a9a2f9da8..2b9df4a87 100644 --- a/doc/nims.txt +++ b/doc/nims.txt @@ -12,8 +12,8 @@ a ``myproject.nims`` file that simply contains Nim code controlling the compilation process. The VM cannot deal with ``importc``, the FFI is not available, so there are not -many stdlib modules that you can use with Nim's VM. However, the following -modules are available: +many stdlib modules that you can use with Nim's VM. However, at least the +following modules are available: * `strutils `_ * `ospaths `_ @@ -40,7 +40,7 @@ NimScript as a build tool ========================= The ``task`` template that the ``system`` module defines allows a NimScript -file to be used as a build tool. The following exampled defines a +file to be used as a build tool. The following example defines a task ``build`` that is an alias for the ``c`` command: .. code-block:: nim diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 5fac1f0af..e6ea19a6b 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -1,13 +1,13 @@ # # # Nim's Runtime Library -# (c) Copyright 2011 Alex Mitchell +# (c) Copyright 2011 Alexander Mitchell-Robinson # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -## :Author: Alex Mitchell +## :Author: Alexander Mitchell-Robinson (Amrykid) ## ## This module implements operations for the built-in `seq`:idx: type which ## were inspired by functional programming languages. If you are looking for diff --git a/lib/pure/events.nim b/lib/pure/events.nim index 01b64c545..62800c5c8 100644 --- a/lib/pure/events.nim +++ b/lib/pure/events.nim @@ -1,13 +1,13 @@ # # # Nim's Runtime Library -# (c) Copyright 2011 Alex Mitchell +# (c) Copyright 2011 Alexander Mitchell-Robinson # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -## :Author: Alex Mitchell +## :Author: Alexander Mitchell-Robinson (Amrykid) ## ## This module implements an event system that is not dependent on external ## graphical toolkits. It was originally called ``NimEE`` because diff --git a/lib/pure/oids.nim b/lib/pure/oids.nim index 174922223..fca10dab6 100644 --- a/lib/pure/oids.nim +++ b/lib/pure/oids.nim @@ -25,6 +25,10 @@ type {.deprecated: [Toid: Oid].} +proc `==`*(oid1: Oid, oid2: Oid): bool = + ## Compare two Mongo Object IDs for equality + return (oid1.time == oid2.time) and (oid1.fuzz == oid2.fuzz) and (oid1.count == oid2.count) + proc hexbyte*(hex: char): int = case hex of '0'..'9': result = (ord(hex) - ord('0')) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index aa4ae5ace..3142952e7 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -11,6 +11,26 @@ ## This module contains routines and types for dealing with time. ## This module is available for the `JavaScript target ## `_. +## +## Examples: +## +## .. code-block:: nim +## +## import times, os +## var +## t = cpuTime() +## +## sleep(100) # replace this with something to be timed +## echo "Time taken: ",cpuTime() - t +## +## echo "My formatted time: ", format(getLocalTime(getTime()), "d MMMM yyyy HH:mm") +## echo "Using predefined formats: ", getClockStr(), " ", getDateStr() +## +## echo "epochTime() float value: ", epochTime() +## echo "getTime() float value: ", toSeconds(getTime()) +## echo "cpuTime() float value: ", cpuTime() +## echo "An hour from now : ", getLocalTime(getTime()) + initInterval(0,0,0,1) +## echo "An hour from (UTC) now: ", getGmTime(getTime()) + initInterval(0,0,0,1) {.push debugger:off.} # the user does not want to trace a part # of the standard library! @@ -288,10 +308,10 @@ proc `+`*(a: TimeInfo, interval: TimeInterval): TimeInfo = ## very accurate. let t = toSeconds(timeInfoToTime(a)) let secs = toSeconds(a, interval) - if a.tzname == "UTC": - result = getGMTime(fromSeconds(t + secs)) - else: - result = getLocalTime(fromSeconds(t + secs)) + #if a.tzname == "UTC": + # result = getGMTime(fromSeconds(t + secs)) + #else: + result = getLocalTime(fromSeconds(t + secs)) proc `-`*(a: TimeInfo, interval: TimeInterval): TimeInfo = ## subtracts ``interval`` time. @@ -300,10 +320,10 @@ proc `-`*(a: TimeInfo, interval: TimeInterval): TimeInfo = ## when you subtract so much that you reach the Julian calendar. let t = toSeconds(timeInfoToTime(a)) let secs = toSeconds(a, interval) - if a.tzname == "UTC": - result = getGMTime(fromSeconds(t - secs)) - else: - result = getLocalTime(fromSeconds(t - secs)) + #if a.tzname == "UTC": + # result = getGMTime(fromSeconds(t - secs)) + #else: + result = getLocalTime(fromSeconds(t - secs)) when not defined(JS): proc epochTime*(): float {.rtl, extern: "nt$1", tags: [TimeEffect].} @@ -1269,3 +1289,28 @@ when isMainModule: assert getDayOfWeekJulian(21, 9, 1970) == dMon assert getDayOfWeekJulian(1, 1, 2000) == dSat assert getDayOfWeekJulian(1, 1, 2021) == dFri + + # toSeconds tests with GM and Local timezones + #var t4 = getGMTime(fromSeconds(876124714)) # Mon 6 Oct 08:58:34 BST 1997 + var t4L = getLocalTime(fromSeconds(876124714)) + assert toSeconds(timeInfoToTime(t4L)) == 876124714 # fromSeconds is effectively "localTime" + assert toSeconds(timeInfoToTime(t4L)) + t4L.timezone.float == toSeconds(timeInfoToTime(t4)) + + assert toSeconds(t4, initInterval(seconds=0)) == 0.0 + assert toSeconds(t4L, initInterval(milliseconds=1)) == toSeconds(t4, initInterval(milliseconds=1)) + assert toSeconds(t4L, initInterval(seconds=1)) == toSeconds(t4, initInterval(seconds=1)) + assert toSeconds(t4L, initInterval(minutes=1)) == toSeconds(t4, initInterval(minutes=1)) + assert toSeconds(t4L, initInterval(hours=1)) == toSeconds(t4, initInterval(hours=1)) + assert toSeconds(t4L, initInterval(days=1)) == toSeconds(t4, initInterval(days=1)) + assert toSeconds(t4L, initInterval(months=1)) == toSeconds(t4, initInterval(months=1)) + assert toSeconds(t4L, initInterval(years=1)) == toSeconds(t4, initInterval(years=1)) + + # adding intervals + var + a1L = toSeconds(timeInfoToTime(t4L + initInterval(hours = 1))) + t4L.timezone.float + a1G = toSeconds(timeInfoToTime(t4)) + 60.0 * 60.0 + assert a1L == a1G + # subtracting intervals + a1L = toSeconds(timeInfoToTime(t4L - initInterval(hours = 1))) + t4L.timezone.float + a1G = toSeconds(timeInfoToTime(t4)) - (60.0 * 60.0) + assert a1L == a1G diff --git a/lib/system.nim b/lib/system.nim index 65b633266..1890ce5be 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1175,9 +1175,12 @@ const seqShallowFlag = low(int) -let nimvm* {.magic: "Nimvm".}: bool = false +when defined(nimKnowsNimvm): + let nimvm* {.magic: "Nimvm".}: bool = false ## may be used only in "when" expression. ## It is true in Nim VM context and false otherwise +else: + const nimvm*: bool = false proc compileOption*(option: string): bool {. magic: "CompileOption", noSideEffect.} @@ -1293,25 +1296,42 @@ proc shallowCopy*[T](x: var T, y: T) {.noSideEffect, magic: "ShallowCopy".} proc del*[T](x: var seq[T], i: Natural) {.noSideEffect.} = ## deletes the item at index `i` by putting ``x[high(x)]`` into position `i`. ## This is an O(1) operation. - let xl = x.len - shallowCopy(x[i], x[xl-1]) - setLen(x, xl-1) + let xl = x.len - 1 + shallowCopy(x[i], x[xl]) + setLen(x, xl) proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect.} = ## deletes the item at index `i` by moving ``x[i+1..]`` by one position. ## This is an O(n) operation. - let xl = x.len - for j in i..xl-2: shallowCopy(x[j], x[j+1]) - setLen(x, xl-1) + template defaultImpl = + let xl = x.len + for j in i..xl-2: shallowCopy(x[j], x[j+1]) + setLen(x, xl-1) + + when nimvm: + defaultImpl() + else: + when defined(js): + {.emit: "`x`[`x`_Idx].splice(`i`, 1);".} + else: + defaultImpl() proc insert*[T](x: var seq[T], item: T, i = 0.Natural) {.noSideEffect.} = ## inserts `item` into `x` at position `i`. - let xl = x.len - setLen(x, xl+1) - var j = xl-1 - while j >= i: - shallowCopy(x[j+1], x[j]) - dec(j) + template defaultImpl = + let xl = x.len + setLen(x, xl+1) + var j = xl-1 + while j >= i: + shallowCopy(x[j+1], x[j]) + dec(j) + when nimvm: + defaultImpl() + else: + when defined(js): + {.emit: "`x`[`x`_Idx].splice(`i`, 0, null);".} + else: + defaultImpl() x[i] = item proc repr*[T](x: T): string {.magic: "Repr", noSideEffect.} @@ -3042,7 +3062,7 @@ template spliceImpl(s, a, L, b: expr): stmt {.immediate.} = # fill the hole: for i in 0 .. @@ -23,7 +23,7 @@ # if t != "index" and t != "community" and t != "news": # let name = c.tabs[i].key # if currentTab == t: - # or greet(p) # declare a C procedure.. proc unsafeScanf(f: File, s: cstring) {.varargs, - importc: "fscanf", + importc: "fscanf", header: "<stdio.h>".} # ..and use it... @@ -191,7 +191,7 @@ runForever() - + # if currentTab == "index": # end if diff --git a/web/news.txt b/web/news.txt index 80983d33d..aaf3c9385 100644 --- a/web/news.txt +++ b/web/news.txt @@ -71,6 +71,8 @@ News are likely to break as well. - Base methods now need to be annotated with the ``base`` pragma. This makes multi methods less error-prone to use with the effect system. + - Nim's parser directive ``#!`` is now ``#?`` in order to produce no conflicts + with Unix's ``#!``. Library Additions @@ -89,7 +91,8 @@ News Compiler Additions ------------------ - - The compiler now supports a new configuration system based on ``NimScript``. + - The compiler now supports a new configuration system based on + `NimScript `_. Language Additions @@ -106,7 +109,7 @@ News is allowed. Note that this doesn't declare ``x`` and ``y`` variables, for this ``let (x, y) == f()`` still needs to be used. - ``when nimvm`` can now be used for compiletime versions of some code - sections. See (XXX) for details. + sections. Click `here `_ for details. Bugfixes