diff options
-rwxr-xr-x | koch.nim | 2 | ||||
-rwxr-xr-x | lib/pure/hashes.nim | 38 | ||||
-rwxr-xr-x | lib/pure/htmlparser.nim | 4 | ||||
-rwxr-xr-x | lib/system.nim | 27 | ||||
-rwxr-xr-x | lib/system/gc.nim | 5 | ||||
-rwxr-xr-x | rod/astalgo.nim | 119 | ||||
-rwxr-xr-x | rod/lookups.nim | 58 | ||||
-rwxr-xr-x | rod/sem.nim | 20 | ||||
-rwxr-xr-x | rod/semdata.nim | 15 | ||||
-rwxr-xr-x | rod/semgnrc.nim | 45 | ||||
-rwxr-xr-x | rod/seminst.nim | 9 | ||||
-rwxr-xr-x | rod/semstmts.nim | 54 | ||||
-rwxr-xr-x | rod/semtypes.nim | 2 | ||||
-rw-r--r-- | tests/accept/run/tkoeniglookup.nim | 4 | ||||
-rwxr-xr-x | tests/reject/ttypenoval.nim | 2 | ||||
-rwxr-xr-x | todo.txt | 2 | ||||
-rwxr-xr-x | web/news.txt | 3 |
17 files changed, 217 insertions, 192 deletions
diff --git a/koch.nim b/koch.nim index 4eddb06e4..0f9b42bec 100755 --- a/koch.nim +++ b/koch.nim @@ -180,7 +180,7 @@ proc cleanAux(dir: string) = of "nimcache": echo "removing dir: ", path removeDir(path) - of "dist", ".bzr": + of "dist", ".git": nil else: cleanAux(path) diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index 1593119bd..87d672ae7 100755 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -1,7 +1,7 @@ # # # Nimrod's Runtime Library -# (c) Copyright 2008 Andreas Rumpf +# (c) Copyright 2011 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -30,14 +30,10 @@ proc finishHash(h: THash): THash {.inline.} = proc hashData*(Data: Pointer, Size: int): THash = ## hashes an array of bytes of size `size` - var - h: THash - p: cstring - i, s: int - h = 0 - p = cast[cstring](Data) - i = 0 - s = size + var h: THash = 0 + var p = cast[cstring](Data) + var i = 0 + var s = size while s > 0: h = concHash(h, ord(p[i])) Inc(i) @@ -62,20 +58,16 @@ proc hash*(x: char): THash {.inline.} = proc hash*(x: string): THash = ## efficient hashing of strings - var h: THash - h = 0 + var h: THash = 0 for i in 0..x.len-1: h = concHash(h, ord(x[i])) result = finishHash(h) proc hashIgnoreStyle*(x: string): THash = ## efficient hashing of strings; style is ignored - var - h: THash - c: Char - h = 0 + var h: THash = 0 for i in 0..x.len-1: - c = x[i] + var c = x[i] if c == '_': continue # skip _ if c in {'A'..'Z'}: @@ -85,13 +77,17 @@ proc hashIgnoreStyle*(x: string): THash = proc hashIgnoreCase*(x: string): THash = ## efficient hashing of strings; case is ignored - var - h: THash - c: Char - h = 0 + var h: THash = 0 for i in 0..x.len-1: - c = x[i] + var c = x[i] if c in {'A'..'Z'}: c = chr(ord(c) + (ord('a') - ord('A'))) # toLower() h = concHash(h, ord(c)) result = finishHash(h) + +proc hash*[T: tuple](x: T): THash = + ## efficient hashing of tuples. + for f in fields(x): + result = concHash(result, hash(f)) + result = finishHash(result) + diff --git a/lib/pure/htmlparser.nim b/lib/pure/htmlparser.nim index d84688be6..4136ecf57 100755 --- a/lib/pure/htmlparser.nim +++ b/lib/pure/htmlparser.nim @@ -333,11 +333,11 @@ proc parse(x: var TXmlParser, errors: var seq[string]): PXmlNode = of xmlElementOpen: result = newElement(x.elementName.toLower) next(x) - result.attr = newStringTable() + result.attrs = newStringTable() while true: case x.kind of xmlAttribute: - result.attr[x.attrKey] = x.attrValue + result.attrs[x.attrKey] = x.attrValue next(x) of xmlElementClose: next(x) diff --git a/lib/system.nim b/lib/system.nim index daf0c5423..c786e8355 100755 --- a/lib/system.nim +++ b/lib/system.nim @@ -1213,14 +1213,14 @@ iterator fieldPairs*(x, y: tuple[]): tuple[a, b: expr] {. ## in the loop body. proc `==`*[T: tuple](x, y: T): bool = - ## generic ``==`` operator that is lifted from the components + ## generic ``==`` operator for tuples that is lifted from the components ## of `x` and `y`. for a, b in fields(x, y): if a != b: return false return true proc `<=`*[T: tuple](x, y: T): bool = - ## generic ``<=`` operator that is lifted from the components + ## generic ``<=`` operator for tuples that is lifted from the components ## of `x` and `y`. This implementation uses `cmp`. for a, b in fields(x, y): var c = cmp(a, b) @@ -1229,7 +1229,7 @@ proc `<=`*[T: tuple](x, y: T): bool = return true proc `<`*[T: tuple](x, y: T): bool = - ## generic ``<`` operator that is lifted from the components + ## generic ``<`` operator for tuples that is lifted from the components ## of `x` and `y`. This implementation uses `cmp`. for a, b in fields(x, y): var c = cmp(a, b) @@ -1238,7 +1238,8 @@ proc `<`*[T: tuple](x, y: T): bool = return false proc `$`*[T: tuple](x: T): string = - ## generic ``$`` operator that is lifted from the components of `x`. + ## generic ``$`` operator for tuples that is lifted from the components + ## of `x`. result = "(" for name, value in fieldPairs(x): if result.len > 1: result.add(", ") @@ -1476,15 +1477,22 @@ when not defined(EcmaScript) and not defined(NimrodVM): ## Opens a file named `filename` with given `mode`. ## ## Default mode is readonly. Returns true iff the file could be opened. - ## This throws no exception if the file could not be opened. The reason is - ## that the programmer needs to provide an appropriate error message - ## anyway. + ## This throws no exception if the file could not be opened. proc Open*(f: var TFile, filehandle: TFileHandle, mode: TFileMode = fmRead): Bool ## Creates a ``TFile`` from a `filehandle` with given `mode`. ## ## Default mode is readonly. Returns true iff the file could be opened. + + proc Open*(filename: string, + mode: TFileMode = fmRead, bufSize: int = -1): TFile = + ## Opens a file named `filename` with given `mode`. + ## + ## Default mode is readonly. Raises an ``IO`` exception if the file + ## could not be opened. + if not open(result, filename, mode, bufSize): + raise newException(EIO, "cannot open: " & filename) proc reopen*(f: TFile, filename: string, mode: TFileMode = fmRead): bool ## reopens the file `f` with given `filename` and `mode`. This @@ -1581,10 +1589,7 @@ when not defined(EcmaScript) and not defined(NimrodVM): iterator lines*(filename: string): string = ## Iterate over any line in the file named `filename`. ## If the file does not exist `EIO` is raised. - var - f: TFile - if not open(f, filename): - raise newException(EIO, "cannot open: " & filename) + var f = open(filename) var res = "" while not endOfFile(f): rawReadLine(f, res) diff --git a/lib/system/gc.nim b/lib/system/gc.nim index 5288316f2..882825f5e 100755 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -265,7 +265,10 @@ proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerProc.} = # reference is in the stack or not (this can happen for var parameters). if not IsOnStack(dest): if src != nil: incRef(usrToCell(src)) - if dest^ != nil: decRef(usrToCell(dest^)) + # XXX finally use assembler for the stack checking instead! + # the test for '!= nil' is correct, but I got tired of the segfaults + # resulting from the crappy stack checking: + if cast[int](dest^) >=% PageSize: decRef(usrToCell(dest^)) dest^ = src proc initGC() = diff --git a/rod/astalgo.nim b/rod/astalgo.nim index bb5a6cf56..2bd04618d 100755 --- a/rod/astalgo.nim +++ b/rod/astalgo.nim @@ -64,8 +64,8 @@ proc NextIter*(ti: var TTabIter, tab: TStrTable): PSym # type - TIdentIter*{.final.} = object # iterator over all syms with the same identifier - h*: THash # current hash + TIdentIter*{.final.} = object # iterator over all syms with same identifier + h*: THash # current hash name*: PIdent @@ -123,7 +123,7 @@ proc getSymFromList*(list: PNode, ident: PIdent, start: int = 0): PSym proc lookupInRecord*(n: PNode, field: PIdent): PSym proc getModule*(s: PSym): PSym proc mustRehash*(length, counter: int): bool -proc nextTry*(h, maxHash: THash): THash +proc nextTry*(h, maxHash: THash): THash {.inline.} # ------------- table[int, int] --------------------------------------------- const @@ -193,19 +193,17 @@ proc toYamlChar(c: Char): string = case c of '\0'..'\x1F', '\x80'..'\xFF': result = "\\u" & strutils.toHex(ord(c), 4) of '\'', '\"', '\\': result = '\\' & c - else: result = c & "" + else: result = $c proc makeYamlString*(s: string): PRope = # We have to split long strings into many ropes. Otherwise # this could trigger InternalError(111). See the ropes module for # further information. - const - MaxLineLength = 64 - var res: string + const MaxLineLength = 64 result = nil - res = "\"" - for i in countup(0, len(s) + 0 - 1): - if (i - 0 + 1) mod MaxLineLength == 0: + var res = "\"" + for i in countup(0, len(s) - 1): + if (i + 1) mod MaxLineLength == 0: add(res, '\"') add(res, "\n") app(result, toRope(res)) @@ -229,17 +227,17 @@ proc lineInfoToStr(info: TLineInfo): PRope = toRope(toLinenumber(info)), toRope(toColumn(info))]) -proc treeToYamlAux(n: PNode, marker: var TIntSet, indent, maxRecDepth: int): PRope -proc symToYamlAux(n: PSym, marker: var TIntSet, indent, maxRecDepth: int): PRope -proc typeToYamlAux(n: PType, marker: var TIntSet, indent, maxRecDepth: int): PRope +proc treeToYamlAux(n: PNode, marker: var TIntSet, + indent, maxRecDepth: int): PRope +proc symToYamlAux(n: PSym, marker: var TIntSet, + indent, maxRecDepth: int): PRope +proc typeToYamlAux(n: PType, marker: var TIntSet, + indent, maxRecDepth: int): PRope proc strTableToYaml(n: TStrTable, marker: var TIntSet, indent: int, maxRecDepth: int): PRope = - var - istr: PRope - mycount: int - istr = spaces(indent + 2) + var istr = spaces(indent + 2) result = toRope("[") - mycount = 0 + var mycount = 0 for i in countup(0, high(n.data)): if n.data[i] != nil: if mycount > 0: app(result, ",") @@ -252,12 +250,9 @@ proc strTableToYaml(n: TStrTable, marker: var TIntSet, indent: int, proc ropeConstr(indent: int, c: openarray[PRope]): PRope = # array of (name, value) pairs - var - istr: PRope - i: int - istr = spaces(indent + 2) + var istr = spaces(indent + 2) result = toRope("{") - i = 0 + var i = 0 while i <= high(c): if i > 0: app(result, ",") appf(result, "$n$1\"$2\": $3", [istr, c[i], c[i + 1]]) @@ -315,13 +310,11 @@ proc typeToYamlAux(n: PType, marker: var TIntSet, indent: int, proc treeToYamlAux(n: PNode, marker: var TIntSet, indent: int, maxRecDepth: int): PRope = - var istr: PRope if n == nil: result = toRope("null") else: - istr = spaces(indent + 2) - result = ropef("{$n$1\"kind\": $2", - [istr, makeYamlString($n.kind)]) + var istr = spaces(indent + 2) + result = ropef("{$n$1\"kind\": $2", [istr, makeYamlString($n.kind)]) if maxRecDepth != 0: appf(result, ",$n$1\"info\": $2", [istr, lineInfoToStr(n.info)]) case n.kind @@ -386,11 +379,10 @@ proc debugType(n: PType): PRope = app(result, ")") proc debugTree(n: PNode, indent: int, maxRecDepth: int): PRope = - var istr: PRope if n == nil: result = toRope("null") else: - istr = spaces(indent + 2) + var istr = spaces(indent + 2) result = ropef("{$n$1\"kind\": $2", [istr, makeYamlString($n.kind)]) if maxRecDepth != 0: @@ -443,8 +435,7 @@ proc nextTry(h, maxHash: THash): THash = proc objectSetContains(t: TObjectSet, obj: PObject): bool = # returns true whether n is in t - var h: THash - h = hashNode(obj) and high(t.data) # start with real hash value + var h: THash = hashNode(obj) and high(t.data) # start with real hash value while t.data[h] != nil: if (t.data[h] == obj): return true @@ -452,8 +443,7 @@ proc objectSetContains(t: TObjectSet, obj: PObject): bool = result = false proc objectSetRawInsert(data: var TObjectSeq, obj: PObject) = - var h: THash - h = HashNode(obj) and high(data) + var h: THash = HashNode(obj) and high(data) while data[h] != nil: assert(data[h] != obj) h = nextTry(h, high(data)) @@ -474,12 +464,9 @@ proc objectSetIncl(t: var TObjectSet, obj: PObject) = proc objectSetContainsOrIncl(t: var TObjectSet, obj: PObject): bool = # returns true if obj is already in the string table: - var - h: THash - it: PObject - h = HashNode(obj) and high(t.data) + var h: THash = HashNode(obj) and high(t.data) while true: - it = t.data[h] + var it = t.data[h] if it == nil: break if it == obj: return true # found it @@ -494,20 +481,18 @@ proc objectSetContainsOrIncl(t: var TObjectSet, obj: PObject): bool = result = false proc TableRawGet(t: TTable, key: PObject): int = - var h: THash - h = hashNode(key) and high(t.data) # start with real hash value + var h: THash = hashNode(key) and high(t.data) # start with real hash value while t.data[h].key != nil: - if (t.data[h].key == key): + if t.data[h].key == key: return h h = nextTry(h, high(t.data)) - result = - 1 + result = -1 proc TableSearch(t: TTable, key, closure: PObject, comparator: TCmpProc): PObject = - var h: THash - h = hashNode(key) and high(t.data) # start with real hash value + var h: THash = hashNode(key) and high(t.data) # start with real hash value while t.data[h].key != nil: - if (t.data[h].key == key): + if t.data[h].key == key: if comparator(t.data[h].val, closure): # BUGFIX 1 return t.data[h].val @@ -520,8 +505,7 @@ proc TableGet(t: TTable, key: PObject): PObject = else: result = nil proc TableRawInsert(data: var TPairSeq, key, val: PObject) = - var h: THash - h = HashNode(key) and high(data) + var h: THash = HashNode(key) and high(data) while data[h].key != nil: assert(data[h].key != key) h = nextTry(h, high(data)) @@ -546,8 +530,7 @@ proc TablePut(t: var TTable, key, val: PObject) = inc(t.counter) proc StrTableContains(t: TStrTable, n: PSym): bool = - var h: THash - h = n.name.h and high(t.data) # start with real hash value + var h: THash = n.name.h and high(t.data) # start with real hash value while t.data[h] != nil: if (t.data[h] == n): return true @@ -555,8 +538,7 @@ proc StrTableContains(t: TStrTable, n: PSym): bool = result = false proc StrTableRawInsert(data: var TSymSeq, n: PSym) = - var h: THash - h = n.name.h and high(data) + var h: THash = n.name.h and high(data) while data[h] != nil: if data[h] == n: InternalError(n.info, "StrTableRawInsert: " & n.name.s) h = nextTry(h, high(data)) @@ -579,12 +561,9 @@ proc StrTableIncl*(t: var TStrTable, n: PSym): bool = # returns true if n is already in the string table: # It is essential that `n` is written nevertheless! # This way the newest redefinition is picked by the semantic analyses! - var - h: THash - it: PSym - h = n.name.h and high(t.data) + var h: THash = n.name.h and high(t.data) while true: - it = t.data[h] + var it = t.data[h] if it == nil: break if it.name.id == n.name.id: t.data[h] = n # overwrite it with newer definition! @@ -600,8 +579,7 @@ proc StrTableIncl*(t: var TStrTable, n: PSym): bool = result = false proc StrTableGet(t: TStrTable, name: PIdent): PSym = - var h: THash - h = name.h and high(t.data) + var h: THash = name.h and high(t.data) while true: result = t.data[h] if result == nil: break @@ -619,7 +597,7 @@ proc NextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym = h = ti.h and high(tab.data) start = h result = tab.data[h] - while (result != nil): + while result != nil: if result.Name.id == ti.name.id: break h = nextTry(h, high(tab.data)) if h == start: @@ -627,6 +605,29 @@ proc NextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym = break result = tab.data[h] ti.h = nextTry(h, high(tab.data)) + +proc NextIdentExcluding*(ti: var TIdentIter, tab: TStrTable, + excluding: TIntSet): PSym = + var h: THash = ti.h and high(tab.data) + var start = h + result = tab.data[h] + while result != nil: + if result.Name.id == ti.name.id and + not IntSetContains(excluding, result.id): break + h = nextTry(h, high(tab.data)) + if h == start: + result = nil + break + result = tab.data[h] + ti.h = nextTry(h, high(tab.data)) + if result != nil and IntSetContains(excluding, result.id): result = nil + +proc FirstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent, + excluding: TIntSet): PSym = + ti.h = s.h + ti.name = s + if tab.Counter == 0: result = nil + else: result = NextIdentExcluding(ti, tab, excluding) proc InitTabIter(ti: var TTabIter, tab: TStrTable): PSym = ti.h = 0 # we start by zero ... diff --git a/rod/lookups.nim b/rod/lookups.nim index 160f9635b..f65fe24b7 100755 --- a/rod/lookups.nim +++ b/rod/lookups.nim @@ -14,12 +14,14 @@ import type TOverloadIterMode* = enum - oimDone, oimNoQualifier, oimSelfModule, oimOtherModule, oimSymChoice + oimDone, oimNoQualifier, oimSelfModule, oimOtherModule, oimSymChoice, + oimSymChoiceLocalLookup TOverloadIter*{.final.} = object stackPtr*: int it*: TIdentIter m*: PSym mode*: TOverloadIterMode + inSymChoice: TIntSet proc getSymRepr*(s: PSym): string = case s.kind @@ -27,12 +29,10 @@ proc getSymRepr*(s: PSym): string = else: result = s.name.s proc CloseScope*(tab: var TSymTab) = - var - it: TTabIter - s: PSym # check if all symbols have been used and defined: if (tab.tos > len(tab.stack)): InternalError("CloseScope") - s = InitTabIter(it, tab.stack[tab.tos - 1]) + var it: TTabIter + var s = InitTabIter(it, tab.stack[tab.tos-1]) while s != nil: if sfForward in s.flags: LocalError(s.info, errImplOfXexpected, getSymRepr(s)) @@ -40,7 +40,7 @@ proc CloseScope*(tab: var TSymTab) = (optHints in s.options): # BUGFIX: check options in s! if not (s.kind in {skForVar, skParam, skMethod, skUnknown}): Message(s.info, hintXDeclaredButNotUsed, getSymRepr(s)) - s = NextIter(it, tab.stack[tab.tos - 1]) + s = NextIter(it, tab.stack[tab.tos-1]) astalgo.rawCloseScope(tab) proc AddSym*(t: var TStrTable, n: PSym) = @@ -144,12 +144,11 @@ proc QualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym = if (result != nil) and (result.kind == skStub): loadStub(result) proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = - result = nil case n.kind of nkIdent: o.stackPtr = c.tab.tos o.mode = oimNoQualifier - while (result == nil): + while result == nil: dec(o.stackPtr) if o.stackPtr < 0: break result = InitIdentIter(o.it, c.tab.stack[o.stackPtr], n.ident) @@ -159,12 +158,12 @@ proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = of nkDotExpr: o.mode = oimOtherModule o.m = qualifiedLookUp(c, n.sons[0]) - if (o.m != nil) and (o.m.kind == skModule): + if o.m != nil and o.m.kind == skModule: var ident: PIdent = nil - if (n.sons[1].kind == nkIdent): + if n.sons[1].kind == nkIdent: ident = n.sons[1].ident - elif (n.sons[1].kind == nkAccQuoted) and - (n.sons[1].sons[0].kind == nkIdent): + elif n.sons[1].kind == nkAccQuoted and + n.sons[1].sons[0].kind == nkIdent: ident = n.sons[1].sons[0].ident if ident != nil: if o.m == c.module: @@ -182,9 +181,10 @@ proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = o.mode = oimSymChoice result = n.sons[0].sym o.stackPtr = 1 - else: - nil - if (result != nil) and (result.kind == skStub): loadStub(result) + IntSetInit(o.inSymChoice) + IntSetIncl(o.inSymChoice, result.id) + else: nil + if result != nil and result.kind == skStub: loadStub(result) proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = case o.mode @@ -192,10 +192,10 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = result = nil of oimNoQualifier: if n.kind == nkAccQuoted: - result = nextOverloadIter(o, c, n.sons[0]) # BUGFIX + result = nextOverloadIter(o, c, n.sons[0]) elif o.stackPtr >= 0: result = nextIdentIter(o.it, c.tab.stack[o.stackPtr]) - while (result == nil): + while result == nil: dec(o.stackPtr) if o.stackPtr < 0: break result = InitIdentIter(o.it, c.tab.stack[o.stackPtr], o.it.name) @@ -209,8 +209,26 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = of oimSymChoice: if o.stackPtr < sonsLen(n): result = n.sons[o.stackPtr].sym + IntSetIncl(o.inSymChoice, result.id) inc(o.stackPtr) - else: - result = nil - if (result != nil) and (result.kind == skStub): loadStub(result) + else: + # try 'local' symbols too for Koenig's lookup: + o.mode = oimSymChoiceLocalLookup + o.stackPtr = c.tab.tos-1 + result = FirstIdentExcluding(o.it, c.tab.stack[o.stackPtr], + n.sons[0].sym.name, o.inSymChoice) + while result == nil: + dec(o.stackPtr) + if o.stackPtr < 0: break + result = FirstIdentExcluding(o.it, c.tab.stack[o.stackPtr], + n.sons[0].sym.name, o.inSymChoice) + of oimSymChoiceLocalLookup: + result = nextIdentExcluding(o.it, c.tab.stack[o.stackPtr], o.inSymChoice) + while result == nil: + dec(o.stackPtr) + if o.stackPtr < 0: break + result = FirstIdentExcluding(o.it, c.tab.stack[o.stackPtr], + n.sons[0].sym.name, o.inSymChoice) + + if result != nil and result.kind == skStub: loadStub(result) diff --git a/rod/sem.nim b/rod/sem.nim index 1ede5f7f8..bb948ffc9 100755 --- a/rod/sem.nim +++ b/rod/sem.nim @@ -29,9 +29,7 @@ proc considerAcc(n: PNode): PIdent = result = nil proc isTopLevel(c: PContext): bool {.inline.} = - # if we encountered an error, we treat as top-level so that - # cascading errors are not that strange: - result = c.tab.tos <= 2 or msgs.gErrorCounter > 0 + result = c.tab.tos <= 2 proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym = result = newSym(kind, considerAcc(n), getCurrOwner()) @@ -166,7 +164,7 @@ proc myOpen(module: PSym, filename: string): PPassContext = if (c.p != nil): InternalError(module.info, "sem.myOpen") c.semConstExpr = semConstExpr c.semExpr = semExprNoFlags - c.p = newProcCon(module) + pushProcCon(c, module) pushOwner(c.module) openScope(c.tab) # scope for imported symbols SymTabAdd(c.tab, module) # a module knows itself @@ -179,7 +177,8 @@ proc myOpen(module: PSym, filename: string): PPassContext = openScope(c.tab) # scope for the module's symbols result = c -proc myOpenCached(module: PSym, filename: string, rd: PRodReader): PPassContext = +proc myOpenCached(module: PSym, filename: string, + rd: PRodReader): PPassContext = var c = PContext(myOpen(module, filename)) c.fromCache = true result = c @@ -195,6 +194,14 @@ proc SemStmtAndGenerateGenerics(c: PContext, n: PNode): PNode = if result.kind != nkEmpty: addSon(a, result) result = a +proc RecoverContext(c: PContext) = + # clean up in case of a semantic error: We clean up the stacks, etc. This is + # faster than wrapping every stack operation in a 'try finally' block and + # requires far less code. + while c.tab.tos-1 > ModuleTablePos: rawCloseScope(c.tab) + while getCurrOwner().kind != skModule: popOwner() + while c.p != nil and c.p.owner.kind != skModule: c.p = c.p.next + proc myProcess(context: PPassContext, n: PNode): PNode = var c = PContext(context) # no need for an expensive 'try' if we stop after the first error anyway: @@ -204,6 +211,7 @@ proc myProcess(context: PPassContext, n: PNode): PNode = try: result = SemStmtAndGenerateGenerics(c, n) except ERecoverableError: + RecoverContext(c) result = ast.emptyNode proc myClose(context: PPassContext, n: PNode): PNode = @@ -216,7 +224,7 @@ proc myClose(context: PPassContext, n: PNode): PNode = InternalError(n.info, "n is not nil") #result := n; addCodeForGenerics(c, result) popOwner() - c.p = nil + popProcCon(c) proc semPass(): TPass = initPass(result) diff --git a/rod/semdata.nim b/rod/semdata.nim index 702e00059..e052a0baf 100755 --- a/rod/semdata.nim +++ b/rod/semdata.nim @@ -23,14 +23,15 @@ type Notes*: TNoteKinds POptionEntry* = ref TOptionEntry + PProcCon* = ref TProcCon TProcCon*{.final.} = object # procedure context; also used for top-level # statements owner*: PSym # the symbol this context belongs to resultSym*: PSym # the result symbol (if we are in a proc) nestedLoopCounter*: int # whether we are in a loop or not nestedBlockCounter*: int # whether we are in a block or not + next*: PProcCon # used for stacking procedure contexts - PProcCon* = ref TProcCon PContext* = ref TContext TContext* = object of TPassContext # a context represents a module module*: PSym # the module sym belonging to the context @@ -58,7 +59,6 @@ var gInstTypes*: TIdTable # map PType to PType proc newContext*(module: PSym, nimfile: string): PContext -proc newProcCon*(owner: PSym): PProcCon proc lastOptionEntry*(c: PContext): POptionEntry proc newOptionEntry*(): POptionEntry proc addConverter*(c: PContext, conv: PSym) @@ -97,10 +97,15 @@ proc PopOwner() = proc lastOptionEntry(c: PContext): POptionEntry = result = POptionEntry(c.optionStack.tail) -proc newProcCon(owner: PSym): PProcCon = +proc pushProcCon*(c: PContext, owner: PSym) {.inline.} = if owner == nil: InternalError("owner is nil") - new(result) - result.owner = owner + var x: PProcCon + new(x) + x.owner = owner + x.next = c.p + c.p = x + +proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next proc newOptionEntry(): POptionEntry = new(result) diff --git a/rod/semgnrc.nim b/rod/semgnrc.nim index 633994942..4894843f8 100755 --- a/rod/semgnrc.nim +++ b/rod/semgnrc.nim @@ -64,10 +64,8 @@ proc getIdentNode(n: PNode): PNode = # if withinBind in flags: result = symChoice(c, n, s) # else: result = semGenericStmtSymbol(c, n, s) -proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode = - var - L: int - a: PNode +proc semGenericStmt(c: PContext, n: PNode, + flags: TSemGenericFlags = {}): PNode = result = n if gCmd == cmdIdeTools: suggestStmt(c, n) case n.kind @@ -124,14 +122,14 @@ proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode openScope(c.tab) n.sons[0] = semGenericStmt(c, n.sons[0]) for i in countup(1, sonsLen(n)-1): - a = n.sons[i] + var a = n.sons[i] checkMinSonsLen(a, 1) - L = sonsLen(a) + var L = sonsLen(a) for j in countup(0, L - 2): a.sons[j] = semGenericStmt(c, a.sons[j]) a.sons[L - 1] = semGenericStmtScope(c, a.sons[L - 1]) closeScope(c.tab) of nkForStmt: - L = sonsLen(n) + var L = sonsLen(n) openScope(c.tab) n.sons[L - 2] = semGenericStmt(c, n.sons[L - 2]) for i in countup(0, L - 3): addDecl(c, newSymS(skUnknown, n.sons[i], c)) @@ -147,36 +145,36 @@ proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode checkMinSonsLen(n, 2) n.sons[0] = semGenericStmtScope(c, n.sons[0]) for i in countup(1, sonsLen(n) - 1): - a = n.sons[i] + var a = n.sons[i] checkMinSonsLen(a, 1) - L = sonsLen(a) + var L = sonsLen(a) for j in countup(0, L - 2): a.sons[j] = semGenericStmt(c, a.sons[j], {withinTypeDesc}) a.sons[L - 1] = semGenericStmtScope(c, a.sons[L - 1]) of nkVarSection: for i in countup(0, sonsLen(n) - 1): - a = n.sons[i] + var a = n.sons[i] if a.kind == nkCommentStmt: continue if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): IllFormedAst(a) checkMinSonsLen(a, 3) - L = sonsLen(a) - a.sons[L - 2] = semGenericStmt(c, a.sons[L - 2], {withinTypeDesc}) - a.sons[L - 1] = semGenericStmt(c, a.sons[L - 1]) - for j in countup(0, L - 3): + var L = sonsLen(a) + a.sons[L-2] = semGenericStmt(c, a.sons[L-2], {withinTypeDesc}) + a.sons[L-1] = semGenericStmt(c, a.sons[L-1]) + for j in countup(0, L-3): addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c)) of nkGenericParams: for i in countup(0, sonsLen(n) - 1): - a = n.sons[i] + var a = n.sons[i] if (a.kind != nkIdentDefs): IllFormedAst(a) checkMinSonsLen(a, 3) - L = sonsLen(a) - a.sons[L - 2] = semGenericStmt(c, a.sons[L - 2], {withinTypeDesc}) + var L = sonsLen(a) + a.sons[L-2] = semGenericStmt(c, a.sons[L-2], {withinTypeDesc}) # do not perform symbol lookup for default expressions - for j in countup(0, L - 3): + for j in countup(0, L-3): addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c)) of nkConstSection: for i in countup(0, sonsLen(n) - 1): - a = n.sons[i] + var a = n.sons[i] if a.kind == nkCommentStmt: continue if (a.kind != nkConstDef): IllFormedAst(a) checkSonsLen(a, 3) @@ -185,13 +183,13 @@ proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode a.sons[2] = semGenericStmt(c, a.sons[2]) of nkTypeSection: for i in countup(0, sonsLen(n) - 1): - a = n.sons[i] + var a = n.sons[i] if a.kind == nkCommentStmt: continue if (a.kind != nkTypeDef): IllFormedAst(a) checkSonsLen(a, 3) addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[0]), c)) for i in countup(0, sonsLen(n) - 1): - a = n.sons[i] + var a = n.sons[i] if a.kind == nkCommentStmt: continue if (a.kind != nkTypeDef): IllFormedAst(a) checkSonsLen(a, 3) @@ -207,6 +205,7 @@ proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode if n.sons[0].kind != nkEmpty: n.sons[0] = semGenericStmt(c, n.sons[0], {withinTypeDesc}) for i in countup(1, sonsLen(n) - 1): + var a: PNode case n.sons[i].kind of nkEnumFieldDef: a = n.sons[i].sons[0] of nkIdent: a = n.sons[i] @@ -219,10 +218,10 @@ proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode if n.sons[0].kind != nkEmpty: n.sons[0] = semGenericStmt(c, n.sons[0], {withinTypeDesc}) for i in countup(1, sonsLen(n) - 1): - a = n.sons[i] + var a = n.sons[i] if (a.kind != nkIdentDefs): IllFormedAst(a) checkMinSonsLen(a, 3) - L = sonsLen(a) + var L = sonsLen(a) a.sons[L-2] = semGenericStmt(c, a.sons[L-2], {withinTypeDesc}) a.sons[L-1] = semGenericStmt(c, a.sons[L-1]) for j in countup(0, L-3): diff --git a/rod/seminst.nim b/rod/seminst.nim index 99fd1fb87..e37c6e0fc 100755 --- a/rod/seminst.nim +++ b/rod/seminst.nim @@ -68,13 +68,12 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, # generates an instantiated proc var oldPrc, oldMod: PSym - oldP: PProcCon n: PNode if c.InstCounter > 1000: InternalError(fn.ast.info, "nesting too deep") inc(c.InstCounter) - oldP = c.p # restore later # NOTE: for access of private fields within generics from a different module # and other identifiers we fake the current module temporarily! + # XXX bad hack! oldMod = c.module c.module = getModule(fn) result = copySym(fn, false) @@ -105,17 +104,17 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, GenericCacheAdd(c, fn, result) addDecl(c, result) if n.sons[codePos].kind != nkEmpty: - c.p = newProcCon(result) + pushProcCon(c, result) if result.kind in {skProc, skMethod, skConverter}: addResult(c, result.typ.sons[0], n.info) addResultNode(c, n) n.sons[codePos] = semStmtScope(c, n.sons[codePos]) - else: + popProcCon(c) + else: result = oldPrc popInfoContext() closeScope(c.tab) # close scope for parameters popOwner() - c.p = oldP # restore c.module = oldMod dec(c.InstCounter) diff --git a/rod/semstmts.nim b/rod/semstmts.nim index b2fae3f31..71d523540 100755 --- a/rod/semstmts.nim +++ b/rod/semstmts.nim @@ -85,7 +85,7 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode = of nkIdent: s = lookUp(c, n.sons[0]) of nkSym: s = n.sons[0].sym else: illFormedAst(n) - if (s.kind == skLabel) and (s.owner.id == c.p.owner.id): + if s.kind == skLabel and s.owner.id == c.p.owner.id: var x = newSymNode(s) x.info = n.info incl(s.flags, sfUsed) @@ -266,6 +266,13 @@ proc fitRemoveHiddenConv(c: PContext, typ: Ptype, n: PNode): PNode = elif not sameType(result.typ, typ): changeType(result, typ) +proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym = + if isTopLevel(c): + result = semIdentWithPragma(c, kind, n, {sfStar, sfMinus}) + incl(result.flags, sfGlobal) + else: + result = semIdentWithPragma(c, kind, n, {}) + proc semVar(c: PContext, n: PNode): PNode = var b: PNode result = copyNode(n) @@ -304,13 +311,8 @@ proc semVar(c: PContext, n: PNode): PNode = b.sons[length - 2] = ast.emptyNode # no type desc b.sons[length - 1] = def addSon(result, b) - for j in countup(0, length - 3): - var v: PSym - if (c.p.owner.kind == skModule): - v = semIdentWithPragma(c, skVar, a.sons[j], {sfStar, sfMinus}) - incl(v.flags, sfGlobal) - else: - v = semIdentWithPragma(c, skVar, a.sons[j], {}) + for j in countup(0, length-3): + var v = semIdentDef(c, a.sons[j], skVar) if v.flags * {sfStar, sfMinus} != {}: incl(v.flags, sfInInterface) addInterfaceDecl(c, v) if a.kind != nkVarTuple: @@ -332,12 +334,7 @@ proc semConst(c: PContext, n: PNode): PNode = if a.kind == nkCommentStmt: continue if (a.kind != nkConstDef): IllFormedAst(a) checkSonsLen(a, 3) - var v: PSym - if (c.p.owner.kind == skModule): - v = semIdentWithPragma(c, skConst, a.sons[0], {sfStar, sfMinus}) - incl(v.flags, sfGlobal) - else: - v = semIdentWithPragma(c, skConst, a.sons[0], {}) + var v = semIdentDef(c, a.sons[0], skConst) var typ: PType = nil if a.sons[1].kind != nkEmpty: typ = semTypeNode(c, a.sons[1], nil) var def = semAndEvalConstExpr(c, a.sons[2]) @@ -524,12 +521,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) = if a.kind == nkCommentStmt: continue if a.kind != nkTypeDef: IllFormedAst(a) checkSonsLen(a, 3) - var s: PSym - if c.p.owner.kind == skModule: - s = semIdentWithPragma(c, skType, a.sons[0], {sfStar, sfMinus}) - incl(s.flags, sfGlobal) - else: - s = semIdentWithPragma(c, skType, a.sons[0], {}) + var s = semIdentDef(c, a.sons[0], skType) if s.flags * {sfStar, sfMinus} != {}: incl(s.flags, sfInInterface) s.typ = newTypeS(tyForward, c) s.typ.sym = s # process pragmas: @@ -547,7 +539,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = checkSonsLen(a, 3) if (a.sons[0].kind != nkSym): IllFormedAst(a) var s = a.sons[0].sym - if (s.magic == mNone) and (a.sons[2].kind == nkEmpty): + if s.magic == mNone and a.sons[2].kind == nkEmpty: GlobalError(a.info, errImplOfXexpected, s.name.s) if s.magic != mNone: processMagicType(c, s) if a.sons[1].kind != nkEmpty: @@ -646,7 +638,6 @@ proc semLambda(c: PContext, n: PNode): PNode = checkSonsLen(n, codePos + 1) var s = newSym(skProc, getIdent(":anonymous"), getCurrOwner()) s.info = n.info - var oldP = c.p # restore later s.ast = n n.sons[namePos] = newSymNode(s) pushOwner(s) @@ -666,31 +657,26 @@ proc semLambda(c: PContext, n: PNode): PNode = if n.sons[codePos].kind != nkEmpty: if sfImportc in s.flags: LocalError(n.sons[codePos].info, errImplOfXNotAllowed, s.name.s) - c.p = newProcCon(s) + pushProcCon(c, s) addResult(c, s.typ.sons[0], n.info) n.sons[codePos] = semStmtScope(c, n.sons[codePos]) addResultNode(c, n) + popProcCon(c) else: LocalError(n.info, errImplOfXexpected, s.name.s) closeScope(c.tab) # close scope for parameters popOwner() - c.p = oldP # restore result.typ = s.typ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, validPragmas: TSpecialWords): PNode = var - s, proto: PSym + proto: PSym gp: PNode result = n checkSonsLen(n, codePos + 1) - if c.p.owner.kind == skModule: - s = semIdentVis(c, kind, n.sons[0], {sfStar}) - incl(s.flags, sfGlobal) - else: - s = semIdentVis(c, kind, n.sons[0], {}) + var s = semIdentDef(c, n.sons[0], kind) n.sons[namePos] = newSymNode(s) - var oldP = c.p # restore later if sfStar in s.flags: incl(s.flags, sfInInterface) s.ast = n pushOwner(s) @@ -716,7 +702,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, proto = SearchForProc(c, s, c.tab.tos - 2) # -2 because we have a scope open # for parameters if proto == nil: - if oldP.owner.kind != skModule: + if c.p.owner.kind != skModule: s.typ.callConv = ccClosure else: s.typ.callConv = lastOptionEntry(c).defaultCC @@ -755,13 +741,14 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, if sfBorrow in s.flags: LocalError(n.sons[codePos].info, errImplOfXNotAllowed, s.name.s) if n.sons[genericParamsPos].kind == nkEmpty: - c.p = newProcCon(s) + pushProcCon(c, s) if (s.typ.sons[0] != nil) and (kind != skIterator): addResult(c, s.typ.sons[0], n.info) if sfImportc notin s.flags: # no semantic checking for importc: n.sons[codePos] = semStmtScope(c, n.sons[codePos]) if s.typ.sons[0] != nil and kind != skIterator: addResultNode(c, n) + popProcCon(c) else: if s.typ.sons[0] != nil and kind != skIterator: addDecl(c, newSym(skUnknown, getIdent("result"), nil)) @@ -776,7 +763,6 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, sideEffectsCheck(c, s) closeScope(c.tab) # close scope for parameters popOwner() - c.p = oldP # restore proc semIterator(c: PContext, n: PNode): PNode = result = semProcAux(c, n, skIterator, iteratorPragmas) diff --git a/rod/semtypes.nim b/rod/semtypes.nim index 79511b716..38f1ffc71 100755 --- a/rod/semtypes.nim +++ b/rod/semtypes.nim @@ -694,6 +694,8 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = if a.sons[L-2].kind != nkEmpty: typ = newTypeS(tyGenericParam, c) semGenericConstraints(c, a.sons[L-2], typ) + if sonsLen(typ) == 1 and typ.sons[0].kind == tyTypeDesc: + typ = typ.sons[0] elif def.kind != nkEmpty: typ = newTypeS(tyExpr, c) else: typ = nil for j in countup(0, L-3): diff --git a/tests/accept/run/tkoeniglookup.nim b/tests/accept/run/tkoeniglookup.nim index 07c5b46be..e6f5c0112 100644 --- a/tests/accept/run/tkoeniglookup.nim +++ b/tests/accept/run/tkoeniglookup.nim @@ -9,8 +9,8 @@ type TMyObj = object x, y: int -proc `$`*(a: TMyObj): bool = - result = "x: " & a.x & " y: " & a.y +proc `$`*(a: TMyObj): string = + result = "x: " & $a.x & " y: " & $a.y var a: TMyObj echo toString(a) diff --git a/tests/reject/ttypenoval.nim b/tests/reject/ttypenoval.nim index ed91b05e2..44b3db879 100755 --- a/tests/reject/ttypenoval.nim +++ b/tests/reject/ttypenoval.nim @@ -1,5 +1,5 @@ discard """ - file: "tambsym.nim" + file: "ttypenoval.nim" line: 36 errormsg: "a type has no value" """ diff --git a/todo.txt b/todo.txt index 09a9117dd..4dc4e17f2 100755 --- a/todo.txt +++ b/todo.txt @@ -1,3 +1,5 @@ +- clean up the tests! +- GC: marker procs for native Nimrod GC and Boehm GC - thread support: threadvar on Windows seems broken; add --deadlock_prevention:on|off switch - built-in serialization diff --git a/web/news.txt b/web/news.txt index 9b1979056..c28eef94e 100755 --- a/web/news.txt +++ b/web/news.txt @@ -67,7 +67,8 @@ Additions - The *interactive mode* (REPL) has been improved and documented for the first time. - Added the ``linearScanEnd``, ``unroll``, ``shallow`` pragmas. -- Added ``system.reset``. +- Added ``system.reset`` and a version of ``system.open`` that + returns a ``TFile`` and raises an exception in case of an error. - The compiler now might use a hashing for string case statements depending on the number of string literals in the case statement. |