123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- #
- #
- # The Nim Compiler
- # (c) Copyright 2012 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, platform, sighashes,
- tables, ndi, lineinfos, pathutils
- from modulegraphs import ModuleGraph, PPassContext
- type
- TLabel* = Rope # 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
- cfsVars, # section for C variable declarations
- cfsData, # section for C constant data
- 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,
- ctInt, ctInt8, ctInt16, ctInt32, ctInt64,
- ctFloat, ctFloat32, ctFloat64, ctFloat128,
- ctUInt, ctUInt8, ctUInt16, ctUInt32, ctUInt64,
- ctArray, ctPtrToArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc,
- ctCString
- TCFileSections* = array[TCFileSection, Rope] # 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, Rope] # represents a generated C proc
- BModule* = ref TCGen
- BProc* = ref TCProc
- TBlock* = object
- id*: int # the ID of the label; positive means that it
- label*: Rope # generated text for the label
- # nil if label is not used
- sections*: TCProcSections # the code beloging
- isLoop*: bool # whether block is a loop
- nestedTryStmts*: int16 # how many try statements is it nested into
- nestedExceptStmts*: int16 # how many except statements is it nested into
- frameLen*: int16
- TCProc = object # represents C proc that is currently generated
- prc*: PSym # the Nim 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
- hasCurFramePointer*: bool # true if _nimCurFrame var needed to recover after
- # exception is generated
- lastLineInfo*: TLineInfo # to avoid generating excessive 'nimln' statements
- currLineInfo*: TLineInfo # AST codegen will make this superfluous
- nestedTryStmts*: seq[tuple[n: PNode, inExcept: bool]]
- # in how many nested try statements we are
- # (the vars must be volatile then)
- # bool is true when are in the except part of a try block
- finallySafePoints*: seq[Rope] # For correctly cleaning up exceptions when
- # using return in finally statements
- labels*: Natural # for generating unique labels in the C proc
- blocks*: seq[TBlock] # nested blocks
- breakIdx*: int # the block that will be exited
- # with a regular break
- options*: TOptions # options that should be used for code
- # generation; this is the same as prc.options
- # unless prc == nil
- maxFrameLen*: int # max length of frame descriptor
- module*: BModule # used to prevent excessive parameter passing
- withinLoop*: int # > 0 if we are within a loop
- splitDecls*: int # > 0 if we are in some context for C++ that
- # requires 'T x = T()' to become 'T x; x = T()'
- # (yes, C++ is weird like that)
- gcFrameId*: Natural # for the GC stack marking
- gcFrameType*: Rope # the struct {} we put the GC markers into
- sigConflicts*: CountTable[string]
- TTypeSeq* = seq[PType]
- TypeCache* = Table[SigHash, Rope]
- Codegenflag* = enum
- preventStackTrace, # true if stack traces need to be prevented
- usesThreadVars, # true if the module uses a thread var
- frameDeclared, # hack for ROD support so that we don't declare
- # a frame var twice in an init proc
- isHeaderFile, # C source file is the header file
- includesStringh, # C source file already includes ``<string.h>``
- objHasKidsValid # whether we can rely on tfObjHasKids
- BModuleList* = ref object of RootObj
- mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: Rope
- mapping*: Rope # the generated mapping file (if requested)
- modules*: seq[BModule] # list of all compiled modules
- forwardedProcsCounter*: int
- generatedHeader*: BModule
- breakPointId*: int
- breakpoints*: Rope # later the breakpoints are inserted into the main proc
- typeInfoMarker*: TypeCache
- config*: ConfigRef
- graph*: ModuleGraph
- strVersion*, seqVersion*: int # version of the string/seq implementation to use
- nimtv*: Rope # Nim thread vars; the struct body
- nimtvDeps*: seq[PType] # type deps: every module needs whole struct
- nimtvDeclared*: IntSet # so that every var/field exists only once
- # in the struct
- # 'nimtv' is incredibly hard to modularize! Best
- # effort is to store all thread vars in a ROD
- # section and with their type deps and load them
- # unconditionally...
- # nimtvDeps is VERY hard to cache because it's
- # not a list of IDs nor can it be made to be one.
- TCGen = object of PPassContext # represents a C source file
- s*: TCFileSections # sections of the C file
- flags*: set[Codegenflag]
- module*: PSym
- filename*: AbsoluteFile
- cfilename*: AbsoluteFile # filename of the module (including path,
- # without extension)
- tmpBase*: Rope # base for temp identifier generation
- typeCache*: TypeCache # cache the generated types
- forwTypeCache*: TypeCache # cache for forward declarations of types
- declaredThings*: IntSet # things we have declared in this .c file
- declaredProtos*: IntSet # prototypes we have declared in this .c file
- headerFiles*: seq[string] # needed headers to include
- typeInfoMarker*: TypeCache # needed for generating type information
- initProc*: BProc # code for init procedure
- preInitProc*: BProc # code executed before the init proc
- typeStack*: TTypeSeq # used for type generation
- dataCache*: TNodeTable
- forwardedProcs*: TSymSeq # keep forwarded procs here
- typeNodes*, nimTypes*: int # used for type info generation
- typeNodesName*, nimTypesName*: Rope # used for type info generation
- labels*: Natural # for generating unique module-scope names
- extensionLoaders*: array['0'..'9', Rope] # special procs for the
- # OpenGL wrapper
- injectStmt*: Rope
- sigConflicts*: CountTable[SigHash]
- g*: BModuleList
- ndi*: NdiFile
- template config*(m: BModule): ConfigRef = m.g.config
- template config*(p: BProc): ConfigRef = p.module.g.config
- proc includeHeader*(this: BModule; header: string) =
- if not this.headerFiles.contains header:
- this.headerFiles.add header
- proc s*(p: BProc, s: TCProcSection): var Rope {.inline.} =
- # section in the current block
- result = p.blocks[p.blocks.len-1].sections[s]
- proc procSec*(p: BProc, s: TCProcSection): var Rope {.inline.} =
- # top level proc sections
- result = p.blocks[0].sections[s]
- 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 = module.config.options
- newSeq(result.blocks, 1)
- result.nestedTryStmts = @[]
- result.finallySafePoints = @[]
- result.sigConflicts = initCountTable[string]()
- proc newModuleList*(g: ModuleGraph): BModuleList =
- BModuleList(modules: @[], typeInfoMarker: initTable[SigHash, Rope](), config: g.config,
- graph: g, nimtvDeps: @[], nimtvDeclared: initIntSet())
- iterator cgenModules*(g: BModuleList): BModule =
- for i in 0..high(g.modules):
- # ultimately, we are iterating over the file ids here.
- # some "files" won't have an associated cgen module (like stdin)
- # and we must skip over them.
- if g.modules[i] != nil: yield g.modules[i]
|