Merge branch 'master' of github.com:Araq/Nimrod into upstream

This commit is contained in:
Zahary Karadjov
2012-06-02 19:52:06 +03:00
31 changed files with 459 additions and 114 deletions

View File

@@ -145,6 +145,7 @@ type
nkIfStmt, # an if statement
nkWhenStmt, # a when expression or statement
nkForStmt, # a for statement
nkParForStmt, # a parallel for statement
nkWhileStmt, # a while statement
nkCaseStmt, # a case statement
nkTypeSection, # a type section (consists of type definitions)
@@ -396,7 +397,7 @@ type
mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT,
mConTArr, mConTT, mSlice,
mFields, mFieldPairs,
mFields, mFieldPairs, mOmpParFor,
mAppendStrCh, mAppendStrStr, mAppendSeqElem,
mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq,
mIsPartOf, mAstToStr, mRand,

View File

@@ -20,7 +20,8 @@ proc hasNoInit(call: PNode): bool {.inline.} =
proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, pl: PRope) =
var pl = pl
var typ = ri.sons[0].typ # getUniqueType() is too expensive here!
# getUniqueType() is too expensive here:
var typ = skipTypes(ri.sons[0].typ, abstractInst)
if typ.sons[0] != nil:
if isInvalidReturnType(typ.sons[0]):
if sonsLen(ri) > 1: app(pl, ", ")
@@ -124,7 +125,8 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
# this is a hotspot in the compiler
initLocExpr(p, ri.sons[0], op)
var pl = con(op.r, "(")
var typ = ri.sons[0].typ # getUniqueType() is too expensive here!
# getUniqueType() is too expensive here:
var typ = skipTypes(ri.sons[0].typ, abstractInst)
assert(typ.kind == tyProc)
var length = sonsLen(ri)
for i in countup(1, length - 1):
@@ -150,7 +152,8 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
var op: TLoc
initLocExpr(p, ri.sons[0], op)
var pl: PRope
var typ = ri.sons[0].typ
var typ = skipTypes(ri.sons[0].typ, abstractInst)
assert(typ.kind == tyProc)
var length = sonsLen(ri)
for i in countup(1, length - 1):
@@ -201,7 +204,8 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
var op, a: TLoc
initLocExpr(p, ri.sons[0], op)
var pl: PRope = nil
var typ = ri.sons[0].typ # getUniqueType() is too expensive here!
# getUniqueType() is too expensive here:
var typ = skipTypes(ri.sons[0].typ, abstractInst)
assert(typ.kind == tyProc)
var length = sonsLen(ri)
assert(sonsLen(typ) == sonsLen(typ.n))
@@ -228,7 +232,8 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
var op, a: TLoc
initLocExpr(p, ri.sons[0], op)
var pl = toRope"["
var typ = ri.sons[0].typ # getUniqueType() is too expensive here!
# getUniqueType() is too expensive here:
var typ = skipTypes(ri.sons[0].typ, abstractInst)
assert(typ.kind == tyProc)
var length = sonsLen(ri)
assert(sonsLen(typ) == sonsLen(typ.n))

View File

