much more efficient rod file generation

This commit is contained in:
Araq
2011-10-18 17:21:51 +02:00
parent 0914ba8980
commit 4de84024e5
18 changed files with 611 additions and 557 deletions

View File

@@ -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()

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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
View 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()

View File

@@ -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

View File

@@ -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",

View File

@@ -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)

View File

@@ -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

View File

@@ -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")

View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -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])

View File

@@ -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

View File

@@ -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:

View File

@@ -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
=========