From 29b63be9808e9b38a95864e41d0e048fcd94174c Mon Sep 17 00:00:00 2001 From: Araq Date: Sun, 20 May 2012 18:42:50 +0200 Subject: [PATCH 01/17] added another system.getStackTrace --- lib/system.nim | 5 +++++ lib/system/excpt.nim | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/lib/system.nim b/lib/system.nim index 5e575c8148..642ee957ff 100755 --- a/lib/system.nim +++ b/lib/system.nim @@ -190,6 +190,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). @@ -1900,6 +1901,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": diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index a523e4e047..204fba3760 100755 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -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 From ea5b74c8321c85fb523fbcdfc4072c3fc3ff1c79 Mon Sep 17 00:00:00 2001 From: Araq Date: Sun, 20 May 2012 23:18:14 +0200 Subject: [PATCH 02/17] todo.txt changes --- todo.txt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/todo.txt b/todo.txt index 6267e34974..5a71d15af5 100755 --- a/todo.txt +++ b/todo.txt @@ -1,7 +1,8 @@ version 0.9.0 ============= -- make stack traces part of the exception in debug builds +- bug: generic assign still buggy + - special case the generic assign that needs to care about case objects - make templates hygienic by default - ``bind`` for overloaded symbols does not work apparently - ``=`` should be overloadable; requires specialization for ``=`` @@ -34,9 +35,6 @@ version 0.9.0 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 = From 7f64e95747954ec36252d59249ef657d0619e9f4 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 22 May 2012 01:02:33 +0200 Subject: [PATCH 03/17] fixes a long standing bug concerning assignment of case objects --- lib/system/assign.nim | 12 ++++++++++-- todo.txt | 2 -- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/system/assign.nim b/lib/system/assign.nim index d1055fbb50..59c44a6cce 100755 --- a/lib/system/assign.nim +++ b/lib/system/assign.nim @@ -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 diff --git a/todo.txt b/todo.txt index 5a71d15af5..87f75c0d57 100755 --- a/todo.txt +++ b/todo.txt @@ -1,8 +1,6 @@ version 0.9.0 ============= -- bug: generic assign still buggy - - special case the generic assign that needs to care about case objects - make templates hygienic by default - ``bind`` for overloaded symbols does not work apparently - ``=`` should be overloadable; requires specialization for ``=`` From 1c01c78be539d31eaec424dcd3498f11103f06a5 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 22 May 2012 19:37:26 +0200 Subject: [PATCH 04/17] TInteger vs TOrdinal --- lib/system.nim | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/system.nim b/lib/system.nim index 642ee957ff..f78ca97388 100755 --- a/lib/system.nim +++ b/lib/system.nim @@ -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 From 848c1b297f8f45fd3b69c3886e8328b738def0be Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 23 May 2012 02:05:28 +0200 Subject: [PATCH 05/17] added system.||; lacks runtime support --- compiler/ast.nim | 3 ++- compiler/ccgstmts.nim | 29 +++++++++++++++++++++++++++++ compiler/ecmasgen.nim | 3 ++- compiler/evals.nim | 2 +- compiler/renderer.nim | 2 +- compiler/semgnrc.nim | 2 +- compiler/semstmts.nim | 8 ++++++-- compiler/transf.nim | 6 +++++- config/nimrod.cfg | 1 + lib/core/macros.nim | 2 +- lib/system.nim | 9 +++++++++ web/news.txt | 2 ++ 12 files changed, 60 insertions(+), 9 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 10a3d80394..978b43b5ef 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -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, diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index db6d5bd67d..891731533a 100755 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -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 & ')') diff --git a/compiler/ecmasgen.nim b/compiler/ecmasgen.nim index 3ab4303c2f..ecdbb022e2 100755 --- a/compiler/ecmasgen.nim +++ b/compiler/ecmasgen.nim @@ -1341,7 +1341,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) diff --git a/compiler/evals.nim b/compiler/evals.nim index a4d4cdd9e9..b2fded071a 100755 --- a/compiler/evals.nim +++ b/compiler/evals.nim @@ -1289,7 +1289,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) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 67b6576578..a5e79762c3 100755 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -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) diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index d8f017c4c5..f7e64bdee0 100755 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -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) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 6b79326fe2..202b7416a8 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -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) @@ -889,7 +893,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) diff --git a/compiler/transf.nim b/compiler/transf.nim index 9e0d4051f9..0ab8bc8d32 100755 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -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)) diff --git a/config/nimrod.cfg b/config/nimrod.cfg index 21cf55ec93..c98f30f021 100755 --- a/config/nimrod.cfg +++ b/config/nimrod.cfg @@ -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" diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 8b08952f0c..21f5134e21 100755 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -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, diff --git a/lib/system.nim b/lib/system.nim index f78ca97388..148df7e34c 100755 --- a/lib/system.nim +++ b/lib/system.nim @@ -1200,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.} diff --git a/web/news.txt b/web/news.txt index e047cf1fc3..f83c86a25f 100755 --- a/web/news.txt +++ b/web/news.txt @@ -46,6 +46,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. @@ -84,6 +85,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 From 25ea5c35b8ee8761f82b844cc11a8051015e541a Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 26 May 2012 01:52:43 +0100 Subject: [PATCH 06/17] Added timezone handling and functions for adding and subtracting time to the times module. Added insert for strings to the system module. --- lib/pure/times.nim | 164 +++++++++++++++++++++++++++++++++++++++++---- lib/system.nim | 13 ++++ 2 files changed, 165 insertions(+), 12 deletions(-) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 968b317d62..d7f9540600 100755 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -41,6 +41,10 @@ when defined(posix): proc posix_gettimeofday(tp: var Ttimeval, unused: pointer = nil) {. importc: "gettimeofday", header: "".} + + var + timezone* {.importc, header: "".}: int + tzname* {.importc, header: "" .}: array[0..1, cstring] elif defined(windows): import winlean @@ -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) @@ -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 ' diff --git a/lib/system.nim b/lib/system.nim index 148df7e34c..0c6aea750b 100755 --- a/lib/system.nim +++ b/lib/system.nim @@ -2290,5 +2290,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() From 558d0db89f7703f7824e7a9150440ce6b248f124 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 26 May 2012 20:35:56 +0100 Subject: [PATCH 07/17] Fixed times on non-posix operating systems. --- lib/pure/times.nim | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index d7f9540600..7a65badffb 100755 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -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: "".}: int + tzname* {.importc, header: "" .}: array[0..1, cstring] + when defined(posix): type TTimeImpl {.importc: "time_t", header: "".} = int @@ -41,10 +45,6 @@ when defined(posix): proc posix_gettimeofday(tp: var Ttimeval, unused: pointer = nil) {. importc: "gettimeofday", header: "".} - - var - timezone* {.importc, header: "".}: int - tzname* {.importc, header: "" .}: array[0..1, cstring] elif defined(windows): import winlean From 82a2dfd816849b3d2bc1adf42faf2a74e7083a1c Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 27 May 2012 01:06:48 +0100 Subject: [PATCH 08/17] Fixed times.format --- lib/pure/times.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 7a65badffb..327dc91875 100755 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -557,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": From 7a249eb8c183cf0db0a49b82ee80700e08473e66 Mon Sep 17 00:00:00 2001 From: Araq Date: Sun, 27 May 2012 14:57:12 +0200 Subject: [PATCH 09/17] bugfix: field names of tuples are treated consistently in the C backend --- compiler/ccgexprs.nim | 36 ++++++++++++++++++------------------ compiler/ccgstmts.nim | 2 +- compiler/ccgtypes.nim | 9 ++++++--- compiler/ccgutils.nim | 9 +++++++-- compiler/types.nim | 8 +++++++- 5 files changed, 39 insertions(+), 25 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 34418f3534..dbe528ab5e 100755 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -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) @@ -1508,11 +1509,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", diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 891731533a..46e4f75dff 100755 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -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") diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 1b3e84cc4e..fc09d9a5d6 100755 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -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) = diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim index 12795358a0..5ba5230702 100755 --- a/compiler/ccgutils.nim +++ b/compiler/ccgutils.nim @@ -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 diff --git a/compiler/types.nim b/compiler/types.nim index 15390bed7e..61e42ac0a0 100755 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -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() From bb7a14fec0fe3b88cddb51ae9550c2b6a4d75099 Mon Sep 17 00:00:00 2001 From: Araq Date: Sun, 27 May 2012 16:22:48 +0200 Subject: [PATCH 10/17] bugfix: UFCS for templates (ttempl3.nim enhanced) --- compiler/lookups.nim | 21 +++++++++++---------- tests/compile/ttempl3.nim | 15 +++++++++++++++ todo.txt | 1 + 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 62f4a3391c..d9725eedfb 100755 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -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.. Date: Mon, 28 May 2012 01:17:17 +0200 Subject: [PATCH 11/17] made tsequtils green again --- lib/core/macros.nim | 21 +++++++++++++++------ tests/run/tdumptree.nim | 24 ++++++++++++++++++++++++ tests/run/tsequtils.nim | 2 +- todo.txt | 3 ++- web/news.txt | 3 +++ 5 files changed, 45 insertions(+), 8 deletions(-) create mode 100644 tests/run/tdumptree.nim diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 21f5134e21..b0f237924d 100755 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -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`. diff --git a/tests/run/tdumptree.nim b/tests/run/tdumptree.nim new file mode 100644 index 0000000000..2a9c7d2051 --- /dev/null +++ b/tests/run/tdumptree.nim @@ -0,0 +1,24 @@ +discard """ +output: '''StmtList + VarSection + IdentDefs + Ident !"x" + nil + Call + DotExpr + Ident !"foo" + Ident !"create" + IntLit 56''' +""" + +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) + diff --git a/tests/run/tsequtils.nim b/tests/run/tsequtils.nim index 2982ca6124..7bc15ef9cc 100644 --- a/tests/run/tsequtils.nim +++ b/tests/run/tsequtils.nim @@ -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 diff --git a/todo.txt b/todo.txt index 377a57ebe0..5f1d7adde9 100755 --- a/todo.txt +++ b/todo.txt @@ -1,7 +1,8 @@ version 0.9.0 ============= -- make templates hygienic by default +- 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 diff --git a/web/news.txt b/web/news.txt index f83c86a25f..3ad0eb4d89 100755 --- a/web/news.txt +++ b/web/news.txt @@ -72,6 +72,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 From b5d8e8bfaa3683d7034f3fad45ce9024188ad92a Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 29 May 2012 00:42:28 +0200 Subject: [PATCH 12/17] '+=' etc for all floating point types --- compiler/ccgtypes.nim | 2 +- compiler/types.nim | 5 +++-- lib/system.nim | 8 ++++---- tests/reject/tenummix.nim | 9 +++++++++ tests/run/tdumptree.nim | 3 +++ todo.txt | 7 +------ 6 files changed, 21 insertions(+), 13 deletions(-) create mode 100644 tests/reject/tenummix.nim diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index fc09d9a5d6..4492c2fea2 100755 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -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) diff --git a/compiler/types.nim b/compiler/types.nim index 61e42ac0a0..b3737b1346 100755 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -869,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: diff --git a/lib/system.nim b/lib/system.nim index 0c6aea750b..9a9984911b 100755 --- a/lib/system.nim +++ b/lib/system.nim @@ -2184,19 +2184,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 diff --git a/tests/reject/tenummix.nim b/tests/reject/tenummix.nim new file mode 100644 index 0000000000..52d4f39d73 --- /dev/null +++ b/tests/reject/tenummix.nim @@ -0,0 +1,9 @@ +discard """ + errormsg: "type mismatch" +""" + +type + TE1 = enum eA, eB + TE2 = enum eC, eD + +assert eA != eC diff --git a/tests/run/tdumptree.nim b/tests/run/tdumptree.nim index 2a9c7d2051..5299a94e33 100644 --- a/tests/run/tdumptree.nim +++ b/tests/run/tdumptree.nim @@ -1,4 +1,5 @@ discard """ +disabled: true output: '''StmtList VarSection IdentDefs @@ -11,6 +12,8 @@ output: '''StmtList IntLit 56''' """ +# disabled; can't work as the output is done by the compiler + import macros #emit("type\n TFoo = object\n bar: int") diff --git a/todo.txt b/todo.txt index 5f1d7adde9..68a3b93b0b 100755 --- a/todo.txt +++ b/todo.txt @@ -33,14 +33,9 @@ version 0.9.0 error handling more light-weight people also want ``inc a; inc b`` + Bugs ---- -- 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? From 04300542da671e0250c67610bc87ef4f335d6902 Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 30 May 2012 22:37:17 +0200 Subject: [PATCH 13/17] fixes #127 --- compiler/ccgcalls.nim | 15 ++++++++++----- tests/run/tgenericprocvar.nim | 19 ++++++++++++++++++- todo.txt | 2 ++ 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index f2fa6a2808..17139f0555 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -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)) diff --git a/tests/run/tgenericprocvar.nim b/tests/run/tgenericprocvar.nim index 7fdc58ca46..088909d58e 100644 --- a/tests/run/tgenericprocvar.nim +++ b/tests/run/tgenericprocvar.nim @@ -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) + diff --git a/todo.txt b/todo.txt index 68a3b93b0b..31b8c7268d 100755 --- a/todo.txt +++ b/todo.txt @@ -1,6 +1,8 @@ version 0.9.0 ============= +- fix the installer +- implement 'gorge' - make templates hygienic by default: try to gensym() everything in the 'block' of a template - ``bind`` for overloaded symbols does not work apparently From 2509c08d3441bd2c98386f69d92005653d97186f Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 30 May 2012 22:35:43 +0100 Subject: [PATCH 14/17] Marshal now works with nil strings. Timezone and tzname vars are not public any more in the times module. --- lib/core/typeinfo.nim | 3 ++- lib/pure/times.nim | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim index 9cc8e4dfd2..ca2b68cc3f 100755 --- a/lib/core/typeinfo.nim +++ b/lib/core/typeinfo.nim @@ -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. diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 327dc91875..2070a39d8c 100755 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -26,8 +26,8 @@ type dMon, dTue, dWed, dThu, dFri, dSat, dSun var - timezone* {.importc, header: "".}: int - tzname* {.importc, header: "" .}: array[0..1, cstring] + timezone {.importc, header: "".}: int + tzname {.importc, header: "" .}: array[0..1, cstring] when defined(posix): type From ec39788b41949b10c44531271162ed5ea5ef0d1f Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 30 May 2012 23:22:09 +0100 Subject: [PATCH 15/17] Fixed times.format handling of month numbers. --- lib/pure/times.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 2070a39d8c..4cb873b1ca 100755 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -580,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": From 761936bad53ef61ba95b0d99f3560a25ea239e13 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 31 May 2012 01:35:13 +0200 Subject: [PATCH 16/17] niminst: use 'set -e'; failing to copy docs and data is no installation error --- tests/reject/tenummix.nim | 2 ++ todo.txt | 1 - tools/niminst/buildsh.tmpl | 7 +++++-- tools/niminst/install.tmpl | 36 +++++++++++++++++++++--------------- 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/tests/reject/tenummix.nim b/tests/reject/tenummix.nim index 52d4f39d73..f32eb82a77 100644 --- a/tests/reject/tenummix.nim +++ b/tests/reject/tenummix.nim @@ -1,4 +1,6 @@ discard """ + file: "system.nim" + line: 640 errormsg: "type mismatch" """ diff --git a/todo.txt b/todo.txt index 31b8c7268d..ee761219c2 100755 --- a/todo.txt +++ b/todo.txt @@ -1,7 +1,6 @@ version 0.9.0 ============= -- fix the installer - implement 'gorge' - make templates hygienic by default: try to gensym() everything in the 'block' of a template diff --git a/tools/niminst/buildsh.tmpl b/tools/niminst/buildsh.tmpl index 936378de23..a9c99a4043 100755 --- a/tools/niminst/buildsh.tmpl +++ b/tools/niminst/buildsh.tmpl @@ -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 *) diff --git a/tools/niminst/install.tmpl b/tools/niminst/install.tmpl index 9dea6887bc..bfba024c76 100755 --- a/tools/niminst/install.tmpl +++ b/tools/niminst/install.tmpl @@ -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 From 232ab71f208e341da327e54afa8a6d287141836b Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 1 Jun 2012 00:25:02 +0200 Subject: [PATCH 17/17] bugfix: RST parser: URLs properly parsed --- packages/docutils/rst.nim | 9 ++++++++- todo.txt | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/docutils/rst.nim b/packages/docutils/rst.nim index 16572abb41..126b21bd60 100755 --- a/packages/docutils/rst.nim +++ b/packages/docutils/rst.nim @@ -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] == '<': diff --git a/todo.txt b/todo.txt index ee761219c2..6bdfefc0d2 100755 --- a/todo.txt +++ b/todo.txt @@ -2,6 +2,7 @@ version 0.9.0 ============= - 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