@@ -283,7 +283,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
proc expr(p: BProc, e: PNode, d: var TLoc)
proc initLocExpr(p: BProc, e: PNode, result: var TLoc) =
initLoc(result, locNone, getUniqueType(e.typ), OnUnknown)
initLoc(result, locNone, e.typ, OnUnknown)
expr(p, e, result)
proc getDestLoc(p: BProc, d: var TLoc, typ: PType) =
@@ -543,17 +543,17 @@ proc genAddr(p: BProc, e: PNode, d: var TLoc) =
proc genRecordFieldAux(p: BProc, e: PNode, d, a: var TLoc): PType =
initLocExpr(p, e.sons[0], a)
if (e.sons[1].kind != nkSym): InternalError(e.info, "genRecordFieldAux")
if e.sons[1].kind != nkSym: InternalError(e.info, "genRecordFieldAux")
if d.k == locNone: d.s = a.s
discard getTypeDesc(p.module, a.t) # fill the record's fields.loc
result = getUniqueType(a.t)
result = a.t
proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
var a: TLoc
var ty = genRecordFieldAux(p, e, d, a)
var r = rdLoc(a)
var f = e.sons[1].sym
if ty.n == nil:
if ty.kind == tyTuple:
# we found a unique tuple type which lacks field information
# so we use Field$i
appf(r, ".Field$1", [toRope(f.position)])
@@ -561,14 +561,14 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
else:
var field: PSym = nil
while ty != nil:
if not (ty.kind in {tyTuple, tyObject}):
if ty.kind notin {tyTuple, tyObject}:
InternalError(e.info, "genRecordField")
field = lookupInRecord(ty.n, f.name)
if field != nil: break
if gCmd != cmdCompileToCpp: app(r, ".Sup")
ty = GetUniqueType(ty.sons[0])
if field == nil: InternalError(e.info, "genRecordField")
if field.loc.r == nil: InternalError(e.info, "genRecordField")
if field == nil: InternalError(e.info, "genRecordField 2 ")
if field.loc.r == nil: InternalError(e.info, "genRecordField 3")
appf(r, ".$1", [field.loc.r])
putIntoDest(p, d, field.typ, r)
@@ -579,16 +579,17 @@ proc genTupleElem(p: BProc, e: PNode, d: var TLoc) =
initLocExpr(p, e.sons[0], a)
if d.k == locNone: d.s = a.s
discard getTypeDesc(p.module, a.t) # fill the record's fields.loc
var ty = getUniqueType(a.t)
var ty = a.t
var r = rdLoc(a)
case e.sons[1].kind
of nkIntLit..nkInt64Lit: i = int(e.sons[1].intVal)
else: internalError(e.info, "genTupleElem")
if ty.n != nil:
var field = ty.n.sons[i].sym
if field == nil: InternalError(e.info, "genTupleElem")
if field.loc.r == nil: InternalError(e.info, "genTupleElem")
appf(r, ".$1", [field.loc.r])
when false:
if ty.n != nil:
var field = ty.n.sons[i].sym
if field == nil: InternalError(e.info, "genTupleElem")
if field.loc.r == nil: InternalError(e.info, "genTupleElem")
appf(r, ".$1", [field.loc.r])
else:
appf(r, ".Field$1", [toRope(i)])
putIntoDest(p, d, ty.sons[i], r)
@@ -1510,11 +1511,10 @@ proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) =
for i in countup(0, sonsLen(n) - 1):
var it = n.sons[i]
if it.kind == nkExprColonExpr: it = it.sons[1]
if t.n == nil:
initLoc(rec, locExpr, it.typ, d.s)
rec.r = ropef("$1.Field$2", [rdLoc(d), toRope(i)])
expr(p, it, rec)
else:
initLoc(rec, locExpr, it.typ, d.s)
rec.r = ropef("$1.Field$2", [rdLoc(d), toRope(i)])
expr(p, it, rec)
when false:
initLoc(rec, locExpr, it.typ, d.s)
if (t.n.sons[i].kind != nkSym): InternalError(n.info, "genTupleConstr")
rec.r = ropef("$1.$2",

View File

@@ -32,7 +32,7 @@ proc genVarTuple(p: BProc, n: PNode) =
assignLocalVar(p, v)
initLocalVar(p, v, immediateAsgn=true)
initLoc(field, locExpr, t.sons[i], tup.s)
if t.n == nil:
if t.kind == tyTuple:
field.r = ropef("$1.Field$2", [rdLoc(tup), toRope(i)])
else:
if (t.n.sons[i].kind != nkSym): InternalError(n.info, "genVarTuple")
@@ -258,6 +258,34 @@ proc genBlock(p: BProc, t: PNode, d: var TLoc) =
else: genStmts(p, t.sons[1])
endBlock(p)
proc genParForStmt(p: BProc, t: PNode) =
assert(sonsLen(t) == 3)
inc(p.withinLoop)
genLineDir(p, t)
preserveBreakIdx:
let forLoopVar = t.sons[0].sym
var rangeA, rangeB: TLoc
assignLocalVar(P, forLoopVar)
#initLoc(forLoopVar.loc, locLocalVar, forLoopVar.typ, onStack)
#discard mangleName(forLoopVar)
let call = t.sons[1]
initLocExpr(p, call.sons[1], rangeA)
initLocExpr(p, call.sons[2], rangeB)
appf(p.s(cpsStmts), "#pragma omp parallel for $4$n" &
"for ($1 = $2; $1 <= $3; ++$1)",
forLoopVar.loc.rdLoc,
rangeA.rdLoc, rangeB.rdLoc,
call.sons[3].getStr.toRope)
p.breakIdx = startBlock(p)
p.blocks[p.breakIdx].isLoop = true
genStmts(p, t.sons[2])
endBlock(p)
dec(p.withinLoop)
proc genBreakStmt(p: BProc, t: PNode) =
var idx = p.breakIdx
if t.sons[0].kind != nkEmpty:
@@ -815,5 +843,6 @@ proc genStmts(p: BProc, t: PNode) =
# we have not only the header:
if prc.getBody.kind != nkEmpty or lfDynamicLib in prc.loc.flags:
genProc(p.module, prc)
of nkParForStmt: genParForStmt(p, t)
else: internalError(t.info, "genStmts(" & $t.kind & ')')

View File

@@ -144,7 +144,7 @@ proc mapSetType(typ: PType): TCTypeKind =
proc mapType(typ: PType): TCTypeKind =
case typ.kind
of tyNone: result = ctVoid
of tyNone, tyStmt: result = ctVoid
of tyBool: result = ctBool
of tyChar: result = ctChar
of tySet: result = mapSetType(typ)
@@ -561,7 +561,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
appf(m.s[cfsForwardTypes], getForwardStructFormat(), [result])
IdTablePut(m.forwTypeCache, t, result)
IdTablePut(m.typeCache, t, result) # always call for sideeffects:
if t.n != nil: recdesc = getRecordDesc(m, t, result, check)
if t.kind != tyTuple: recdesc = getRecordDesc(m, t, result, check)
else: recdesc = getTupleDesc(m, t, result, check)
if not isImportedType(t): app(m.s[cfsTypes], recdesc)
of tySet:
@@ -889,8 +889,11 @@ proc genTypeInfo(m: BModule, typ: PType): PRope =
of tyEnum: genEnumInfo(gNimDat, t, result)
of tyObject: genObjectInfo(gNimDat, t, result)
of tyTuple:
if t.n != nil: genObjectInfo(gNimDat, t, result)
else: genTupleInfo(gNimDat, t, result)
# if t.n != nil: genObjectInfo(gNimDat, t, result)
# else:
# BUGFIX: use consistently RTTI without proper field names; otherwise
# results are not deterministic!
genTupleInfo(gNimDat, t, result)
else: InternalError("genTypeInfo(" & $t.kind & ')')
proc genTypeSection(m: BModule, n: PNode) =

View File

@@ -87,14 +87,19 @@ proc GetUniqueType*(key: PType): PType =
of tyGenericInst, tyDistinct, tyOrdinal, tyMutable, tyConst, tyIter:
result = GetUniqueType(lastSon(key))
of tyArrayConstr, tyGenericInvokation, tyGenericBody,
tyOpenArray, tyArray, tyTuple, tySet, tyRange,
tyOpenArray, tyArray, tySet, tyRange, tyTuple,
tyPtr, tyRef, tySequence, tyForward, tyVarargs, tyProxy, tyVar:
# tuples are quite horrible as C does not support them directly and
# tuple[string, string] is a (strange) subtype of
# tuple[nameA, nameB: string]. This bites us here, so we
# use 'sameBackendType' instead of 'sameType'.
# we have to do a slow linear search because types may need
# to be compared by their structure:
if IdTableHasObjectAsKey(gTypeTable[k], key): return key
for h in countup(0, high(gTypeTable[k].data)):
var t = PType(gTypeTable[k].data[h].key)
if t != nil and sameType(t, key):
if t != nil and sameBackendType(t, key):
return t
IdTablePut(gTypeTable[k], key, key)
result = key

View File

@@ -1343,7 +1343,8 @@ proc genStmt(p: var TProc, n: PNode, r: var TCompRes) =
of nkWhileStmt: genWhileStmt(p, n, r)
of nkVarSection, nkLetSection: genVarStmt(p, n, r)
of nkConstSection: genConstStmt(p, n, r)
of nkForStmt: internalError(n.info, "for statement not eliminated")
of nkForStmt, nkParForStmt:
internalError(n.info, "for statement not eliminated")
of nkCaseStmt: genCaseStmt(p, n, r)
of nkReturnStmt: genReturnStmt(p, n, r)
of nkBreakStmt: genBreakStmt(p, n, r)

View File

@@ -1331,7 +1331,7 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
of nkPragmaBlock:
result = evalAux(c, n.sons[1], flags)
of nkIdentDefs, nkCast, nkYieldStmt, nkAsmStmt, nkForStmt, nkPragmaExpr,
nkLambdaKinds, nkContinueStmt, nkIdent:
nkLambdaKinds, nkContinueStmt, nkIdent, nkParForStmt:
result = raiseCannotEval(c, n.info)
of nkRefTy:
result = evalAux(c, n.sons[0], flags)

View File

@@ -21,18 +21,19 @@ proc considerAcc*(n: PNode): PIdent =
case n.len
of 0: GlobalError(n.info, errIdentifierExpected, renderTree(n))
of 1: result = considerAcc(n.sons[0])
of 2:
if n[0].ident.id == ord(wStar):
else:
if n.len == 2 and n[0].kind == nkIdent and n[0].ident.id == ord(wStar):
# XXX find a better way instead of `*x` for 'genSym'
result = genSym(n[1].ident.s)
else:
result = getIdent(n[0].ident.s & n[1].ident.s)
else:
var id = ""
for i in 0.. <n.len:
if n.sons[i].kind != nkIdent:
GlobalError(n.info, errIdentifierExpected, renderTree(n))
id.add(n.sons[i].ident.s)
result = getIdent(id)
var id = ""
for i in 0.. <n.len:
let x = n.sons[i]
case x.kind
of nkIdent: id.add(x.ident.s)
of nkSym: id.add(x.sym.name.s)
else: GlobalError(n.info, errIdentifierExpected, renderTree(n))
result = getIdent(id)
else:
GlobalError(n.info, errIdentifierExpected, renderTree(n))

View File

@@ -984,7 +984,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
of nkCaseStmt, nkRecCase: gcase(g, n)
of nkMacroStmt: gmacro(g, n)
of nkTryStmt: gtry(g, n)
of nkForStmt: gfor(g, n)
of nkForStmt, nkParForStmt: gfor(g, n)
of nkBlockStmt, nkBlockExpr: gblock(g, n)
of nkStaticStmt: gstaticStmt(g, n)
of nkAsmStmt: gasm(g, n)

View File

@@ -142,7 +142,7 @@ proc semGenericStmt(c: PContext, n: PNode,
a.sons[j] = semGenericStmt(c, a.sons[j], flags, toBind)
a.sons[L - 1] = semGenericStmtScope(c, a.sons[L-1], flags, toBind)
closeScope(c.tab)
of nkForStmt:
of nkForStmt, nkParForStmt:
var L = sonsLen(n)
openScope(c.tab)
n.sons[L - 2] = semGenericStmt(c, n.sons[L-2], flags, toBind)

View File

@@ -465,7 +465,11 @@ proc semFor(c: PContext, n: PNode): PNode =
else:
GlobalError(n.sons[length - 2].info, errIteratorExpected)
elif call.sons[0].sym.magic != mNone:
result = semForFields(c, n, call.sons[0].sym.magic)
if call.sons[0].sym.magic == mOmpParFor:
result = semForVars(c, n)
result.kind = nkParForStmt
else:
result = semForFields(c, n, call.sons[0].sym.magic)
else:
result = semForVars(c, n)
closeScope(c.tab)
@@ -979,7 +983,7 @@ proc SemStmt(c: PContext, n: PNode): PNode =
of nkWhileStmt: result = semWhile(c, n)
of nkTryStmt: result = semTry(c, n)
of nkBreakStmt, nkContinueStmt: result = semBreakOrContinue(c, n)
of nkForStmt: result = semFor(c, n)
of nkForStmt, nkParForStmt: result = semFor(c, n)
of nkCaseStmt: result = semCase(c, n)
of nkReturnStmt: result = semReturn(c, n)
of nkAsmStmt: result = semAsm(c, n)

View File

@@ -247,7 +247,7 @@ proc transformConstSection(c: PTransf, v: PNode): PTransNode =
proc hasContinue(n: PNode): bool =
case n.kind
of nkEmpty..nkNilLit, nkForStmt, nkWhileStmt: nil
of nkEmpty..nkNilLit, nkForStmt, nkParForStmt, nkWhileStmt: nil
of nkContinueStmt: result = true
else:
for i in countup(0, sonsLen(n) - 1):
@@ -659,6 +659,10 @@ proc transform(c: PTransf, n: PNode): PTransNode =
inc c.inLoop
result = transformFor(c, n)
dec c.inLoop
of nkParForStmt:
inc c.inLoop
result = transformSons(c, n)
dec c.inLoop
of nkCaseStmt: result = transformCase(c, n)
of nkContinueStmt:
result = PTransNode(newNode(nkBreakStmt))

View File

@@ -550,6 +550,7 @@ type
TSameTypeClosure = object {.pure.}
cmp: TDistinctCompare
ignoreTupleFields: bool
recCheck: int
s: seq[tuple[a,b: int]] # seq for a set as it's hopefully faster
# (few elements expected)
@@ -645,7 +646,7 @@ proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool =
for i in countup(0, sonsLen(a) - 1):
result = SameTypeAux(a.sons[i], b.sons[i], c)
if not result: return
if a.n != nil and b.n != nil:
if a.n != nil and b.n != nil and not c.ignoreTupleFields:
for i in countup(0, sonsLen(a.n) - 1):
# check field names:
if a.n.sons[i].kind != nkSym: InternalError(a.n.info, "sameTuple")
@@ -787,6 +788,11 @@ proc SameType*(x, y: PType): bool =
var c = initSameTypeClosure()
result = sameTypeAux(x, y, c)
proc sameBackendType*(x, y: PType): bool =
var c = initSameTypeClosure()
c.ignoreTupleFields = true
result = sameTypeAux(x, y, c)
proc compareTypes*(x, y: PType, cmp: TDistinctCompare): bool =
## compares two type for equality (modulo type distinction)
var c = initSameTypeClosure()
@@ -863,8 +869,9 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
result = typeAllowedAux(marker, t.sons[0], skResult)
of tyExpr, tyStmt, tyTypeDesc:
result = true
of tyGenericBody, tyGenericParam, tyForward, tyNone, tyGenericInvokation, tyTypeClass:
result = false #InternalError('shit found');
of tyGenericBody, tyGenericParam, tyForward, tyNone, tyGenericInvokation,
tyTypeClass:
result = false
of tyEmpty, tyNil:
result = kind == skConst
of tyString, tyBool, tyChar, tyEnum, tyInt..tyBigNum, tyCString, tyPointer:

View File

@@ -60,6 +60,7 @@ hint[LineTooLong]=off
@if unix:
@if not bsd:
# -fopenmp
gcc.options.linker = "-ldl"
clang.options.linker = "-ldl"
tcc.options.linker = "-ldl"

View File

@@ -36,7 +36,7 @@ type
nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch,
nnkElifBranch, nnkExceptBranch, nnkElse, nnkMacroStmt,
nnkAsmStmt, nnkPragma, nnkPragmaBlock, nnkIfStmt, nnkWhenStmt,
nnkForStmt, nnkWhileStmt, nnkCaseStmt,
nnkForStmt, nnkParForStmt, nnkWhileStmt, nnkCaseStmt,
nnkTypeSection, nnkVarSection, nnkLetSection, nnkConstSection,
nnkConstDef, nnkTypeDef,
nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt,
@@ -217,10 +217,19 @@ template emit*(s: expr): stmt =
## Example:
##
## emit("echo " & '"' & "hello world".toUpper & '"')
##
block:
const evaluated = s
eval: result = evaluated.parseStmt
##
block:
const evaluated = s
eval: result = evaluated.parseStmt
when false:
template once(x: expr): expr =
block:
const y = x
y
macro `payload`(x: stmt): stmt = result = once(s).parseStmt
`payload`()
proc expectKind*(n: PNimrodNode, k: TNimrodNodeKind) {.compileTime.} =
## checks that `n` is of kind `k`. If this is not the case,
@@ -323,7 +332,7 @@ proc lispRepr*(n: PNimrodNode): string {.compileTime.} =
macro dumpTree*(s: stmt): stmt = echo s[1].treeRepr
## Accepts a block of nimrod code and prints the parsed abstract syntax
## tree using the `toTree` function.
## tree using the `toTree` function. Printing is done *at compile time*.
##
## You can use this as a tool to explore the Nimrod's abstract syntax
## tree and to discover what kind of nodes must be created to represent
@@ -331,7 +340,7 @@ macro dumpTree*(s: stmt): stmt = echo s[1].treeRepr
macro dumpLisp*(s: stmt): stmt = echo s[1].lispRepr
## Accepts a block of nimrod code and prints the parsed abstract syntax
## tree using the `toLisp` function.
## tree using the `toLisp` function. Printing is done *at compile time*.
##
## See `dumpTree`.

View File

@@ -479,7 +479,8 @@ proc setBiggestFloat*(x: TAny, y: biggestFloat) =
proc getString*(x: TAny): string =
## retrieve the string value out of `x`. `x` needs to represent a string.
assert x.rawtype.kind == tyString
result = cast[ptr string](x.value)[]
if not isNil(cast[ptr pointer](x.value)[]):
result = cast[ptr string](x.value)[]
proc setString*(x: TAny, y: string) =
## sets the string value of `x`. `x` needs to represent a string.

View File

@@ -24,7 +24,11 @@ type
mJan, mFeb, mMar, mApr, mMay, mJun, mJul, mAug, mSep, mOct, mNov, mDec
TWeekDay* = enum ## represents a weekday
dMon, dTue, dWed, dThu, dFri, dSat, dSun
var
timezone {.importc, header: "<time.h>".}: int
tzname {.importc, header: "<time.h>" .}: array[0..1, cstring]
when defined(posix):
type
TTimeImpl {.importc: "time_t", header: "<sys/time.h>".} = int
@@ -112,6 +116,20 @@ type
yearday*: range[0..365] ## The number of days since January 1,
## in the range 0 to 365.
## Always 0 if the target is ECMAScript.
isDST*: bool ## Determines whether DST is in effect. Always
## ``False`` if time is UTC.
tzname*: string ## The timezone this time is in. E.g. GMT
timezone*: int ## The offset of the (non-DST) timezone in seconds
## west of UTC.
TTimeInterval* = object
miliseconds*: int ## The number of miliseconds
seconds*: int ## The number of seconds
minutes*: int ## The number of minutes
hours*: int ## The number of hours
days*: int ## The number of days
months*: int ## The number of months
years*: int ## The number of years
proc getTime*(): TTime ## gets the current calendar time
proc getLocalTime*(t: TTime): TTimeInfo
@@ -122,7 +140,7 @@ proc getGMTime*(t: TTime): TTimeInfo
## expressed in Coordinated Universal Time (UTC).
proc TimeInfoToTime*(timeInfo: TTimeInfo): TTime
## converts a broken-down time structure, expressed as local time, to
## converts a broken-down time structure to
## calendar time representation. The function ignores the specified
## contents of the structure members `weekday` and `yearday` and recomputes
## them from the other information in the broken-down time structure.
@@ -146,10 +164,90 @@ proc `<=` * (a, b: TTime): bool {.
## returns true iff ``a <= b``.
result = a - b <= 0
proc getTzname*(): tuple[nonDST, DST: string]
## returns the local timezone; ``nonDST`` is the name of the local non-DST
## timezone, ``DST`` is the name of the local DST timezone.
proc getTimezone*(): int
## returns the offset of the local (non-DST) timezone in seconds west of UTC.
proc getStartMilsecs*(): int {.deprecated.}
## get the miliseconds from the start of the program. **Deprecated since
## version 0.8.10.** Use ``epochTime`` or ``cpuTime`` instead.
proc newInterval*(miliseconds, seconds, minutes, hours, days, months,
years: int = 0): TTimeInterval =
## creates a new ``TTimeInterval``.
result.miliseconds = miliseconds
result.seconds = seconds
result.minutes = minutes
result.hours = hours
result.days = days
result.months = months
result.years = years
proc isLeapYear(year: int): bool =
if year mod 400 == 0:
return true
elif year mod 100 == 0:
return false
elif year mod 4 == 0:
return true
else:
return false
proc getDaysInMonth(month: TMonth, year: int): int =
# http://www.dispersiondesign.com/articles/time/number_of_days_in_a_month
if month == mFeb: # Feb
if isLeapYear(year):
result = 29
else:
result = 28
elif month in [mApr, mJun, mSep, mNov]: result = 30
else: result = 31
proc calculateSeconds(a: TTimeInfo, interval: TTimeInterval): float =
var anew = a
var newinterv = interval
result = 0.0
newinterv.months += interval.years * 12
var curMonth = anew.month
for mth in 1 .. newinterv.months:
result += float(getDaysInMonth(curMonth, anew.year) * 24 * 60 * 60)
if curMonth == mDec:
curMonth = mJan
anew.year.inc()
else:
curMonth.inc()
result += float(newinterv.days * 24 * 60 * 60)
result += float(newinterv.minutes * 60 * 60)
result += newinterv.seconds.float
result += newinterv.miliseconds / 1000
proc `+`*(a: TTimeInfo, interval: TTimeInterval): TTimeInfo =
## adds ``interval`` time.
##
## **Note:** This has been only briefly tested and it may not be very accurate.
let t = timeInfoToTime(a)
var secs = calculateSeconds(a, interval)
if a.tzname == "UTC":
result = getGMTime(TTime(float(t) + secs))
else:
result = getLocalTime(TTime(float(t) + secs))
proc `-`*(a: TTimeInfo, interval: TTimeInterval): TTimeInfo =
## subtracts ``interval`` time.
##
## **Note:** This has been only briefly tested, it is inaccurate especially
## when you subtract so much that you reach the Julian calendar.
let t = timeInfoToTime(a)
var secs = calculateSeconds(a, interval)
if a.tzname == "UTC":
result = getGMTime(TTime(float(t) - secs))
else:
result = getLocalTime(TTime(float(t) - secs))
when not defined(ECMAScript):
proc epochTime*(): float {.rtl, extern: "nt$1".}
## gets time after the UNIX epoch (1970) in seconds. It is a float
@@ -169,7 +267,8 @@ when not defined(ECMAScript):
## doWork()
## echo "CPU time [s] ", cpuTime() - t0
when not defined(ECMAScript):
when not defined(ECMAScript):
# C wrapper:
type
structTM {.importc: "struct tm", final.} = object
@@ -205,7 +304,7 @@ when not defined(ECMAScript):
clocksPerSec {.importc: "CLOCKS_PER_SEC", nodecl.}: int
# our own procs on top of that:
proc tmToTimeInfo(tm: structTM): TTimeInfo =
proc tmToTimeInfo(tm: structTM, local: bool): TTimeInfo =
const
weekDays: array [0..6, TWeekDay] = [
dSun, dMon, dTue, dWed, dThu, dFri, dSat]
@@ -217,6 +316,18 @@ when not defined(ECMAScript):
result.year = tm.year + 1900'i32
result.weekday = weekDays[int(tm.weekDay)]
result.yearday = int(tm.yearday)
result.isDST = tm.isDST > 0
#result.tzname = if local: getTzname()[if result.isDST: 0 else: 1] else: "UTC"
# TODO: ^^^ Crashes the compiler.
if local:
if result.isDST:
result.tzname = getTzname()[0]
if not result.isDST:
result.tzname = getTzname()[1]
else:
result.tzname = "UTC"
result.timezone = if local: getTimezone() else: 0
proc timeInfoToTM(t: TTimeInfo): structTM =
const
@@ -229,7 +340,7 @@ when not defined(ECMAScript):
result.year = t.year - 1900
result.weekday = weekDays[t.weekDay]
result.yearday = t.yearday
result.isdst = -1
result.isdst = if t.isDST: 1 else: 0
when not defined(useNimRtl):
proc `-` (a, b: TTime): int64 =
@@ -251,13 +362,13 @@ when not defined(ECMAScript):
proc getTime(): TTime = return timec(nil)
proc getLocalTime(t: TTime): TTimeInfo =
var a = t
result = tmToTimeInfo(localtime(addr(a))[])
result = tmToTimeInfo(localtime(addr(a))[], true)
# copying is needed anyway to provide reentrancity; thus
# the convertion is not expensive
proc getGMTime(t: TTime): TTimeInfo =
var a = t
result = tmToTimeInfo(gmtime(addr(a))[])
result = tmToTimeInfo(gmtime(addr(a))[], false)
# copying is needed anyway to provide reentrancity; thus
# the convertion is not expensive
@@ -294,7 +405,13 @@ when not defined(ECMAScript):
proc winTimeToUnixTime*(t: int64): TTime =
## converts a Windows time to a UNIX `TTime` (``time_t``)
result = TTime((t - epochDiff) div rateDiff)
proc getTzname(): tuple[nonDST, DST: string] =
return ($tzname[0], $tzname[1])
proc getTimezone(): int =
return timezone
when not defined(useNimRtl):
proc epochTime(): float =
when defined(posix):
@@ -417,18 +534,21 @@ proc format*(info: TTimeInfo, f: string): string =
## tt Same as above, but ``AM`` and ``PM`` instead of ``A`` and ``P`` respectively.
## y(yyyy) This displays the year to different digits. You most likely only want 2 or 4 'y's
## yy Displays the year to two digits. ``2012 -> 12``
## yyyy Displays the year to four digits. ``2012 -> 2012``
## yyyy Displays the year to four digits. ``2012 -> 2012``
## z Displays the timezone offset from UTC. ``GMT+7 -> +7``, ``GMT-5 -> -5``
## zz Same as above but with leading 0. ``GMT+7 -> +07``, ``GMT-5 -> -05``
## zzz Same as above but with ``:00``. ``GMT+7 -> +07:00``, ``GMT-5 -> -05:00``
## ZZZ Displays the name of the timezone. ``GMT -> GMT``, ``EST -> EST``
## ========== ================================================================================= ================================================
##
## Other strings can be inserted by putting them in ``''``. For example ``hh'->'mm`` will give ``01->56``.
result = ""
var i = 0
var currentF = ""
while True:
case f[i]
of '\0':
break
of ' ', '-', '/', ':', '\'':
of ' ', '-', '/', ':', '\'', '\0':
case currentF
of "d":
result.add($info.monthday)
@@ -437,9 +557,9 @@ proc format*(info: TTimeInfo, f: string): string =
result.add("0")
result.add($info.monthday)
of "ddd":
result.add(($info.month)[0 .. 2])
result.add(($info.monthday)[0 .. 2])
of "dddd":
result.add($info.month)
result.add($info.monthday)
of "h":
result.add($(info.hour - 12))
of "hh":
@@ -460,11 +580,11 @@ proc format*(info: TTimeInfo, f: string): string =
result.add('0')
result.add($info.minute)
of "M":
result.add($(int(info.month)))
result.add($(int(info.month)+1))
of "MM":
if int(info.month) < 10:
result.add('0')
result.add($(int(info.month)))
result.add($(int(info.month)+1))
of "MMM":
result.add(($info.month)[0..2])
of "MMMM":
@@ -500,12 +620,32 @@ proc format*(info: TTimeInfo, f: string): string =
of "yyyyy":
result.add('0')
result.add($info.year)
of "z":
let hrs = (info.timezone div 60) div 60
result.add($hrs)
of "zz":
let hrs = (info.timezone div 60) div 60
result.add($hrs)
if hrs.abs < 10:
var atIndex = result.len-(($hrs).len-(if hrs < 0: 1 else: 0))
result.insert("0", atIndex)
of "zzz":
let hrs = (info.timezone div 60) div 60
result.add($hrs & ":00")
if hrs.abs < 10:
var atIndex = result.len-(($hrs & ":00").len-(if hrs < 0: 1 else: 0))
result.insert("0", atIndex)
of "ZZZ":
result.add(info.tzname)
of "":
nil # Do nothing.
else:
raise newException(EInvalidValue, "Invalid format string: " & currentF)
currentF = ""
if f[i] == '\0': break
if f[i] == '\'':
inc(i) # Skip '

View File

@@ -49,9 +49,13 @@ type
## a type description (for templates)
void* {.magic: "VoidType".} ## meta type to denote the absense of any type
TInteger* = int|char|int8|int16|int32|int64|bool|enum
TInteger* = int|int8|int16|int32|int64
## type class matching all integer types
TOrdinal* = TInteger|bool|enum
## type class matching all ordinal types; however this includes enums with
## holes.
TNumber* = TInteger|float|float32|float64
## type class matching all number types
@@ -190,6 +194,7 @@ type
msg* {.exportc: "message".}: string ## the exception's message. Not
## providing an exception message
## is bad style.
trace: string
EAsynch* = object of E_Base ## Abstract exception class for
## *asynchronous exceptions* (interrupts).
@@ -1195,6 +1200,15 @@ iterator `..`*[S, T](a: S, b: T): T {.inline.} =
yield res
inc res
iterator `||`*[S, T](a: S, b: T, annotation=""): T {.
inline, magic: "OmpParFor", sideEffect.} =
## parallel loop iterator. Same as `..` but the loop may run in parallel.
## `annotation` is an additional annotation for the code generator to use.
## Note that the compiler maps that to
## the ``#pragma omp parallel for`` construct of `OpenMP`:idx: and as
## such isn't aware of the parallelism in your code. Be careful.
nil
proc min*(x, y: int): int {.magic: "MinI", noSideEffect.}
proc min*(x, y: int8): int8 {.magic: "MinI", noSideEffect.}
proc min*(x, y: int16): int16 {.magic: "MinI", noSideEffect.}
@@ -1900,6 +1914,10 @@ when not defined(EcmaScript) and not defined(NimrodVM):
when hostOS != "standalone":
proc getStackTrace*(): string
## gets the current stack trace. This is only works for debug builds.
proc getStackTrace*(e: ref E_Base): string
## gets the stack trace associated with `e`, which is the stack that
## lead to the ``raise`` statement. This is only works for debug builds.
{.push stack_trace: off.}
when hostOS == "standalone":
@@ -2177,19 +2195,19 @@ proc `*=`*[T](x: var ordinal[T], y: ordinal[T]) {.inline, noSideEffect.} =
## Binary `*=` operator for ordinals
x = x * y
proc `+=` *(x: var float, y:float) {.inline, noSideEffect.} =
proc `+=`*[T: float|float32|float64] (x: var T, y: T) {.inline, noSideEffect.} =
## Increments in placee a floating point number
x = x + y
proc `-=` *(x: var float, y:float) {.inline, noSideEffect.} =
proc `-=`*[T: float|float32|float64] (x: var T, y: T) {.inline, noSideEffect.} =
## Decrements in place a floating point number
x = x - y
proc `*=` *(x: var float, y:float) {.inline, noSideEffect.} =
proc `*=`*[T: float|float32|float64] (x: var T, y: T) {.inline, noSideEffect.} =
## Multiplies in place a floating point number
x = x * y
proc `/=` *(x: var float, y:float) {.inline, noSideEffect.} =
proc `/=`*[T: float|float32|float64] (x: var T, y: T) {.inline, noSideEffect.} =
## Divides in place a floating point number
x = x / y
@@ -2283,5 +2301,18 @@ template eval*(blk: stmt): stmt =
macro payload(x: stmt): stmt = blk
payload()
proc insert*(x: var string, item: string, i = 0) {.noSideEffect.} =
## inserts `item` into `x` at position `i`.
var xl = x.len
setLen(x, xl+item.len)
var j = xl-1
while j >= i:
shallowCopy(x[j+item.len], x[j])
dec(j)
j = 0
while j < item.len:
x[j+i] = item[j]
inc(j)
when defined(initDebugger):
initDebugger()

View File

@@ -7,6 +7,8 @@
# distribution, for details about the copyright.
#
proc genericResetAux(dest: Pointer, n: ptr TNimNode)
proc genericAssignAux(dest, src: Pointer, mt: PNimType, shallow: bool)
proc genericAssignAux(dest, src: Pointer, n: ptr TNimNode, shallow: bool) =
var
@@ -20,10 +22,16 @@ proc genericAssignAux(dest, src: Pointer, n: ptr TNimNode, shallow: bool) =
for i in 0..n.len-1:
genericAssignAux(dest, src, n.sons[i], shallow)
of nkCase:
var dd = selectBranch(dest, n)
var m = selectBranch(src, n)
# reset if different branches are in use; note different branches also
# imply that's not self-assignment (``x = x``)!
if m != dd and dd != nil:
genericResetAux(dest, dd)
copyMem(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset),
n.typ.size)
var m = selectBranch(src, n)
if m != nil: genericAssignAux(dest, src, m, shallow)
if m != nil:
genericAssignAux(dest, src, m, shallow)
of nkNone: sysAssert(false, "genericAssignAux")
#else:
# echo "ugh memory corruption! ", n.kind

View File

@@ -194,6 +194,9 @@ proc quitOrDebug() {.inline.} =
proc raiseException(e: ref E_Base, ename: CString) {.compilerRtl.} =
e.name = ename
when hasSomeStackTrace:
e.trace = ""
rawWriteStackTrace(e.trace)
if localRaiseHook != nil:
if not localRaiseHook(e): return
if globalRaiseHook != nil:
@@ -253,6 +256,12 @@ proc getStackTrace(): string =
else:
result = "No stack traceback available\n"
proc getStackTrace(e: ref E_Base): string =
if not isNil(e) and not isNil(e.trace):
result = e.trace
else:
result = ""
when defined(endb):
var
dbgAborting: bool # whether the debugger wants to abort

View File

@@ -608,9 +608,16 @@ proc parseSmiley(p: var TRstParser): PRstNode =
result.text = val
return
when false:
const
urlChars = {'A'..'Z', 'a'..'z', '0'..'9', ':', '#', '@', '%', '/', ';',
'$', '(', ')', '~', '_', '?', '+', '-', '=', '\\', '.', '&',
'\128'..'\255'}
proc isURL(p: TRstParser, i: int): bool =
result = (p.tok[i+1].symbol == ":") and (p.tok[i+2].symbol == "//") and
(p.tok[i+3].kind == tkWord) and (p.tok[i+4].symbol == ".")
(p.tok[i+3].kind == tkWord) and
(p.tok[i].symbol in ["http", "ftp", "gopher", "telnet", "file"])
proc parseURL(p: var TRstParser, father: PRstNode) =
#if p.tok[p.idx].symbol[strStart] == '<':

View File

@@ -40,3 +40,18 @@ template typedef(name: expr, typ: typeDesc) {.immediate.} =
typedef(myint, int)
var x: PMyInt
# Test UFCS
type
Foo = object
arg: int
proc initFoo(arg: int): Foo =
result.arg = arg
template create(typ: typeDesc, arg: expr): expr = `init typ`(arg)
var ff = Foo.create(12)
echo ff.arg

11
tests/reject/tenummix.nim Normal file
View File

@@ -0,0 +1,11 @@
discard """
file: "system.nim"
line: 640
errormsg: "type mismatch"
"""
type
TE1 = enum eA, eB
TE2 = enum eC, eD
assert eA != eC

27
tests/run/tdumptree.nim Normal file
View File

@@ -0,0 +1,27 @@
discard """
disabled: true
output: '''StmtList
VarSection
IdentDefs
Ident !"x"
nil
Call
DotExpr
Ident !"foo"
Ident !"create"
IntLit 56'''
"""
# disabled; can't work as the output is done by the compiler
import macros
#emit("type\n TFoo = object\n bar: int")
#var f: TFoo
#f.bar = 5
#echo(f.bar)
dumpTree:
var x = foo.create(56)

View File

@@ -1,5 +1,5 @@
discard """
output: "0false"
output: "0false12"
"""
# Test multiple generic instantiation of generic proc vars:
@@ -17,3 +17,20 @@ proc threadProcWrapper[TMsg]() =
threadProcWrapper[int]()
threadProcWrapper[bool]()
type
TFilterProc[T,D] = proc (item: T, env:D): bool
proc filter[T,D](data: seq[T], env:D, pred: TFilterProc[T,D]): seq[T] =
result = @[]
for e in data:
if pred(e, env): result.add(e)
proc predTest(item: int, value: int): Bool =
return item <= value
proc test(data: seq[int], value: int): seq[int] =
return filter(data, value, predTest)
for x in items(test(@[1,2,3], 2)):
stdout.write(x)

View File

@@ -1,6 +1,6 @@
discard """
file: "tsequtils.nim"
output: '''Zip: [{"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "b": 6}]
output: '''Zip: [{"Field0": 1, "Field1": 2}, {"Field0": 3, "Field1": 4}, {"Field0": 5, "Field1": 6}]
Filter Iterator: 3
Filter Iterator: 5
Filter Iterator: 7

View File

@@ -1,8 +1,10 @@
version 0.9.0
=============
- make stack traces part of the exception in debug builds
- make templates hygienic by default
- implement 'gorge'
- implement a warning message for shadowed 'result' variable
- make templates hygienic by default: try to gensym() everything in the 'block'
of a template
- ``bind`` for overloaded symbols does not work apparently
- ``=`` should be overloadable; requires specialization for ``=``
- fix remaining generics bugs
@@ -24,6 +26,7 @@ version 0.9.0
- we need to support iteration of 2 different data structures in parallel
- make exceptions compatible with C++ exceptions
- change how comments are part of the AST
- find a better solution for gensym instead of `*ident`
- extract nimdoc properly and document it finally
- rethink the syntax: distinction between expr and stmt is unfortunate;
indentation handling is quite complex too; problem with exception handling
@@ -32,17 +35,9 @@ version 0.9.0
error handling more light-weight
people also want ``inc a; inc b``
Bugs
----
- bug: generic assign still buggy
- special case the generic assign that needs to care about case objects
- bug: returning a tyVar does not mean it is save to return it:
proc forward[T](x: var T): var T = result = x
proc p(): var int =
var x: int
# reject this call via alias analysis:
result = forward(x)
- bug: stress testing basic method example (eval example)
without ``-d:release`` leaks memory?

View File

@@ -3,6 +3,9 @@
# result = "#! /bin/sh\n# Generated from niminst\n" &
# "# Template is in tools/buildsh.tmpl\n" &
# "# To regenerate run ``niminst csource`` or ``koch csource``\n"
set -e
while :
do
case "$1" in
@@ -108,11 +111,11 @@ case $myos in
# var linkCmd = ""
# for f in items(c.cfiles[osA][cpuA]):
echo "$CC $COMP_FLAGS -Ibuild -c ?{f} -o ?{changeFileExt(f, "o")}"
$CC $COMP_FLAGS -Ibuild -c ?{f} -o ?{changeFileExt(f, "o")} || exit 1
$CC $COMP_FLAGS -Ibuild -c ?{f} -o ?{changeFileExt(f, "o")}
# add(linkCmd, " \\\n" & changeFileExt(f, "o"))
# end for
echo "$LINKER $LINK_FLAGS -o ?{firstBinPath(c)/toLower(c.name)} ?linkCmd"
$LINKER $LINK_FLAGS -o ?{firstBinPath(c)/toLower(c.name)} ?linkCmd || exit 1
$LINKER $LINK_FLAGS -o ?{firstBinPath(c)/toLower(c.name)} ?linkCmd
;;
# end for
*)

View File

@@ -3,6 +3,8 @@
# result = "#! /bin/sh\n# Generated by niminst\n"
# var proj = c.name.toLower
set -e
if [ $# -eq 1 ] ; then
# if c.cat[fcUnixBin].len > 0:
if test -f ?{c.cat[fcUnixBin][0]}
@@ -47,13 +49,13 @@ if [ $# -eq 1 ] ; then
docdir="$1/?proj/doc"
datadir="$1/?proj/data"
mkdir -p $1/?proj || exit 1
mkdir -p $bindir || exit 1
mkdir -p $configdir || exit 1
mkdir -p $1/?proj
mkdir -p $bindir
mkdir -p $configdir
;;
esac
mkdir -p $libdir || exit 1
mkdir -p $docdir || exit 1
mkdir -p $libdir
mkdir -p $docdir
echo "copying files..."
#var createdDirs = newStringTable()
#for cat in fcConfig..fcLib:
@@ -63,30 +65,34 @@ if [ $# -eq 1 ] ; then
# mk = unixDirVars[cat] & "/" & mk
# if not createdDirs.hasKey(mk):
# createdDirs[mk] = "true"
mkdir -p ?mk || exit 1
mkdir -p ?mk
# end if
# end if
# end for
#end for
#for f in items(c.cat[fcUnixBin]):
cp ?f $bindir/?f.skipRoot || exit 1
cp ?f $bindir/?f.skipRoot
chmod 755 $bindir/?f.skipRoot
#end for
#for f in items(c.cat[fcConfig]):
cp ?f $configdir/?f.skipRoot || exit 1
cp ?f $configdir/?f.skipRoot
chmod 644 $configdir/?f.skipRoot
#end for
#for f in items(c.cat[fcData]):
cp ?f $datadir/?f.skipRoot || exit 1
chmod 644 $datadir/?f.skipRoot
if [ -f ?f ]; then
cp ?f $datadir/?f.skipRoot
chmod 644 $datadir/?f.skipRoot
fi
#end for
#for f in items(c.cat[fcDoc]):
cp ?f $docdir/?f.skipRoot || exit 1
chmod 644 $docdir/?f.skipRoot
#for f in items(c.cat[fcDoc]):
if [ -f ?f ]; then
cp ?f $docdir/?f.skipRoot
chmod 644 $docdir/?f.skipRoot
fi
#end for
#for f in items(c.cat[fcLib]):
cp ?f $libdir/?f.skipRoot || exit 1
#for f in items(c.cat[fcLib]):
cp ?f $libdir/?f.skipRoot
chmod 644 $libdir/?f.skipRoot
#end for

View File

@@ -48,6 +48,7 @@ Library Additions
- Added ``system.clamp`` to limit a value within an interval ``[a, b]``.
- Added ``strutils.continuesWith``.
- Added ``system.getStackTrace``.
- Added ``system.||`` for parallel for loop support.
- The GC supports (soft) realtime systems via ``GC_setMaxPause``
and ``GC_step`` procs.
@@ -73,6 +74,9 @@ Changes affecting backwards compatibility
- Deprecated ``system.GC_setStrategy``.
- ``re.findAll`` and ``pegs.findAll`` don't return *captures* anymore but
matching *substrings*.
- RTTI and thus the ``marshall`` module don't contain the proper field names
of tuples anymore. This had to be changed as the old behaviour never
produced consistent results.
Compiler Additions
@@ -86,6 +90,7 @@ Compiler Additions
option or pragma.
- The compiler now generates marker procs that the GC can use instead of RTTI.
This speeds up the GC quite a bit.
- The compiler now supports OpenMP's parallel for loop.
Language Additions