Merge remote-tracking branch 'nim-lang/devel' into emscripten-support

This commit is contained in:
Andrey Sobolev 2015-09-11 17:37:11 +06:00
commit c16c1b47b8
26 changed files with 282 additions and 118 deletions

View file

@ -709,6 +709,7 @@ type
lfSingleUse # no location yet and will only be used once lfSingleUse # no location yet and will only be used once
TStorageLoc* = enum TStorageLoc* = enum
OnUnknown, # location is unknown (stack, heap or static) OnUnknown, # location is unknown (stack, heap or static)
OnStatic, # in a static section
OnStack, # location is on hardware stack OnStack, # location is on hardware stack
OnHeap # location is on heap or global OnHeap # location is on heap or global
# (reference counting needed) # (reference counting needed)

View file

@ -221,7 +221,7 @@ proc optAsgnLoc(a: TLoc, t: PType, field: Rope): TLoc =
proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
let newflags = let newflags =
if src.k == locData: if src.s == OnStatic:
flags + {needToCopy} flags + {needToCopy}
elif tfShallow in dest.t.flags: elif tfShallow in dest.t.flags:
flags - {needToCopy} flags - {needToCopy}
@ -238,7 +238,7 @@ proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags,
t: PNode) = t: PNode) =
if t == nil: return if t == nil: return
let newflags = let newflags =
if src.k == locData: if src.s == OnStatic:
flags + {needToCopy} flags + {needToCopy}
elif tfShallow in dest.t.flags: elif tfShallow in dest.t.flags:
flags - {needToCopy} flags - {needToCopy}
@ -287,13 +287,13 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
of tyRef: of tyRef:
genRefAssign(p, dest, src, flags) genRefAssign(p, dest, src, flags)
of tySequence: of tySequence:
if needToCopy notin flags and src.k != locData: if needToCopy notin flags and src.s != OnStatic:
genRefAssign(p, dest, src, flags) genRefAssign(p, dest, src, flags)
else: else:
linefmt(p, cpsStmts, "#genericSeqAssign($1, $2, $3);$n", linefmt(p, cpsStmts, "#genericSeqAssign($1, $2, $3);$n",
addrLoc(dest), rdLoc(src), genTypeInfo(p.module, dest.t)) addrLoc(dest), rdLoc(src), genTypeInfo(p.module, dest.t))
of tyString: of tyString:
if needToCopy notin flags and src.k != locData: if needToCopy notin flags and src.s != OnStatic:
genRefAssign(p, dest, src, flags) genRefAssign(p, dest, src, flags)
else: else:
if dest.s == OnStack or not usesNativeGC(): 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 var a: TLoc
if d.k != locNone: if d.k != locNone:
# need to generate an assignment here # need to generate an assignment here
initLoc(a, locData, t, OnUnknown) initLoc(a, locData, t, OnStatic)
a.r = r a.r = r
if lfNoDeepCopy in d.flags: genAssignment(p, d, a, {}) if lfNoDeepCopy in d.flags: genAssignment(p, d, a, {})
else: genAssignment(p, d, a, {needToCopy}) 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.t = t
d.r = r 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 var a: TLoc
if d.k != locNone: if d.k != locNone:
# need to generate an assignment here # need to generate an assignment here
initLoc(a, locExpr, t, OnUnknown) initLoc(a, locExpr, t, s)
a.r = r a.r = r
if lfNoDeepCopy in d.flags: genAssignment(p, d, a, {}) if lfNoDeepCopy in d.flags: genAssignment(p, d, a, {})
else: genAssignment(p, d, a, {needToCopy}) else: genAssignment(p, d, a, {needToCopy})
@ -685,7 +685,7 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
d.s = OnUnknown d.s = OnUnknown
if tfVarIsPtr notin typ.flags and p.module.compileToCpp and if tfVarIsPtr notin typ.flags and p.module.compileToCpp and
e.kind == nkHiddenDeref: e.kind == nkHiddenDeref:
putIntoDest(p, d, e.typ, rdLoc(a)) putIntoDest(p, d, e.typ, rdLoc(a), a.s)
return return
of tyPtr: of tyPtr:
d.s = OnUnknown # BUGFIX! 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) let typ = skipTypes(a.t, abstractInst)
if typ.kind == tyVar and tfVarIsPtr notin typ.flags and if typ.kind == tyVar and tfVarIsPtr notin typ.flags and
e.kind == nkHiddenDeref: e.kind == nkHiddenDeref:
putIntoDest(p, d, e.typ, rdLoc(a)) putIntoDest(p, d, e.typ, rdLoc(a), a.s)
return return
if enforceDeref and mt == ctPtrToArray: if enforceDeref and mt == ctPtrToArray:
# we lie about the type for better C interop: 'ptr array[3,T]' is # 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 # See tmissingderef. So we get rid of the deref instead. The codegen
# ends up using 'memcpy' for the array assignment, # ends up using 'memcpy' for the array assignment,
# so the '&' and '*' cancel out: # 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: 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) = proc genAddr(p: BProc, e: PNode, d: var TLoc) =
# careful 'addr(myptrToArray)' needs to get the ampersand: # careful 'addr(myptrToArray)' needs to get the ampersand:
if e.sons[0].typ.skipTypes(abstractInst).kind in {tyRef, tyPtr}: if e.sons[0].typ.skipTypes(abstractInst).kind in {tyRef, tyPtr}:
var a: TLoc var a: TLoc
initLocExpr(p, e.sons[0], a) 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 &") #Message(e.info, warnUser, "HERE NEW &")
elif mapType(e.sons[0].typ) == ctArray or isCppRef(p, e.sons[0].typ): elif mapType(e.sons[0].typ) == ctArray or isCppRef(p, e.sons[0].typ):
expr(p, e.sons[0], d) expr(p, e.sons[0], d)
else: else:
var a: TLoc var a: TLoc
initLocExpr(p, e.sons[0], a) 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) = template inheritLocation(d: var TLoc, a: TLoc) =
if d.k == locNone: d.s = a.s 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) of nkIntLit..nkUInt64Lit: i = int(e.sons[1].intVal)
else: internalError(e.info, "genTupleElem") else: internalError(e.info, "genTupleElem")
addf(r, ".Field$1", [rope(i)]) 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) = proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
var a: 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 # we found a unique tuple type which lacks field information
# so we use Field$i # so we use Field$i
addf(r, ".Field$1", [rope(f.position)]) addf(r, ".Field$1", [rope(f.position)])
putIntoDest(p, d, f.typ, r) putIntoDest(p, d, f.typ, r, a.s)
else: else:
var field: PSym = nil var field: PSym = nil
while ty != 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 == nil: internalError(e.info, "genRecordField 2 ")
if field.loc.r == nil: internalError(e.info, "genRecordField 3") if field.loc.r == nil: internalError(e.info, "genRecordField 3")
addf(r, ".$1", [field.loc.r]) addf(r, ".$1", [field.loc.r])
putIntoDest(p, d, field.typ, r) putIntoDest(p, d, field.typ, r, a.s)
#d.s = a.s #d.s = a.s
proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc) 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: internalError(e.info, "genCheckedRecordField") # generate the checks:
genFieldCheck(p, e, r, field) genFieldCheck(p, e, r, field)
add(r, rfmt(nil, ".$1", field.loc.r)) add(r, rfmt(nil, ".$1", field.loc.r))
putIntoDest(p, d, field.typ, r) putIntoDest(p, d, field.typ, r, a.s)
else: else:
genRecordField(p, e.sons[0], d) genRecordField(p, e.sons[0], d)
@ -851,7 +851,7 @@ proc genArrayElem(p: BProc, x, y: PNode, d: var TLoc) =
localError(x.info, errIndexOutOfBounds) localError(x.info, errIndexOutOfBounds)
d.inheritLocation(a) d.inheritLocation(a)
putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)), 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) = proc genCStringElem(p: BProc, x, y: PNode, d: var TLoc) =
var a, b: 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) var ty = skipTypes(a.t, abstractVarRange)
if d.k == locNone: d.s = a.s if d.k == locNone: d.s = a.s
putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)), 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) = proc genOpenArrayElem(p: BProc, x, y: PNode, d: var TLoc) =
var a, b: 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 ``>``! rdLoc(b), rdLoc(a)) # BUGFIX: ``>=`` and not ``>``!
if d.k == locNone: d.s = a.s if d.k == locNone: d.s = a.s
putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)), 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) = proc genSeqElem(p: BProc, x, y: PNode, d: var TLoc) =
var a, b: 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}: if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}:
a.r = rfmt(nil, "(*$1)", a.r) a.r = rfmt(nil, "(*$1)", a.r)
putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)), 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) = proc genBracketExpr(p: BProc; n: PNode; d: var TLoc) =
var ty = skipTypes(n.sons[0].typ, abstractVarRange) 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)) r = rfmt(p.module, "(($1) && ($2))", nilCheck, genOfHelper(p, dest, r))
else: else:
r = rfmt(p.module, "($1)", genOfHelper(p, dest, r)) 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) = proc genOf(p: BProc, n: PNode, d: var TLoc) =
genOf(p, n.sons[1], n.sons[2].typ, d) 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 case t.kind
of tyInt..tyInt64, tyUInt..tyUInt64: of tyInt..tyInt64, tyUInt..tyUInt64:
putIntoDest(p, d, e.typ, 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: 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: 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: 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: of tyEnum, tyOrdinal:
putIntoDest(p, d, e.typ, putIntoDest(p, d, e.typ,
ropecg(p.module, "#reprEnum($1, $2)", [ ropecg(p.module, "#reprEnum($1, $2)", [
rdLoc(a), genTypeInfo(p.module, t)])) rdLoc(a), genTypeInfo(p.module, t)]), a.s)
of tyString: 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: of tySet:
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprSet($1, $2)", [ 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: of tyOpenArray, tyVarargs:
var b: TLoc var b: TLoc
case a.t.kind case a.t.kind
of tyOpenArray, tyVarargs: 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: of tyString, tySequence:
putIntoDest(p, b, e.typ, 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: of tyArray, tyArrayConstr:
putIntoDest(p, b, e.typ, 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()") else: internalError(e.sons[0].info, "genRepr()")
putIntoDest(p, d, e.typ, putIntoDest(p, d, e.typ,
ropecg(p.module, "#reprOpenArray($1, $2)", [rdLoc(b), 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, of tyCString, tyArray, tyArrayConstr, tyRef, tyPtr, tyPointer, tyNil,
tySequence: tySequence:
putIntoDest(p, d, e.typ, putIntoDest(p, d, e.typ,
ropecg(p.module, "#reprAny($1, $2)", [ ropecg(p.module, "#reprAny($1, $2)", [
rdLoc(a), genTypeInfo(p.module, t)])) rdLoc(a), genTypeInfo(p.module, t)]), a.s)
of tyEmpty: of tyEmpty:
localError(e.info, "'repr' doesn't support 'void' type") localError(e.info, "'repr' doesn't support 'void' type")
else: else:
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprAny($1, $2)", 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) gcUsage(e)
proc genGetTypeInfo(p: BProc, e: PNode, d: var TLoc) = 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) let etyp = skipTypes(e.typ, abstractRange)
if etyp.kind in ValueTypes and lfIndirect notin a.flags: if etyp.kind in ValueTypes and lfIndirect notin a.flags:
putIntoDest(p, d, e.typ, "(*($1*) ($2))" % 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: elif etyp.kind == tyProc and etyp.callConv == ccClosure:
putIntoDest(p, d, e.typ, "(($1) ($2))" % putIntoDest(p, d, e.typ, "(($1) ($2))" %
[getClosureType(p.module, etyp, clHalfWithEnv), rdCharLoc(a)]) [getClosureType(p.module, etyp, clHalfWithEnv), rdCharLoc(a)], a.s)
else: else:
putIntoDest(p, d, e.typ, "(($1) ($2))" % 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) = proc genCast(p: BProc, e: PNode, d: var TLoc) =
const floatTypes = {tyFloat..tyFloat128} const floatTypes = {tyFloat..tyFloat128}
@ -1575,7 +1575,7 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) =
tmp.s = OnStack tmp.s = OnStack
tmp.flags = {} tmp.flags = {}
expr(p, e.sons[1], tmp) 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: else:
# I prefer the shorter cast version for pointer types -> generate less # I prefer the shorter cast version for pointer types -> generate less
# C code; plus it's the right thing to do for closures: # 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}: {tyUInt..tyUInt64}:
initLocExpr(p, n.sons[0], a) initLocExpr(p, n.sons[0], a)
putIntoDest(p, d, n.typ, "(($1) ($2))" % putIntoDest(p, d, n.typ, "(($1) ($2))" %
[getTypeDesc(p.module, dest), rdCharLoc(a)]) [getTypeDesc(p.module, dest), rdCharLoc(a)], a.s)
else: else:
initLocExpr(p, n.sons[0], a) initLocExpr(p, n.sons[0], a)
putIntoDest(p, d, dest, ropecg(p.module, "(($1)#$5($2, $3, $4))", [ putIntoDest(p, d, dest, ropecg(p.module, "(($1)#$5($2, $3, $4))", [
getTypeDesc(p.module, dest), rdCharLoc(a), getTypeDesc(p.module, dest), rdCharLoc(a),
genLiteral(p, n.sons[1], dest), genLiteral(p, n.sons[2], dest), 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) = proc genConv(p: BProc, e: PNode, d: var TLoc) =
let destType = e.typ.skipTypes({tyVar, tyGenericInst}) 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) = proc convStrToCStr(p: BProc, n: PNode, d: var TLoc) =
var a: TLoc var a: TLoc
initLocExpr(p, n.sons[0], a) 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) = proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) =
var a: TLoc var a: TLoc
initLocExpr(p, n.sons[0], a) initLocExpr(p, n.sons[0], a)
putIntoDest(p, d, skipTypes(n.typ, abstractVar), 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) gcUsage(n)
proc genStrEquals(p: BProc, e: PNode, d: var TLoc) = 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) var t = getUniqueType(n.typ)
discard getTypeDesc(p.module, t) # so that any fields are initialized discard getTypeDesc(p.module, t) # so that any fields are initialized
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId) 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: if id == gBackendId:
# expression not found in the cache: # expression not found in the cache:
inc(gBackendId) inc(gBackendId)
@ -1849,7 +1849,7 @@ proc genClosure(p: BProc, n: PNode, d: var TLoc) =
var tmp = "LOC" & rope(p.labels) var tmp = "LOC" & rope(p.labels)
addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n", addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(p.module, n.typ), tmp, genConstExpr(p, n)]) [getTypeDesc(p.module, n.typ), tmp, genConstExpr(p, n)])
putIntoDest(p, d, n.typ, tmp) putIntoDest(p, d, n.typ, tmp, OnStatic)
else: else:
var tmp, a, b: TLoc var tmp, a, b: TLoc
initLocExpr(p, n.sons[0], a) initLocExpr(p, n.sons[0], a)
@ -1903,10 +1903,10 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
r, genTypeInfo(p.module, dest)) r, genTypeInfo(p.module, dest))
if n.sons[0].typ.kind != tyObject: if n.sons[0].typ.kind != tyObject:
putIntoDest(p, d, n.typ, 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: else:
putIntoDest(p, d, n.typ, "(*($1*) ($2))" % 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) = proc downConv(p: BProc, n: PNode, d: var TLoc) =
if p.module.compileToCpp: 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) linefmt(p, cpsStmts, "$1 = &$2;$n", rdLoc(d), r)
else: else:
r = "&" & r r = "&" & r
putIntoDest(p, d, n.typ, r) putIntoDest(p, d, n.typ, r, a.s)
else: else:
putIntoDest(p, d, n.typ, r) putIntoDest(p, d, n.typ, r, a.s)
proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) = proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
var t = getUniqueType(n.typ) 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)]) [getTypeDesc(p.module, t), tmp, genConstExpr(p, n)])
if d.k == locNone: if d.k == locNone:
fillLoc(d, locData, t, tmp, OnHeap) fillLoc(d, locData, t, tmp, OnStatic)
else: else:
putDataIntoDest(p, d, t, tmp) 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) if sfGlobal in sym.flags: genVarPrototype(p.module, sym)
putLocIntoDest(p, d, sym.loc) putLocIntoDest(p, d, sym.loc)
elif isSimpleConst(sym.typ): 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: else:
genComplexConst(p, sym, d) genComplexConst(p, sym, d)
of skEnumField: of skEnumField:

