diff options
author | Araq <rumpf_a@web.de> | 2012-07-05 00:03:33 +0200 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2012-07-05 00:03:33 +0200 |
commit | 36247e0947699a56d5bc51d48188b6dda1815587 (patch) | |
tree | af837b557356d4495ce93d5fe735c9ccab169e2e | |
parent | 8ef48a34e5916deccd58a312228c7d2efe39d170 (diff) | |
download | Nim-36247e0947699a56d5bc51d48188b6dda1815587.tar.gz |
added devel/logging; weakrefs test; next steps for proper unsigned support
-rwxr-xr-x | compiler/evals.nim | 2 | ||||
-rwxr-xr-x | compiler/msgs.nim | 2 | ||||
-rwxr-xr-x | compiler/renderer.nim | 4 | ||||
-rwxr-xr-x | compiler/semexprs.nim | 1 | ||||
-rwxr-xr-x | compiler/semfold.nim | 5 | ||||
-rwxr-xr-x | compiler/sigmatch.nim | 6 | ||||
-rwxr-xr-x | compiler/transf.nim | 13 | ||||
-rw-r--r-- | devel/logging.nim | 145 | ||||
-rwxr-xr-x | doc/manual.txt | 30 | ||||
-rwxr-xr-x | lib/system/repr.nim | 5 | ||||
-rwxr-xr-x | lib/system/sysio.nim | 2 | ||||
-rw-r--r-- | tests/gc/weakrefs.nim | 48 | ||||
-rw-r--r-- | tests/specials.nim | 2 | ||||
-rwxr-xr-x | web/news.txt | 3 |
14 files changed, 243 insertions, 25 deletions
diff --git a/compiler/evals.nim b/compiler/evals.nim index adff11567..40f1f8e01 100755 --- a/compiler/evals.nim +++ b/compiler/evals.nim @@ -829,7 +829,7 @@ proc isEmpty(n: PNode): bool = # Maybe the lexer should mark both the beginning and the end of expressions, # then this function could be removed. proc stringStartingLine(s: PNode): int = - result = s.info.line - countLines(s.strVal) + result = s.info.line.int - countLines(s.strVal) proc evalParseExpr(c: PEvalContext, n: PNode): PNode = var code = evalAux(c, n.sons[1], {}) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index efd83cfd9..03ee28df3 100755 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -345,7 +345,7 @@ const warnAnalysisLoophole: "thread analysis incomplete due to unkown call '$1' [AnalysisLoophole]", warnDifferentHeaps: "possible inconsistency of thread local heaps [DifferentHeaps]", warnWriteToForeignHeap: "write to foreign heap [WriteToForeignHeap]", - warnImplicitNarrowing: "implicit narrowing conversion: '$1'", + warnImplicitNarrowing: "implicit narrowing conversion: '$1' [ImplicitNarrowing]", warnUser: "$1 [User]", hintSuccess: "operation successful [Success]", hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#) [SuccessX]", diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 30daf7c52..58c60834f 100755 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -1209,8 +1209,8 @@ proc initTokRender(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {}) = proc getNextTok(r: var TSrcGen, kind: var TTokType, literal: var string) = if r.idx < len(r.tokens): kind = r.tokens[r.idx].kind - var length = r.tokens[r.idx].length - literal = substr(r.buf, r.pos + 0, r.pos + 0 + length - 1) + var length = r.tokens[r.idx].length.int + literal = substr(r.buf, r.pos, r.pos + length - 1) inc(r.pos, length) inc(r.idx) else: diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 501b7ed72..22af8b4e0 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1302,6 +1302,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = of nkNilLit: result.typ = getSysType(tyNil) of nkIntLit: + # XXX this is stupid: if result.typ == nil: let i = result.intVal if i >= low(int32) and i <= high(int32): diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 66d7e98fc..ce9e03513 100755 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -190,8 +190,8 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode = of mCopyStr: result = newStrNodeT(substr(getStr(a), int(getOrdValue(b))), n) of mCopyStrLast: result = newStrNodeT(substr(getStr(a), int(getOrdValue(b)), - int(getOrdValue(c))), n) - of mFloatToStr: result = newStrNodeT($(getFloat(a)), n) + int(getOrdValue(c))), n) + of mFloatToStr: result = newStrNodeT($getFloat(a), n) of mCStrToStr, mCharToStr: result = newStrNodeT(getStrOrChar(a), n) of mStrToStr: result = a of mEnumToStr: result = newStrNodeT(ordinalValToString(a), n) @@ -298,6 +298,7 @@ proc getAppType(n: PNode): PNode = result = newStrNodeT("console", n) proc foldConv*(n, a: PNode): PNode = + # XXX range checks? case skipTypes(n.typ, abstractRange).kind of tyInt..tyInt64: case skipTypes(a.typ, abstractRange).kind diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 7a5d959df..6819bb37f 100755 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -162,7 +162,7 @@ proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation = else: var k = skipTypes(a, {tyRange}).kind if k == f.kind: result = isSubtype - elif k == tyInt: + elif k == tyInt and f.kind in {tyRange, tyInt8..tyUInt64}: # and a.n != nil and a.n.intVal >= firstOrd(f) and # a.n.intVal <= lastOrd(f): # integer literal in the proper range; we want ``i16 + 4`` to stay an @@ -188,7 +188,9 @@ proc handleFloatRange(f, a: PType): TTypeRelation = else: var k = skipTypes(a, {tyRange}).kind if k == f.kind: result = isSubtype - elif (k >= tyFloat) and (k <= tyFloat128): result = isConvertible + elif k == tyInt and f.kind >= tyFloat and f.kind <= tyFloat128: + result = isIntConv + elif k >= tyFloat and k <= tyFloat128: result = isConvertible else: result = isNone proc isObjectSubtype(a, f: PType): bool = diff --git a/compiler/transf.nim b/compiler/transf.nim index 19530b82a..bf6354665 100755 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -640,6 +640,14 @@ proc dontInlineConstant(orig, cnst: PNode): bool {.inline.} = result = orig.kind == nkSym and cnst.kind in {nkCurly, nkPar, nkBracket} and cnst.len != 0 +proc warnNarrowingConversion(n: PNode) = + if n.kind == nkHiddenStdConv: + var dest = skipTypes(n.typ, abstractVarRange) + var source = skipTypes(n.sons[1].typ, abstractVarRange) + if source.kind == tyInt and + source.size > dest.size and n.sons[1].kind != nkIntLit: + Message(n.info, warnImplicitNarrowing, renderTree(n.sons[1])) + proc transform(c: PTransf, n: PNode): PTransNode = case n.kind of nkSym: @@ -725,8 +733,9 @@ proc transform(c: PTransf, n: PNode): PTransNode = var cnst = getConstExpr(c.module, PNode(result)) # we inline constants if they are not complex constants: if cnst != nil and not dontInlineConstant(n, cnst): - result = PTransNode(cnst) # do not miss an optimization - + result = PTransNode(cnst) # do not miss an optimization + warnNarrowingConversion(result.pnode) + proc processTransf(context: PPassContext, n: PNode): PNode = # Note: For interactive mode we cannot call 'passes.skipCodegen' and skip # this step! We have to rely that the semantic pass transforms too errornous diff --git a/devel/logging.nim b/devel/logging.nim new file mode 100644 index 000000000..7ae4d7eee --- /dev/null +++ b/devel/logging.nim @@ -0,0 +1,145 @@ +# +# +# Nimrod's Runtime Library +# (c) Copyright 2012 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements a simple logger. It is based on the following design: +## * Runtime log formating is a bug: Sooner or later every log file is parsed. +## * Keep it simple: If this library does not fullfill your needs, write your +## own. Trying to support every logging feature just leads to bloat. +## +## Format is:: +## +## DEBUG|INFO|... (2009-11-02 00:00:00)? (Component: )? Message +## +## + +type + TLevel* = enum ## logging level + lvlAll, ## all levels active + lvlDebug, ## debug level (and any above) active + lvlInfo, ## info level (and any above) active + lvlWarn, ## warn level (and any above) active + lvlError, ## error level (and any above) active + lvlFatal ## fatal level (and any above) active + +const + LevelNames*: array [TLevel, string] = [ + "DEBUG", "DEBUG", "INFO", "WARN", "ERROR", "FATAL" + ] + +type + TLogger* = object of TObject ## abstract logger; the base type of all loggers + levelThreshold*: TLevel ## only messages of level >= levelThreshold + ## should be processed + TConsoleLogger* = object of TLogger ## logger that writes the messages to the + ## console + + TFileLogger* = object of TLogger ## logger that writes the messages to a file + f: TFile + + TRollingFileLogger* = object of TFileLogger ## logger that writes the + ## message to a file + maxlines: int # maximum number of lines + lines: seq[string] + +method log*(L: ref TLogger, level: TLevel, + frmt: string, args: openArray[string]) = + ## override this method in custom loggers. Default implementation does + ## nothing. + nil + +method log*(L: ref TConsoleLogger, level: TLevel, + frmt: string, args: openArray[string]) = + Writeln(stdout, LevelNames[level], " ", frmt % args) + +method log*(L: ref TFileLogger, level: TLevel, + frmt: string, args: openArray[string]) = + Writeln(L.f, LevelNames[level], " ", frmt % args) + +proc defaultFilename*(): string = + ## returns the default filename for a logger + var (path, name, ext) = splitFile(getAppFilename()) + result = changeFileExt(path / name & "_" & getDateStr(), "log") + +proc substituteLog*(frmt: string): string = + ## converts $date to the current date + ## converts $time to the current time + ## converts $app to getAppFilename() + ## converts + result = newStringOfCap(frmt.len + 20) + var i = 0 + while i < frmt.len: + if frmt[i] != '$': + result.add(frmt[i]) + inc(i) + else: + inc(i) + var v = "" + var app = getAppFilename() + while frmt[i] in IdentChars: + v.add(toLower(frmt[i])) + inc(i) + case v + of "date": result.add(getDateStr()) + of "time": result.add(getClockStr()) + of "app": result.add(app) + of "appdir": result.add(app.splitFile.dir) + of "appname": result.add(app.splitFile.name) + + +proc newFileLogger*(filename = defaultFilename(), + mode: TFileMode = fmAppend, + levelThreshold = lvlNone): ref TFileLogger = + new(result) + result.levelThreshold = levelThreshold + result.f = open(filename, mode) + +proc newRollingFileLogger*(filename = defaultFilename(), + mode: TFileMode = fmAppend, + levelThreshold = lvlNone, + maxLines = 1000): ref TFileLogger = + new(result) + result.levelThreshold = levelThreshold + result.maxLines = maxLines + result.f = open(filename, mode) + +var + level* = lvlNone + handlers*: seq[ref TLogger] = @[] + +proc logLoop(level: TLevel, msg: string) = + for logger in items(handlers): + if level >= logger.levelThreshold: + log(logger, level, msg) + +template log*(level: TLevel, msg: string) = + ## logs a message of the given level + bind logLoop + if level >= logging.Level: + logLoop(level, frmt, args) + +template debug*(msg: string) = + ## logs a debug message + log(lvlDebug, msg) + +template info*(msg: string) = + ## logs an info message + log(lvlInfo, msg) + +template warn*(msg: string) = + ## logs a warning message + log(lvlWarn, msg) + +template error*(msg: string) = + ## logs an error message + log(lvlError, msg) + +template fatal*(msg: string) = + ## logs a fatal error message + log(lvlFatal, msg) + diff --git a/doc/manual.txt b/doc/manual.txt index 4f7e8db15..02c1294e5 100755 --- a/doc/manual.txt +++ b/doc/manual.txt @@ -794,7 +794,7 @@ variadic proc, it is implicitely converted to ``cstring`` too: printf("This works %s", "as expected") -Even though the conversion is implict, it is not *safe*: The garbage collector +Even though the conversion is implicit, it is not *safe*: The garbage collector does not consider a ``cstring`` to be a root and may collect the underlying memory. However in practice this almost never happens as the GC considers stack roots conservatively. One can use the builtin procs ``GC_ref`` and @@ -1461,22 +1461,28 @@ algorithm returns true: # XXX range types? proc isImplicitlyConvertible(a, b: PType): bool = case a.kind - of int8: result = b.kind in {int16, int32, int64, int} - of int16: result = b.kind in {int32, int64, int} - of int32: result = b.kind in {int64, int} - of float: result = b.kind in {float32, float64} - of float32: result = b.kind in {float64, float} - of float64: result = b.kind in {float32, float} + of int: result = b in {int8, int16, int32, int64, uint, uint8, uint16, + uint32, uint64, float, float32, float64} + of int8: result = b in {int16, int32, int64, int} + of int16: result = b in {int32, int64, int} + of int32: result = b in {int64, int} + of uint: result = b in {uint32, uint64} + of uint8: result = b in {uint16, uint32, uint64} + of uint16: result = b in {uint32, uint64} + of uint32: result = b in {uint64} + of float: result = b in {float32, float64} + of float32: result = b in {float64, float} + of float64: result = b in {float32, float} of seq: - result = b.kind == openArray and typeEquals(a.baseType, b.baseType) + result = b == openArray and typeEquals(a.baseType, b.baseType) of array: - result = b.kind == openArray and typeEquals(a.baseType, b.baseType) + result = b == openArray and typeEquals(a.baseType, b.baseType) if a.baseType == char and a.indexType.rangeA == 0: - result = b.kind = cstring + result = b = cstring of cstring, ptr: - result = b.kind == pointer + result = b == pointer of string: - result = b.kind == cstring + result = b == cstring A type ``a`` is **explicitly** convertible to type ``b`` iff the following algorithm returns true: diff --git a/lib/system/repr.nim b/lib/system/repr.nim index ec02f5e08..83fa7aa1d 100755 --- a/lib/system/repr.nim +++ b/lib/system/repr.nim @@ -75,7 +75,7 @@ proc addSetElem(result: var string, elem: int, typ: PNimType) = of tyBool: add result, reprBool(bool(elem)) of tyChar: add result, reprChar(chr(elem)) of tyRange: addSetElem(result, elem, typ.base) - of tyInt..tyInt64: add result, reprInt(elem) + of tyInt..tyInt64, tyUInt8, tyUInt16: add result, reprInt(elem) else: # data corrupt --> inform the user add result, " (invalid data!)" @@ -221,6 +221,9 @@ when not defined(useNimRtl): of tyInt16: add result, $int(cast[ptr Int16](p)[]) of tyInt32: add result, $int(cast[ptr Int32](p)[]) of tyInt64: add result, $(cast[ptr Int64](p)[]) + of tyUInt8: add result, $ze(cast[ptr Int8](p)[]) + of tyUInt16: add result, $ze(cast[ptr Int16](p)[]) + of tyFloat: add result, $(cast[ptr float](p)[]) of tyFloat32: add result, $(cast[ptr float32](p)[]) of tyFloat64: add result, $(cast[ptr float64](p)[]) diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim index 15f87896a..ac0880f79 100755 --- a/lib/system/sysio.nim +++ b/lib/system/sysio.nim @@ -199,7 +199,7 @@ proc Open(f: var TFile, filename: string, var p: pointer = fopen(filename, FormatOpen[mode]) result = (p != nil) f = cast[TFile](p) - if bufSize > 0 and bufSize <= high(cint): + if bufSize > 0 and bufSize <= high(cint).int: if setvbuf(f, nil, IOFBF, bufSize.cint) != 0'i32: raise newException(EOutOfMemory, "out of memory") elif bufSize == 0: diff --git a/tests/gc/weakrefs.nim b/tests/gc/weakrefs.nim new file mode 100644 index 000000000..3b12d7998 --- /dev/null +++ b/tests/gc/weakrefs.nim @@ -0,0 +1,48 @@ +discard """ + output: "true" +""" + +import intsets + +type + TMyObject = object + id: int + StrongObject = ref TMyObject + WeakObject = object + id: int + data: ptr TMyObject + +var + gid: int # for id generation + valid = initIntSet() + +proc finalizer(x: StrongObject) = + valid.excl(x.id) + +proc create: StrongObject = + new(result, finalizer) + result.id = gid + valid.incl(gid) + inc gid + +proc register(s: StrongObject): WeakObject = + result.data = cast[ptr TMyObject](s) + result.id = s.id + +proc access(w: WeakObject): StrongObject = + ## returns nil if the object doesn't exist anymore + if valid.contains(w.id): + result = cast[StrongObject](w.data) + +proc main = + var s: seq[WeakObject] + newSeq(s, 10_000) + for i in 0 .. s.high: + s[i] = register(create()) + # test that we have at least 80% unreachable weak objects by now: + var unreachable = 0 + for i in 0 .. s.high: + if access(s[i]) == nil: inc unreachable + echo unreachable > 8_000 + +main() diff --git a/tests/specials.nim b/tests/specials.nim index 7e1a58d78..f0f471c02 100644 --- a/tests/specials.nim +++ b/tests/specials.nim @@ -131,7 +131,7 @@ proc runGcTests(r: var TResults, options: string) = test "gctest" # disabled for now as it somehow runs very slowly ('delete' bug?) but works: test "gcleak3" - + test "weakrefs" # ------------------------- threading tests ----------------------------------- diff --git a/web/news.txt b/web/news.txt index aa255a0b1..d4a03488c 100755 --- a/web/news.txt +++ b/web/news.txt @@ -87,6 +87,7 @@ Changes affecting backwards compatibility - Deprecated the ``ssl`` module. - Deprecated ``nimrod pretty`` as it never worked good enough and has some inherent problems. +- The integer promotion rules changed. Compiler Additions @@ -120,6 +121,8 @@ Language Additions - Stand-alone ``finally`` and ``except`` blocks are now supported. - Macros and templates can now be invoked as pragmas. - The apostrophe in type suffixes for numerical literal is now optional. +- Unsigned integer types have been added. +- The integer promotion rules changed. 2012-02-09 Version 0.8.14 released |