mirror of
https://github.com/nim-lang/Nim.git
synced 2026-02-25 12:25:08 +00:00
much more efficient rod file generation
This commit is contained in:
@@ -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()
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
57
compiler/idgen.nim
Normal file
57
compiler/idgen.nim
Normal file
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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, ")")
|
||||
encodeNode(w, n.info, n.sons[i], result)
|
||||
add(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)])
|
||||
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 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): PRope =
|
||||
var
|
||||
codeAst: PNode
|
||||
col, line: PRope
|
||||
codeAst = nil
|
||||
if s == nil:
|
||||
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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
36
todo.txt
36
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
|
||||
=========
|
||||
|
||||
|
||||
Reference in New Issue
Block a user