View file

@ -760,7 +760,7 @@ proc requestConstImpl(p: BProc, sym: PSym) =
var m = p.module var m = p.module
useHeader(m, sym) useHeader(m, sym)
if sym.loc.k == locNone: 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 if lfNoDecl in sym.loc.flags: return
# declare implementation: # declare implementation:
var q = findPendingModule(m, sym) var q = findPendingModule(m, sym)

View file

@ -645,11 +645,18 @@ proc processSwitch*(pass: TCmdLinePass; p: OptParser) =
proc processArgument*(pass: TCmdLinePass; p: OptParser; proc processArgument*(pass: TCmdLinePass; p: OptParser;
argsCount: var int): bool = argsCount: var int): bool =
if argsCount == 0: 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: else:
if pass == passCmd1: options.commandArgs.add p.key if pass == passCmd1: options.commandArgs.add p.key
if argsCount == 1: 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) options.gProjectName = unixToNativePath(p.key)
arguments = cmdLineRest(p) arguments = cmdLineRest(p)
result = true result = true

View file

@ -91,3 +91,4 @@ proc initDefines*() =
defineSymbol("nimnomagic64") defineSymbol("nimnomagic64")
defineSymbol("nimvarargstyped") defineSymbol("nimvarargstyped")
defineSymbol("nimtypedescfixed") defineSymbol("nimtypedescfixed")
defineSymbol("nimKnowsNimvm")

