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
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
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)

View File

@@ -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:

View File

@@ -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)

View File

@@ -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

View File

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

View File

@@ -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)

View File

@@ -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(

View File

@@ -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

View File

@@ -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) =

View File

@@ -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

View File

@@ -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

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
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 = ""
<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
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 = ""
<xml>
@@ -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]) =
<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
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.

View File

@@ -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))

View File

@@ -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 <strutils.html>`_
* `ospaths <ospaths.html>`_
@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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'))

View File

@@ -11,6 +11,26 @@
## This module contains routines and types for dealing with time.
## This module is available for 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
# 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

View File

@@ -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 .. <b.len: s[i+a] = b[i]
when hasAlloc:
when hasAlloc or defined(nimscript):
proc `[]`*(s: string, x: Slice[int]): string {.inline.} =
## slice operation for strings.
result = s.substr(x.a, x.b)

View File

@@ -13,6 +13,9 @@
template builtin = discard
# We know the effects better than the compiler:
{.push hint[XDeclaredButNotUsed]: off.}
proc listDirs*(dir: string): seq[string] =
## Lists all the subdirectories (non-recursively) in the directory `dir`.
builtin
@@ -61,10 +64,17 @@ proc setCommand*(cmd: string) =
proc cmpIgnoreStyle(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 existsEnv*(key: string): bool = builtin
proc getEnv*(key: string): string {.tags: [ReadIOEffect].} =
## 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].} =
## Checks if the file exists.
@@ -96,8 +106,13 @@ proc strip(s: string): string =
while s[i] in {' ', '\c', '\L'}: inc i
result = s.substr(i)
template `--`*(key, val: untyped) = switch(astToStr(key), strip astToStr(val))
template `--`*(key: untyped) = switch(astToStr(key), "")
template `--`*(key, val: untyped) =
## 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
ScriptMode* {.pure.} = enum ## Controls the behaviour of the script.
@@ -158,7 +173,8 @@ proc exec*(command: string) =
raise newException(OSError, "FAILED: " & command)
checkOsError()
proc exec*(command: string, input: string, cache = "") =
proc exec*(command: string, input: string, cache = "") {.
raises: [OSError], tags: [ExecIOEffect].} =
## Executes an external process.
log "exec: " & command:
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
## package.
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 """
output: '''(name: hello)'''
output: '''(name: hello)
(-1, 0)'''
"""
# bug #2774
# bug #2774, bug #3195
type Foo = object
name: string
@@ -12,3 +13,24 @@ const fooArray = [
]
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
#proc generateHTMLPage(c: var TConfigData, currentTab, content, rss: string): string =
#? stdtmpl | standard
#proc generateHTMLPage(c: var TConfigData, currentTab, content, rss: string): string =
# result = ""
<!DOCTYPE html>
<html>
@@ -23,7 +23,7 @@
# if t != "index" and t != "community" and t != "news":
# let name = c.tabs[i].key
# if currentTab == t:
<a class="active"
<a class="active"
# else:
<a
# 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="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>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="cmt"># ..and use it...</span>
@@ -191,7 +191,7 @@ runForever()
</div>
</div>
</footer>
# if currentTab == "index":
<script src="assets/index.js"></script>
# end if

View File

@@ -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 <docs/nims.html>`_.
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 <docs/manual.html#when-nimvm-statement>`_ for details.
Bugfixes