mirror of
https://github.com/nim-lang/Nim.git
synced 2026-02-18 17:08:32 +00:00
first steps to C file merge operation for incremental compilation
This commit is contained in:
@@ -720,6 +720,11 @@ proc IdTableGet(t: TIdTable, key: int): PObject =
|
||||
var index = IdTableRawGet(t, key)
|
||||
if index >= 0: result = t.data[index].val
|
||||
else: result = nil
|
||||
|
||||
iterator pairs*(t: TIdTable): tuple[key: int, value: PObject] =
|
||||
for i in 0..high(t.data):
|
||||
if t.data[i].key != nil:
|
||||
yield (t.data[i].key.id, t.data[i].val)
|
||||
|
||||
proc IdTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: PObject) =
|
||||
var h: THash
|
||||
|
||||
253
compiler/ccgmerge.nim
Normal file
253
compiler/ccgmerge.nim
Normal file
@@ -0,0 +1,253 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2011 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This module implements the merge operation of 2 different C files. This
|
||||
## is needed for incremental compilation.
|
||||
|
||||
import
|
||||
ast, astalgo, ropes, options, strutils, lexbase, msgs, cgendata, rodutils,
|
||||
intsets, platform, llstream
|
||||
|
||||
# Careful! Section marks need to contain a tabulator so that they cannot
|
||||
# be part of C string literals.
|
||||
|
||||
const
|
||||
CFileSectionNames: array[TCFileSection, string] = [
|
||||
cfsMergeInfo: "",
|
||||
cfsHeaders: "NIM_merge_HEADERS",
|
||||
cfsForwardTypes: "NIM_merge_FORWARD_TYPES",
|
||||
cfsTypes: "NIM_merge_TYPES",
|
||||
cfsSeqTypes: "NIM_merge_SEQ_TYPES",
|
||||
cfsFieldInfo: "NIM_merge_FIELD_INFO",
|
||||
cfsTypeInfo: "NIM_merge_TYPE_INFO",
|
||||
cfsProcHeaders: "NIM_merge_PROC_HEADERS",
|
||||
cfsData: "NIM_merge_DATA",
|
||||
cfsVars: "NIM_merge_VARS",
|
||||
cfsProcs: "NIM_merge_PROCS",
|
||||
cfsInitProc: "NIM_merge_INIT_PROC",
|
||||
cfsTypeInit1: "NIM_merge_TYPE_INIT1",
|
||||
cfsTypeInit2: "NIM_merge_TYPE_INIT2",
|
||||
cfsTypeInit3: "NIM_merge_TYPE_INIT3",
|
||||
cfsDebugInit: "NIM_merge_DEBUG_INIT",
|
||||
cfsDynLibInit: "NIM_merge_DYNLIB_INIT",
|
||||
cfsDynLibDeinit: "NIM_merge_DYNLIB_DEINIT",
|
||||
]
|
||||
CProcSectionNames: array[TCProcSection, string] = [
|
||||
cpsLocals: "NIM_merge_PROC_LOCALS",
|
||||
cpsInit: "NIM_merge_PROC_INIT",
|
||||
cpsStmts: "NIM_merge_PROC_BODY"
|
||||
]
|
||||
|
||||
proc genSectionStart*(fs: TCFileSection): PRope =
|
||||
if optSymbolFiles in gGlobalOptions:
|
||||
result = toRope(tnl)
|
||||
app(result, "/*\t")
|
||||
app(result, CFileSectionNames[fs])
|
||||
app(result, "*/")
|
||||
app(result, tnl)
|
||||
|
||||
proc genSectionEnd*(fs: TCFileSection): PRope =
|
||||
if optSymbolFiles in gGlobalOptions:
|
||||
result = toRope("/*\tNIM_merge_END*/" & tnl)
|
||||
|
||||
proc genSectionStart*(ps: TCProcSection): PRope =
|
||||
if optSymbolFiles in gGlobalOptions:
|
||||
result = toRope(tnl)
|
||||
app(result, "/*\t")
|
||||
app(result, CProcSectionNames[ps])
|
||||
app(result, "*/")
|
||||
app(result, tnl)
|
||||
|
||||
proc genSectionEnd*(ps: TCProcSection): PRope =
|
||||
if optSymbolFiles in gGlobalOptions:
|
||||
result = toRope("/*\tNIM_merge_END*/" & tnl)
|
||||
|
||||
proc writeTypeCache(a: TIdTable, s: var string) =
|
||||
var i = 0
|
||||
for id, value in pairs(a):
|
||||
if i == 10:
|
||||
i = 0
|
||||
s.add(tnl)
|
||||
else:
|
||||
s.add(' ')
|
||||
encodeVInt(id, s)
|
||||
s.add(':')
|
||||
encodeStr(PRope(value).ropeToStr, s)
|
||||
inc i
|
||||
s.add('}')
|
||||
|
||||
proc writeIntSet(a: TIntSet, s: var string) =
|
||||
var i = 0
|
||||
for x in items(a):
|
||||
if i == 10:
|
||||
i = 0
|
||||
s.add(tnl)
|
||||
else:
|
||||
s.add(' ')
|
||||
encodeVInt(x, s)
|
||||
inc i
|
||||
s.add('}')
|
||||
|
||||
proc genMergeInfo*(m: BModule): PRope =
|
||||
if optSymbolFiles notin gGlobalOptions: return nil
|
||||
var s = "/*\tNIM_merge_INFO:"
|
||||
s.add(tnl)
|
||||
s.add("typeCache:{")
|
||||
writeTypeCache(m.typeCache, s)
|
||||
s.add("declared:{")
|
||||
writeIntSet(m.declaredThings, s)
|
||||
s.add("typeInfo:{")
|
||||
writeIntSet(m.typeInfoMarker, s)
|
||||
s.add("labels:")
|
||||
encodeVInt(m.labels, s)
|
||||
s.add(tnl)
|
||||
s.add("*/")
|
||||
result = s.toRope
|
||||
|
||||
template `^`(pos: expr): expr = L.buf[pos]
|
||||
|
||||
proc skipWhite(L: var TBaseLexer) =
|
||||
var pos = L.bufpos
|
||||
while true:
|
||||
case ^pos
|
||||
of CR: pos = lexbase.HandleCR(L, pos)
|
||||
of LF: pos = lexbase.HandleLF(L, pos)
|
||||
of ' ': inc pos
|
||||
else: break
|
||||
L.bufpos = pos
|
||||
|
||||
proc skipUntilCmd(L: var TBaseLexer) =
|
||||
var pos = L.bufpos
|
||||
while true:
|
||||
case ^pos
|
||||
of CR: pos = lexbase.HandleCR(L, pos)
|
||||
of LF: pos = lexbase.HandleLF(L, pos)
|
||||
of '\0': break
|
||||
of '/':
|
||||
if ^(pos+1) == '*' and ^(pos+2) == '\t':
|
||||
inc pos, 3
|
||||
break
|
||||
inc pos
|
||||
else: inc pos
|
||||
L.bufpos = pos
|
||||
|
||||
proc readVerbatimSection(L: var TBaseLexer): PRope =
|
||||
const section = "/*\tNIM_merge_END*/"
|
||||
var pos = L.bufpos
|
||||
var buf = L.buf
|
||||
result = newMutableRope(30_000)
|
||||
while true:
|
||||
case buf[pos]
|
||||
of CR:
|
||||
pos = lexbase.HandleCR(L, pos)
|
||||
buf = L.buf
|
||||
result.data.add(tnl)
|
||||
of LF:
|
||||
pos = lexbase.HandleLF(L, pos)
|
||||
buf = L.buf
|
||||
result.data.add(tnl)
|
||||
of '\0': break
|
||||
else: nil
|
||||
if buf[pos] == section[0]:
|
||||
var s = 0
|
||||
while buf[pos+1] == section[s+1]:
|
||||
inc s
|
||||
inc pos
|
||||
if section[s] != '\0':
|
||||
# reset:
|
||||
dec pos, s
|
||||
else:
|
||||
break
|
||||
result.data.add(buf[pos])
|
||||
inc pos
|
||||
L.bufpos = pos
|
||||
result.length = result.data.len
|
||||
|
||||
proc readKey(L: var TBaseLexer): string =
|
||||
var pos = L.bufpos
|
||||
var buf = L.buf
|
||||
while buf[pos] in IdentChars:
|
||||
result.add(buf[pos])
|
||||
inc pos
|
||||
if buf[pos] != ':': internalError("ccgmerge: ':' expected")
|
||||
L.bufpos = pos + 1 # skip ':'
|
||||
|
||||
proc NewFakeType(id: int): PType =
|
||||
new(result)
|
||||
result.id = id
|
||||
|
||||
proc readTypeCache(L: var TBaseLexer, result: var TIdTable) =
|
||||
if ^L.bufpos != '{': internalError("ccgmerge: '{' expected")
|
||||
inc L.bufpos
|
||||
while ^L.bufpos != '}':
|
||||
skipWhite(L)
|
||||
var key = decodeVInt(L.buf, L.bufpos)
|
||||
if ^L.bufpos != ':': internalError("ccgmerge: ':' expected")
|
||||
inc L.bufpos
|
||||
var value = decodeStr(L.buf, L.bufpos)
|
||||
# XXX little hack: we create a "fake" type object with the correct Id
|
||||
# better would be to adapt the data structure to not even store the
|
||||
# object as key, but only the Id
|
||||
IdTablePut(result, newFakeType(key), value.toRope)
|
||||
inc L.bufpos
|
||||
|
||||
proc readIntSet(L: var TBaseLexer, result: var TIntSet) =
|
||||
if ^L.bufpos != '{': internalError("ccgmerge: '{' expected")
|
||||
inc L.bufpos
|
||||
while ^L.bufpos != '}':
|
||||
skipWhite(L)
|
||||
var key = decodeVInt(L.buf, L.bufpos)
|
||||
result.incl(key)
|
||||
inc L.bufpos
|
||||
|
||||
proc processMergeInfo(L: var TBaseLexer, m: BModule) =
|
||||
while true:
|
||||
skipWhite(L)
|
||||
if ^L.bufpos == '*' and ^(L.bufpos+1) == '/':
|
||||
inc(L.bufpos, 2)
|
||||
break
|
||||
var k = readKey(L)
|
||||
case k
|
||||
of "typeCache": readTypeCache(L, m.typeCache)
|
||||
of "declared": readIntSet(L, m.declaredThings)
|
||||
of "typeInfo": readIntSet(L, m.typeInfoMarker)
|
||||
of "labels": m.labels = decodeVInt(L.buf, L.bufpos)
|
||||
else: InternalError("ccgmerge: unkown key: " & k)
|
||||
|
||||
proc readMergeInfo*(cfilename: string, m: BModule) =
|
||||
## reads the merge information into `m`.
|
||||
var s = LLStreamOpen(cfilename, fmRead)
|
||||
if s == nil: return
|
||||
var L: TBaseLexer
|
||||
openBaseLexer(L, s)
|
||||
while true:
|
||||
skipUntilCmd(L)
|
||||
if ^L.bufpos == '\0': break
|
||||
var k = readKey(L)
|
||||
if k == "NIM_merge_INFO":
|
||||
processMergeInfo(L, m)
|
||||
elif ^L.bufpos == '*' and ^(L.bufpos+1) == '/':
|
||||
inc(L.bufpos, 2)
|
||||
# read back into section
|
||||
skipWhite(L)
|
||||
var verbatim = readVerbatimSection(L)
|
||||
skipWhite(L)
|
||||
var sectionA = CFileSectionNames.find(k)
|
||||
if sectionA > 0 and sectionA <= high(TCFileSection).int:
|
||||
m.s[TCFileSection(sectionA)] = verbatim
|
||||
else:
|
||||
var sectionB = CProcSectionNames.find(k)
|
||||
if sectionB >= 0 and sectionB <= high(TCProcSection).int:
|
||||
m.initProc.s[TCProcSection(sectionB)] = verbatim
|
||||
else:
|
||||
InternalError("ccgmerge: unknown section: " & k)
|
||||
else:
|
||||
InternalError("ccgmerge: */ expected")
|
||||
closeBaseLexer(L)
|
||||
|
||||
@@ -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, idgen
|
||||
rodutils, renderer, idgen, cgendata, ccgmerge
|
||||
|
||||
when options.hasTinyCBackend:
|
||||
import tccgen
|
||||
@@ -23,96 +23,6 @@ when options.hasTinyCBackend:
|
||||
proc cgenPass*(): TPass
|
||||
# implementation
|
||||
|
||||
type
|
||||
TLabel = PRope # for the C generator a label is just a rope
|
||||
TCFileSection = enum # the sections a generated C file consists of
|
||||
cfsHeaders, # section for C include file headers
|
||||
cfsForwardTypes, # section for C forward typedefs
|
||||
cfsTypes, # section for C typedefs
|
||||
cfsSeqTypes, # section for sequence types only
|
||||
# this is needed for strange type generation
|
||||
# reasons
|
||||
cfsFieldInfo, # section for field information
|
||||
cfsTypeInfo, # section for type information
|
||||
cfsProcHeaders, # section for C procs prototypes
|
||||
cfsData, # section for C constant data
|
||||
cfsVars, # section for C variable declarations
|
||||
cfsProcs, # section for C procs that are not inline
|
||||
cfsTypeInit1, # section 1 for declarations of type information
|
||||
cfsTypeInit2, # section 2 for init of type information
|
||||
cfsTypeInit3, # section 3 for init of type information
|
||||
cfsDebugInit, # section for init of debug information
|
||||
cfsDynLibInit, # section for init of dynamic library binding
|
||||
cfsDynLibDeinit # section for deinitialization of dynamic
|
||||
# libraries
|
||||
TCTypeKind = enum # describes the type kind of a C type
|
||||
ctVoid, ctChar, ctBool, ctUInt, ctUInt8, ctUInt16, ctUInt32, ctUInt64,
|
||||
ctInt, ctInt8, ctInt16, ctInt32, ctInt64, ctFloat, ctFloat32, ctFloat64,
|
||||
ctFloat128, ctArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc, ctCString
|
||||
TCFileSections = array[TCFileSection, PRope] # represents a generated C file
|
||||
TCProcSection = enum # the sections a generated C proc consists of
|
||||
cpsLocals, # section of local variables for C proc
|
||||
cpsInit, # section for init of variables for C proc
|
||||
cpsStmts # section of local statements for C proc
|
||||
TCProcSections = array[TCProcSection, PRope] # represents a generated C proc
|
||||
BModule = ref TCGen
|
||||
BProc = ref TCProc
|
||||
TBlock{.final.} = object
|
||||
id*: int # the ID of the label; positive means that it
|
||||
# has been used (i.e. the label should be emitted)
|
||||
nestedTryStmts*: int # how many try statements is it nested into
|
||||
|
||||
TCProc{.final.} = object # represents C proc that is currently generated
|
||||
s: TCProcSections # the procs sections; short name for readability
|
||||
prc: PSym # the Nimrod proc that this C proc belongs to
|
||||
BeforeRetNeeded: bool # true iff 'BeforeRet' label for proc is needed
|
||||
ThreadVarAccessed: bool # true if the proc already accessed some threadvar
|
||||
nestedTryStmts: seq[PNode] # in how many nested try statements we are
|
||||
# (the vars must be volatile then)
|
||||
labels: Natural # for generating unique labels in the C proc
|
||||
blocks: seq[TBlock] # nested blocks
|
||||
options: TOptions # options that should be used for code
|
||||
# generation; this is the same as prc.options
|
||||
# unless prc == nil
|
||||
frameLen: int # current length of frame descriptor
|
||||
sendClosure: PType # closure record type that we pass
|
||||
receiveClosure: PType # closure record type that we get
|
||||
module: BModule # used to prevent excessive parameter passing
|
||||
withinLoop: int # > 0 if we are within a loop
|
||||
|
||||
TTypeSeq = seq[PType]
|
||||
TCGen = object of TPassContext # represents a C source file
|
||||
module*: PSym
|
||||
filename*: string
|
||||
s*: TCFileSections # sections of the C file
|
||||
PreventStackTrace: bool # true if stack traces need to be prevented
|
||||
usesThreadVars: bool # true if the module uses a thread var
|
||||
cfilename*: string # filename of the module (including path,
|
||||
# without extension)
|
||||
typeCache*: TIdTable # cache the generated types
|
||||
forwTypeCache*: TIdTable # cache for forward declarations of types
|
||||
declaredThings*: TIntSet # things we have declared in this .c file
|
||||
declaredProtos*: TIntSet # prototypes we have declared in this .c file
|
||||
headerFiles*: TLinkedList # needed headers to include
|
||||
typeInfoMarker*: TIntSet # needed for generating type information
|
||||
initProc*: BProc # code for init procedure
|
||||
typeStack*: TTypeSeq # used for type generation
|
||||
dataCache*: TNodeTable
|
||||
forwardedProcs*: TSymSeq # keep forwarded procs here
|
||||
typeNodes*, nimTypes*: int # used for type info generation
|
||||
typeNodesName*, nimTypesName*: PRope # used for type info generation
|
||||
labels*: natural # for generating unique module-scope names
|
||||
|
||||
var
|
||||
mainModProcs, mainModInit: PRope # parts of the main module
|
||||
gMapping: PRope # the generated mapping file (if requested)
|
||||
gProcProfile: Natural # proc profile counter
|
||||
gGeneratedSyms: TIntSet # set of ID's of generated symbols
|
||||
gPendingModules: seq[BModule] = @[] # list of modules that are not
|
||||
# finished with code generation
|
||||
gForwardedProcsCounter: int = 0
|
||||
gNimDat: BModule # generated global data
|
||||
|
||||
proc ropeff(cformat, llvmformat: string, args: openarray[PRope]): PRope =
|
||||
if gCmd == cmdCompileToLLVM: result = ropef(llvmformat, args)
|
||||
else: result = ropef(cformat, args)
|
||||
@@ -157,15 +67,6 @@ proc fillLoc(a: var TLoc, k: TLocKind, typ: PType, r: PRope, s: TStorageLoc) =
|
||||
a.s = s
|
||||
if a.r == nil: a.r = r
|
||||
|
||||
proc newProc(prc: PSym, module: BModule): BProc =
|
||||
new(result)
|
||||
result.prc = prc
|
||||
result.module = module
|
||||
if prc != nil: result.options = prc.options
|
||||
else: result.options = gOptions
|
||||
result.blocks = @[]
|
||||
result.nestedTryStmts = @[]
|
||||
|
||||
proc isSimpleConst(typ: PType): bool =
|
||||
result = not (skipTypes(typ, abstractVar).kind in
|
||||
{tyTuple, tyObject, tyArray, tyArrayConstr, tySet, tySequence})
|
||||
@@ -864,31 +765,53 @@ proc genInitCode(m: BModule) =
|
||||
# BUT: the generated init code might depend on a current frame, so
|
||||
# declare it nevertheless:
|
||||
getFrameDecl(m.initProc)
|
||||
|
||||
app(prc, genSectionStart(cpsLocals))
|
||||
app(prc, m.initProc.s[cpsLocals])
|
||||
app(prc, genSectionEnd(cpsLocals))
|
||||
|
||||
app(prc, genSectionStart(cfsTypeInit1))
|
||||
app(prc, m.s[cfsTypeInit1])
|
||||
if optStackTrace in m.initProc.options and not m.PreventStackTrace:
|
||||
app(prc, m.initProc.s[cpsLocals])
|
||||
app(prc, m.s[cfsTypeInit1])
|
||||
var procname = CStringLit(m.initProc, prc, m.module.name.s)
|
||||
var filename = CStringLit(m.initProc, prc, toFilename(m.module.info))
|
||||
app(prc, initFrame(m.initProc, procname, filename))
|
||||
else:
|
||||
app(prc, m.initProc.s[cpsLocals])
|
||||
app(prc, m.s[cfsTypeInit1])
|
||||
app(prc, m.s[cfsTypeInit2])
|
||||
app(prc, m.s[cfsTypeInit3])
|
||||
app(prc, m.s[cfsDebugInit])
|
||||
app(prc, m.s[cfsDynLibInit])
|
||||
app(prc, genSectionEnd(cfsTypeInit1))
|
||||
|
||||
for i in cfsTypeInit2..cfsDynLibInit:
|
||||
app(prc, genSectionStart(i))
|
||||
app(prc, m.s[i])
|
||||
app(prc, genSectionEnd(i))
|
||||
|
||||
app(prc, genSectionStart(cpsInit))
|
||||
app(prc, m.initProc.s[cpsInit])
|
||||
app(prc, genSectionEnd(cpsInit))
|
||||
|
||||
app(prc, genSectionStart(cpsStmts))
|
||||
app(prc, m.initProc.s[cpsStmts])
|
||||
if optStackTrace in m.initProc.options and not m.PreventStackTrace:
|
||||
app(prc, deinitFrame(m.initProc))
|
||||
app(prc, genSectionEnd(cpsStmts))
|
||||
appf(prc, "}$n$n")
|
||||
app(m.s[cfsProcs], prc)
|
||||
# we cannot simply add the init proc to ``m.s[cfsProcs]`` anymore because
|
||||
# that would lead to a *nesting* of merge sections which the merger does
|
||||
# not support. So we add it to another special section: ``cfsInitProc``
|
||||
app(m.s[cfsInitProc], prc)
|
||||
|
||||
proc genModule(m: BModule, cfilenoext: string): PRope =
|
||||
result = getFileHeader(cfilenoext)
|
||||
result.app(genMergeInfo(m))
|
||||
|
||||
app(m.s[cfsHeaders], genSectionStart(cfsHeaders))
|
||||
generateHeaders(m)
|
||||
app(m.s[cfsHeaders], genSectionEnd(cfsHeaders))
|
||||
|
||||
generateThreadLocalStorage(m)
|
||||
for i in countup(low(TCFileSection), cfsProcs): app(result, m.s[i])
|
||||
for i in countup(low(TCFileSection), cfsProcs):
|
||||
app(result, genSectionStart(i))
|
||||
app(result, m.s[i])
|
||||
app(result, genSectionEnd(i))
|
||||
app(result, m.s[cfsInitProc])
|
||||
|
||||
proc rawNewModule(module: PSym, filename: string): BModule =
|
||||
new(result)
|
||||
|
||||
116
compiler/cgendata.nim
Normal file
116
compiler/cgendata.nim
Normal file
@@ -0,0 +1,116 @@
|
||||
#
|
||||
#
|
||||
# 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 the data structures for the C code generation phase.
|
||||
|
||||
import
|
||||
ast, astalgo, ropes, passes, options, intsets, lists, platform
|
||||
|
||||
type
|
||||
TLabel* = PRope # for the C generator a label is just a rope
|
||||
TCFileSection* = enum # the sections a generated C file consists of
|
||||
cfsMergeInfo, # section containing merge information
|
||||
cfsHeaders, # section for C include file headers
|
||||
cfsForwardTypes, # section for C forward typedefs
|
||||
cfsTypes, # section for C typedefs
|
||||
cfsSeqTypes, # section for sequence types only
|
||||
# this is needed for strange type generation
|
||||
# reasons
|
||||
cfsFieldInfo, # section for field information
|
||||
cfsTypeInfo, # section for type information
|
||||
cfsProcHeaders, # section for C procs prototypes
|
||||
cfsData, # section for C constant data
|
||||
cfsVars, # section for C variable declarations
|
||||
cfsProcs, # section for C procs that are not inline
|
||||
cfsInitProc, # section for the C init proc
|
||||
cfsTypeInit1, # section 1 for declarations of type information
|
||||
cfsTypeInit2, # section 2 for init of type information
|
||||
cfsTypeInit3, # section 3 for init of type information
|
||||
cfsDebugInit, # section for init of debug information
|
||||
cfsDynLibInit, # section for init of dynamic library binding
|
||||
cfsDynLibDeinit # section for deinitialization of dynamic
|
||||
# libraries
|
||||
TCTypeKind* = enum # describes the type kind of a C type
|
||||
ctVoid, ctChar, ctBool, ctUInt, ctUInt8, ctUInt16, ctUInt32, ctUInt64,
|
||||
ctInt, ctInt8, ctInt16, ctInt32, ctInt64, ctFloat, ctFloat32, ctFloat64,
|
||||
ctFloat128, ctArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc, ctCString
|
||||
TCFileSections = array[TCFileSection, PRope] # represents a generated C file
|
||||
TCProcSection* = enum # the sections a generated C proc consists of
|
||||
cpsLocals, # section of local variables for C proc
|
||||
cpsInit, # section for init of variables for C proc
|
||||
cpsStmts # section of local statements for C proc
|
||||
TCProcSections = array[TCProcSection, PRope] # represents a generated C proc
|
||||
BModule* = ref TCGen
|
||||
BProc* = ref TCProc
|
||||
TBlock{.final.} = object
|
||||
id*: int # the ID of the label; positive means that it
|
||||
# has been used (i.e. the label should be emitted)
|
||||
nestedTryStmts*: int # how many try statements is it nested into
|
||||
|
||||
TCProc{.final.} = object # represents C proc that is currently generated
|
||||
s*: TCProcSections # the procs sections; short name for readability
|
||||
prc*: PSym # the Nimrod proc that this C proc belongs to
|
||||
BeforeRetNeeded*: bool # true iff 'BeforeRet' label for proc is needed
|
||||
ThreadVarAccessed*: bool # true if the proc already accessed some threadvar
|
||||
nestedTryStmts*: seq[PNode] # in how many nested try statements we are
|
||||
# (the vars must be volatile then)
|
||||
labels*: Natural # for generating unique labels in the C proc
|
||||
blocks*: seq[TBlock] # nested blocks
|
||||
options*: TOptions # options that should be used for code
|
||||
# generation; this is the same as prc.options
|
||||
# unless prc == nil
|
||||
frameLen*: int # current length of frame descriptor
|
||||
sendClosure*: PType # closure record type that we pass
|
||||
receiveClosure*: PType # closure record type that we get
|
||||
module*: BModule # used to prevent excessive parameter passing
|
||||
withinLoop*: int # > 0 if we are within a loop
|
||||
|
||||
TTypeSeq* = seq[PType]
|
||||
TCGen = object of TPassContext # represents a C source file
|
||||
module*: PSym
|
||||
filename*: string
|
||||
s*: TCFileSections # sections of the C file
|
||||
PreventStackTrace*: bool # true if stack traces need to be prevented
|
||||
usesThreadVars*: bool # true if the module uses a thread var
|
||||
cfilename*: string # filename of the module (including path,
|
||||
# without extension)
|
||||
typeCache*: TIdTable # cache the generated types
|
||||
forwTypeCache*: TIdTable # cache for forward declarations of types
|
||||
declaredThings*: TIntSet # things we have declared in this .c file
|
||||
declaredProtos*: TIntSet # prototypes we have declared in this .c file
|
||||
headerFiles*: TLinkedList # needed headers to include
|
||||
typeInfoMarker*: TIntSet # needed for generating type information
|
||||
initProc*: BProc # code for init procedure
|
||||
typeStack*: TTypeSeq # used for type generation
|
||||
dataCache*: TNodeTable
|
||||
forwardedProcs*: TSymSeq # keep forwarded procs here
|
||||
typeNodes*, nimTypes*: int # used for type info generation
|
||||
typeNodesName*, nimTypesName*: PRope # used for type info generation
|
||||
labels*: natural # for generating unique module-scope names
|
||||
|
||||
var
|
||||
mainModProcs*, mainModInit*: PRope # parts of the main module
|
||||
gMapping*: PRope # the generated mapping file (if requested)
|
||||
gProcProfile*: Natural # proc profile counter
|
||||
gGeneratedSyms*: TIntSet # set of ID's of generated symbols
|
||||
gPendingModules*: seq[BModule] = @[] # list of modules that are not
|
||||
# finished with code generation
|
||||
gForwardedProcsCounter*: int = 0
|
||||
gNimDat*: BModule # generated global data
|
||||
|
||||
|
||||
proc newProc*(prc: PSym, module: BModule): BProc =
|
||||
new(result)
|
||||
result.prc = prc
|
||||
result.module = module
|
||||
if prc != nil: result.options = prc.options
|
||||
else: result.options = gOptions
|
||||
result.blocks = @[]
|
||||
result.nestedTryStmts = @[]
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
## This module contains a simple persistent id generator.
|
||||
|
||||
import idents, strutils, os
|
||||
import idents, strutils, os, options
|
||||
|
||||
var gFrontEndId, gBackendId*: int
|
||||
|
||||
@@ -40,15 +40,18 @@ proc setId*(id: int) {.inline.} =
|
||||
proc IDsynchronizationPoint*(idRange: int) =
|
||||
gFrontEndId = (gFrontEndId div IdRange + 1) * IdRange + 1
|
||||
|
||||
proc toGid(f: string): string =
|
||||
result = options.completeGeneratedFilePath(f.addFileExt("gid"))
|
||||
|
||||
proc saveMaxIds*(project: string) =
|
||||
var f = open(project.addFileExt("gid"), fmWrite)
|
||||
var f = open(project.toGid, fmWrite)
|
||||
f.writeln($gFrontEndId)
|
||||
f.writeln($gBackEndId)
|
||||
f.close()
|
||||
|
||||
proc loadMaxIds*(project: string) =
|
||||
var f: TFile
|
||||
if open(f, project.addFileExt("gid"), fmRead):
|
||||
if open(f, project.toGid, fmRead):
|
||||
var frontEndId = parseInt(f.readLine)
|
||||
var backEndId = parseInt(f.readLine)
|
||||
gFrontEndId = max(gFrontEndId, frontEndId)
|
||||
|
||||
@@ -59,8 +59,8 @@ const
|
||||
chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
|
||||
# since negative numbers require a leading '-' they use up 1 byte. Thus we
|
||||
# subtract/add vintDelta here to save space for little negative numbers
|
||||
# which are common in ROD files:
|
||||
# subtract/add `vintDelta` here to save space for small negative numbers
|
||||
# which are common in ROD files:
|
||||
const
|
||||
vintDelta = 5
|
||||
|
||||
|
||||
@@ -111,6 +111,12 @@ proc newRope(data: string = nil): PRope =
|
||||
result.length = len(data)
|
||||
result.data = data
|
||||
|
||||
proc newMutableRope*(capacity = 30): PRope =
|
||||
## creates a new rope that supports direct modifications of the rope's
|
||||
## 'data' and 'length' fields.
|
||||
new(result)
|
||||
result.data = newStringOfCap(capacity)
|
||||
|
||||
var
|
||||
cache: PRope # the root of the cache tree
|
||||
misses, hits: int
|
||||
|
||||
21
todo.txt
21
todo.txt
@@ -2,19 +2,33 @@ Version 0.8.14
|
||||
==============
|
||||
|
||||
- optimize unused constants away
|
||||
- 'let x = y'; const ptr/ref
|
||||
- 'let x = y'
|
||||
- fix actors.nim
|
||||
- make threadvar efficient again on linux after testing
|
||||
- test the sort implementation again
|
||||
- optional indentation for 'case' statement
|
||||
- document & test splicing; don't forget to test negative indexes
|
||||
- thread local vs. global raiseHook()
|
||||
- incremental compilation (!)
|
||||
- make pegs support a compile-time option and make c2nim use regexes instead
|
||||
per default
|
||||
|
||||
|
||||
incremental compilation
|
||||
-----------------------
|
||||
|
||||
- implement C file merge operation
|
||||
- adapt thread var implementation to care about the new merge operation
|
||||
- write test cases: needs test script support
|
||||
- fix remaining bugs
|
||||
- write documentation
|
||||
- make the compiler output a warning if linking fails with --symbolFiles:on
|
||||
(necessary?)
|
||||
|
||||
|
||||
version 0.9.0
|
||||
=============
|
||||
|
||||
- const ptr/ref
|
||||
- unsigned ints and bignums
|
||||
- warning for implicit openArray -> varargs convention
|
||||
- implement explicit varargs
|
||||
@@ -24,6 +38,8 @@ version 0.9.0
|
||||
- make exceptions compatible with C++ exceptions
|
||||
- ``=`` should be overloadable; requires specialization for ``=``
|
||||
- 'const' objects including case objects
|
||||
- os module should use Windows Unicode versions
|
||||
- 64bit build for Windows
|
||||
|
||||
Bugs
|
||||
----
|
||||
@@ -141,5 +157,6 @@ Version 2
|
||||
a full blown statement; a ``try`` expression might be a good idea to make
|
||||
error handling more light-weight
|
||||
people also want ``inc a; inc b``
|
||||
--> solved by providing an expr version of most control structures?
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user