View file

@ -67,9 +67,9 @@ proc parseLine(p: var TTmplParser) =
keyw: string keyw: string
j = 0 j = 0
while p.x[j] == ' ': inc(j) 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) newLine(p)
elif (p.x[j] == p.nimDirective): elif p.x[j] == p.nimDirective:
newLine(p) newLine(p)
inc(j) inc(j)
while p.x[j] == ' ': inc(j) while p.x[j] == ' ': inc(j)

View file

@ -435,7 +435,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq, mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq,
mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait, mDotDot, mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait, mDotDot,
mNLen..mNError, mEqRef, mSlurp, mStaticExec, mNGenSym, mSpawn, mNLen..mNError, mEqRef, mSlurp, mStaticExec, mNGenSym, mSpawn,
mParallel, mPlugin, mGetTypeInfo: mParallel, mPlugin, mGetTypeInfo, mTypeOf:
discard discard
of mEqProc: of mEqProc:
result = newIntNodeT(ord( result = newIntNodeT(ord(

View file

@ -92,10 +92,15 @@ proc parsePipe(filename: string, inputStream: PLLStream): PNode =
var line = newStringOfCap(80) var line = newStringOfCap(80)
discard llStreamReadLine(s, line) discard llStreamReadLine(s, line)
var i = utf8Bom(line) var i = utf8Bom(line)
var linenumber = 1
if containsShebang(line, i): if containsShebang(line, i):
discard llStreamReadLine(s, line) discard llStreamReadLine(s, line)
i = 0 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) inc(i, 2)
while line[i] in Whitespace: inc(i) while line[i] in Whitespace: inc(i)
var q: TParser var q: TParser

View file

@ -200,7 +200,7 @@ proc deps(w: var W; n: PNode) =
proc possibleAliases(w: var W; result: var seq[ptr TSym]) = proc possibleAliases(w: var W; result: var seq[ptr TSym]) =
# this is an expensive fixpoint iteration. We could speed up this analysis # 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. # expensive. Usually 'w.assignments' is small enough.
var alreadySeen = initIntSet() var alreadySeen = initIntSet()
template addNoDup(x) = template addNoDup(x) =

View file

@ -1,4 +1,4 @@
Comex Comex
Eric Doughty-Papassideris Eric Doughty-Papassideris
Simon Hafner Simon Hafner
Keita Haga Keita Haga
@ -6,7 +6,7 @@ Grzegorz Adam Hankiewicz
Philippe Lhoste Philippe Lhoste
Zahary Karadjov Zahary Karadjov
Mario Ray Mahardhika Mario Ray Mahardhika
Alex Mitchell Alexander Mitchell-Robinson (Amrykid)
Dominik Picheta Dominik Picheta
Jonathan Plona Jonathan Plona
Alexander Rødseth Alexander Rødseth

View file

@ -4,12 +4,12 @@ Short description of Nim's modules
============== ========================================================== ============== ==========================================================
Module Description Module Description
============== ========================================================== ============== ==========================================================
nim main module: parses the command line and calls nim main module: parses the command line and calls
``main.MainCommand`` ``main.MainCommand``
main implements the top-level command dispatching main implements the top-level command dispatching
nimconf implements the config file reader nimconf implements the config file reader
syntaxes dispatcher for the different parsers and filters 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 lexbase buffer handling of the lexical analyser
lexer lexical analyser lexer lexical analyser
parser Nim's parser parser Nim's parser

View file

@ -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 output stream before parsing. A filter can be used to provide templating
systems or preprocessors. 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 = #proc generateXML(name, age: string): string =
# result = "" # result = ""
<xml> <xml>
@ -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 As the example shows, passing arguments to a filter can be done
just like an ordinary procedure call with named or positional arguments. The 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 Pipe operator
@ -28,7 +29,7 @@ Pipe operator
Filters can be combined with the ``|`` pipe operator:: Filters can be combined with the ``|`` pipe operator::
#! strip(startswith="<") | stdtmpl #? strip(startswith="<") | stdtmpl
#proc generateXML(name, age: string): string = #proc generateXML(name, age: string): string =
# result = "" # result = ""
<xml> <xml>
@ -104,7 +105,7 @@ Parameters and their defaults:
Example:: Example::
#! stdtmpl | standard #? stdtmpl | standard
#proc generateHTMLPage(title, currentTab, content: string, #proc generateHTMLPage(title, currentTab, content: string,
# tabs: openArray[string]): string = # tabs: openArray[string]): string =
# result = "" # result = ""
@ -172,7 +173,7 @@ produces ``$``.
The template engine is quite flexible. It is easy to produce a procedure that The template engine is quite flexible. It is easy to produce a procedure that
writes the template code directly to a file:: 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, #proc writeHTMLPage(f: File, title, currentTab, content: string,
# tabs: openArray[string]) = # tabs: openArray[string]) =
<head><title>$title</title></head> <head><title>$title</title></head>

View file

@ -329,8 +329,10 @@ The ``when`` statement enables conditional compilation techniques. As
a special syntactic extension, the ``when`` construct is also available a special syntactic extension, the ``when`` construct is also available
within ``object`` definitions. within ``object`` definitions.
When nimvm statement When nimvm statement
--------------------- --------------------
``nimvm`` is a special symbol, that may be used as expression of ``when nimvm`` ``nimvm`` is a special symbol, that may be used as expression of ``when nimvm``
statement to differentiate execution path between runtime and compile time. statement to differentiate execution path between runtime and compile time.

View file

@ -68,13 +68,13 @@ Strong spaces
------------- -------------
The number of spaces preceding a non-keyword operator affects precedence 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 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`` 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``: is still parsed as ``1 + (3 * 4)``, but ``1+3 * 4`` is parsed as ``(1+3) * 4``:
.. code-block:: nim .. code-block:: nim
#! strongSpaces #? strongSpaces
if foo+4 * 4 == 8 and b&c | 9 ++ if foo+4 * 4 == 8 and b&c | 9 ++
bar: bar:
echo "" echo ""
@ -86,7 +86,7 @@ Furthermore whether an operator is used a prefix operator is affected by the
number of spaces: number of spaces:
.. code-block:: nim .. code-block:: nim
#! strongSpaces #? strongSpaces
echo $foo echo $foo
# is parsed as # is parsed as
echo($foo) echo($foo)
@ -95,7 +95,7 @@ This also affects whether ``[]``, ``{}``, ``()`` are parsed as constructors
or as accessors: or as accessors:
.. code-block:: nim .. code-block:: nim
#! strongSpaces #? strongSpaces
echo (1,2) echo (1,2)
# is parsed as # is parsed as
echo((1,2)) echo((1,2))

View file

@ -12,8 +12,8 @@ a ``myproject.nims`` file that simply contains Nim code controlling the
compilation process. compilation process.
The VM cannot deal with ``importc``, the FFI is not available, so there are not 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 many stdlib modules that you can use with Nim's VM. However, at least the
modules are available: following modules are available:
* `strutils <strutils.html>`_ * `strutils <strutils.html>`_
* `ospaths <ospaths.html>`_ * `ospaths <ospaths.html>`_
@ -40,7 +40,7 @@ NimScript as a build tool
========================= =========================
The ``task`` template that the ``system`` module defines allows a NimScript 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: task ``build`` that is an alias for the ``c`` command:
.. code-block:: nim .. code-block:: nim

View file

@ -1,13 +1,13 @@
# #
# #
# Nim's Runtime Library # Nim's Runtime Library
# (c) Copyright 2011 Alex Mitchell # (c) Copyright 2011 Alexander Mitchell-Robinson
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # 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 ## This module implements operations for the built-in `seq`:idx: type which
## were inspired by functional programming languages. If you are looking for ## were inspired by functional programming languages. If you are looking for

View file

@ -1,13 +1,13 @@
# #
# #
# Nim's Runtime Library # Nim's Runtime Library
# (c) Copyright 2011 Alex Mitchell # (c) Copyright 2011 Alexander Mitchell-Robinson
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # 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 ## This module implements an event system that is not dependent on external
## graphical toolkits. It was originally called ``NimEE`` because ## graphical toolkits. It was originally called ``NimEE`` because

View file

@ -25,6 +25,10 @@ type
{.deprecated: [Toid: Oid].} {.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 = proc hexbyte*(hex: char): int =
case hex case hex
of '0'..'9': result = (ord(hex) - ord('0')) of '0'..'9': result = (ord(hex) - ord('0'))

View file

@ -11,6 +11,26 @@
## This module contains routines and types for dealing with time. ## This module contains routines and types for dealing with time.
## This module is available for the `JavaScript target ## This module is available for the `JavaScript target
## <backends.html#the-javascript-target>`_. ## <backends.html#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 {.push debugger:off.} # the user does not want to trace a part
# of the standard library! # of the standard library!
@ -288,10 +308,10 @@ proc `+`*(a: TimeInfo, interval: TimeInterval): TimeInfo =
## very accurate. ## very accurate.
let t = toSeconds(timeInfoToTime(a)) let t = toSeconds(timeInfoToTime(a))
let secs = toSeconds(a, interval) let secs = toSeconds(a, interval)
if a.tzname == "UTC": #if a.tzname == "UTC":
result = getGMTime(fromSeconds(t + secs)) # result = getGMTime(fromSeconds(t + secs))
else: #else:
result = getLocalTime(fromSeconds(t + secs)) result = getLocalTime(fromSeconds(t + secs))
proc `-`*(a: TimeInfo, interval: TimeInterval): TimeInfo = proc `-`*(a: TimeInfo, interval: TimeInterval): TimeInfo =
## subtracts ``interval`` time. ## subtracts ``interval`` time.
@ -300,10 +320,10 @@ proc `-`*(a: TimeInfo, interval: TimeInterval): TimeInfo =
## when you subtract so much that you reach the Julian calendar. ## when you subtract so much that you reach the Julian calendar.
let t = toSeconds(timeInfoToTime(a)) let t = toSeconds(timeInfoToTime(a))
let secs = toSeconds(a, interval) let secs = toSeconds(a, interval)
if a.tzname == "UTC": #if a.tzname == "UTC":
result = getGMTime(fromSeconds(t - secs)) # result = getGMTime(fromSeconds(t - secs))
else: #else:
result = getLocalTime(fromSeconds(t - secs)) result = getLocalTime(fromSeconds(t - secs))
when not defined(JS): when not defined(JS):
proc epochTime*(): float {.rtl, extern: "nt$1", tags: [TimeEffect].} proc epochTime*(): float {.rtl, extern: "nt$1", tags: [TimeEffect].}
@ -1269,3 +1289,28 @@ when isMainModule:
assert getDayOfWeekJulian(21, 9, 1970) == dMon assert getDayOfWeekJulian(21, 9, 1970) == dMon
assert getDayOfWeekJulian(1, 1, 2000) == dSat assert getDayOfWeekJulian(1, 1, 2000) == dSat
assert getDayOfWeekJulian(1, 1, 2021) == dFri 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

View file

@ -1175,9 +1175,12 @@ const
seqShallowFlag = low(int) 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. ## may be used only in "when" expression.
## It is true in Nim VM context and false otherwise ## It is true in Nim VM context and false otherwise
else:
const nimvm*: bool = false
proc compileOption*(option: string): bool {. proc compileOption*(option: string): bool {.
magic: "CompileOption", noSideEffect.} 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.} = proc del*[T](x: var seq[T], i: Natural) {.noSideEffect.} =
## deletes the item at index `i` by putting ``x[high(x)]`` into position `i`. ## deletes the item at index `i` by putting ``x[high(x)]`` into position `i`.
## This is an O(1) operation. ## This is an O(1) operation.
let xl = x.len let xl = x.len - 1
shallowCopy(x[i], x[xl-1]) shallowCopy(x[i], x[xl])
setLen(x, xl-1) setLen(x, xl)
proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect.} = proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect.} =
## deletes the item at index `i` by moving ``x[i+1..]`` by one position. ## deletes the item at index `i` by moving ``x[i+1..]`` by one position.
## This is an O(n) operation. ## This is an O(n) operation.
let xl = x.len template defaultImpl =
for j in i..xl-2: shallowCopy(x[j], x[j+1]) let xl = x.len
setLen(x, xl-1) 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.} = proc insert*[T](x: var seq[T], item: T, i = 0.Natural) {.noSideEffect.} =
## inserts `item` into `x` at position `i`. ## inserts `item` into `x` at position `i`.
let xl = x.len template defaultImpl =
setLen(x, xl+1) let xl = x.len
var j = xl-1 setLen(x, xl+1)
while j >= i: var j = xl-1
shallowCopy(x[j+1], x[j]) while j >= i:
dec(j) 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 x[i] = item
proc repr*[T](x: T): string {.magic: "Repr", noSideEffect.} 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: # fill the hole:
for i in 0 .. <b.len: s[i+a] = b[i] for i in 0 .. <b.len: s[i+a] = b[i]
when hasAlloc: when hasAlloc or defined(nimscript):
proc `[]`*(s: string, x: Slice[int]): string {.inline.} = proc `[]`*(s: string, x: Slice[int]): string {.inline.} =
## slice operation for strings. ## slice operation for strings.
result = s.substr(x.a, x.b) result = s.substr(x.a, x.b)

View file

@ -13,6 +13,9 @@
template builtin = discard template builtin = discard
# We know the effects better than the compiler:
{.push hint[XDeclaredButNotUsed]: off.}
proc listDirs*(dir: string): seq[string] = proc listDirs*(dir: string): seq[string] =
## Lists all the subdirectories (non-recursively) in the directory `dir`. ## Lists all the subdirectories (non-recursively) in the directory `dir`.
builtin builtin
@ -61,10 +64,17 @@ proc setCommand*(cmd: string) =
proc cmpIgnoreStyle(a, b: string): int = builtin proc cmpIgnoreStyle(a, b: string): int = builtin
proc cmpIgnoreCase(a, b: string): int = builtin proc cmpIgnoreCase(a, b: string): int = builtin
proc cmpic*(a, b: string): int = cmpIgnoreCase(a, b) proc cmpic*(a, b: string): int =
## Compares `a` and `b` ignoring case.
cmpIgnoreCase(a, b)
proc getEnv*(key: string): string = builtin proc getEnv*(key: string): string {.tags: [ReadIOEffect].} =
proc existsEnv*(key: string): bool = builtin ## Retrieves the environment variable of name `key`.
builtin
proc existsEnv*(key: string): bool {.tags: [ReadIOEffect].} =
## Checks for the existance of an environment variable named `key`.
builtin
proc fileExists*(filename: string): bool {.tags: [ReadIOEffect].} = proc fileExists*(filename: string): bool {.tags: [ReadIOEffect].} =
## Checks if the file exists. ## Checks if the file exists.
@ -96,8 +106,13 @@ proc strip(s: string): string =
while s[i] in {' ', '\c', '\L'}: inc i while s[i] in {' ', '\c', '\L'}: inc i
result = s.substr(i) result = s.substr(i)
template `--`*(key, val: untyped) = switch(astToStr(key), strip astToStr(val)) template `--`*(key, val: untyped) =
template `--`*(key: untyped) = switch(astToStr(key), "") ## A shortcut for ``switch(astToStr(key), astToStr(val))``.
switch(astToStr(key), strip astToStr(val))
template `--`*(key: untyped) =
## A shortcut for ``switch(astToStr(key)``.
switch(astToStr(key), "")
type type
ScriptMode* {.pure.} = enum ## Controls the behaviour of the script. ScriptMode* {.pure.} = enum ## Controls the behaviour of the script.
@ -158,7 +173,8 @@ proc exec*(command: string) =
raise newException(OSError, "FAILED: " & command) raise newException(OSError, "FAILED: " & command)
checkOsError() checkOsError()
proc exec*(command: string, input: string, cache = "") = proc exec*(command: string, input: string, cache = "") {.
raises: [OSError], tags: [ExecIOEffect].} =
## Executes an external process. ## Executes an external process.
log "exec: " & command: log "exec: " & command:
echo staticExec(command, input, cache) echo staticExec(command, input, cache)
@ -256,3 +272,5 @@ proc requires*(deps: varargs[string]) =
## Nimble support: Call this to set the list of requirements of your Nimble ## Nimble support: Call this to set the list of requirements of your Nimble
## package. ## package.
for d in deps: requiresData.add(d) for d in deps: requiresData.add(d)
{.pop.}

View file

@ -0,0 +1,19 @@
discard """
output: "adf"
"""
import asyncdispatch
const
test = ["adf"]
proc foo() {.async.} =
for i in test:
echo(i)
var finished = false
let x = foo()
x.callback =
proc () =
finished = true
while not finished: discard

View file

@ -0,0 +1,16 @@
discard """
output: '''@[a, c]'''
"""
# bug #3230
import sequtils
const
test_strings = ["a", "b", "c"]
proc is_doc(x: string): bool = x == "b"
let
tests = @test_strings.filter_it(not it.is_doc)
echo tests

View file

@ -1,8 +1,9 @@
discard """ discard """
output: '''(name: hello)''' output: '''(name: hello)
(-1, 0)'''
""" """
# bug #2774 # bug #2774, bug #3195
type Foo = object type Foo = object
name: string name: string
@ -12,3 +13,24 @@ const fooArray = [
] ]
echo fooArray[0] echo fooArray[0]
type
Position = object
x, y: int
proc `$`(pos: Position): string =
result = "(" & $pos.x & ", " & $pos.y & ")"
proc newPos(x, y: int): Position =
result = Position(x: x, y: y)
const
offset: array[1..4, Position] = [
newPos(-1, 0),
newPos(1, 0),
newPos(0, -1),
newPos(0, 1)
]
echo offset[1]

