ccgtypes.nim 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2017 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. # included from cgen.nim
  10. # ------------------------- Name Mangling --------------------------------
  11. import sighashes
  12. from lowerings import createObj
  13. proc isKeyword(w: PIdent): bool =
  14. # Nim and C++ share some keywords
  15. # it's more efficient to test the whole Nim keywords range
  16. case w.id
  17. of ccgKeywordsLow..ccgKeywordsHigh,
  18. nimKeywordsLow..nimKeywordsHigh,
  19. ord(wInline): return true
  20. else: return false
  21. proc mangleField(m: BModule; name: PIdent): string =
  22. result = mangle(name.s)
  23. # fields are tricky to get right and thanks to generic types producing
  24. # duplicates we can end up mangling the same field multiple times. However
  25. # if we do so, the 'cppDefines' table might be modified in the meantime
  26. # meaning we produce inconsistent field names (see bug #5404).
  27. # Hence we do not check for ``m.g.config.cppDefines.contains(result)`` here
  28. # anymore:
  29. if isKeyword(name):
  30. result.add "_0"
  31. when false:
  32. proc hashOwner(s: PSym): SigHash =
  33. var m = s
  34. while m.kind != skModule: m = m.owner
  35. let p = m.owner
  36. assert p.kind == skPackage
  37. result = gDebugInfo.register(p.name.s, m.name.s)
  38. proc idOrSig(m: BModule; s: PSym): Rope =
  39. if s.kind in routineKinds and s.typ != nil:
  40. # signatures for exported routines are reliable enough to
  41. # produce a unique name and this means produced C++ is more stable wrt
  42. # Nim changes:
  43. let sig = hashProc(s)
  44. result = rope($sig)
  45. #let m = if s.typ.callConv != ccInline: findPendingModule(m, s) else: m
  46. let counter = m.sigConflicts.getOrDefault(sig)
  47. #if sigs == "_jckmNePK3i2MFnWwZlp6Lg" and s.name.s == "contains":
  48. # echo "counter ", counter, " ", s.id
  49. if counter != 0:
  50. result.add "_" & rope(counter+1)
  51. # this minor hack is necessary to make tests/collections/thashes compile.
  52. # The inlined hash function's original module is ambiguous so we end up
  53. # generating duplicate names otherwise:
  54. if s.typ.callConv == ccInline:
  55. result.add rope(m.module.name.s)
  56. m.sigConflicts.inc(sig)
  57. else:
  58. let sig = hashNonProc(s)
  59. result = rope($sig)
  60. let counter = m.sigConflicts.getOrDefault(sig)
  61. if counter != 0:
  62. result.add "_" & rope(counter+1)
  63. m.sigConflicts.inc(sig)
  64. proc mangleName(m: BModule; s: PSym): Rope =
  65. result = s.loc.r
  66. if result == nil:
  67. result = s.name.s.mangle.rope
  68. add(result, m.idOrSig(s))
  69. s.loc.r = result
  70. writeMangledName(m.ndi, s)
  71. proc mangleParamName(m: BModule; s: PSym): Rope =
  72. ## we cannot use 'sigConflicts' here since we have a BModule, not a BProc.
  73. ## Fortunately C's scoping rules are sane enough so that that doesn't
  74. ## cause any trouble.
  75. result = s.loc.r
  76. if result == nil:
  77. var res = s.name.s.mangle
  78. if isKeyword(s.name) or m.g.config.cppDefines.contains(res):
  79. res.add "_0"
  80. result = res.rope
  81. s.loc.r = result
  82. writeMangledName(m.ndi, s)
  83. proc mangleLocalName(p: BProc; s: PSym): Rope =
  84. assert s.kind in skLocalVars+{skTemp}
  85. #assert sfGlobal notin s.flags
  86. result = s.loc.r
  87. if result == nil:
  88. var key = s.name.s.mangle
  89. shallow(key)
  90. let counter = p.sigConflicts.getOrDefault(key)
  91. result = key.rope
  92. if s.kind == skTemp:
  93. # speed up conflict search for temps (these are quite common):
  94. if counter != 0: result.add "_" & rope(counter+1)
  95. elif counter != 0 or isKeyword(s.name) or p.module.g.config.cppDefines.contains(key):
  96. result.add "_" & rope(counter+1)
  97. p.sigConflicts.inc(key)
  98. s.loc.r = result
  99. if s.kind != skTemp: writeMangledName(p.module.ndi, s)
  100. proc scopeMangledParam(p: BProc; param: PSym) =
  101. ## parameter generation only takes BModule, not a BProc, so we have to
  102. ## remember these parameter names are already in scope to be able to
  103. ## generate unique identifiers reliably (consider that ``var a = a`` is
  104. ## even an idiom in Nim).
  105. var key = param.name.s.mangle
  106. shallow(key)
  107. p.sigConflicts.inc(key)
  108. const
  109. irrelevantForBackend = {tyGenericBody, tyGenericInst, tyGenericInvocation,
  110. tyDistinct, tyRange, tyStatic, tyAlias, tyInferred}
  111. proc typeName(typ: PType): Rope =
  112. let typ = typ.skipTypes(irrelevantForBackend)
  113. result =
  114. if typ.sym != nil and typ.kind in {tyObject, tyEnum}:
  115. rope($typ.kind & '_' & typ.sym.name.s.mangle)
  116. else:
  117. rope($typ.kind)
  118. proc getTypeName(m: BModule; typ: PType; sig: SigHash): Rope =
  119. var t = typ
  120. while true:
  121. if t.sym != nil and {sfImportc, sfExportc} * t.sym.flags != {}:
  122. return t.sym.loc.r
  123. if t.kind in irrelevantForBackend:
  124. t = t.lastSon
  125. else:
  126. break
  127. let typ = if typ.kind == tyAlias: typ.lastSon else: typ
  128. if typ.loc.r == nil:
  129. typ.loc.r = typ.typeName & $sig
  130. else:
  131. when defined(debugSigHashes):
  132. # check consistency:
  133. assert($typ.loc.r == $(typ.typeName & $sig))
  134. result = typ.loc.r
  135. if result == nil: internalError("getTypeName: " & $typ.kind)
  136. proc mapSetType(typ: PType): TCTypeKind =
  137. case int(getSize(typ))
  138. of 1: result = ctInt8
  139. of 2: result = ctInt16
  140. of 4: result = ctInt32
  141. of 8: result = ctInt64
  142. else: result = ctArray
  143. proc mapType(typ: PType): TCTypeKind =
  144. ## Maps a Nim type to a C type
  145. case typ.kind
  146. of tyNone, tyStmt: result = ctVoid
  147. of tyBool: result = ctBool
  148. of tyChar: result = ctChar
  149. of tySet: result = mapSetType(typ)
  150. of tyOpenArray, tyArray, tyVarargs: result = ctArray
  151. of tyObject, tyTuple: result = ctStruct
  152. of tyUserTypeClasses:
  153. internalAssert typ.isResolvedUserTypeClass
  154. return mapType(typ.lastSon)
  155. of tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal,
  156. tyTypeDesc, tyAlias, tyInferred:
  157. result = mapType(lastSon(typ))
  158. of tyEnum:
  159. if firstOrd(typ) < 0:
  160. result = ctInt32
  161. else:
  162. case int(getSize(typ))
  163. of 1: result = ctUInt8
  164. of 2: result = ctUInt16
  165. of 4: result = ctInt32
  166. of 8: result = ctInt64
  167. else: internalError("mapType")
  168. of tyRange: result = mapType(typ.sons[0])
  169. of tyPtr, tyVar, tyRef, tyOptAsRef:
  170. var base = skipTypes(typ.lastSon, typedescInst)
  171. case base.kind
  172. of tyOpenArray, tyArray, tyVarargs: result = ctPtrToArray
  173. #of tySet:
  174. # if mapSetType(base) == ctArray: result = ctPtrToArray
  175. # else: result = ctPtr
  176. # XXX for some reason this breaks the pegs module
  177. else: result = ctPtr
  178. of tyPointer: result = ctPtr
  179. of tySequence: result = ctNimSeq
  180. of tyOpt:
  181. case optKind(typ)
  182. of oBool: result = ctStruct
  183. of oNil, oPtr: result = ctPtr
  184. of oEnum:
  185. # The 'nil' value is always negative, so we always use a signed integer
  186. result = if getSize(typ.sons[0]) == 8: ctInt64 else: ctInt32
  187. of tyProc: result = if typ.callConv != ccClosure: ctProc else: ctStruct
  188. of tyString: result = ctNimStr
  189. of tyCString: result = ctCString
  190. of tyInt..tyUInt64:
  191. result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt))
  192. of tyStatic:
  193. if typ.n != nil: result = mapType(lastSon typ)
  194. else: internalError("mapType")
  195. else: internalError("mapType")
  196. proc mapReturnType(typ: PType): TCTypeKind =
  197. #if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr
  198. #else:
  199. result = mapType(typ)
  200. proc isImportedType(t: PType): bool =
  201. result = t.sym != nil and sfImportc in t.sym.flags
  202. proc isImportedCppType(t: PType): bool =
  203. let x = t.skipTypes(irrelevantForBackend)
  204. result = (t.sym != nil and sfInfixCall in t.sym.flags) or
  205. (x.sym != nil and sfInfixCall in x.sym.flags)
  206. proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope
  207. proc needsComplexAssignment(typ: PType): bool =
  208. result = containsGarbageCollectedRef(typ)
  209. proc isObjLackingTypeField(typ: PType): bool {.inline.} =
  210. result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and
  211. (typ.sons[0] == nil) or isPureObject(typ))
  212. proc isInvalidReturnType(rettype: PType): bool =
  213. # Arrays and sets cannot be returned by a C procedure, because C is
  214. # such a poor programming language.
  215. # We exclude records with refs too. This enhances efficiency and
  216. # is necessary for proper code generation of assignments.
  217. if rettype == nil: result = true
  218. else:
  219. case mapType(rettype)
  220. of ctArray:
  221. result = not (skipTypes(rettype, typedescInst).kind in
  222. {tyVar, tyRef, tyPtr})
  223. of ctStruct:
  224. let t = skipTypes(rettype, typedescInst)
  225. if rettype.isImportedCppType or t.isImportedCppType: return false
  226. result = needsComplexAssignment(t) or
  227. (t.kind == tyObject and not isObjLackingTypeField(t))
  228. else: result = false
  229. const
  230. CallingConvToStr: array[TCallingConvention, string] = ["N_NIMCALL",
  231. "N_STDCALL", "N_CDECL", "N_SAFECALL",
  232. "N_SYSCALL", # this is probably not correct for all platforms,
  233. # but one can #define it to what one wants
  234. "N_INLINE", "N_NOINLINE", "N_FASTCALL", "N_CLOSURE", "N_NOCONV"]
  235. proc cacheGetType(tab: TypeCache; sig: SigHash): Rope =
  236. # returns nil if we need to declare this type
  237. # since types are now unique via the ``getUniqueType`` mechanism, this slow
  238. # linear search is not necessary anymore:
  239. result = tab.getOrDefault(sig)
  240. proc addAbiCheck(m: BModule, t: PType, name: Rope) =
  241. if isDefined("checkabi"):
  242. addf(m.s[cfsTypeInfo], "NIM_CHECK_SIZE($1, $2);$n", [name, rope(getSize(t))])
  243. proc getTempName(m: BModule): Rope =
  244. result = m.tmpBase & rope(m.labels)
  245. inc m.labels
  246. proc ccgIntroducedPtr(s: PSym): bool =
  247. var pt = skipTypes(s.typ, typedescInst)
  248. assert skResult != s.kind
  249. if tfByRef in pt.flags: return true
  250. elif tfByCopy in pt.flags: return false
  251. case pt.kind
  252. of tyObject:
  253. if (optByRef in s.options) or (getSize(pt) > platform.floatSize * 3):
  254. result = true # requested anyway
  255. elif (tfFinal in pt.flags) and (pt.sons[0] == nil):
  256. result = false # no need, because no subtyping possible
  257. else:
  258. result = true # ordinary objects are always passed by reference,
  259. # otherwise casting doesn't work
  260. of tyTuple:
  261. result = (getSize(pt) > platform.floatSize*3) or (optByRef in s.options)
  262. else: result = false
  263. proc fillResult(param: PNode) =
  264. fillLoc(param.sym.loc, locParam, param, ~"Result",
  265. OnStack)
  266. let t = param.sym.typ
  267. if mapReturnType(t) != ctArray and isInvalidReturnType(t):
  268. incl(param.sym.loc.flags, lfIndirect)
  269. param.sym.loc.storage = OnUnknown
  270. proc typeNameOrLiteral(m: BModule; t: PType, literal: string): Rope =
  271. if t.sym != nil and sfImportc in t.sym.flags and t.sym.magic == mNone:
  272. result = t.sym.loc.r
  273. else:
  274. result = rope(literal)
  275. proc getSimpleTypeDesc(m: BModule, typ: PType): Rope =
  276. const
  277. NumericalTypeToStr: array[tyInt..tyUInt64, string] = [
  278. "NI", "NI8", "NI16", "NI32", "NI64",
  279. "NF", "NF32", "NF64", "NF128",
  280. "NU", "NU8", "NU16", "NU32", "NU64"]
  281. case typ.kind
  282. of tyPointer:
  283. result = typeNameOrLiteral(m, typ, "void*")
  284. of tyString:
  285. discard cgsym(m, "NimStringDesc")
  286. result = typeNameOrLiteral(m, typ, "NimStringDesc*")
  287. of tyCString: result = typeNameOrLiteral(m, typ, "NCSTRING")
  288. of tyBool: result = typeNameOrLiteral(m, typ, "NIM_BOOL")
  289. of tyChar: result = typeNameOrLiteral(m, typ, "NIM_CHAR")
  290. of tyNil: result = typeNameOrLiteral(m, typ, "0")
  291. of tyInt..tyUInt64:
  292. result = typeNameOrLiteral(m, typ, NumericalTypeToStr[typ.kind])
  293. of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ.sons[0])
  294. of tyStatic:
  295. if typ.n != nil: result = getSimpleTypeDesc(m, lastSon typ)
  296. else: internalError("tyStatic for getSimpleTypeDesc")
  297. of tyGenericInst, tyAlias:
  298. result = getSimpleTypeDesc(m, lastSon typ)
  299. else: result = nil
  300. if result != nil and typ.isImportedType():
  301. let sig = hashType typ
  302. if cacheGetType(m.typeCache, sig) == nil:
  303. m.typeCache[sig] = result
  304. addAbiCheck(m, typ, result)
  305. proc pushType(m: BModule, typ: PType) =
  306. add(m.typeStack, typ)
  307. proc getTypePre(m: BModule, typ: PType; sig: SigHash): Rope =
  308. if typ == nil: result = rope("void")
  309. else:
  310. result = getSimpleTypeDesc(m, typ)
  311. if result == nil: result = cacheGetType(m.typeCache, sig)
  312. proc structOrUnion(t: PType): Rope =
  313. let t = t.skipTypes({tyAlias})
  314. (if tfUnion in t.flags: rope("union") else: rope("struct"))
  315. proc getForwardStructFormat(m: BModule): string =
  316. if m.compileToCpp: result = "$1 $2;$n"
  317. else: result = "typedef $1 $2 $2;$n"
  318. proc getTypeForward(m: BModule, typ: PType; sig: SigHash): Rope =
  319. result = cacheGetType(m.forwTypeCache, sig)
  320. if result != nil: return
  321. result = getTypePre(m, typ, sig)
  322. if result != nil: return
  323. let concrete = typ.skipTypes(abstractInst + {tyOpt})
  324. case concrete.kind
  325. of tySequence, tyTuple, tyObject:
  326. result = getTypeName(m, typ, sig)
  327. m.forwTypeCache[sig] = result
  328. if not isImportedType(concrete):
  329. addf(m.s[cfsForwardTypes], getForwardStructFormat(m),
  330. [structOrUnion(typ), result])
  331. doAssert m.forwTypeCache[sig] == result
  332. else: internalError("getTypeForward(" & $typ.kind & ')')
  333. proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope =
  334. ## like getTypeDescAux but creates only a *weak* dependency. In other words
  335. ## we know we only need a pointer to it so we only generate a struct forward
  336. ## declaration:
  337. let etB = t.skipTypes(abstractInst)
  338. case etB.kind
  339. of tyObject, tyTuple:
  340. if isImportedCppType(etB) and t.kind == tyGenericInst:
  341. result = getTypeDescAux(m, t, check)
  342. else:
  343. result = getTypeForward(m, t, hashType(t))
  344. pushType(m, t)
  345. of tySequence:
  346. result = getTypeForward(m, t, hashType(t)) & "*"
  347. pushType(m, t)
  348. of tyOpt:
  349. if optKind(etB) == oPtr:
  350. result = getTypeForward(m, t, hashType(t)) & "*"
  351. pushType(m, t)
  352. else:
  353. result = getTypeDescAux(m, t, check)
  354. else:
  355. result = getTypeDescAux(m, t, check)
  356. proc paramStorageLoc(param: PSym): TStorageLoc =
  357. if param.typ.skipTypes({tyVar, tyTypeDesc}).kind notin {
  358. tyArray, tyOpenArray, tyVarargs}:
  359. result = OnStack
  360. else:
  361. result = OnUnknown
  362. proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
  363. check: var IntSet, declareEnvironment=true;
  364. weakDep=false) =
  365. params = nil
  366. if t.sons[0] == nil or isInvalidReturnType(t.sons[0]):
  367. rettype = ~"void"
  368. else:
  369. rettype = getTypeDescAux(m, t.sons[0], check)
  370. for i in countup(1, sonsLen(t.n) - 1):
  371. if t.n.sons[i].kind != nkSym: internalError(t.n.info, "genProcParams")
  372. var param = t.n.sons[i].sym
  373. if isCompileTimeOnly(param.typ): continue
  374. if params != nil: add(params, ~", ")
  375. fillLoc(param.loc, locParam, t.n.sons[i], mangleParamName(m, param),
  376. param.paramStorageLoc)
  377. if ccgIntroducedPtr(param):
  378. add(params, getTypeDescWeak(m, param.typ, check))
  379. add(params, ~"*")
  380. incl(param.loc.flags, lfIndirect)
  381. param.loc.storage = OnUnknown
  382. elif weakDep:
  383. add(params, getTypeDescWeak(m, param.typ, check))
  384. else:
  385. add(params, getTypeDescAux(m, param.typ, check))
  386. add(params, ~" ")
  387. add(params, param.loc.r)
  388. # declare the len field for open arrays:
  389. var arr = param.typ
  390. if arr.kind == tyVar: arr = arr.sons[0]
  391. var j = 0
  392. while arr.kind in {tyOpenArray, tyVarargs}:
  393. # this fixes the 'sort' bug:
  394. if param.typ.kind == tyVar: param.loc.storage = OnUnknown
  395. # need to pass hidden parameter:
  396. addf(params, ", NI $1Len_$2", [param.loc.r, j.rope])
  397. inc(j)
  398. arr = arr.sons[0]
  399. if t.sons[0] != nil and isInvalidReturnType(t.sons[0]):
  400. var arr = t.sons[0]
  401. if params != nil: add(params, ", ")
  402. if mapReturnType(t.sons[0]) != ctArray:
  403. add(params, getTypeDescWeak(m, arr, check))
  404. add(params, "*")
  405. else:
  406. add(params, getTypeDescAux(m, arr, check))
  407. addf(params, " Result", [])
  408. if t.callConv == ccClosure and declareEnvironment:
  409. if params != nil: add(params, ", ")
  410. add(params, "void* ClE_0")
  411. if tfVarargs in t.flags:
  412. if params != nil: add(params, ", ")
  413. add(params, "...")
  414. if params == nil: add(params, "void)")
  415. else: add(params, ")")
  416. params = "(" & params
  417. proc mangleRecFieldName(m: BModule; field: PSym, rectype: PType): Rope =
  418. if (rectype.sym != nil) and
  419. ({sfImportc, sfExportc} * rectype.sym.flags != {}):
  420. result = field.loc.r
  421. else:
  422. result = rope(mangleField(m, field.name))
  423. if result == nil: internalError(field.info, "mangleRecFieldName")
  424. proc genRecordFieldsAux(m: BModule, n: PNode,
  425. accessExpr: Rope, rectype: PType,
  426. check: var IntSet): Rope =
  427. result = nil
  428. case n.kind
  429. of nkRecList:
  430. for i in countup(0, sonsLen(n) - 1):
  431. add(result, genRecordFieldsAux(m, n.sons[i], accessExpr, rectype, check))
  432. of nkRecCase:
  433. if n.sons[0].kind != nkSym: internalError(n.info, "genRecordFieldsAux")
  434. add(result, genRecordFieldsAux(m, n.sons[0], accessExpr, rectype, check))
  435. let uname = rope(mangle(n.sons[0].sym.name.s) & 'U')
  436. let ae = if accessExpr != nil: "$1.$2" % [accessExpr, uname]
  437. else: uname
  438. var unionBody: Rope = nil
  439. for i in countup(1, sonsLen(n) - 1):
  440. case n.sons[i].kind
  441. of nkOfBranch, nkElse:
  442. let k = lastSon(n.sons[i])
  443. if k.kind != nkSym:
  444. let sname = "S" & rope(i)
  445. let a = genRecordFieldsAux(m, k, "$1.$2" % [ae, sname], rectype,
  446. check)
  447. if a != nil:
  448. if tfPacked notin rectype.flags:
  449. add(unionBody, "struct {")
  450. else:
  451. if hasAttribute in CC[cCompiler].props:
  452. add(unionBody, "struct __attribute__((__packed__)){" )
  453. else:
  454. addf(unionBody, "#pragma pack(1)$nstruct{", [])
  455. add(unionBody, a)
  456. addf(unionBody, "} $1;$n", [sname])
  457. if tfPacked in rectype.flags and hasAttribute notin CC[cCompiler].props:
  458. addf(unionBody, "#pragma pack(pop)$n", [])
  459. else:
  460. add(unionBody, genRecordFieldsAux(m, k, ae, rectype, check))
  461. else: internalError("genRecordFieldsAux(record case branch)")
  462. if unionBody != nil:
  463. addf(result, "union{$n$1} $2;$n", [unionBody, uname])
  464. of nkSym:
  465. let field = n.sym
  466. if field.typ.kind == tyVoid: return
  467. #assert(field.ast == nil)
  468. let sname = mangleRecFieldName(m, field, rectype)
  469. let ae = if accessExpr != nil: "$1.$2" % [accessExpr, sname]
  470. else: sname
  471. fillLoc(field.loc, locField, n, ae, OnUnknown)
  472. # for importcpp'ed objects, we only need to set field.loc, but don't
  473. # have to recurse via 'getTypeDescAux'. And not doing so prevents problems
  474. # with heavily templatized C++ code:
  475. if not isImportedCppType(rectype):
  476. let fieldType = field.loc.lode.typ.skipTypes(abstractInst)
  477. if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
  478. addf(result, "$1 $2[SEQ_DECL_SIZE];$n",
  479. [getTypeDescAux(m, fieldType.elemType, check), sname])
  480. elif fieldType.kind in {tySequence, tyOpt}:
  481. # we need to use a weak dependency here for trecursive_table.
  482. addf(result, "$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check), sname])
  483. elif field.bitsize != 0:
  484. addf(result, "$1 $2:$3;$n", [getTypeDescAux(m, field.loc.t, check), sname, rope($field.bitsize)])
  485. else:
  486. # don't use fieldType here because we need the
  487. # tyGenericInst for C++ template support
  488. addf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname])
  489. else: internalError(n.info, "genRecordFieldsAux()")
  490. proc getRecordFields(m: BModule, typ: PType, check: var IntSet): Rope =
  491. result = genRecordFieldsAux(m, typ.n, nil, typ, check)
  492. proc fillObjectFields*(m: BModule; typ: PType) =
  493. # sometimes generic objects are not consistently merged. We patch over
  494. # this fact here.
  495. var check = initIntSet()
  496. discard getRecordFields(m, typ, check)
  497. proc getRecordDesc(m: BModule, typ: PType, name: Rope,
  498. check: var IntSet): Rope =
  499. # declare the record:
  500. var hasField = false
  501. if tfPacked in typ.flags:
  502. if hasAttribute in CC[cCompiler].props:
  503. result = structOrUnion(typ) & " __attribute__((__packed__))"
  504. else:
  505. result = "#pragma pack(1)" & tnl & structOrUnion(typ)
  506. else:
  507. result = structOrUnion(typ)
  508. result.add " "
  509. result.add name
  510. if typ.kind == tyObject:
  511. if typ.sons[0] == nil:
  512. if (typ.sym != nil and sfPure in typ.sym.flags) or tfFinal in typ.flags:
  513. appcg(m, result, " {$n", [])
  514. else:
  515. appcg(m, result, " {$n#TNimType* m_type;$n", [])
  516. hasField = true
  517. elif m.compileToCpp:
  518. appcg(m, result, " : public $1 {$n",
  519. [getTypeDescAux(m, typ.sons[0].skipTypes(skipPtrs), check)])
  520. hasField = true
  521. else:
  522. appcg(m, result, " {$n $1 Sup;$n",
  523. [getTypeDescAux(m, typ.sons[0].skipTypes(skipPtrs), check)])
  524. hasField = true
  525. else:
  526. addf(result, " {$n", [name])
  527. let desc = getRecordFields(m, typ, check)
  528. if desc == nil and not hasField:
  529. addf(result, "char dummy;$n", [])
  530. else:
  531. add(result, desc)
  532. add(result, "};" & tnl)
  533. if tfPacked in typ.flags and hasAttribute notin CC[cCompiler].props:
  534. result.add "#pragma pack(pop)" & tnl
  535. proc getTupleDesc(m: BModule, typ: PType, name: Rope,
  536. check: var IntSet): Rope =
  537. result = "$1 $2 {$n" % [structOrUnion(typ), name]
  538. var desc: Rope = nil
  539. for i in countup(0, sonsLen(typ) - 1):
  540. addf(desc, "$1 Field$2;$n",
  541. [getTypeDescAux(m, typ.sons[i], check), rope(i)])
  542. if desc == nil: add(result, "char dummy;" & tnl)
  543. else: add(result, desc)
  544. add(result, "};" & tnl)
  545. proc scanCppGenericSlot(pat: string, cursor, outIdx, outStars: var int): bool =
  546. # A helper proc for handling cppimport patterns, involving numeric
  547. # placeholders for generic types (e.g. '0, '**2, etc).
  548. # pre: the cursor must be placed at the ' symbol
  549. # post: the cursor will be placed after the final digit
  550. # false will returned if the input is not recognized as a placeholder
  551. inc cursor
  552. let begin = cursor
  553. while pat[cursor] == '*': inc cursor
  554. if pat[cursor] in Digits:
  555. outIdx = pat[cursor].ord - '0'.ord
  556. outStars = cursor - begin
  557. inc cursor
  558. return true
  559. else:
  560. return false
  561. proc resolveStarsInCppType(typ: PType, idx, stars: int): PType =
  562. # XXX: we should catch this earlier and report it as a semantic error
  563. if idx >= typ.len: internalError "invalid apostrophe type parameter index"
  564. result = typ.sons[idx]
  565. for i in 1..stars:
  566. if result != nil and result.len > 0:
  567. result = if result.kind == tyGenericInst: result.sons[1]
  568. else: result.elemType
  569. proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
  570. # returns only the type's name
  571. var t = origTyp.skipTypes(irrelevantForBackend)
  572. if containsOrIncl(check, t.id):
  573. if not (isImportedCppType(origTyp) or isImportedCppType(t)):
  574. internalError("cannot generate C type for: " & typeToString(origTyp))
  575. # XXX: this BUG is hard to fix -> we need to introduce helper structs,
  576. # but determining when this needs to be done is hard. We should split
  577. # C type generation into an analysis and a code generation phase somehow.
  578. if t.sym != nil: useHeader(m, t.sym)
  579. if t != origTyp and origTyp.sym != nil: useHeader(m, origTyp.sym)
  580. let sig = hashType(origTyp)
  581. result = getTypePre(m, t, sig)
  582. if result != nil:
  583. excl(check, t.id)
  584. return
  585. case t.kind
  586. of tyRef, tyOptAsRef, tyPtr, tyVar:
  587. var star = if t.kind == tyVar and tfVarIsPtr notin origTyp.flags and
  588. compileToCpp(m): "&" else: "*"
  589. var et = origTyp.skipTypes(abstractInst).lastSon
  590. var etB = et.skipTypes(abstractInst)
  591. if etB.kind in {tyArray, tyOpenArray, tyVarargs}:
  592. # this is correct! sets have no proper base type, so we treat
  593. # ``var set[char]`` in `getParamTypeDesc`
  594. et = elemType(etB)
  595. etB = et.skipTypes(abstractInst)
  596. star[0] = '*'
  597. case etB.kind
  598. of tyObject, tyTuple:
  599. if isImportedCppType(etB) and et.kind == tyGenericInst:
  600. result = getTypeDescAux(m, et, check) & star
  601. else:
  602. # no restriction! We have a forward declaration for structs
  603. let name = getTypeForward(m, et, hashType et)
  604. result = name & star
  605. m.typeCache[sig] = result
  606. pushType(m, et)
  607. of tySequence:
  608. # no restriction! We have a forward declaration for structs
  609. let name = getTypeForward(m, et, hashType et)
  610. result = name & "*" & star
  611. m.typeCache[sig] = result
  612. pushType(m, et)
  613. of tyOpt:
  614. if etB.sons[0].kind in {tyObject, tyTuple}:
  615. let name = getTypeForward(m, et, hashType et)
  616. result = name & "*" & star
  617. m.typeCache[sig] = result
  618. pushType(m, et)
  619. elif optKind(etB) == oBool:
  620. let name = getTypeForward(m, et, hashType et)
  621. result = name & "*"
  622. m.typeCache[sig] = result
  623. pushType(m, et)
  624. else:
  625. # else we have a strong dependency :-(
  626. result = getTypeDescAux(m, et, check) & star
  627. m.typeCache[sig] = result
  628. else:
  629. # else we have a strong dependency :-(
  630. result = getTypeDescAux(m, et, check) & star
  631. m.typeCache[sig] = result
  632. of tyOpenArray, tyVarargs:
  633. result = getTypeDescWeak(m, t.sons[0], check) & "*"
  634. m.typeCache[sig] = result
  635. of tyEnum:
  636. result = cacheGetType(m.typeCache, sig)
  637. if result == nil:
  638. result = getTypeName(m, origTyp, sig)
  639. if not (isImportedCppType(t) or
  640. (sfImportc in t.sym.flags and t.sym.magic == mNone)):
  641. m.typeCache[sig] = result
  642. var size: int
  643. if firstOrd(t) < 0:
  644. addf(m.s[cfsTypes], "typedef NI32 $1;$n", [result])
  645. size = 4
  646. else:
  647. size = int(getSize(t))
  648. case size
  649. of 1: addf(m.s[cfsTypes], "typedef NU8 $1;$n", [result])
  650. of 2: addf(m.s[cfsTypes], "typedef NU16 $1;$n", [result])
  651. of 4: addf(m.s[cfsTypes], "typedef NI32 $1;$n", [result])
  652. of 8: addf(m.s[cfsTypes], "typedef NI64 $1;$n", [result])
  653. else: internalError(t.sym.info, "getTypeDescAux: enum")
  654. when false:
  655. let owner = hashOwner(t.sym)
  656. if not gDebugInfo.hasEnum(t.sym.name.s, t.sym.info.line, owner):
  657. var vals: seq[(string, int)] = @[]
  658. for i in countup(0, t.n.len - 1):
  659. assert(t.n.sons[i].kind == nkSym)
  660. let field = t.n.sons[i].sym
  661. vals.add((field.name.s, field.position.int))
  662. gDebugInfo.registerEnum(EnumDesc(size: size, owner: owner, id: t.sym.id,
  663. name: t.sym.name.s, values: vals))
  664. of tyProc:
  665. result = getTypeName(m, origTyp, sig)
  666. m.typeCache[sig] = result
  667. var rettype, desc: Rope
  668. genProcParams(m, t, rettype, desc, check, true, true)
  669. if not isImportedType(t):
  670. if t.callConv != ccClosure: # procedure vars may need a closure!
  671. addf(m.s[cfsTypes], "typedef $1_PTR($2, $3) $4;$n",
  672. [rope(CallingConvToStr[t.callConv]), rettype, result, desc])
  673. else:
  674. addf(m.s[cfsTypes], "typedef struct {$n" &
  675. "N_NIMCALL_PTR($2, ClP_0) $3;$n" &
  676. "void* ClE_0;$n} $1;$n",
  677. [result, rettype, desc])
  678. of tySequence:
  679. # we cannot use getTypeForward here because then t would be associated
  680. # with the name of the struct, not with the pointer to the struct:
  681. result = cacheGetType(m.forwTypeCache, sig)
  682. if result == nil:
  683. result = getTypeName(m, origTyp, sig)
  684. if not isImportedType(t):
  685. addf(m.s[cfsForwardTypes], getForwardStructFormat(m),
  686. [structOrUnion(t), result])
  687. m.forwTypeCache[sig] = result
  688. assert(cacheGetType(m.typeCache, sig) == nil)
  689. m.typeCache[sig] = result & "*"
  690. if not isImportedType(t):
  691. if skipTypes(t.sons[0], typedescInst).kind != tyEmpty:
  692. const
  693. cppSeq = "struct $2 : #TGenericSeq {$n"
  694. cSeq = "struct $2 {$n" &
  695. " #TGenericSeq Sup;$n"
  696. appcg(m, m.s[cfsSeqTypes],
  697. (if m.compileToCpp: cppSeq else: cSeq) &
  698. " $1 data[SEQ_DECL_SIZE];$n" &
  699. "};$n", [getTypeDescAux(m, t.sons[0], check), result])
  700. else:
  701. result = rope("TGenericSeq")
  702. add(result, "*")
  703. of tyOpt:
  704. result = cacheGetType(m.typeCache, sig)
  705. if result == nil:
  706. case optKind(t)
  707. of oBool:
  708. result = cacheGetType(m.forwTypeCache, sig)
  709. if result == nil:
  710. result = getTypeName(m, origTyp, sig)
  711. addf(m.s[cfsForwardTypes], getForwardStructFormat(m),
  712. [structOrUnion(t), result])
  713. m.forwTypeCache[sig] = result
  714. appcg(m, m.s[cfsSeqTypes], "struct $2 {$n" &
  715. " NIM_BOOL Field0;$n" &
  716. " $1 Field1;$n" &
  717. "};$n", [getTypeDescAux(m, t.sons[0], check), result])
  718. of oPtr:
  719. let et = t.sons[0]
  720. if et.kind in {tyTuple, tyObject}:
  721. let name = getTypeForward(m, et, hashType et)
  722. result = name & "*"
  723. pushType(m, et)
  724. else:
  725. result = getTypeDescAux(m, t.sons[0], check) & "*"
  726. of oNil:
  727. result = getTypeDescAux(m, t.sons[0], check)
  728. of oEnum:
  729. result = getTypeName(m, origTyp, sig)
  730. if getSize(t.sons[0]) == 8:
  731. addf(m.s[cfsTypes], "typedef NI64 $1;$n", [result])
  732. else:
  733. addf(m.s[cfsTypes], "typedef NI32 $1;$n", [result])
  734. m.typeCache[sig] = result
  735. of tyArray:
  736. var n: BiggestInt = lengthOrd(t)
  737. if n <= 0: n = 1 # make an array of at least one element
  738. result = getTypeName(m, origTyp, sig)
  739. m.typeCache[sig] = result
  740. if not isImportedType(t):
  741. let foo = getTypeDescAux(m, t.sons[1], check)
  742. addf(m.s[cfsTypes], "typedef $1 $2[$3];$n",
  743. [foo, result, rope(n)])
  744. else: addAbiCheck(m, t, result)
  745. of tyObject, tyTuple:
  746. if isImportedCppType(t) and origTyp.kind == tyGenericInst:
  747. # for instantiated templates we do not go through the type cache as the
  748. # the type cache is not aware of 'tyGenericInst'.
  749. let cppName = getTypeName(m, t, sig)
  750. var i = 0
  751. var chunkStart = 0
  752. while i < cppName.data.len:
  753. if cppName.data[i] == '\'':
  754. var chunkEnd = <i
  755. var idx, stars: int
  756. if scanCppGenericSlot(cppName.data, i, idx, stars):
  757. result.add cppName.data.substr(chunkStart, chunkEnd)
  758. chunkStart = i
  759. let typeInSlot = resolveStarsInCppType(origTyp, idx + 1, stars)
  760. if typeInSlot == nil or typeInSlot.kind == tyVoid:
  761. result.add(~"void")
  762. else:
  763. result.add getTypeDescAux(m, typeInSlot, check)
  764. else:
  765. inc i
  766. if chunkStart != 0:
  767. result.add cppName.data.substr(chunkStart)
  768. else:
  769. result = cppName & "<"
  770. for i in 1 .. origTyp.len-2:
  771. if i > 1: result.add(" COMMA ")
  772. result.add(getTypeDescAux(m, origTyp.sons[i], check))
  773. result.add("> ")
  774. # always call for sideeffects:
  775. assert t.kind != tyTuple
  776. discard getRecordDesc(m, t, result, check)
  777. else:
  778. when false:
  779. if t.sym != nil and t.sym.name.s == "KeyValuePair":
  780. if t == origTyp:
  781. echo "wtf: came here"
  782. writeStackTrace()
  783. quit 1
  784. result = cacheGetType(m.forwTypeCache, sig)
  785. if result == nil:
  786. when false:
  787. if t.sym != nil and t.sym.name.s == "KeyValuePair":
  788. # or {sfImportc, sfExportc} * t.sym.flags == {}:
  789. if t.loc.r != nil:
  790. echo t.kind, " ", hashType t
  791. echo origTyp.kind, " ", sig
  792. assert t.loc.r == nil
  793. result = getTypeName(m, origTyp, sig)
  794. m.forwTypeCache[sig] = result
  795. if not isImportedType(t):
  796. addf(m.s[cfsForwardTypes], getForwardStructFormat(m),
  797. [structOrUnion(t), result])
  798. assert m.forwTypeCache[sig] == result
  799. m.typeCache[sig] = result # always call for sideeffects:
  800. let recdesc = if t.kind != tyTuple: getRecordDesc(m, t, result, check)
  801. else: getTupleDesc(m, t, result, check)
  802. if not isImportedType(t):
  803. add(m.s[cfsTypes], recdesc)
  804. elif tfIncompleteStruct notin t.flags: addAbiCheck(m, t, result)
  805. of tySet:
  806. result = $t.kind & '_' & getTypeName(m, t.lastSon, hashType t.lastSon)
  807. m.typeCache[sig] = result
  808. if not isImportedType(t):
  809. let s = int(getSize(t))
  810. case s
  811. of 1, 2, 4, 8: addf(m.s[cfsTypes], "typedef NU$2 $1;$n", [result, rope(s*8)])
  812. else: addf(m.s[cfsTypes], "typedef NU8 $1[$2];$n",
  813. [result, rope(getSize(t))])
  814. of tyGenericInst, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias,
  815. tyUserTypeClass, tyUserTypeClassInst, tyInferred:
  816. result = getTypeDescAux(m, lastSon(t), check)
  817. else:
  818. internalError("getTypeDescAux(" & $t.kind & ')')
  819. result = nil
  820. # fixes bug #145:
  821. excl(check, t.id)
  822. proc getTypeDesc(m: BModule, typ: PType): Rope =
  823. var check = initIntSet()
  824. result = getTypeDescAux(m, typ, check)
  825. type
  826. TClosureTypeKind = enum
  827. clHalf, clHalfWithEnv, clFull
  828. proc getClosureType(m: BModule, t: PType, kind: TClosureTypeKind): Rope =
  829. assert t.kind == tyProc
  830. var check = initIntSet()
  831. result = getTempName(m)
  832. var rettype, desc: Rope
  833. genProcParams(m, t, rettype, desc, check, declareEnvironment=kind != clHalf)
  834. if not isImportedType(t):
  835. if t.callConv != ccClosure or kind != clFull:
  836. addf(m.s[cfsTypes], "typedef $1_PTR($2, $3) $4;$n",
  837. [rope(CallingConvToStr[t.callConv]), rettype, result, desc])
  838. else:
  839. addf(m.s[cfsTypes], "typedef struct {$n" &
  840. "N_NIMCALL_PTR($2, ClP_0) $3;$n" &
  841. "void* ClE_0;$n} $1;$n",
  842. [result, rettype, desc])
  843. proc finishTypeDescriptions(m: BModule) =
  844. var i = 0
  845. while i < len(m.typeStack):
  846. discard getTypeDesc(m, m.typeStack[i])
  847. inc(i)
  848. template cgDeclFrmt*(s: PSym): string = s.constraint.strVal
  849. proc genProcHeader(m: BModule, prc: PSym): Rope =
  850. var
  851. rettype, params: Rope
  852. genCLineDir(result, prc.info)
  853. # using static is needed for inline procs
  854. if lfExportLib in prc.loc.flags:
  855. if isHeaderFile in m.flags:
  856. result.add "N_LIB_IMPORT "
  857. else:
  858. result.add "N_LIB_EXPORT "
  859. elif prc.typ.callConv == ccInline:
  860. result.add "static "
  861. var check = initIntSet()
  862. fillLoc(prc.loc, locProc, prc.ast[namePos], mangleName(m, prc), OnUnknown)
  863. genProcParams(m, prc.typ, rettype, params, check)
  864. # careful here! don't access ``prc.ast`` as that could reload large parts of
  865. # the object graph!
  866. if prc.constraint.isNil:
  867. addf(result, "$1($2, $3)$4",
  868. [rope(CallingConvToStr[prc.typ.callConv]), rettype, prc.loc.r,
  869. params])
  870. else:
  871. result = prc.cgDeclFrmt % [rettype, prc.loc.r, params]
  872. # ------------------ type info generation -------------------------------------
  873. proc genTypeInfo(m: BModule, t: PType): Rope
  874. proc getNimNode(m: BModule): Rope =
  875. result = "$1[$2]" % [m.typeNodesName, rope(m.typeNodes)]
  876. inc(m.typeNodes)
  877. proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; name, base: Rope) =
  878. var nimtypeKind: int
  879. #allocMemTI(m, typ, name)
  880. if isObjLackingTypeField(typ):
  881. nimtypeKind = ord(tyPureObject)
  882. else:
  883. nimtypeKind = ord(typ.kind)
  884. var size: Rope
  885. if tfIncompleteStruct in typ.flags: size = rope"void*"
  886. else: size = getTypeDesc(m, origType)
  887. addf(m.s[cfsTypeInit3],
  888. "$1.size = sizeof($2);$n" & "$1.kind = $3;$n" & "$1.base = $4;$n",
  889. [name, size, rope(nimtypeKind), base])
  890. # compute type flags for GC optimization
  891. var flags = 0
  892. if not containsGarbageCollectedRef(typ): flags = flags or 1
  893. if not canFormAcycle(typ): flags = flags or 2
  894. #else MessageOut("can contain a cycle: " & typeToString(typ))
  895. if flags != 0:
  896. addf(m.s[cfsTypeInit3], "$1.flags = $2;$n", [name, rope(flags)])
  897. discard cgsym(m, "TNimType")
  898. if isDefined("nimTypeNames"):
  899. addf(m.s[cfsTypeInit3], "$1.name = $2;$n",
  900. [name, makeCstring typeToString(origType, preferName)])
  901. discard cgsym(m, "nimTypeRoot")
  902. addf(m.s[cfsTypeInit3], "$1.nextType = nimTypeRoot; nimTypeRoot=&$1;$n",
  903. [name])
  904. addf(m.s[cfsVars], "TNimType $1;$n", [name])
  905. proc genTypeInfoAux(m: BModule, typ, origType: PType, name: Rope) =
  906. var base: Rope
  907. if sonsLen(typ) > 0 and typ.lastSon != nil:
  908. var x = typ.lastSon
  909. if typ.kind == tyObject: x = x.skipTypes(skipPtrs)
  910. base = genTypeInfo(m, x)
  911. else:
  912. base = rope("0")
  913. genTypeInfoAuxBase(m, typ, origType, name, base)
  914. proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): Rope =
  915. # bugfix: we need to search the type that contains the discriminator:
  916. var objtype = objtype
  917. while lookupInRecord(objtype.n, d.name) == nil:
  918. objtype = objtype.sons[0]
  919. if objtype.sym == nil:
  920. internalError(d.info, "anonymous obj with discriminator")
  921. result = "NimDT_$1_$2" % [rope($hashType(objtype)), rope(d.name.s.mangle)]
  922. proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): Rope =
  923. discard cgsym(m, "TNimNode")
  924. var tmp = discriminatorTableName(m, objtype, d)
  925. result = "TNimNode* $1[$2];$n" % [tmp, rope(lengthOrd(d.typ)+1)]
  926. proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope) =
  927. case n.kind
  928. of nkRecList:
  929. var L = sonsLen(n)
  930. if L == 1:
  931. genObjectFields(m, typ, origType, n.sons[0], expr)
  932. elif L > 0:
  933. var tmp = getTempName(m)
  934. addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, rope(L)])
  935. for i in countup(0, L-1):
  936. var tmp2 = getNimNode(m)
  937. addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, rope(i), tmp2])
  938. genObjectFields(m, typ, origType, n.sons[i], tmp2)
  939. addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n",
  940. [expr, rope(L), tmp])
  941. else:
  942. addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2;$n", [expr, rope(L)])
  943. of nkRecCase:
  944. assert(n.sons[0].kind == nkSym)
  945. var field = n.sons[0].sym
  946. var tmp = discriminatorTableName(m, typ, field)
  947. var L = lengthOrd(field.typ)
  948. assert L > 0
  949. if field.loc.r == nil: fillObjectFields(m, typ)
  950. if field.loc.t == nil:
  951. internalError(n.info, "genObjectFields")
  952. addf(m.s[cfsTypeInit3], "$1.kind = 3;$n" &
  953. "$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" &
  954. "$1.name = $5;$n" & "$1.sons = &$6[0];$n" &
  955. "$1.len = $7;$n", [expr, getTypeDesc(m, origType), field.loc.r,
  956. genTypeInfo(m, field.typ),
  957. makeCString(field.name.s),
  958. tmp, rope(L)])
  959. addf(m.s[cfsData], "TNimNode* $1[$2];$n", [tmp, rope(L+1)])
  960. for i in countup(1, sonsLen(n)-1):
  961. var b = n.sons[i] # branch
  962. var tmp2 = getNimNode(m)
  963. genObjectFields(m, typ, origType, lastSon(b), tmp2)
  964. case b.kind
  965. of nkOfBranch:
  966. if sonsLen(b) < 2:
  967. internalError(b.info, "genObjectFields; nkOfBranch broken")
  968. for j in countup(0, sonsLen(b) - 2):
  969. if b.sons[j].kind == nkRange:
  970. var x = int(getOrdValue(b.sons[j].sons[0]))
  971. var y = int(getOrdValue(b.sons[j].sons[1]))
  972. while x <= y:
  973. addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, rope(x), tmp2])
  974. inc(x)
  975. else:
  976. addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n",
  977. [tmp, rope(getOrdValue(b.sons[j])), tmp2])
  978. of nkElse:
  979. addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n",
  980. [tmp, rope(L), tmp2])
  981. else: internalError(n.info, "genObjectFields(nkRecCase)")
  982. of nkSym:
  983. var field = n.sym
  984. if field.bitsize == 0:
  985. if field.loc.r == nil: fillObjectFields(m, typ)
  986. if field.loc.t == nil:
  987. internalError(n.info, "genObjectFields")
  988. addf(m.s[cfsTypeInit3], "$1.kind = 1;$n" &
  989. "$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" &
  990. "$1.name = $5;$n", [expr, getTypeDesc(m, origType),
  991. field.loc.r, genTypeInfo(m, field.typ), makeCString(field.name.s)])
  992. else: internalError(n.info, "genObjectFields")
  993. proc genObjectInfo(m: BModule, typ, origType: PType, name: Rope) =
  994. if typ.kind == tyObject: genTypeInfoAux(m, typ, origType, name)
  995. else: genTypeInfoAuxBase(m, typ, origType, name, rope("0"))
  996. var tmp = getNimNode(m)
  997. if not isImportedType(typ):
  998. genObjectFields(m, typ, origType, typ.n, tmp)
  999. addf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, tmp])
  1000. var t = typ.sons[0]
  1001. while t != nil:
  1002. t = t.skipTypes(skipPtrs)
  1003. t.flags.incl tfObjHasKids
  1004. t = t.sons[0]
  1005. proc genTupleInfo(m: BModule, typ, origType: PType, name: Rope) =
  1006. genTypeInfoAuxBase(m, typ, typ, name, rope("0"))
  1007. var expr = getNimNode(m)
  1008. var length = sonsLen(typ)
  1009. if length > 0:
  1010. var tmp = getTempName(m)
  1011. addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, rope(length)])
  1012. for i in countup(0, length - 1):
  1013. var a = typ.sons[i]
  1014. var tmp2 = getNimNode(m)
  1015. addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, rope(i), tmp2])
  1016. addf(m.s[cfsTypeInit3], "$1.kind = 1;$n" &
  1017. "$1.offset = offsetof($2, Field$3);$n" &
  1018. "$1.typ = $4;$n" &
  1019. "$1.name = \"Field$3\";$n",
  1020. [tmp2, getTypeDesc(m, origType), rope(i), genTypeInfo(m, a)])
  1021. addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n",
  1022. [expr, rope(length), tmp])
  1023. else:
  1024. addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2;$n",
  1025. [expr, rope(length)])
  1026. addf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, expr])
  1027. proc genEnumInfo(m: BModule, typ: PType, name: Rope) =
  1028. # Type information for enumerations is quite heavy, so we do some
  1029. # optimizations here: The ``typ`` field is never set, as it is redundant
  1030. # anyway. We generate a cstring array and a loop over it. Exceptional
  1031. # positions will be reset after the loop.
  1032. genTypeInfoAux(m, typ, typ, name)
  1033. var nodePtrs = getTempName(m)
  1034. var length = sonsLen(typ.n)
  1035. addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n",
  1036. [nodePtrs, rope(length)])
  1037. var enumNames, specialCases: Rope
  1038. var firstNimNode = m.typeNodes
  1039. var hasHoles = false
  1040. for i in countup(0, length - 1):
  1041. assert(typ.n.sons[i].kind == nkSym)
  1042. var field = typ.n.sons[i].sym
  1043. var elemNode = getNimNode(m)
  1044. if field.ast == nil:
  1045. # no explicit string literal for the enum field, so use field.name:
  1046. add(enumNames, makeCString(field.name.s))
  1047. else:
  1048. add(enumNames, makeCString(field.ast.strVal))
  1049. if i < length - 1: add(enumNames, ", " & tnl)
  1050. if field.position != i or tfEnumHasHoles in typ.flags:
  1051. addf(specialCases, "$1.offset = $2;$n", [elemNode, rope(field.position)])
  1052. hasHoles = true
  1053. var enumArray = getTempName(m)
  1054. var counter = getTempName(m)
  1055. addf(m.s[cfsTypeInit1], "NI $1;$n", [counter])
  1056. addf(m.s[cfsTypeInit1], "static char* NIM_CONST $1[$2] = {$n$3};$n",
  1057. [enumArray, rope(length), enumNames])
  1058. addf(m.s[cfsTypeInit3], "for ($1 = 0; $1 < $2; $1++) {$n" &
  1059. "$3[$1+$4].kind = 1;$n" & "$3[$1+$4].offset = $1;$n" &
  1060. "$3[$1+$4].name = $5[$1];$n" & "$6[$1] = &$3[$1+$4];$n" & "}$n", [counter,
  1061. rope(length), m.typeNodesName, rope(firstNimNode), enumArray, nodePtrs])
  1062. add(m.s[cfsTypeInit3], specialCases)
  1063. addf(m.s[cfsTypeInit3],
  1064. "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n$4.node = &$1;$n",
  1065. [getNimNode(m), rope(length), nodePtrs, name])
  1066. if hasHoles:
  1067. # 1 << 2 is {ntfEnumHole}
  1068. addf(m.s[cfsTypeInit3], "$1.flags = 1<<2;$n", [name])
  1069. proc genSetInfo(m: BModule, typ: PType, name: Rope) =
  1070. assert(typ.sons[0] != nil)
  1071. genTypeInfoAux(m, typ, typ, name)
  1072. var tmp = getNimNode(m)
  1073. addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 0;$n" & "$3.node = &$1;$n",
  1074. [tmp, rope(firstOrd(typ)), name])
  1075. proc genArrayInfo(m: BModule, typ: PType, name: Rope) =
  1076. genTypeInfoAuxBase(m, typ, typ, name, genTypeInfo(m, typ.sons[1]))
  1077. proc fakeClosureType(owner: PSym): PType =
  1078. # we generate the same RTTI as for a tuple[pointer, ref tuple[]]
  1079. result = newType(tyTuple, owner)
  1080. result.rawAddSon(newType(tyPointer, owner))
  1081. var r = newType(tyRef, owner)
  1082. let obj = createObj(owner, owner.info, final=false)
  1083. r.rawAddSon(obj)
  1084. result.rawAddSon(r)
  1085. type
  1086. TTypeInfoReason = enum ## for what do we need the type info?
  1087. tiNew, ## for 'new'
  1088. include ccgtrav
  1089. proc genDeepCopyProc(m: BModule; s: PSym; result: Rope) =
  1090. genProc(m, s)
  1091. addf(m.s[cfsTypeInit3], "$1.deepcopy =(void* (N_RAW_NIMCALL*)(void*))$2;$n",
  1092. [result, s.loc.r])
  1093. proc genTypeInfo(m: BModule, t: PType): Rope =
  1094. let origType = t
  1095. var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses)
  1096. if t.kind == tyOpt:
  1097. return genTypeInfo(m, optLowering(t))
  1098. let sig = hashType(origType)
  1099. result = m.typeInfoMarker.getOrDefault(sig)
  1100. if result != nil:
  1101. return "(&".rope & result & ")".rope
  1102. result = m.g.typeInfoMarker.getOrDefault(sig)
  1103. if result != nil:
  1104. discard cgsym(m, "TNimType")
  1105. discard cgsym(m, "TNimNode")
  1106. addf(m.s[cfsVars], "extern TNimType $1;$n", [result])
  1107. # also store in local type section:
  1108. m.typeInfoMarker[sig] = result
  1109. return "(&".rope & result & ")".rope
  1110. result = "NTI$1_" % [rope($sig)]
  1111. m.typeInfoMarker[sig] = result
  1112. let owner = t.skipTypes(typedescPtrs).owner.getModule
  1113. if owner != m.module:
  1114. # make sure the type info is created in the owner module
  1115. discard genTypeInfo(m.g.modules[owner.position], origType)
  1116. # reference the type info as extern here
  1117. discard cgsym(m, "TNimType")
  1118. discard cgsym(m, "TNimNode")
  1119. addf(m.s[cfsVars], "extern TNimType $1;$n", [result])
  1120. return "(&".rope & result & ")".rope
  1121. m.g.typeInfoMarker[sig] = result
  1122. case t.kind
  1123. of tyEmpty, tyVoid: result = rope"0"
  1124. of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar:
  1125. genTypeInfoAuxBase(m, t, t, result, rope"0")
  1126. of tyStatic:
  1127. if t.n != nil: result = genTypeInfo(m, lastSon t)
  1128. else: internalError("genTypeInfo(" & $t.kind & ')')
  1129. of tyUserTypeClasses:
  1130. internalAssert t.isResolvedUserTypeClass
  1131. return genTypeInfo(m, t.lastSon)
  1132. of tyProc:
  1133. if t.callConv != ccClosure:
  1134. genTypeInfoAuxBase(m, t, t, result, rope"0")
  1135. else:
  1136. let x = fakeClosureType(t.owner)
  1137. genTupleInfo(m, x, x, result)
  1138. of tySequence, tyRef, tyOptAsRef:
  1139. genTypeInfoAux(m, t, t, result)
  1140. if gSelectedGC >= gcMarkAndSweep:
  1141. let markerProc = genTraverseProc(m, origType, sig, tiNew)
  1142. addf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [result, markerProc])
  1143. of tyPtr, tyRange: genTypeInfoAux(m, t, t, result)
  1144. of tyArray: genArrayInfo(m, t, result)
  1145. of tySet: genSetInfo(m, t, result)
  1146. of tyEnum: genEnumInfo(m, t, result)
  1147. of tyObject: genObjectInfo(m, t, origType, result)
  1148. of tyTuple:
  1149. # if t.n != nil: genObjectInfo(m, t, result)
  1150. # else:
  1151. # BUGFIX: use consistently RTTI without proper field names; otherwise
  1152. # results are not deterministic!
  1153. genTupleInfo(m, t, origType, result)
  1154. else: internalError("genTypeInfo(" & $t.kind & ')')
  1155. if t.deepCopy != nil:
  1156. genDeepCopyProc(m, t.deepCopy, result)
  1157. elif origType.deepCopy != nil:
  1158. genDeepCopyProc(m, origType.deepCopy, result)
  1159. result = "(&".rope & result & ")".rope
  1160. proc genTypeSection(m: BModule, n: PNode) =
  1161. discard