File: cgendata.nim

package info (click to toggle)
nim 0.19.4-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 462,356 kB
  • sloc: sh: 11,089; ansic: 4,699; makefile: 706; python: 309; sql: 297; asm: 141; xml: 13
file content (199 lines) | stat: -rw-r--r-- 9,934 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
#
#
#           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]