diff options
-rwxr-xr-x | compiler/ast.nim | 38 | ||||
-rwxr-xr-x | compiler/ccgexprs.nim | 22 | ||||
-rwxr-xr-x | compiler/ccgtypes.nim | 6 | ||||
-rwxr-xr-x | compiler/cgen.nim | 2 | ||||
-rwxr-xr-x | compiler/idents.nim | 100 | ||||
-rw-r--r-- | compiler/idgen.nim | 57 | ||||
-rwxr-xr-x | compiler/main.nim | 42 | ||||
-rwxr-xr-x | compiler/msgs.nim | 2 | ||||
-rwxr-xr-x | compiler/passaux.nim | 4 | ||||
-rwxr-xr-x | compiler/passes.nim | 2 | ||||
-rwxr-xr-x | compiler/rodread.nim | 235 | ||||
-rwxr-xr-x | compiler/rodutils.nim | 98 | ||||
-rwxr-xr-x | compiler/rodwrite.nim | 519 | ||||
-rwxr-xr-x | compiler/sem.nim | 2 | ||||
-rwxr-xr-x | compiler/semstmts.nim | 2 | ||||
-rwxr-xr-x | compiler/treetab.nim | 2 | ||||
-rwxr-xr-x | lib/impure/db_sqlite.nim | 3 | ||||
-rwxr-xr-x | todo.txt | 36 |
18 files changed, 613 insertions, 559 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index fd79c90e0..351ceeb36 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -10,7 +10,8 @@ # abstract syntax tree + symbol table import - msgs, hashes, nversion, options, strutils, crc, ropes, idents, lists, intsets + msgs, hashes, nversion, options, strutils, crc, ropes, idents, lists, + intsets, idgen const ImportTablePos* = 0 @@ -377,7 +378,6 @@ type type PNode* = ref TNode - PNodePtr* = ptr PNode TNodeSeq* = seq[PNode] PType* = ref TType PSym* = ref TSym @@ -562,8 +562,8 @@ const tySet, tyTuple, tyRange, tyPtr, tyRef, tyVar, tySequence, tyProc, tyPointer, tyOpenArray, tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128, - tyUInt..tyUInt64} - + tyUInt..tyUInt64} + ConstantDataTypes*: TTypeKinds = {tyArrayConstr, tyArray, tySet, tyTuple, tySequence} ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType, skIterator, @@ -577,12 +577,6 @@ const resultPos* = 5 dispatcherPos* = 6 -var gId*: int - -proc getID*(): int {.inline.} -proc setID*(id: int) {.inline.} -proc IDsynchronizationPoint*(idRange: int) - # creator procs: proc NewSym*(symKind: TSymKind, Name: PIdent, owner: PSym): PSym proc NewType*(kind: TTypeKind, owner: PSym): PType @@ -660,27 +654,6 @@ proc leValue*(a, b: PNode): bool # a <= b? a, b are literals proc ValueToString*(a: PNode): string -const - debugIds* = false - -when debugIds: - var usedIds: TIntSet - -proc registerID*(id: PIdObj) = - when debugIDs: - if (id.id == - 1) or ContainsOrIncl(usedIds, id.id): - InternalError("ID already used: " & $(id.id)) - -proc getID(): int = - result = gId - inc(gId) - -proc setId(id: int) = - gId = max(gId, id + 1) - -proc IDsynchronizationPoint(idRange: int) = - gId = (gId div IdRange + 1) * IdRange + 1 - proc leValue(a, b: PNode): bool = # a <= b? result = false @@ -1031,5 +1004,4 @@ proc getStrOrChar*(a: PNode): string = else: internalError(a.info, "getStrOrChar") result = "" - -when debugIDs: usedIds = InitIntSet() + diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 826832438..a06a5db43 100755 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -38,7 +38,7 @@ proc genHexLiteral(v: PNode): PRope = proc getStrLit(m: BModule, s: string): PRope = discard cgsym(m, "TGenericSeq") - result = con("TMP", toRope(getID())) + result = con("TMP", toRope(backendId())) appf(m.s[cfsData], "STRING_LITERAL($1, $2, $3);$n", [result, makeCString(s), ToRope(len(s))]) @@ -70,8 +70,8 @@ proc genLiteral(p: BProc, v: PNode, ty: PType): PRope = result = toRope("NIM_NIL") of nkStrLit..nkTripleStrLit: if skipTypes(ty, abstractVarRange).kind == tyString: - var id = NodeTableTestOrSet(p.module.dataCache, v, gid) - if id == gid: + var id = NodeTableTestOrSet(p.module.dataCache, v, gBackendId) + if id == gBackendId: # string literal not found in the cache: result = ropecg(p.module, "((#NimStringDesc*) &$1)", [getStrLit(p.module, v.strVal)]) @@ -123,11 +123,11 @@ proc genSetNode(p: BProc, n: PNode): PRope = var size = int(getSize(n.typ)) toBitSet(n, cs) if size > 8: - var id = NodeTableTestOrSet(p.module.dataCache, n, gid) + var id = NodeTableTestOrSet(p.module.dataCache, n, gBackendId) result = con("TMP", toRope(id)) - if id == gid: + if id == gBackendId: # not found in cache: - inc(gid) + inc(gBackendId) appf(p.module.s[cfsData], "static NIM_CONST $1 $2 = $3;$n", [getTypeDesc(p.module, n.typ), result, genRawSetData(cs, size)]) else: @@ -618,8 +618,8 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) = v.r = ropef("$1.$2", [r, it.sons[2].sym.loc.r]) genInExprAux(p, it, u, v, test) id = NodeTableTestOrSet(p.module.dataCache, - newStrNode(nkStrLit, field.name.s), gid) - if id == gid: strLit = getStrLit(p.module, field.name.s) + newStrNode(nkStrLit, field.name.s), gBackendId) + if id == gBackendId: strLit = getStrLit(p.module, field.name.s) else: strLit = con("TMP", toRope(id)) if op.magic == mNot: appcg(p, cpsStmts, @@ -1581,11 +1581,11 @@ proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool = if (nfAllConst in n.flags) and (d.k == locNone) and (sonsLen(n) > 0): var t = getUniqueType(n.typ) discard getTypeDesc(p.module, t) # so that any fields are initialized - var id = NodeTableTestOrSet(p.module.dataCache, n, gid) + var id = NodeTableTestOrSet(p.module.dataCache, n, gBackendId) fillLoc(d, locData, t, con("TMP", toRope(id)), OnHeap) - if id == gid: + if id == gBackendId: # expression not found in the cache: - inc(gid) + inc(gBackendId) appf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n", [getTypeDesc(p.module, t), d.r, genConstExpr(p, n)]) result = true diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index b1465c215..37df89cfd 100755 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -145,12 +145,10 @@ proc CacheGetType(tab: TIdTable, key: PType): PRope = result = PRope(IdTableGet(tab, key)) proc getTempName(): PRope = - result = ropeff("TMP$1", "%TMP$1", [toRope(gId)]) - inc(gId) + result = ropeff("TMP$1", "%TMP$1", [toRope(backendId())]) proc getGlobalTempName(): PRope = - result = ropeff("TMP$1", "@TMP$1", [toRope(gId)]) - inc(gId) + result = ropeff("TMP$1", "@TMP$1", [toRope(backendId())]) proc ccgIntroducedPtr(s: PSym): bool = var pt = skipTypes(s.typ, abstractInst) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 70b3069cf..d4a9dd278 100755 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -15,7 +15,7 @@ import options, intsets, nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os, times, ropes, math, passes, rodread, wordrecg, treetab, cgmeth, - rodutils, renderer + rodutils, renderer, idgen when options.hasTinyCBackend: import tccgen diff --git a/compiler/idents.nim b/compiler/idents.nim index 422112e4f..efed7ae62 100755 --- a/compiler/idents.nim +++ b/compiler/idents.nim @@ -1,14 +1,14 @@ # # # The Nimrod Compiler -# (c) Copyright 2009 Andreas Rumpf +# (c) Copyright 2011 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # # Identifier handling -# An identifier is a shared non-modifiable string that can be compared by its +# An identifier is a shared immutable string that can be compared by its # id. This module is essential for the compiler's performance. import @@ -25,76 +25,48 @@ type next*: PIdent # for hash-table chaining h*: THash # hash value of s - -proc getIdent*(identifier: string): PIdent -proc getIdent*(identifier: string, h: THash): PIdent -proc getIdent*(identifier: cstring, length: int, h: THash): PIdent - # special version for the scanner; the scanner's buffering scheme makes - # this horribly efficient. Most of the time no character copying is needed! -proc IdentEq*(id: PIdent, name: string): bool -# implementation - -proc IdentEq(id: PIdent, name: string): bool = - result = id.id == getIdent(name).id - var buckets: array[0..4096 * 2 - 1, PIdent] -proc cmpIgnoreStyle(a, b: cstring, blen: int): int = - var - aa, bb: char - i, j: int - i = 0 - j = 0 +proc cmpIgnoreStyle(a, b: cstring, blen: int): int = + var i = 0 + var j = 0 result = 1 - while j < blen: + while j < blen: while a[i] == '_': inc(i) while b[j] == '_': inc(j) # tolower inlined: - aa = a[i] - bb = b[j] - if (aa >= 'A') and (aa <= 'Z'): aa = chr(ord(aa) + (ord('a') - ord('A'))) - if (bb >= 'A') and (bb <= 'Z'): bb = chr(ord(bb) + (ord('a') - ord('A'))) + var aa = a[i] + var bb = b[j] + if aa >= 'A' and aa <= 'Z': aa = chr(ord(aa) + (ord('a') - ord('A'))) + if bb >= 'A' and bb <= 'Z': bb = chr(ord(bb) + (ord('a') - ord('A'))) result = ord(aa) - ord(bb) if (result != 0) or (aa == '\0'): break inc(i) inc(j) - if result == 0: + if result == 0: if a[i] != '\0': result = 1 -proc cmpExact(a, b: cstring, blen: int): int = - var - aa, bb: char - i, j: int - i = 0 - j = 0 +proc cmpExact(a, b: cstring, blen: int): int = + var i = 0 + var j = 0 result = 1 - while j < blen: - aa = a[i] - bb = b[j] + while j < blen: + var aa = a[i] + var bb = b[j] result = ord(aa) - ord(bb) if (result != 0) or (aa == '\0'): break inc(i) inc(j) if result == 0: if a[i] != '\0': result = 1 - -proc getIdent(identifier: string): PIdent = - result = getIdent(cstring(identifier), len(identifier), - hashIgnoreStyle(identifier)) -proc getIdent(identifier: string, h: THash): PIdent = - result = getIdent(cstring(identifier), len(identifier), h) +var wordCounter = 1 -var wordCounter: int = 1 - -proc getIdent(identifier: cstring, length: int, h: THash): PIdent = - var - idx, id: int - last: PIdent - idx = h and high(buckets) +proc getIdent*(identifier: cstring, length: int, h: THash): PIdent = + var idx = h and high(buckets) result = buckets[idx] - last = nil - id = 0 + var last: PIdent = nil + var id = 0 while result != nil: if cmpExact(cstring(result.s), identifier, length) == 0: if last != nil: @@ -103,17 +75,7 @@ proc getIdent(identifier: cstring, length: int, h: THash): PIdent = result.next = buckets[idx] buckets[idx] = result return - elif cmpIgnoreStyle(cstring(result.s), identifier, length) == 0: - #if (id <> 0) and (id <> result.id) then begin - # result := buckets[idx]; - # writeln('current id ', id); - # for i := 0 to len-1 do write(identifier[i]); - # writeln; - # while result <> nil do begin - # writeln(result.s, ' ', result.id); - # result := result.next - # end - # end; + elif cmpIgnoreStyle(cstring(result.s), identifier, length) == 0: assert((id == 0) or (id == result.id)) id = result.id last = result @@ -121,12 +83,22 @@ proc getIdent(identifier: cstring, length: int, h: THash): PIdent = new(result) result.h = h result.s = newString(length) - for i in countup(0, length + 0 - 1): result.s[i] = identifier[i - 0] + for i in countup(0, length - 1): result.s[i] = identifier[i] result.next = buckets[idx] buckets[idx] = result if id == 0: inc(wordCounter) - result.id = - wordCounter + result.id = -wordCounter else: - result.id = id # writeln('new word ', result.s); + result.id = id + +proc getIdent*(identifier: string): PIdent = + result = getIdent(cstring(identifier), len(identifier), + hashIgnoreStyle(identifier)) + +proc getIdent*(identifier: string, h: THash): PIdent = + result = getIdent(cstring(identifier), len(identifier), h) + +proc IdentEq*(id: PIdent, name: string): bool = + result = id.id == getIdent(name).id diff --git a/compiler/idgen.nim b/compiler/idgen.nim new file mode 100644 index 000000000..f5ae8a1f8 --- /dev/null +++ b/compiler/idgen.nim @@ -0,0 +1,57 @@ +# +# +# The Nimrod Compiler +# (c) Copyright 2011 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module contains a simple persistent id generator. + +import idents, strutils, os + +var gFrontEndId, gBackendId*: int + +const + debugIds* = false + +when debugIds: + import intsets + + var usedIds = InitIntSet() + +proc registerID*(id: PIdObj) = + when debugIDs: + if (id.id == - 1) or ContainsOrIncl(usedIds, id.id): + InternalError("ID already used: " & $id.id) + +proc getID*(): int {.inline.} = + result = gFrontEndId + inc(gFrontEndId) + +proc backendId*(): int {.inline.} = + result = gBackendId + inc(gBackendId) + +proc setId*(id: int) {.inline.} = + gFrontEndId = max(gFrontEndId, id + 1) + +proc IDsynchronizationPoint*(idRange: int) = + gFrontEndId = (gFrontEndId div IdRange + 1) * IdRange + 1 + +proc saveMaxIds*(project: string) = + var f = open(project.addFileExt("gid"), fmWrite) + f.writeln($gFrontEndId) + f.writeln($gBackEndId) + f.close() + +proc loadMaxIds*(project: string) = + var f: TFile + if open(f, project.addFileExt("gid"), fmRead): + var frontEndId = parseInt(f.readLine) + var backEndId = parseInt(f.readLine) + gFrontEndId = max(gFrontEndId, frontEndId) + gBackEndId = max(gBackEndId, backEndId) + f.close() + diff --git a/compiler/main.nim b/compiler/main.nim index 017d188b5..f09ceb997 100755 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -15,7 +15,7 @@ import os, lists, condsyms, rodread, rodwrite, ropes, trees, wordrecg, sem, semdata, idents, passes, docgen, extccomp, cgen, ecmasgen, - platform, nimconf, importer, passaux, depends, transf, evals, types + platform, nimconf, importer, passaux, depends, transf, evals, types, idgen const has_LLVM_Backend = false @@ -24,24 +24,17 @@ when has_LLVM_Backend: import llvmgen proc MainCommand*(cmd, filename: string) -# implementation + # ------------------ module handling ----------------------------------------- type - TFileModuleRec{.final.} = object - filename*: string - module*: PSym - + TFileModuleRec = tuple[filename: string, module: PSym] TFileModuleMap = seq[TFileModuleRec] -var compMods: TFileModuleMap = @[] +var compMods: TFileModuleMap = @[] # all compiled modules proc registerModule(filename: string, module: PSym) = - # all compiled modules - var length = len(compMods) - setlen(compMods, length + 1) - compMods[length].filename = filename - compMods[length].module = module + compMods.add((filename, module)) proc getModule(filename: string): PSym = for i in countup(0, high(compMods)): @@ -65,23 +58,22 @@ proc newModule(filename: string): PSym = RegisterModule(filename, result) StrTableAdd(result.tab, result) # a module knows itself -proc CompileModule(filename: string, isMainFile, isSystemFile: bool): PSym +proc CompileModule(filename: string, flags: TSymFlags): PSym proc importModule(filename: string): PSym = # this is called by the semantic checking phase result = getModule(filename) if result == nil: # compile the module - result = compileModule(filename, false, false) + result = compileModule(filename, {}) elif sfSystemModule in result.flags: LocalError(result.info, errAttemptToRedefine, result.Name.s) -proc CompileModule(filename: string, isMainFile, isSystemFile: bool): PSym = +proc CompileModule(filename: string, flags: TSymFlags): PSym = var rd: PRodReader = nil var f = addFileExt(filename, nimExt) result = newModule(filename) - if isMainFile: incl(result.flags, sfMainModule) - if isSystemFile: incl(result.flags, sfSystemModule) - if (gCmd == cmdCompileToC) or (gCmd == cmdCompileToCpp): + result.flags = result.flags + flags + if gCmd in {cmdCompileToC, cmdCompileToCpp}: rd = handleSymbolFile(result, f) if result.id < 0: InternalError("handleSymbolFile should have set the module\'s ID") @@ -90,9 +82,9 @@ proc CompileModule(filename: string, isMainFile, isSystemFile: bool): PSym = processModule(result, f, nil, rd) proc CompileProject(filename: string) = - discard CompileModule(JoinPath(options.libpath, addFileExt("system", nimExt)), - false, true) - discard CompileModule(addFileExt(filename, nimExt), true, false) + discard CompileModule(options.libpath / addFileExt("system", nimExt), + {sfSystemModule}) + discard CompileModule(addFileExt(filename, nimExt), {sfMainModule}) proc semanticPasses() = registerPass(verbosePass()) @@ -147,8 +139,8 @@ proc CommandInteractive() = registerPass(verbosePass()) registerPass(sem.semPass()) registerPass(evals.evalPass()) # load system module: - discard CompileModule(JoinPath(options.libpath, addFileExt("system", nimExt)), - false, true) + discard CompileModule(options.libpath / addFileExt("system", nimExt), + {sfSystemModule}) var m = newModule("stdin") m.id = getID() incl(m.flags, sfMainModule) @@ -230,9 +222,9 @@ proc MainCommand(cmd, filename: string) = CommandCompileToLLVM(filename) else: rawMessage(errInvalidCommandX, cmd) - of "pretty": + of "pretty": gCmd = cmdPretty - wantFile(filename) #CommandExportSymbols(filename); + wantFile(filename) CommandPretty(filename) of "doc": gCmd = cmdDoc diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 4f8a21f54..7fe6f649d 100755 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -76,6 +76,7 @@ type errNamedExprNotAllowed, errXExpectsOneTypeParam, errArrayExpectsTwoTypeParams, errInvalidVisibilityX, errInitHereNotAllowed, errXCannotBeAssignedTo, errIteratorNotAllowed, errXNeedsReturnType, + errNoReturnTypeDeclared, errInvalidCommandX, errXOnlyAtModuleScope, errXNeedsParamObjectType, errTemplateInstantiationTooNested, errInstantiationFrom, @@ -284,6 +285,7 @@ const errXCannotBeAssignedTo: "\'$1\' cannot be assigned to", errIteratorNotAllowed: "iterators can only be defined at the module\'s top level", errXNeedsReturnType: "$1 needs a return type", + errNoReturnTypeDeclared: "no return type declared", errInvalidCommandX: "invalid command: \'$1\'", errXOnlyAtModuleScope: "\'$1\' is only allowed at top level", errXNeedsParamObjectType: "'$1' needs a parameter that has an object type", diff --git a/compiler/passaux.nim b/compiler/passaux.nim index a57963c06..659a9a346 100755 --- a/compiler/passaux.nim +++ b/compiler/passaux.nim @@ -10,7 +10,7 @@ ## implements some little helper passes import - strutils, ast, astalgo, passes, msgs, options + strutils, ast, astalgo, passes, msgs, options, idgen proc verboseOpen(s: PSym, filename: string): PPassContext = #MessageOut('compiling ' + s.name.s); @@ -24,7 +24,7 @@ proc verboseProcess(context: PPassContext, n: PNode): PNode = # system.nim deactivates all hints, for verbosity:3 we want the processing # messages nonetheless, so we activate them again unconditionally: incl(msgs.gNotes, hintProcessing) - Message(n.info, hintProcessing, $ast.gid) + Message(n.info, hintProcessing, $idgen.gBackendId) proc verbosePass*(): TPass = initPass(result) diff --git a/compiler/passes.nim b/compiler/passes.nim index 5b60d2805..d5aeb50d1 100755 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -13,7 +13,7 @@ import strutils, lists, options, ast, astalgo, llstream, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math, magicsys, nversion, - nimsets, syntaxes, times, rodread, semthreads + nimsets, syntaxes, times, rodread, semthreads, idgen type TPassContext* = object of TObject # the pass's context diff --git a/compiler/rodread.nim b/compiler/rodread.nim index 4de77ff42..1a59916a4 100755 --- a/compiler/rodread.nim +++ b/compiler/rodread.nim @@ -73,7 +73,7 @@ import os, options, strutils, nversion, ast, astalgo, msgs, platform, condsyms, - ropes, idents, crc + ropes, idents, crc, idgen, rodutils type TReasonForRecompile* = enum @@ -100,12 +100,12 @@ type TIndex*{.final.} = object # an index with compression lastIdxKey*, lastIdxVal*: int tab*: TIITable - r*: PRope # writers use this + r*: string # writers use this offset*: int # readers use this TRodReader* = object of TObject pos*: int # position; used for parsing - s*: string # the whole file in memory + s*: string # the whole file in memory; XXX mmap this! options*: TOptions reason*: TReasonForRecompile modDeps*: TStringSeq @@ -116,7 +116,7 @@ type filename*: string index*, imports*: TIndex readerIndex*: int - line*: int # only used for debugging, but is always in the code + line*: int # only used for debugging, but is always in the code moduleID*: int syms*: TIdTable # already processed symbols @@ -132,8 +132,7 @@ proc handleSymbolFile*(module: PSym, filename: string): PRodReader proc GetCRC*(filename: string): TCrc32 proc loadInitSection*(r: PRodReader): PNode proc loadStub*(s: PSym) -proc encodeInt*(x: BiggestInt): PRope -proc encode*(s: string): PRope + # implementation var gTypeTable: TIdTable @@ -141,52 +140,19 @@ var gTypeTable: TIdTable proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym # `info` is only used for debugging purposes proc rrGetType(r: PRodReader, id: int, info: TLineInfo): PType -proc decode(r: PRodReader): string -proc decodeInt(r: PRodReader): int -proc decodeBInt(r: PRodReader): biggestInt - -proc encode(s: string): PRope = - var res = "" - for i in countup(0, len(s) - 1): - case s[i] - of 'a'..'z', 'A'..'Z', '0'..'9', '_': add(res, s[i]) - else: add(res, '\\' & toHex(ord(s[i]), 2)) - result = toRope(res) - -proc encodeIntAux(str: var string, x: BiggestInt) = - const chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" - var d: char - var v = x - var rem: biggestInt = v mod 190 - if (rem < 0): - add(str, '-') - v = - (v div 190) - rem = - rem - else: - v = v div 190 - var idx = int(rem) - if idx < 62: d = chars[idx + 0] - else: d = chr(idx - 62 + 128) - if (v != 0): encodeIntAux(str, v) - add(str, d) - -proc encodeInt(x: BiggestInt): PRope = - var res = "" - encodeIntAux(res, x) - result = toRope(res) proc decodeLineInfo(r: PRodReader, info: var TLineInfo) = if r.s[r.pos] == '?': inc(r.pos) if r.s[r.pos] == ',': info.col = int16(- 1) - else: info.col = int16(decodeInt(r)) + else: info.col = int16(decodeVInt(r.s, r.pos)) if r.s[r.pos] == ',': inc(r.pos) if r.s[r.pos] == ',': info.line = int16(- 1) - else: info.line = int16(decodeInt(r)) + else: info.line = int16(decodeVInt(r.s, r.pos)) if r.s[r.pos] == ',': inc(r.pos) - info = newLineInfo(r.files[decodeInt(r)], info.line, info.col) + info = newLineInfo(r.files[decodeVInt(r.s, r.pos)], info.line, info.col) proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode = result = nil @@ -195,42 +161,42 @@ proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode = if r.s[r.pos] == ')': inc(r.pos) return # nil node - result = newNodeI(TNodeKind(decodeInt(r)), fInfo) + result = newNodeI(TNodeKind(decodeVInt(r.s, r.pos)), fInfo) decodeLineInfo(r, result.info) if r.s[r.pos] == '$': inc(r.pos) - result.flags = cast[TNodeFlags](int32(decodeInt(r))) + result.flags = cast[TNodeFlags](int32(decodeVInt(r.s, r.pos))) if r.s[r.pos] == '^': inc(r.pos) - var id = decodeInt(r) + var id = decodeVInt(r.s, r.pos) result.typ = rrGetType(r, id, result.info) case result.kind of nkCharLit..nkInt64Lit: if r.s[r.pos] == '!': inc(r.pos) - result.intVal = decodeBInt(r) + result.intVal = decodeVBiggestInt(r.s, r.pos) of nkFloatLit..nkFloat64Lit: if r.s[r.pos] == '!': inc(r.pos) - var fl = decode(r) + var fl = decodeStr(r.s, r.pos) result.floatVal = parseFloat(fl) of nkStrLit..nkTripleStrLit: if r.s[r.pos] == '!': inc(r.pos) - result.strVal = decode(r) + result.strVal = decodeStr(r.s, r.pos) else: result.strVal = "" # BUGFIX of nkIdent: if r.s[r.pos] == '!': inc(r.pos) - var fl = decode(r) + var fl = decodeStr(r.s, r.pos) result.ident = getIdent(fl) else: internalError(result.info, "decodeNode: nkIdent") of nkSym: if r.s[r.pos] == '!': inc(r.pos) - var id = decodeInt(r) + var id = decodeVInt(r.s, r.pos) result.sym = rrGetSym(r, id, result.info) else: internalError(result.info, "decodeNode: nkSym") @@ -245,32 +211,32 @@ proc decodeLoc(r: PRodReader, loc: var TLoc, info: TLineInfo) = if r.s[r.pos] == '<': inc(r.pos) if r.s[r.pos] in {'0'..'9', 'a'..'z', 'A'..'Z'}: - loc.k = TLocKind(decodeInt(r)) + loc.k = TLocKind(decodeVInt(r.s, r.pos)) else: loc.k = low(loc.k) if r.s[r.pos] == '*': inc(r.pos) - loc.s = TStorageLoc(decodeInt(r)) + loc.s = TStorageLoc(decodeVInt(r.s, r.pos)) else: loc.s = low(loc.s) if r.s[r.pos] == '$': inc(r.pos) - loc.flags = cast[TLocFlags](int32(decodeInt(r))) + loc.flags = cast[TLocFlags](int32(decodeVInt(r.s, r.pos))) else: loc.flags = {} if r.s[r.pos] == '^': inc(r.pos) - loc.t = rrGetType(r, decodeInt(r), info) + loc.t = rrGetType(r, decodeVInt(r.s, r.pos), info) else: loc.t = nil if r.s[r.pos] == '!': inc(r.pos) - loc.r = toRope(decode(r)) + loc.r = toRope(decodeStr(r.s, r.pos)) else: loc.r = nil if r.s[r.pos] == '?': inc(r.pos) - loc.a = decodeInt(r) + loc.a = decodeVInt(r.s, r.pos) else: loc.a = 0 if r.s[r.pos] == '>': inc(r.pos) @@ -284,10 +250,10 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType = inc(r.pos) return # nil type new(result) - result.kind = TTypeKind(decodeInt(r)) + result.kind = TTypeKind(decodeVInt(r.s, r.pos)) if r.s[r.pos] == '+': inc(r.pos) - result.id = decodeInt(r) + result.id = decodeVInt(r.s, r.pos) setId(result.id) if debugIds: registerID(result) else: @@ -297,29 +263,29 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType = if r.s[r.pos] == '(': result.n = decodeNode(r, UnknownLineInfo()) if r.s[r.pos] == '$': inc(r.pos) - result.flags = cast[TTypeFlags](int32(decodeInt(r))) + result.flags = cast[TTypeFlags](int32(decodeVInt(r.s, r.pos))) if r.s[r.pos] == '?': inc(r.pos) - result.callConv = TCallingConvention(decodeInt(r)) + result.callConv = TCallingConvention(decodeVInt(r.s, r.pos)) if r.s[r.pos] == '*': inc(r.pos) - result.owner = rrGetSym(r, decodeInt(r), info) + result.owner = rrGetSym(r, decodeVInt(r.s, r.pos), info) if r.s[r.pos] == '&': inc(r.pos) - result.sym = rrGetSym(r, decodeInt(r), info) + result.sym = rrGetSym(r, decodeVInt(r.s, r.pos), info) if r.s[r.pos] == '/': inc(r.pos) - result.size = decodeInt(r) + result.size = decodeVInt(r.s, r.pos) else: result.size = - 1 if r.s[r.pos] == '=': inc(r.pos) - result.align = decodeInt(r) + result.align = decodeVInt(r.s, r.pos) else: result.align = 2 if r.s[r.pos] == '@': inc(r.pos) - result.containerID = decodeInt(r) + result.containerID = decodeVInt(r.s, r.pos) decodeLoc(r, result.loc, info) while r.s[r.pos] == '^': inc(r.pos) @@ -329,7 +295,7 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType = else: InternalError(info, "decodeType ^(" & r.s[r.pos]) addSon(result, nil) else: - var d = decodeInt(r) + var d = decodeVInt(r.s, r.pos) addSon(result, rrGetType(r, d, info)) proc decodeLib(r: PRodReader, info: TLineInfo): PLib = @@ -337,10 +303,10 @@ proc decodeLib(r: PRodReader, info: TLineInfo): PLib = if r.s[r.pos] == '|': new(result) inc(r.pos) - result.kind = TLibKind(decodeInt(r)) + result.kind = TLibKind(decodeVInt(r.s, r.pos)) if r.s[r.pos] != '|': InternalError("decodeLib: 1") inc(r.pos) - result.name = toRope(decode(r)) + result.name = toRope(decodeStr(r.s, r.pos)) if r.s[r.pos] != '|': InternalError("decodeLib: 2") inc(r.pos) result.path = decodeNode(r, info) @@ -355,16 +321,16 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym = if r.s[r.pos] == '}': inc(r.pos) return # nil sym - var k = TSymKind(decodeInt(r)) + var k = TSymKind(decodeVInt(r.s, r.pos)) if r.s[r.pos] == '+': inc(r.pos) - id = decodeInt(r) + id = decodeVInt(r.s, r.pos) setId(id) else: InternalError(info, "decodeSym: no id") if r.s[r.pos] == '&': inc(r.pos) - ident = getIdent(decode(r)) + ident = getIdent(decodeStr(r.s, r.pos)) else: InternalError(info, "decodeSym: no ident") result = PSym(IdTableGet(r.syms, id)) @@ -379,100 +345,37 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym = result.name = ident # read the rest of the symbol description: if r.s[r.pos] == '^': inc(r.pos) - result.typ = rrGetType(r, decodeInt(r), info) + result.typ = rrGetType(r, decodeVInt(r.s, r.pos), info) decodeLineInfo(r, result.info) if r.s[r.pos] == '*': inc(r.pos) - result.owner = rrGetSym(r, decodeInt(r), result.info) + result.owner = rrGetSym(r, decodeVInt(r.s, r.pos), result.info) if r.s[r.pos] == '$': inc(r.pos) - result.flags = cast[TSymFlags](int32(decodeInt(r))) + result.flags = cast[TSymFlags](int32(decodeVInt(r.s, r.pos))) if r.s[r.pos] == '@': inc(r.pos) - result.magic = TMagic(decodeInt(r)) + result.magic = TMagic(decodeVInt(r.s, r.pos)) if r.s[r.pos] == '(': result.ast = decodeNode(r, result.info) if r.s[r.pos] == '!': inc(r.pos) - result.options = cast[TOptions](int32(decodeInt(r))) + result.options = cast[TOptions](int32(decodeVInt(r.s, r.pos))) else: result.options = r.options if r.s[r.pos] == '%': inc(r.pos) - result.position = decodeInt(r) + result.position = decodeVInt(r.s, r.pos) else: result.position = 0 # BUGFIX: this may have been misused as reader index! if r.s[r.pos] == '`': inc(r.pos) - result.offset = decodeInt(r) + result.offset = decodeVInt(r.s, r.pos) else: result.offset = - 1 decodeLoc(r, result.loc, result.info) result.annex = decodeLib(r, info) -proc decodeInt(r: PRodReader): int = - # base 190 numbers - var i = r.pos - var sign = - 1 - assert(r.s[i] in {'a'..'z', 'A'..'Z', '0'..'9', '-', '\x80'..'\xFF'}) - if r.s[i] == '-': - inc(i) - sign = 1 - result = 0 - while true: - case r.s[i] - of '0'..'9': result = result * 190 - (ord(r.s[i]) - ord('0')) - of 'a'..'z': result = result * 190 - (ord(r.s[i]) - ord('a') + 10) - of 'A'..'Z': result = result * 190 - (ord(r.s[i]) - ord('A') + 36) - of '\x80'..'\xFF': result = result * 190 - (ord(r.s[i]) - 128 + 62) - else: break - inc(i) - result = result * sign - r.pos = i - -proc decodeBInt(r: PRodReader): biggestInt = - var i = r.pos - var sign: biggestInt = - 1 - assert(r.s[i] in {'a'..'z', 'A'..'Z', '0'..'9', '-', '\x80'..'\xFF'}) - if r.s[i] == '-': - inc(i) - sign = 1 - result = 0 - while true: - case r.s[i] - of '0'..'9': result = result * 190 - (ord(r.s[i]) - ord('0')) - of 'a'..'z': result = result * 190 - (ord(r.s[i]) - ord('a') + 10) - of 'A'..'Z': result = result * 190 - (ord(r.s[i]) - ord('A') + 36) - of '\x80'..'\xFF': result = result * 190 - (ord(r.s[i]) - 128 + 62) - else: break - inc(i) - result = result * sign - r.pos = i - -proc hexChar(c: char, xi: var int) = - case c - of '0'..'9': xi = (xi shl 4) or (ord(c) - ord('0')) - of 'a'..'f': xi = (xi shl 4) or (ord(c) - ord('a') + 10) - of 'A'..'F': xi = (xi shl 4) or (ord(c) - ord('A') + 10) - else: nil - -proc decode(r: PRodReader): string = - var i = r.pos - result = "" - while true: - case r.s[i] - of '\\': - inc(i, 3) - var xi = 0 - hexChar(r.s[i-2], xi) - hexChar(r.s[i-1], xi) - add(result, chr(xi)) - of 'a'..'z', 'A'..'Z', '0'..'9', '_': - add(result, r.s[i]) - inc(i) - else: break - r.pos = i - proc skipSection(r: PRodReader) = if r.s[r.pos] == ':': while r.s[r.pos] > '\x0A': inc(r.pos) @@ -514,9 +417,9 @@ proc processInterf(r: PRodReader, module: PSym) = if r.interfIdx == 0: InternalError("processInterf") r.pos = r.interfIdx while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'): - var w = decode(r) + var w = decodeStr(r.s, r.pos) inc(r.pos) - var key = decodeInt(r) + var key = decodeVInt(r.s, r.pos) inc(r.pos) # #10 var s = newStub(r, w, key) s.owner = module @@ -527,9 +430,9 @@ proc processCompilerProcs(r: PRodReader, module: PSym) = if r.compilerProcsIdx == 0: InternalError("processCompilerProcs") r.pos = r.compilerProcsIdx while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'): - var w = decode(r) + var w = decodeStr(r.s, r.pos) inc(r.pos) - var key = decodeInt(r) + var key = decodeVInt(r.s, r.pos) inc(r.pos) # #10 var s = PSym(IdTableGet(r.syms, key)) if s == nil: @@ -543,11 +446,11 @@ proc processIndex(r: PRodReader, idx: var TIndex) = inc(r.pos, 2) # skip "(\10" inc(r.line) while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'): - tmp = decodeInt(r) + tmp = decodeVInt(r.s, r.pos) if r.s[r.pos] == ' ': inc(r.pos) key = idx.lastIdxKey + tmp - val = decodeInt(r) + idx.lastIdxVal + val = decodeVInt(r.s, r.pos) + idx.lastIdxVal else: key = idx.lastIdxKey + 1 val = tmp + idx.lastIdxVal @@ -571,20 +474,20 @@ proc processRodFile(r: PRodReader, crc: TCrc32) = case section of "CRC": inc(r.pos) # skip ':' - if int(crc) != decodeInt(r): r.reason = rrCrcChange + if int(crc) != decodeVInt(r.s, r.pos): r.reason = rrCrcChange of "ID": inc(r.pos) # skip ':' - r.moduleID = decodeInt(r) + r.moduleID = decodeVInt(r.s, r.pos) setID(r.moduleID) of "OPTIONS": inc(r.pos) # skip ':' - r.options = cast[TOptions](int32(decodeInt(r))) + r.options = cast[TOptions](int32(decodeVInt(r.s, r.pos))) if options.gOptions != r.options: r.reason = rrOptions of "DEFINES": inc(r.pos) # skip ':' d = 0 while r.s[r.pos] > '\x0A': - w = decode(r) + w = decodeStr(r.s, r.pos) inc(d) if not condsyms.isDefined(getIdent(w)): r.reason = rrDefines #MessageOut('not defined, but should: ' + w); @@ -596,7 +499,7 @@ proc processRodFile(r: PRodReader, crc: TCrc32) = L = 0 while r.s[r.pos] > '\x0A' and r.s[r.pos] != ')': setlen(r.files, L + 1) - r.files[L] = decode(r) + r.files[L] = decodeStr(r.s, r.pos) inc(r.pos) # skip #10 inc(r.line) inc(L) @@ -605,9 +508,9 @@ proc processRodFile(r: PRodReader, crc: TCrc32) = inc(r.pos, 2) # skip "(\10" inc(r.line) while r.s[r.pos] > '\x0A' and r.s[r.pos] != ')': - w = r.files[decodeInt(r)] + w = r.files[decodeVInt(r.s, r.pos)] inc(r.pos) # skip ' ' - inclCrc = decodeInt(r) + inclCrc = decodeVInt(r.s, r.pos) if r.reason == rrNone: if not ExistsFile(w) or (inclCrc != int(crcFromFile(w))): r.reason = rrInclDeps @@ -620,7 +523,7 @@ proc processRodFile(r: PRodReader, crc: TCrc32) = L = 0 while r.s[r.pos] > '\x0A': setlen(r.modDeps, L + 1) - r.modDeps[L] = r.files[decodeInt(r)] + r.modDeps[L] = r.files[decodeVInt(r.s, r.pos)] inc(L) if r.s[r.pos] == ' ': inc(r.pos) of "INTERF": @@ -723,8 +626,9 @@ proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym = if d == invalidKey: var moduleID = IiTableGet(r.imports.tab, id) if moduleID < 0: - InternalError(info, - "missing from both indexes: +" & ropeToStr(encodeInt(id))) + var x = "" + encodeVInt(id, x) + InternalError(info, "missing from both indexes: +" & x) # find the reader with the correct moduleID: for i in countup(0, high(gMods)): var rd = gMods[i].rd @@ -734,10 +638,11 @@ proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym = if d != invalidKey: result = decodeSymSafePos(rd, d, info) break - else: - InternalError(info, "rrGetSym: no reader found: +" & - ropeToStr(encodeInt(id))) - else: + else: + var x = "" + encodeVInt(id, x) + InternalError(info, "rrGetSym: no reader found: +" & x) + else: #if IiTableGet(rd.index.tab, id) <> invalidKey then # XXX expensive check! #InternalError(info, @@ -753,7 +658,7 @@ proc loadInitSection(r: PRodReader): PNode = r.pos = r.initIdx result = newNode(nkStmtList) while r.s[r.pos] > '\x0A' and r.s[r.pos] != ')': - var d = decodeInt(r) + var d = decodeVInt(r.s, r.pos) inc(r.pos) # #10 var p = r.pos r.pos = d + r.dataIdx @@ -767,7 +672,7 @@ proc loadConverters(r: PRodReader) = InternalError("importConverters") r.pos = r.convertersIdx while (r.s[r.pos] > '\x0A'): - var d = decodeInt(r) + var d = decodeVInt(r.s, r.pos) discard rrGetSym(r, d, UnknownLineInfo()) if r.s[r.pos] == ' ': inc(r.pos) @@ -818,9 +723,11 @@ proc checkDep(filename: string): TReasonForRecompile = gMods[idx].reason = result # now we know better proc handleSymbolFile(module: PSym, filename: string): PRodReader = - if not (optSymbolFiles in gGlobalOptions): + if optSymbolFiles notin gGlobalOptions: module.id = getID() return nil + idgen.loadMaxIds(options.projectPath / options.projectName) + discard checkDep(filename) var idx = getModuleIdx(filename) if gMods[idx].reason == rrEmpty: InternalError("handleSymbolFile") diff --git a/compiler/rodutils.nim b/compiler/rodutils.nim index dad5d679f..037bf450d 100755 --- a/compiler/rodutils.nim +++ b/compiler/rodutils.nim @@ -7,8 +7,8 @@ # distribution, for details about the copyright. # -## Utilities for the compiler. Aim is to reduce the coupling between -## the compiler and the evolving stdlib. +## Serialization utilities for the compiler. +import strutils proc c_sprintf(buf, frmt: cstring) {.importc: "sprintf", nodecl, varargs.} @@ -25,3 +25,97 @@ proc ToStrMaxPrecision*(f: BiggestFloat): string = c_sprintf(buf, "%#.16e", f) result = $buf +proc encodeStr*(s: string, result: var string) = + for i in countup(0, len(s) - 1): + case s[i] + of 'a'..'z', 'A'..'Z', '0'..'9', '_': add(result, s[i]) + else: add(result, '\\' & toHex(ord(s[i]), 2)) + +proc hexChar(c: char, xi: var int) = + case c + of '0'..'9': xi = (xi shl 4) or (ord(c) - ord('0')) + of 'a'..'f': xi = (xi shl 4) or (ord(c) - ord('a') + 10) + of 'A'..'F': xi = (xi shl 4) or (ord(c) - ord('A') + 10) + else: nil + +proc decodeStr*(s: cstring, pos: var int): string = + var i = pos + result = "" + while true: + case s[i] + of '\\': + inc(i, 3) + var xi = 0 + hexChar(s[i-2], xi) + hexChar(s[i-1], xi) + add(result, chr(xi)) + of 'a'..'z', 'A'..'Z', '0'..'9', '_': + add(result, s[i]) + inc(i) + else: break + pos = i + +const + chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + +template encodeIntImpl(self: expr) = + var d: char + var v = x + var rem = v mod 190 + if rem < 0: + add(result, '-') + v = - (v div 190) + rem = - rem + else: + v = v div 190 + var idx = int(rem) + if idx < 62: d = chars[idx] + else: d = chr(idx - 62 + 128) + if v != 0: self(v, result) + add(result, d) + +proc encodeVBiggestInt*(x: BiggestInt, result: var string) = + ## encode a biggest int as a variable length base 190 int. + encodeIntImpl(encodeVBiggestInt) + +proc encodeVInt*(x: int, result: var string) = + ## encode an int as a variable length base 190 int. + encodeIntImpl(encodeVInt) + +template decodeIntImpl() = + var i = pos + var sign = - 1 + assert(s[i] in {'a'..'z', 'A'..'Z', '0'..'9', '-', '\x80'..'\xFF'}) + if s[i] == '-': + inc(i) + sign = 1 + result = 0 + while true: + case s[i] + of '0'..'9': result = result * 190 - (ord(s[i]) - ord('0')) + of 'a'..'z': result = result * 190 - (ord(s[i]) - ord('a') + 10) + of 'A'..'Z': result = result * 190 - (ord(s[i]) - ord('A') + 36) + of '\x80'..'\xFF': result = result * 190 - (ord(s[i]) - 128 + 62) + else: break + inc(i) + result = result * sign + pos = i + +proc decodeVInt*(s: cstring, pos: var int): int = + decodeIntImpl() + +proc decodeVBiggestInt*(s: cstring, pos: var int): biggestInt = + decodeIntImpl() + +iterator decodeVIntArray*(s: cstring): int = + var i = 0 + while s[i] != '\0': + yield decodeVInt(s, i) + if s[i] == ' ': inc i + +iterator decodeStrArray*(s: cstring): string = + var i = 0 + while s[i] != '\0': + yield decodeStr(s, i) + if s[i] == ' ': inc i + diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim index 0bc73d6f1..247b92ebe 100755 --- a/compiler/rodwrite.nim +++ b/compiler/rodwrite.nim @@ -1,7 +1,7 @@ # # # The Nimrod Compiler -# (c) Copyright 2008 Andreas Rumpf +# (c) Copyright 2011 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -13,29 +13,29 @@ import intsets, os, options, strutils, nversion, ast, astalgo, msgs, platform, - condsyms, ropes, idents, crc, rodread, passes, importer + condsyms, ropes, idents, crc, rodread, passes, importer, idgen, rodutils proc rodwritePass*(): TPass # implementation type TRodWriter = object of TPassContext - module*: PSym - crc*: TCrc32 - options*: TOptions - defines*: PRope - inclDeps*: PRope - modDeps*: PRope - interf*: PRope - compilerProcs*: PRope - index*, imports*: TIndex - converters*: PRope - init*: PRope - data*: PRope - filename*: string - sstack*: TSymSeq # a stack of symbols to process - tstack*: TTypeSeq # a stack of types to process - files*: TStringSeq + module: PSym + crc: TCrc32 + options: TOptions + defines: string + inclDeps: string + modDeps: string + interf: string + compilerProcs: string + index, imports: TIndex + converters: string + init: string + data: string + filename: string + sstack: TSymSeq # a stack of symbols to process + tstack: TTypeSeq # a stack of types to process + files: TStringSeq PRodWriter = ref TRodWriter @@ -45,19 +45,17 @@ proc addInclDep(w: PRodWriter, dep: string) proc addInterfaceSym(w: PRodWriter, s: PSym) proc addStmt(w: PRodWriter, n: PNode) proc writeRod(w: PRodWriter) -proc encodeStr(w: PRodWriter, s: string): PRope = - result = encode(s) proc processStacks(w: PRodWriter) -proc getDefines(): PRope = +proc getDefines(): string = var it: TTabIter var s = InitTabIter(it, gSymbols) - result = nil + result = "" while s != nil: if s.position == 1: - if result != nil: app(result, " ") - app(result, s.name.s) + if result.len != 0: add(result, " ") + add(result, s.name.s) s = nextIter(it, gSymbols) proc fileIdx(w: PRodWriter, filename: string): int = @@ -74,205 +72,279 @@ proc newRodWriter(modfilename: string, crc: TCrc32, module: PSym): PRodWriter = result.tstack = @[] InitIITable(result.index.tab) InitIITable(result.imports.tab) + result.index.r = "" + result.imports.r = "" result.filename = modfilename result.crc = crc result.module = module result.defines = getDefines() result.options = options.gOptions result.files = @[] - + result.inclDeps = "" + result.modDeps = "" + result.interf = newStringOfCap(2_000) + result.compilerProcs = "" + result.converters = "" + result.init = "" + result.data = newStringOfCap(12_000) + proc addModDep(w: PRodWriter, dep: string) = - if w.modDeps != nil: app(w.modDeps, " ") - app(w.modDeps, encodeInt(fileIdx(w, dep))) + if w.modDeps.len != 0: add(w.modDeps, ' ') + encodeVInt(fileIdx(w, dep), w.modDeps) const rodNL = "\x0A" proc addInclDep(w: PRodWriter, dep: string) = - app(w.inclDeps, encodeInt(fileIdx(w, dep))) - app(w.inclDeps, " ") - app(w.inclDeps, encodeInt(crcFromFile(dep))) - app(w.inclDeps, rodNL) + encodeVInt(fileIdx(w, dep), w.inclDeps) + add(w.inclDeps, " ") + encodeVInt(crcFromFile(dep), w.inclDeps) + add(w.inclDeps, rodNL) -proc pushType(w: PRodWriter, t: PType) = +proc pushType(w: PRodWriter, t: PType) = # check so that the stack does not grow too large: - if IiTableGet(w.index.tab, t.id) == invalidKey: - var L = len(w.tstack) - setlen(w.tstack, L + 1) - w.tstack[L] = t + if IiTableGet(w.index.tab, t.id) == invalidKey: + w.tstack.add(t) -proc pushSym(w: PRodWriter, s: PSym) = +proc pushSym(w: PRodWriter, s: PSym) = # check so that the stack does not grow too large: - if IiTableGet(w.index.tab, s.id) == invalidKey: - var L = len(w.sstack) - setlen(w.sstack, L + 1) - w.sstack[L] = s + if IiTableGet(w.index.tab, s.id) == invalidKey: + w.sstack.add(s) -proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode): PRope = +proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode, + result: var string) = if n == nil: # nil nodes have to be stored too: - return toRope("()") - result = toRope("(") - app(result, encodeInt(ord(n.kind))) + result.add("()") + return + result.add('(') + encodeVInt(ord(n.kind), result) # we do not write comments for now # Line information takes easily 20% or more of the filesize! Therefore we # omit line information if it is the same as the father's line information: if finfo.fileIndex != n.info.fileIndex: - appf(result, "?$1,$2,$3", [encodeInt(n.info.col), encodeInt(n.info.line), - encodeInt(fileIdx(w, toFilename(n.info)))]) + result.add('?') + encodeVInt(n.info.col, result) + result.add(',') + encodeVInt(n.info.line, result) + result.add(',') + encodeVInt(fileIdx(w, toFilename(n.info)), result) elif finfo.line != n.info.line: - appf(result, "?$1,$2", [encodeInt(n.info.col), encodeInt(n.info.line)]) + result.add('?') + encodeVInt(n.info.col, result) + result.add(',') + encodeVInt(n.info.line, result) elif finfo.col != n.info.col: - appf(result, "?$1", [encodeInt(n.info.col)]) + result.add('?') + encodeVInt(n.info.col, result) # No need to output the file index, as this is the serialization of one # file. var f = n.flags * PersistentNodeFlags - if f != {}: appf(result, "$$$1", [encodeInt(cast[int32](f))]) - if n.typ != nil: - appf(result, "^$1", [encodeInt(n.typ.id)]) + if f != {}: + result.add('$') + encodeVInt(cast[int32](f), result) + if n.typ != nil: + result.add('^') + encodeVInt(n.typ.id, result) pushType(w, n.typ) case n.kind of nkCharLit..nkInt64Lit: - if n.intVal != 0: appf(result, "!$1", [encodeInt(n.intVal)]) + if n.intVal != 0: + result.add('!') + encodeVBiggestInt(n.intVal, result) of nkFloatLit..nkFloat64Lit: - if n.floatVal != 0.0: appf(result, "!$1", [encodeStr(w, $n.floatVal)]) - of nkStrLit..nkTripleStrLit: - if n.strVal != "": appf(result, "!$1", [encodeStr(w, n.strVal)]) - of nkIdent: - appf(result, "!$1", [encodeStr(w, n.ident.s)]) - of nkSym: - appf(result, "!$1", [encodeInt(n.sym.id)]) + if n.floatVal != 0.0: + result.add('!') + encodeStr($n.floatVal, result) + of nkStrLit..nkTripleStrLit: + if n.strVal != "": + result.add('!') + encodeStr(n.strVal, result) + of nkIdent: + result.add('!') + encodeStr(n.ident.s, result) + of nkSym: + result.add('!') + encodeVInt(n.sym.id, result) pushSym(w, n.sym) - else: + else: for i in countup(0, sonsLen(n) - 1): - app(result, encodeNode(w, n.info, n.sons[i])) - app(result, ")") - -proc encodeLoc(w: PRodWriter, loc: TLoc): PRope = - result = nil - if loc.k != low(loc.k): app(result, encodeInt(ord(loc.k))) - if loc.s != low(loc.s): appf(result, "*$1", [encodeInt(ord(loc.s))]) - if loc.flags != {}: appf(result, "$$$1", [encodeInt(cast[int32](loc.flags))]) - if loc.t != nil: - appf(result, "^$1", [encodeInt(loc.t.id)]) + encodeNode(w, n.info, n.sons[i], result) + add(result, ')') + +proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) = + var oldLen = result.len + result.add('<') + if loc.k != low(loc.k): encodeVInt(ord(loc.k), result) + if loc.s != low(loc.s): + add(result, '*') + encodeVInt(ord(loc.s), result) + if loc.flags != {}: + add(result, '$') + encodeVInt(cast[int32](loc.flags), result) + if loc.t != nil: + add(result, '^') + encodeVInt(cast[int32](loc.t.id), result) pushType(w, loc.t) - if loc.r != nil: appf(result, "!$1", [encodeStr(w, ropeToStr(loc.r))]) - if loc.a != 0: appf(result, "?$1", [encodeInt(loc.a)]) - if result != nil: result = ropef("<$1>", [result]) + if loc.r != nil: + add(result, '!') + encodeStr(ropeToStr(loc.r), result) + if loc.a != 0: + add(result, '?') + encodeVInt(loc.a, result) + if oldlen + 1 == result.len: + # no data was necessary, so remove the '<' again: + setLen(result, oldLen) + else: + add(result, '>') -proc encodeType(w: PRodWriter, t: PType): PRope = +proc encodeType(w: PRodWriter, t: PType, result: var string) = if t == nil: # nil nodes have to be stored too: - return toRope("[]") - result = nil + result.add("[]") + return + # we need no surrounding [] here because the type is in a line of its own if t.kind == tyForward: InternalError("encodeType: tyForward") - app(result, encodeInt(ord(t.kind))) - appf(result, "+$1", [encodeInt(t.id)]) - if t.n != nil: app(result, encodeNode(w, UnknownLineInfo(), t.n)) - if t.flags != {}: appf(result, "$$$1", [encodeInt(cast[int32](t.flags))]) + encodeVInt(ord(t.kind), result) + add(result, '+') + encodeVInt(t.id, result) + if t.n != nil: + encodeNode(w, UnknownLineInfo(), t.n, result) + if t.flags != {}: + add(result, '$') + encodeVInt(cast[int32](t.flags), result) if t.callConv != low(t.callConv): - appf(result, "?$1", [encodeInt(ord(t.callConv))]) + add(result, '?') + encodeVInt(ord(t.callConv), result) if t.owner != nil: - appf(result, "*$1", [encodeInt(t.owner.id)]) + add(result, '*') + encodeVInt(t.owner.id, result) pushSym(w, t.owner) if t.sym != nil: - appf(result, "&$1", [encodeInt(t.sym.id)]) + add(result, '&') + encodeVInt(t.sym.id, result) pushSym(w, t.sym) - if t.size != - 1: appf(result, "/$1", [encodeInt(t.size)]) - if t.align != 2: appf(result, "=$1", [encodeInt(t.align)]) - if t.containerID != 0: appf(result, "@$1", [encodeInt(t.containerID)]) - app(result, encodeLoc(w, t.loc)) + if t.size != - 1: + add(result, '/') + encodeVBiggestInt(t.size, result) + if t.align != 2: + add(result, '=') + encodeVInt(t.align, result) + if t.containerID != 0: + add(result, '@') + encodeVInt(t.containerID, result) + encodeLoc(w, t.loc, result) for i in countup(0, sonsLen(t) - 1): if t.sons[i] == nil: - app(result, "^()") + add(result, "^()") else: - appf(result, "^$1", [encodeInt(t.sons[i].id)]) + add(result, '^') + encodeVInt(t.sons[i].id, result) pushType(w, t.sons[i]) -proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo): PRope = - result = nil - appf(result, "|$1", [encodeInt(ord(lib.kind))]) - appf(result, "|$1", [encodeStr(w, ropeToStr(lib.name))]) - appf(result, "|$1", [encodeNode(w, info, lib.path)]) - -proc encodeSym(w: PRodWriter, s: PSym): PRope = - var - codeAst: PNode - col, line: PRope - codeAst = nil - if s == nil: +proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) = + add(result, '|') + encodeVInt(ord(lib.kind), result) + add(result, '|') + encodeStr(ropeToStr(lib.name), result) + add(result, '|') + encodeNode(w, info, lib.path, result) + +proc encodeSym(w: PRodWriter, s: PSym, result: var string) = + if s == nil: # nil nodes have to be stored too: - return toRope("{}") - result = nil - app(result, encodeInt(ord(s.kind))) - appf(result, "+$1", [encodeInt(s.id)]) - appf(result, "&$1", [encodeStr(w, s.name.s)]) - if s.typ != nil: - appf(result, "^$1", [encodeInt(s.typ.id)]) + result.add("{}") + return + # we need no surrounding {} here because the symbol is in a line of its own + encodeVInt(ord(s.kind), result) + result.add('+') + encodeVInt(s.id, result) + result.add('&') + encodeStr(s.name.s, result) + if s.typ != nil: + result.add('^') + encodeVInt(s.typ.id, result) pushType(w, s.typ) - if s.info.col == int16(- 1): col = nil - else: col = encodeInt(s.info.col) - if s.info.line == int16(- 1): line = nil - else: line = encodeInt(s.info.line) - appf(result, "?$1,$2,$3", - [col, line, encodeInt(fileIdx(w, toFilename(s.info)))]) - if s.owner != nil: - appf(result, "*$1", [encodeInt(s.owner.id)]) + result.add('?') + if s.info.col != -1'i16: encodeVInt(s.info.col, result) + result.add(',') + if s.info.line != -1'i16: encodeVInt(s.info.line, result) + result.add(',') + encodeVInt(fileIdx(w, toFilename(s.info)), result) + if s.owner != nil: + result.add('*') + encodeVInt(s.owner.id, result) pushSym(w, s.owner) - if s.flags != {}: appf(result, "$$$1", [encodeInt(cast[int32](s.flags))]) - if s.magic != mNone: appf(result, "@$1", [encodeInt(ord(s.magic))]) - if (s.ast != nil): - if not astNeeded(s): + if s.flags != {}: + result.add('$') + encodeVInt(cast[int32](s.flags), result) + if s.magic != mNone: + result.add('@') + encodeVInt(ord(s.magic), result) + if s.ast != nil: + var codeAst: PNode = nil + if not astNeeded(s): codeAst = s.ast.sons[codePos] + # ugly hack to not store the AST: s.ast.sons[codePos] = nil - app(result, encodeNode(w, s.info, s.ast)) - if codeAst != nil: + encodeNode(w, s.info, s.ast, result) + if codeAst != nil: + # resore the AST: s.ast.sons[codePos] = codeAst if s.options != w.options: - appf(result, "!$1", [encodeInt(cast[int32](s.options))]) - if s.position != 0: appf(result, "%$1", [encodeInt(s.position)]) - if s.offset != - 1: appf(result, "`$1", [encodeInt(s.offset)]) - app(result, encodeLoc(w, s.loc)) - if s.annex != nil: app(result, encodeLib(w, s.annex, s.info)) + result.add('!') + encodeVInt(cast[int32](s.options), result) + if s.position != 0: + result.add('%') + encodeVInt(s.position, result) + if s.offset != - 1: + result.add('`') + encodeVInt(s.offset, result) + encodeLoc(w, s.loc, result) + if s.annex != nil: encodeLib(w, s.annex, s.info, result) -proc addToIndex(w: var TIndex, key, val: int) = - if key - w.lastIdxKey == 1: +proc addToIndex(w: var TIndex, key, val: int) = + if key - w.lastIdxKey == 1: # we do not store a key-diff of 1 to safe space - app(w.r, encodeInt(val - w.lastIdxVal)) - app(w.r, rodNL) - else: - appf(w.r, "$1 $2" & rodNL, - [encodeInt(key - w.lastIdxKey), encodeInt(val - w.lastIdxVal)]) + encodeVInt(val - w.lastIdxVal, w.r) + else: + encodeVInt(key - w.lastIdxKey, w.r) + add(w.r, ' ') + encodeVInt(val - w.lastIdxVal, w.r) + add(w.r, rodNL) w.lastIdxKey = key w.lastIdxVal = val IiTablePut(w.tab, key, val) var debugWritten: TIntSet -proc symStack(w: PRodWriter) = - var - i, L: int - s, m: PSym - i = 0 +proc symStack(w: PRodWriter) = + var i = 0 while i < len(w.sstack): - s = w.sstack[i] + var s = w.sstack[i] if IiTableGet(w.index.tab, s.id) == invalidKey: - m = getModule(s) + var m = getModule(s) if m == nil: InternalError("symStack: module nil: " & s.name.s) if (m.id == w.module.id) or (sfFromGeneric in s.flags): # put definition in here - L = ropeLen(w.data) - addToIndex(w.index, s.id, L) #intSetIncl(debugWritten, s.id); - app(w.data, encodeSym(w, s)) - app(w.data, rodNL) + var L = w.data.len + addToIndex(w.index, s.id, L) + #intSetIncl(debugWritten, s.id) + encodeSym(w, s, w.data) + add(w.data, rodNL) if sfExported in s.flags: - appf(w.interf, "$1 $2" & rodNL, [encode(s.name.s), encodeInt(s.id)]) - if sfCompilerProc in s.flags: - appf(w.compilerProcs, "$1 $2" & rodNL, - [encode(s.name.s), encodeInt(s.id)]) + encodeStr(s.name.s, w.interf) + add(w.interf, ' ') + encodeVInt(s.id, w.interf) + add(w.interf, rodNL) + if sfCompilerProc in s.flags: + encodeStr(s.name.s, w.compilerProcs) + add(w.compilerProcs, ' ') + encodeVInt(s.id, w.compilerProcs) + add(w.compilerProcs, rodNL) if s.kind == skConverter: - if w.converters != nil: app(w.converters, " ") - app(w.converters, encodeInt(s.id)) + if w.converters.len != 0: add(w.converters, ' ') + encodeVInt(s.id, w.converters) elif IiTableGet(w.imports.tab, s.id) == invalidKey: addToIndex(w.imports, s.id, m.id) #if not Contains(debugWritten, s.id): # MessageOut(w.filename); @@ -287,10 +359,10 @@ proc typeStack(w: PRodWriter) = var i = 0 while i < len(w.tstack): if IiTableGet(w.index.tab, w.tstack[i].id) == invalidKey: - var L = ropeLen(w.data) + var L = w.data.len addToIndex(w.index, w.tstack[i].id, L) - app(w.data, encodeType(w, w.tstack[i])) - app(w.data, rodNL) + encodeType(w, w.tstack[i], w.data) + add(w.data, rodNL) inc(i) setlen(w.tstack, 0) @@ -309,66 +381,88 @@ proc addInterfaceSym(w: PRodWriter, s: PSym) = rawAddInterfaceSym(w, s) proc addStmt(w: PRodWriter, n: PNode) = - app(w.init, encodeInt(ropeLen(w.data))) - app(w.init, rodNL) - app(w.data, encodeNode(w, UnknownLineInfo(), n)) - app(w.data, rodNL) + encodeVInt(w.data.len, w.init) + add(w.init, rodNL) + encodeNode(w, UnknownLineInfo(), n, w.data) + add(w.data, rodNL) processStacks(w) proc writeRod(w: PRodWriter) = - processStacks(w) # write header: - var content = toRope("NIM:") - app(content, toRope(FileVersion)) - app(content, rodNL) - app(content, toRope("ID:")) - app(content, encodeInt(w.module.id)) - app(content, rodNL) - app(content, toRope("CRC:")) - app(content, encodeInt(w.crc)) - app(content, rodNL) - app(content, toRope("OPTIONS:")) - app(content, encodeInt(cast[int32](w.options))) - app(content, rodNL) - app(content, toRope("DEFINES:")) - app(content, w.defines) - app(content, rodNL) - app(content, toRope("FILES(" & rodNL)) + processStacks(w) + var f: TFile + if not open(f, completeGeneratedFilePath(changeFileExt(w.filename, "rod")), + fmWrite): + return + # write header: + f.write("NIM:") + f.write(FileVersion) + f.write(rodNL) + var id = "ID:" + encodeVInt(w.module.id, id) + f.write(id) + f.write(rodNL) + + var crc = "CRC:" + encodeVInt(w.crc, crc) + f.write(crc) + f.write(rodNL) + + var options = "OPTIONS:" + encodeVInt(cast[int32](w.options), options) + f.write(options) + f.write(rodNL) + + f.write("DEFINES:") + f.write(w.defines) + f.write(rodNL) + + var files = "FILES(" & rodNL for i in countup(0, high(w.files)): - app(content, encode(w.files[i])) - app(content, rodNL) - app(content, toRope(')' & rodNL)) - app(content, toRope("INCLUDES(" & rodNL)) - app(content, w.inclDeps) - app(content, toRope(')' & rodNL)) - app(content, toRope("DEPS:")) - app(content, w.modDeps) - app(content, rodNL) - app(content, toRope("INTERF(" & rodNL)) - app(content, w.interf) - app(content, toRope(')' & rodNL)) - app(content, toRope("COMPILERPROCS(" & rodNL)) - app(content, w.compilerProcs) - app(content, toRope(')' & rodNL)) - app(content, toRope("INDEX(" & rodNL)) - app(content, w.index.r) - app(content, toRope(')' & rodNL)) - app(content, toRope("IMPORTS(" & rodNL)) - app(content, w.imports.r) - app(content, toRope(')' & rodNL)) - app(content, toRope("CONVERTERS:")) - app(content, w.converters) - app(content, toRope(rodNL)) - app(content, toRope("INIT(" & rodNL)) - app(content, w.init) - app(content, toRope(')' & rodNL)) - app(content, toRope("DATA(" & rodNL)) - app(content, w.data) - app(content, toRope(')' & rodNL)) - #MessageOut('interf ' + ToString(ropeLen(w.interf))); - #MessageOut('index ' + ToString(ropeLen(w.indexRope))); - #MessageOut('init ' + ToString(ropeLen(w.init))); - #MessageOut('data ' + ToString(ropeLen(w.data))); - writeRope(content, completeGeneratedFilePath(changeFileExt(w.filename, "rod"))) + encodeStr(w.files[i], files) + files.add(rodNL) + f.write(files) + f.write(')' & rodNL) + + f.write("INCLUDES(" & rodNL) + f.write(w.inclDeps) + f.write(')' & rodNL) + + f.write("DEPS:") + f.write(w.modDeps) + f.write(rodNL) + + f.write("INTERF(" & rodNL) + f.write(w.interf) + f.write(')' & rodNL) + + f.write("COMPILERPROCS(" & rodNL) + f.write(w.compilerProcs) + f.write(')' & rodNL) + + f.write("INDEX(" & rodNL) + f.write(w.index.r) + f.write(')' & rodNL) + + f.write("IMPORTS(" & rodNL) + f.write(w.imports.r) + f.write(')' & rodNL) + + f.write("CONVERTERS:") + f.write(w.converters) + f.write(rodNL) + + f.write("INIT(" & rodNL) + f.write(w.init) + f.write(')' & rodNL) + + f.write("DATA(" & rodNL) + f.write(w.data) + f.write(')' & rodNL) + f.close() + #MessageOut('interf ' + ToString(ropeLen(w.interf))) + #MessageOut('index ' + ToString(ropeLen(w.indexRope))) + #MessageOut('init ' + ToString(ropeLen(w.init))) + #MessageOut('data ' + ToString(ropeLen(w.data))) proc process(c: PPassContext, n: PNode): PNode = result = n @@ -438,6 +532,7 @@ proc myClose(c: PPassContext, n: PNode): PNode = var w = PRodWriter(c) writeRod(w) result = n + idgen.saveMaxIds(options.projectPath / options.projectName) proc rodwritePass(): TPass = initPass(result) @@ -446,4 +541,4 @@ proc rodwritePass(): TPass = result.close = myClose result.process = process -debugWritten= initIntSet() +debugWritten = initIntSet() diff --git a/compiler/sem.nim b/compiler/sem.nim index 7b9f7c4e1..1cb0e3b68 100755 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -14,7 +14,7 @@ import wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math, magicsys, parser, nversion, semdata, nimsets, semfold, importer, procfind, lookups, rodread, pragmas, passes, semtypinst, sigmatch, suggest, - semthreads, intsets, transf, evals + semthreads, intsets, transf, evals, idgen proc semPass*(): TPass # implementation diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 1a8182437..d98d60224 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -158,7 +158,7 @@ proc SemReturn(c: PContext, n: PNode): PNode = globalError(n.info, errXNotAllowedHere, "\'return\'") if n.sons[0].kind != nkEmpty: # transform ``return expr`` to ``result = expr; return`` - if c.p.resultSym == nil: InternalError(n.info, "semReturn") + if c.p.resultSym == nil: globalError(n.info, errNoReturnTypeDeclared) var a = newNodeI(nkAsgn, n.sons[0].info) addSon(a, newSymNode(c.p.resultSym)) addSon(a, n.sons[0]) diff --git a/compiler/treetab.nim b/compiler/treetab.nim index e8fc39be9..d13e4587f 100755 --- a/compiler/treetab.nim +++ b/compiler/treetab.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -# Implements a table from trees to trees. Does structural equavilent checking. +# Implements a table from trees to trees. Does structural equivalence checking. import hashes, ast, astalgo, types diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim index 8c2de0dc7..d09051cd4 100755 --- a/lib/impure/db_sqlite.nim +++ b/lib/impure/db_sqlite.nim @@ -118,8 +118,7 @@ proc GetValue*(db: TDbConn, query: TSqlQuery, ## of the first row. Returns "" if the dataset contains no rows. var stmt = setupQuery(db, query, args) if step(stmt) == SQLITE_ROW: - result = newString(column_bytes(stmt, 0)) - setLen(result, 0) + result = newStringOfCap(column_bytes(stmt, 0)) add(result, column_text(stmt, 0)) if finalize(stmt) != SQLITE_OK: dbError(db) else: diff --git a/todo.txt b/todo.txt index 233504fd6..5d54a6386 100755 --- a/todo.txt +++ b/todo.txt @@ -9,6 +9,7 @@ Version 0.8.14 - optional indentation for 'case' statement - document & test splicing; don't forget to test negative indexes - thread local vs. global raiseHook() +- incremental compilation (!) version 0.9.0 @@ -105,41 +106,6 @@ Low priority - timeout for locks -Super operators -=============== - -macro (pattern) [T](arg: array[T]) = - - - -Patterns --------- - -Patterns are PEGs over the Nimrod AST. Patterns consist of: - - type - TPatternKind = enum - pkAny, ## any node (.) - pkNodeClass, ## set of node kinds - pkTerminal, ## 'xyz' - pkNonTerminal, ## a - pkSequence, ## a b c - pkOrderedChoice, ## a / b / c - pkGreedyRep, ## a* - ## a+ --> (a a*) - pkOption, ## a? - pkAndPredicate, ## &a - pkNotPredicate, ## !a - pkCapture, ## {a} - pkBackRef, ## $i - pkSearch, ## @a - pkCapturedSearch, ## {@} a - pkRule, ## a <- b - pkGrammar, ## list of rules - -Choice operator requires capture. - - Version 2 ========= |