diff options
author | Araq <rumpf_a@web.de> | 2018-02-17 00:37:41 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2018-02-17 00:40:49 +0100 |
commit | 564cff729a9a945924e40e57ce5be5af79dd6497 (patch) | |
tree | d59a55ce455627215ac3d8937f4a03358328447b | |
parent | 037ce16f44315271ec3da49bc80e117e29403d20 (diff) | |
download | Nim-564cff729a9a945924e40e57ce5be5af79dd6497.tar.gz |
new symbol files: loading of ASTs and module graphs
-rw-r--r-- | compiler/rod.nim | 1 | ||||
-rw-r--r-- | compiler/rodimpl.nim | 379 |
2 files changed, 378 insertions, 2 deletions
diff --git a/compiler/rod.nim b/compiler/rod.nim index 6d34e9ea0..23c816498 100644 --- a/compiler/rod.nim +++ b/compiler/rod.nim @@ -14,6 +14,7 @@ import ast, idgen when not defined(nimSymbolfiles): template setupModuleCache* = discard template storeNode*(module: PSym; n: PNode) = discard + template loadNode*(module: PSym; index: var int): PNode = discard template getModuleId*(fullpath: string): int = getID() diff --git a/compiler/rodimpl.nim b/compiler/rodimpl.nim index aca576b23..a6f525787 100644 --- a/compiler/rodimpl.nim +++ b/compiler/rodimpl.nim @@ -9,8 +9,8 @@ ## This module implements the canonalization for the various caching mechanisms. -import strutils, os, intsets, ropes, db_sqlite, msgs, options, types, - renderer, rodutils, std / sha1 +import strutils, os, intsets, tables, ropes, db_sqlite, msgs, options, types, + renderer, rodutils, std / sha1, idents var db: DbConn @@ -367,6 +367,381 @@ proc storeNode*(module: PSym; n: PNode) = break inc i +# ---------------- decoder ----------------------------------- +type + TRodReader = object + module: PSym + #sstack: seq[(PSym, ptr PSym)] # a stack of symbols to process + #tstack: seq[(PType, ptr PType)] # a stack of types to process + + #tmarks, smarks: IntSet + syms: Table[int, PSym] ## XXX make this more efficients + types: Table[int, PType] + cache: IdentCache + + BlobReader = object + s: string + pos: int + + PRodReader = var TRodReader + +proc initRodReader(cache: IdentCache): TRodReader = + TRodReader(module: nil, + syms: initTable[int, PSym](), types: initTable[int, PType](), + cache: cache) + +var gr = initRodReader(newIdentCache()) + +using + r: PRodReader + b: var BlobReader + +proc loadSym(r; id: int, info: TLineInfo): PSym +proc loadType(r; id: int, info: TLineInfo): PType + +proc decodeLineInfo(r; b; info: var TLineInfo) = + if b.s[b.pos] == '?': + inc(b.pos) + if b.s[b.pos] == ',': info.col = -1'i16 + else: info.col = int16(decodeVInt(b.s, b.pos)) + if b.s[b.pos] == ',': + inc(b.pos) + if b.s[b.pos] == ',': info.line = -1'i16 + else: info.line = int16(decodeVInt(b.s, b.pos)) + if b.s[b.pos] == ',': + inc(b.pos) + info.fileIndex = int32(decodeVInt(b.s, b.pos)) + +proc skipNode(b) = + assert b.s[b.pos] == '(' + var par = 0 + var pos = b.pos+1 + while true: + case b.s[pos] + of ')': + if par == 0: break + dec par + of '(': inc par + else: discard + inc pos + b.pos = pos+1 # skip ')' + +proc decodeNodeLazyBody(r; b; fInfo: TLineInfo, + belongsTo: PSym): PNode = + result = nil + if b.s[b.pos] == '(': + inc(b.pos) + if b.s[b.pos] == ')': + inc(b.pos) + return # nil node + result = newNodeI(TNodeKind(decodeVInt(b.s, b.pos)), fInfo) + decodeLineInfo(r, b, result.info) + if b.s[b.pos] == '$': + inc(b.pos) + result.flags = cast[TNodeFlags](int32(decodeVInt(b.s, b.pos))) + if b.s[b.pos] == '^': + inc(b.pos) + var id = decodeVInt(b.s, b.pos) + result.typ = loadType(r, id, result.info) + case result.kind + of nkCharLit..nkUInt64Lit: + if b.s[b.pos] == '!': + inc(b.pos) + result.intVal = decodeVBiggestInt(b.s, b.pos) + of nkFloatLit..nkFloat64Lit: + if b.s[b.pos] == '!': + inc(b.pos) + var fl = decodeStr(b.s, b.pos) + result.floatVal = parseFloat(fl) + of nkStrLit..nkTripleStrLit: + if b.s[b.pos] == '!': + inc(b.pos) + result.strVal = decodeStr(b.s, b.pos) + else: + result.strVal = "" + of nkIdent: + if b.s[b.pos] == '!': + inc(b.pos) + var fl = decodeStr(b.s, b.pos) + result.ident = r.cache.getIdent(fl) + else: + internalError(result.info, "decodeNode: nkIdent") + of nkSym: + if b.s[b.pos] == '!': + inc(b.pos) + var id = decodeVInt(b.s, b.pos) + result.sym = loadSym(r, id, result.info) + else: + internalError(result.info, "decodeNode: nkSym") + else: + var i = 0 + while b.s[b.pos] != ')': + when false: + if belongsTo != nil and i == bodyPos: + addSonNilAllowed(result, nil) + belongsTo.offset = b.pos + skipNode(b) + else: + discard + addSonNilAllowed(result, decodeNodeLazyBody(r, b, result.info, nil)) + inc i + if b.s[b.pos] == ')': inc(b.pos) + else: internalError(result.info, "decodeNode: ')' missing") + else: + internalError(fInfo, "decodeNode: '(' missing " & $b.pos) + +proc decodeNode(r; b; fInfo: TLineInfo): PNode = + result = decodeNodeLazyBody(r, b, fInfo, nil) + +proc decodeLoc(r; b; loc: var TLoc, info: TLineInfo) = + if b.s[b.pos] == '<': + inc(b.pos) + if b.s[b.pos] in {'0'..'9', 'a'..'z', 'A'..'Z'}: + loc.k = TLocKind(decodeVInt(b.s, b.pos)) + else: + loc.k = low(loc.k) + if b.s[b.pos] == '*': + inc(b.pos) + loc.storage = TStorageLoc(decodeVInt(b.s, b.pos)) + else: + loc.storage = low(loc.storage) + if b.s[b.pos] == '$': + inc(b.pos) + loc.flags = cast[TLocFlags](int32(decodeVInt(b.s, b.pos))) + else: + loc.flags = {} + if b.s[b.pos] == '^': + inc(b.pos) + loc.lode = decodeNode(r, b, info) + # rrGetType(b, decodeVInt(b.s, b.pos), info) + else: + loc.lode = nil + if b.s[b.pos] == '!': + inc(b.pos) + loc.r = rope(decodeStr(b.s, b.pos)) + else: + loc.r = nil + if b.s[b.pos] == '>': inc(b.pos) + else: internalError(info, "decodeLoc " & b.s[b.pos]) + +proc loadBlob(query: SqlQuery; id: int): BlobReader = + let blob = db.getValue(query, id) + if blob.len == 0: + internalError("symbolfiles: cannot find ID " & $ id) + result = BlobReader(pos: 0) + shallowCopy(result.s, blob) + +proc loadType(r; id: int; info: TLineInfo): PType = + result = r.types.getOrDefault(id) + if result != nil: return result + var b = loadBlob(sql"select data from types where nimid = ?", id) + + if b.s[b.pos] == '[': + inc(b.pos) + if b.s[b.pos] == ']': + inc(b.pos) + return # nil type + new(result) + result.kind = TTypeKind(decodeVInt(b.s, b.pos)) + if b.s[b.pos] == '+': + inc(b.pos) + result.id = decodeVInt(b.s, b.pos) + setId(result.id) + #if debugIds: registerID(result) + else: + internalError(info, "decodeType: no id") + # here this also avoids endless recursion for recursive type + r.types[result.id] = result + if b.s[b.pos] == '(': result.n = decodeNode(r, b, unknownLineInfo()) + if b.s[b.pos] == '$': + inc(b.pos) + result.flags = cast[TTypeFlags](int32(decodeVInt(b.s, b.pos))) + if b.s[b.pos] == '?': + inc(b.pos) + result.callConv = TCallingConvention(decodeVInt(b.s, b.pos)) + if b.s[b.pos] == '*': + inc(b.pos) + result.owner = loadSym(r, decodeVInt(b.s, b.pos), info) + if b.s[b.pos] == '&': + inc(b.pos) + result.sym = loadSym(r, decodeVInt(b.s, b.pos), info) + if b.s[b.pos] == '/': + inc(b.pos) + result.size = decodeVInt(b.s, b.pos) + else: + result.size = - 1 + if b.s[b.pos] == '=': + inc(b.pos) + result.align = decodeVInt(b.s, b.pos).int16 + else: + result.align = 2 + + if b.s[b.pos] == '\14': + inc(b.pos) + result.lockLevel = decodeVInt(b.s, b.pos).TLockLevel + else: + result.lockLevel = UnspecifiedLockLevel + + if b.s[b.pos] == '\15': + inc(b.pos) + result.destructor = loadSym(r, decodeVInt(b.s, b.pos), info) + if b.s[b.pos] == '\16': + inc(b.pos) + result.deepCopy = loadSym(r, decodeVInt(b.s, b.pos), info) + if b.s[b.pos] == '\17': + inc(b.pos) + result.assignment = loadSym(r, decodeVInt(b.s, b.pos), info) + if b.s[b.pos] == '\18': + inc(b.pos) + result.sink = loadSym(r, decodeVInt(b.s, b.pos), info) + while b.s[b.pos] == '\19': + inc(b.pos) + let x = decodeVInt(b.s, b.pos) + doAssert b.s[b.pos] == '\20' + inc(b.pos) + let y = loadSym(r, decodeVInt(b.s, b.pos), info) + result.methods.safeAdd((x, y)) + decodeLoc(r, b, result.loc, info) + while b.s[b.pos] == '^': + inc(b.pos) + if b.s[b.pos] == '(': + inc(b.pos) + if b.s[b.pos] == ')': inc(b.pos) + else: internalError(info, "decodeType ^(" & b.s[b.pos]) + rawAddSon(result, nil) + else: + var d = decodeVInt(b.s, b.pos) + rawAddSon(result, loadType(r, d, info)) + +proc decodeLib(r; b; info: TLineInfo): PLib = + result = nil + if b.s[b.pos] == '|': + new(result) + inc(b.pos) + result.kind = TLibKind(decodeVInt(b.s, b.pos)) + if b.s[b.pos] != '|': internalError("decodeLib: 1") + inc(b.pos) + result.name = rope(decodeStr(b.s, b.pos)) + if b.s[b.pos] != '|': internalError("decodeLib: 2") + inc(b.pos) + result.path = decodeNode(r, b, info) + +proc decodeInstantiations(r; b; info: TLineInfo; + s: var seq[PInstantiation]) = + while b.s[b.pos] == '\15': + inc(b.pos) + var ii: PInstantiation + new ii + ii.sym = loadSym(r, decodeVInt(b.s, b.pos), info) + ii.concreteTypes = @[] + while b.s[b.pos] == '\17': + inc(b.pos) + ii.concreteTypes.add loadType(r, decodeVInt(b.s, b.pos), info) + if b.s[b.pos] == '\20': + inc(b.pos) + ii.compilesId = decodeVInt(b.s, b.pos) + s.safeAdd ii + +proc loadSym(r; id: int; info: TLineInfo): PSym = + var + id: int + ident: PIdent + result = r.syms.getOrDefault(id) + if result != nil: return result + var b = loadBlob(sql"select data from syms where nimid = ?", id) + if b.s[b.pos] == '{': + inc(b.pos) + if b.s[b.pos] == '}': + inc(b.pos) + return # nil sym + var k = TSymKind(decodeVInt(b.s, b.pos)) + if b.s[b.pos] == '+': + inc(b.pos) + id = decodeVInt(b.s, b.pos) + setId(id) + else: + internalError(info, "decodeSym: no id") + if b.s[b.pos] == '&': + inc(b.pos) + ident = r.cache.getIdent(decodeStr(b.s, b.pos)) + else: + internalError(info, "decodeSym: no ident") + #echo "decoding: {", ident.s + new(result) + result.id = id + result.kind = k + result.name = ident # read the rest of the symbol description: + r.syms[result.id] = result + if b.s[b.pos] == '^': + inc(b.pos) + result.typ = loadType(r, decodeVInt(b.s, b.pos), info) + decodeLineInfo(r, b, result.info) + if b.s[b.pos] == '*': + inc(b.pos) + result.owner = loadSym(r, decodeVInt(b.s, b.pos), result.info) + if b.s[b.pos] == '$': + inc(b.pos) + result.flags = cast[TSymFlags](int32(decodeVInt(b.s, b.pos))) + if b.s[b.pos] == '@': + inc(b.pos) + result.magic = TMagic(decodeVInt(b.s, b.pos)) + if b.s[b.pos] == '!': + inc(b.pos) + result.options = cast[TOptions](int32(decodeVInt(b.s, b.pos))) + else: + result.options = r.module.options + if b.s[b.pos] == '%': + inc(b.pos) + result.position = decodeVInt(b.s, b.pos) + if b.s[b.pos] == '`': + inc(b.pos) + result.offset = decodeVInt(b.s, b.pos) + else: + result.offset = - 1 + decodeLoc(r, b, result.loc, result.info) + result.annex = decodeLib(r, b, info) + if b.s[b.pos] == '#': + inc(b.pos) + result.constraint = decodeNode(r, b, unknownLineInfo()) + case result.kind + of skType, skGenericParam: + while b.s[b.pos] == '\14': + inc(b.pos) + result.typeInstCache.safeAdd loadType(r, decodeVInt(b.s, b.pos), result.info) + of routineKinds: + decodeInstantiations(r, b, result.info, result.procInstCache) + if b.s[b.pos] == '\16': + inc(b.pos) + result.gcUnsafetyReason = loadSym(r, decodeVInt(b.s, b.pos), result.info) + of skModule, skPackage: + decodeInstantiations(r, b, result.info, result.usedGenerics) + of skLet, skVar, skField, skForVar: + if b.s[b.pos] == '\18': + inc(b.pos) + result.guard = loadSym(r, decodeVInt(b.s, b.pos), result.info) + if b.s[b.pos] == '\19': + inc(b.pos) + result.bitsize = decodeVInt(b.s, b.pos).int16 + else: discard + + if b.s[b.pos] == '(': + #if result.kind in routineKinds: + # result.ast = decodeNodeLazyBody(b, result.info, result) + #else: + result.ast = decodeNode(r, b, result.info) + +proc loadNode*(module: PSym; index: var int): PNode = + if index == 0: + index = parseInt db.getValue( + sql"select min(id) from toplevelstmts where module = ?", abs module.id) + var b = BlobReader(pos: 0) + b.s = db.getValue(sql"select data from toplevelstmts where id = ?", index) + if b.s.len == 0: return nil # end marker + gr.module = module + result = decodeNode(gr, b, module.info) + +# --------------- Database model --------------------------------------------- + proc createDb() = db.exec(sql""" create table if not exists controlblock( |