View file

@ -1,5 +1,5 @@
#! stdtmpl | standard #? stdtmpl | standard
#proc generateHTMLPage(c: var TConfigData, currentTab, content, rss: string): string = #proc generateHTMLPage(c: var TConfigData, currentTab, content, rss: string): string =
# result = "" # result = ""
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
@ -23,7 +23,7 @@
# if t != "index" and t != "community" and t != "news": # if t != "index" and t != "community" and t != "news":
# let name = c.tabs[i].key # let name = c.tabs[i].key
# if currentTab == t: # if currentTab == t:
<a class="active" <a class="active"
# else: # else:
<a <a
# end if # end if
@ -104,7 +104,7 @@ p.greet() <span class="cmt"># or greet(p)</span>
<span class="cmt"># declare a C procedure..</span> <span class="cmt"># declare a C procedure..</span>
<span class="kwd">proc</span> <span class="def">unsafeScanf</span>(f: <span class="typ">File</span>, s: <span class="typ">cstring</span>) <span class="kwd">proc</span> <span class="def">unsafeScanf</span>(f: <span class="typ">File</span>, s: <span class="typ">cstring</span>)
<span class="tab"> </span>{.varargs, <span class="tab"> </span>{.varargs,
<span class="tab"> </span>importc: <span class="val">"fscanf"</span>, <span class="tab"> </span>importc: <span class="val">"fscanf"</span>,
<span class="tab end"> </span>header: <span class="val">"&lt;stdio.h&gt;"</span>.} <span class="tab end"> </span>header: <span class="val">"&lt;stdio.h&gt;"</span>.}
<span class="cmt"># ..and use it...</span> <span class="cmt"># ..and use it...</span>
@ -191,7 +191,7 @@ runForever()
</div> </div>
</div> </div>
</footer> </footer>
# if currentTab == "index": # if currentTab == "index":
<script src="assets/index.js"></script> <script src="assets/index.js"></script>
# end if # end if

View file

@ -71,6 +71,8 @@ News
are likely to break as well. are likely to break as well.
- Base methods now need to be annotated with the ``base`` pragma. This makes - Base methods now need to be annotated with the ``base`` pragma. This makes
multi methods less error-prone to use with the effect system. 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 Library Additions
@ -89,7 +91,8 @@ News
Compiler Additions Compiler Additions
------------------ ------------------
- The compiler now supports a new configuration system based on ``NimScript``. - The compiler now supports a new configuration system based on
`NimScript <docs/nims.html>`_.
Language Additions Language Additions
@ -106,7 +109,7 @@ News
is allowed. Note that this doesn't declare ``x`` and ``y`` variables, for is allowed. Note that this doesn't declare ``x`` and ``y`` variables, for
this ``let (x, y) == f()`` still needs to be used. this ``let (x, y) == f()`` still needs to be used.
- ``when nimvm`` can now be used for compiletime versions of some code - ``when nimvm`` can now be used for compiletime versions of some code
sections. See (XXX) for details. sections. Click `here <docs/manual.html#when-nimvm-statement>`_ for details.
Bugfixes Bugfixes