cbuilderdecls.nim 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669
  1. type VarKind = enum
  2. Local
  3. Global
  4. Threadvar
  5. Const
  6. AlwaysConst ## const even on C++
  7. proc addVarHeader(builder: var Builder, kind: VarKind) =
  8. ## adds modifiers for given var kind:
  9. ## Local has no modifier
  10. ## Global has `static` modifier
  11. ## Const has `static NIM_CONST` modifier
  12. ## AlwaysConst has `static const` modifier (NIM_CONST is no-op on C++)
  13. ## Threadvar is unimplemented
  14. case kind
  15. of Local: discard
  16. of Global:
  17. builder.add("static ")
  18. of Const:
  19. builder.add("static NIM_CONST ")
  20. of AlwaysConst:
  21. builder.add("static const ")
  22. of Threadvar:
  23. doAssert false, "unimplemented"
  24. proc addVar(builder: var Builder, kind: VarKind = Local, name: string, typ: Snippet, initializer: Snippet = "") =
  25. ## adds a variable declaration to the builder
  26. builder.addVarHeader(kind)
  27. builder.add(typ)
  28. builder.add(" ")
  29. builder.add(name)
  30. if initializer.len != 0:
  31. builder.add(" = ")
  32. builder.add(initializer)
  33. builder.addLineEnd(";")
  34. template addVarWithType(builder: var Builder, kind: VarKind = Local, name: string, body: typed) =
  35. ## adds a variable declaration to the builder, with the `body` building the type
  36. builder.addVarHeader(kind)
  37. body
  38. builder.add(" ")
  39. builder.add(name)
  40. builder.addLineEnd(";")
  41. template addVarWithInitializer(builder: var Builder, kind: VarKind = Local, name: string,
  42. typ: Snippet, initializerBody: typed) =
  43. ## adds a variable declaration to the builder, with
  44. ## `initializerBody` building the initializer. initializer must be provided
  45. builder.addVarHeader(kind)
  46. builder.add(typ)
  47. builder.add(" ")
  48. builder.add(name)
  49. builder.add(" = ")
  50. initializerBody
  51. builder.addLineEnd(";")
  52. template addVarWithTypeAndInitializer(builder: var Builder, kind: VarKind = Local, name: string,
  53. typeBody, initializerBody: typed) =
  54. ## adds a variable declaration to the builder, with `typeBody` building the type, and
  55. ## `initializerBody` building the initializer. initializer must be provided
  56. builder.addVarHeader(kind)
  57. typeBody
  58. builder.add(" ")
  59. builder.add(name)
  60. builder.add(" = ")
  61. initializerBody
  62. builder.addLineEnd(";")
  63. proc addArrayVar(builder: var Builder, kind: VarKind = Local, name: string, elementType: Snippet, len: int, initializer: Snippet = "") =
  64. ## adds an array variable declaration to the builder
  65. builder.addVarHeader(kind)
  66. builder.add(elementType)
  67. builder.add(" ")
  68. builder.add(name)
  69. builder.add("[")
  70. builder.addIntValue(len)
  71. builder.add("]")
  72. if initializer.len != 0:
  73. builder.add(" = ")
  74. builder.add(initializer)
  75. builder.addLineEnd(";")
  76. template addArrayVarWithInitializer(builder: var Builder, kind: VarKind = Local, name: string, elementType: Snippet, len: int, body: typed) =
  77. ## adds an array variable declaration to the builder with the initializer built according to `body`
  78. builder.addVarHeader(kind)
  79. builder.add(elementType)
  80. builder.add(" ")
  81. builder.add(name)
  82. builder.add("[")
  83. builder.addIntValue(len)
  84. builder.add("] = ")
  85. body
  86. builder.addLineEnd(";")
  87. template addTypedef(builder: var Builder, name: string, typeBody: typed) =
  88. ## adds a typedef declaration to the builder with name `name` and type as
  89. ## built in `typeBody`
  90. builder.add("typedef ")
  91. typeBody
  92. builder.add(" ")
  93. builder.add(name)
  94. builder.addLineEnd(";")
  95. proc addProcTypedef(builder: var Builder, callConv: TCallingConvention, name: string, rettype, params: Snippet) =
  96. builder.add("typedef ")
  97. builder.add(CallingConvToStr[callConv])
  98. builder.add("_PTR(")
  99. builder.add(rettype)
  100. builder.add(", ")
  101. builder.add(name)
  102. builder.add(")")
  103. builder.add(params)
  104. builder.addLineEnd(";")
  105. template addArrayTypedef(builder: var Builder, name: string, len: BiggestInt, typeBody: typed) =
  106. ## adds an array typedef declaration to the builder with name `name`,
  107. ## length `len`, and element type as built in `typeBody`
  108. builder.add("typedef ")
  109. typeBody
  110. builder.add(" ")
  111. builder.add(name)
  112. builder.add("[")
  113. builder.addIntValue(len)
  114. builder.addLineEnd("];")
  115. type
  116. StructInitializerKind = enum
  117. siOrderedStruct ## struct constructor, but without named fields on C
  118. siNamedStruct ## struct constructor, with named fields i.e. C99 designated initializer
  119. siArray ## array constructor
  120. siWrapper ## wrapper for a single field, generates it verbatim
  121. StructInitializer = object
  122. ## context for building struct initializers, i.e. `{ field1, field2 }`
  123. kind: StructInitializerKind
  124. ## if true, fields will not be named, instead values are placed in order
  125. needsComma: bool
  126. proc initStructInitializer(builder: var Builder, kind: StructInitializerKind): StructInitializer =
  127. ## starts building a struct initializer, i.e. braced initializer list
  128. result = StructInitializer(kind: kind, needsComma: false)
  129. if kind != siWrapper:
  130. builder.add("{")
  131. template addField(builder: var Builder, constr: var StructInitializer, name: string, valueBody: typed) =
  132. ## adds a field to a struct initializer, with the value built in `valueBody`
  133. if constr.needsComma:
  134. assert constr.kind != siWrapper, "wrapper constructor cannot have multiple fields"
  135. builder.add(", ")
  136. else:
  137. constr.needsComma = true
  138. case constr.kind
  139. of siArray, siWrapper:
  140. # no name, can just add value
  141. valueBody
  142. of siOrderedStruct:
  143. # no name, can just add value on C
  144. assert name.len != 0, "name has to be given for struct initializer field"
  145. valueBody
  146. of siNamedStruct:
  147. assert name.len != 0, "name has to be given for struct initializer field"
  148. builder.add(".")
  149. builder.add(name)
  150. builder.add(" = ")
  151. valueBody
  152. proc finishStructInitializer(builder: var Builder, constr: StructInitializer) =
  153. ## finishes building a struct initializer
  154. if constr.kind != siWrapper:
  155. builder.add("}")
  156. template addStructInitializer(builder: var Builder, constr: out StructInitializer, kind: StructInitializerKind, body: typed) =
  157. ## builds a struct initializer, i.e. `{ field1, field2 }`
  158. ## a `var StructInitializer` must be declared and passed as a parameter so
  159. ## that it can be used with `addField`
  160. constr = builder.initStructInitializer(kind)
  161. body
  162. builder.finishStructInitializer(constr)
  163. proc addField(obj: var Builder; name, typ: Snippet; isFlexArray: bool = false; initializer: Snippet = "") =
  164. ## adds a field inside a struct/union type
  165. obj.add('\t')
  166. obj.add(typ)
  167. obj.add(" ")
  168. obj.add(name)
  169. if isFlexArray:
  170. obj.add("[SEQ_DECL_SIZE]")
  171. if initializer.len != 0:
  172. obj.add(initializer)
  173. obj.add(";\n")
  174. proc addArrayField(obj: var Builder; name, elementType: Snippet; len: int; initializer: Snippet = "") =
  175. ## adds an array field inside a struct/union type
  176. obj.add('\t')
  177. obj.add(elementType)
  178. obj.add(" ")
  179. obj.add(name)
  180. obj.add("[")
  181. obj.addIntValue(len)
  182. obj.add("]")
  183. if initializer.len != 0:
  184. obj.add(initializer)
  185. obj.add(";\n")
  186. proc addField(obj: var Builder; field: PSym; name, typ: Snippet; isFlexArray: bool = false; initializer: Snippet = "") =
  187. ## adds an field inside a struct/union type, based on an `skField` symbol
  188. obj.add('\t')
  189. if field.alignment > 0:
  190. obj.add("NIM_ALIGN(")
  191. obj.addIntValue(field.alignment)
  192. obj.add(") ")
  193. obj.add(typ)
  194. if sfNoalias in field.flags:
  195. obj.add(" NIM_NOALIAS")
  196. obj.add(" ")
  197. obj.add(name)
  198. if isFlexArray:
  199. obj.add("[SEQ_DECL_SIZE]")
  200. if field.bitsize != 0:
  201. obj.add(":")
  202. obj.addIntValue(field.bitsize)
  203. if initializer.len != 0:
  204. obj.add(initializer)
  205. obj.add(";\n")
  206. proc addProcField(obj: var Builder, callConv: TCallingConvention, name: string, rettype, params: Snippet) =
  207. obj.add(CallingConvToStr[callConv])
  208. obj.add("_PTR(")
  209. obj.add(rettype)
  210. obj.add(", ")
  211. obj.add(name)
  212. obj.add(")")
  213. obj.add(params)
  214. obj.add(";\n")
  215. type
  216. BaseClassKind = enum
  217. ## denotes how and whether or not the base class/RTTI should be stored
  218. bcNone, bcCppInherit, bcSupField, bcNoneRtti, bcNoneTinyRtti
  219. StructBuilderInfo = object
  220. ## context for building `struct` types
  221. baseKind: BaseClassKind
  222. named: bool
  223. preFieldsLen: int
  224. proc structOrUnion(t: PType): Snippet =
  225. let t = t.skipTypes({tyAlias, tySink})
  226. if tfUnion in t.flags: "union"
  227. else: "struct"
  228. proc startSimpleStruct(obj: var Builder; m: BModule; name: string; baseType: Snippet): StructBuilderInfo =
  229. result = StructBuilderInfo(baseKind: bcNone, named: name.len != 0)
  230. obj.add("struct")
  231. if result.named:
  232. obj.add(" ")
  233. obj.add(name)
  234. if baseType.len != 0:
  235. if m.compileToCpp:
  236. result.baseKind = bcCppInherit
  237. else:
  238. result.baseKind = bcSupField
  239. if result.baseKind == bcCppInherit:
  240. obj.add(" : public ")
  241. obj.add(baseType)
  242. obj.add(" ")
  243. obj.add("{\n")
  244. result.preFieldsLen = obj.buf.len
  245. if result.baseKind == bcSupField:
  246. obj.addField(name = "Sup", typ = baseType)
  247. proc finishSimpleStruct(obj: var Builder; m: BModule; info: StructBuilderInfo) =
  248. if info.baseKind == bcNone and info.preFieldsLen == obj.buf.len:
  249. # no fields were added, add dummy field
  250. obj.addField(name = "dummy", typ = CChar)
  251. if info.named:
  252. obj.add("};\n")
  253. else:
  254. obj.add("}")
  255. template addSimpleStruct(obj: var Builder; m: BModule; name: string; baseType: Snippet; body: typed) =
  256. ## builds a struct type not based on a Nim type with fields according to `body`,
  257. ## `name` can be empty to build as a type expression and not a statement
  258. let info = startSimpleStruct(obj, m, name, baseType)
  259. body
  260. finishSimpleStruct(obj, m, info)
  261. proc startStruct(obj: var Builder; m: BModule; t: PType; name: string; baseType: Snippet): StructBuilderInfo =
  262. result = StructBuilderInfo(baseKind: bcNone, named: name.len != 0)
  263. if tfPacked in t.flags:
  264. if hasAttribute in CC[m.config.cCompiler].props:
  265. obj.add(structOrUnion(t))
  266. obj.add(" __attribute__((__packed__))")
  267. else:
  268. obj.add("#pragma pack(push, 1)\n")
  269. obj.add(structOrUnion(t))
  270. else:
  271. obj.add(structOrUnion(t))
  272. if result.named:
  273. obj.add(" ")
  274. obj.add(name)
  275. if t.kind == tyObject:
  276. if t.baseClass == nil:
  277. if lacksMTypeField(t):
  278. result.baseKind = bcNone
  279. elif optTinyRtti in m.config.globalOptions:
  280. result.baseKind = bcNoneTinyRtti
  281. else:
  282. result.baseKind = bcNoneRtti
  283. elif m.compileToCpp:
  284. result.baseKind = bcCppInherit
  285. else:
  286. result.baseKind = bcSupField
  287. elif baseType.len != 0:
  288. if m.compileToCpp:
  289. result.baseKind = bcCppInherit
  290. else:
  291. result.baseKind = bcSupField
  292. if result.baseKind == bcCppInherit:
  293. obj.add(" : public ")
  294. obj.add(baseType)
  295. obj.add(" ")
  296. obj.add("{\n")
  297. result.preFieldsLen = obj.buf.len
  298. case result.baseKind
  299. of bcNone:
  300. # rest of the options add a field or don't need it due to inheritance,
  301. # we need to add the dummy field for uncheckedarray ahead of time
  302. # so that it remains trailing
  303. if t.itemId notin m.g.graph.memberProcsPerType and
  304. t.n != nil and t.n.len == 1 and t.n[0].kind == nkSym and
  305. t.n[0].sym.typ.skipTypes(abstractInst).kind == tyUncheckedArray:
  306. # only consists of flexible array field, add *initial* dummy field
  307. obj.addField(name = "dummy", typ = CChar)
  308. of bcCppInherit: discard
  309. of bcNoneRtti:
  310. obj.addField(name = "m_type", typ = ptrType(cgsymValue(m, "TNimType")))
  311. of bcNoneTinyRtti:
  312. obj.addField(name = "m_type", typ = ptrType(cgsymValue(m, "TNimTypeV2")))
  313. of bcSupField:
  314. obj.addField(name = "Sup", typ = baseType)
  315. proc finishStruct(obj: var Builder; m: BModule; t: PType; info: StructBuilderInfo) =
  316. if info.baseKind == bcNone and info.preFieldsLen == obj.buf.len and
  317. t.itemId notin m.g.graph.memberProcsPerType:
  318. # no fields were added, add dummy field
  319. obj.addField(name = "dummy", typ = CChar)
  320. if info.named:
  321. obj.add("};\n")
  322. else:
  323. obj.add("}")
  324. if tfPacked in t.flags and hasAttribute notin CC[m.config.cCompiler].props:
  325. obj.add("#pragma pack(pop)\n")
  326. template addStruct(obj: var Builder; m: BModule; typ: PType; name: string; baseType: Snippet; body: typed) =
  327. ## builds a struct type directly based on `typ` with fields according to `body`,
  328. ## `name` can be empty to build as a type expression and not a statement
  329. let info = startStruct(obj, m, typ, name, baseType)
  330. body
  331. finishStruct(obj, m, typ, info)
  332. template addFieldWithStructType(obj: var Builder; m: BModule; parentTyp: PType; fieldName: string, body: typed) =
  333. ## adds a field with a `struct { ... }` type, building the fields according to `body`
  334. obj.add('\t')
  335. if tfPacked in parentTyp.flags:
  336. if hasAttribute in CC[m.config.cCompiler].props:
  337. obj.add("struct __attribute__((__packed__)) {\n")
  338. else:
  339. obj.add("#pragma pack(push, 1)\nstruct {")
  340. else:
  341. obj.add("struct {\n")
  342. body
  343. obj.add("} ")
  344. obj.add(fieldName)
  345. obj.add(";\n")
  346. if tfPacked in parentTyp.flags and hasAttribute notin CC[m.config.cCompiler].props:
  347. obj.add("#pragma pack(pop)\n")
  348. template addAnonUnion(obj: var Builder; body: typed) =
  349. ## adds an anonymous union i.e. `union { ... };` with fields according to `body`
  350. obj.add "union{\n"
  351. body
  352. obj.add("};\n")
  353. template addUnionType(obj: var Builder; body: typed) =
  354. ## adds a union type i.e. `union { ... }` with fields according to `body`
  355. obj.add "union{\n"
  356. body
  357. obj.add("}")
  358. type DeclVisibility = enum
  359. None
  360. Extern
  361. ExternC
  362. ImportLib
  363. ExportLib
  364. ExportLibVar
  365. Private
  366. StaticProc
  367. proc addVisibilityPrefix(builder: var Builder, visibility: DeclVisibility) =
  368. # internal proc
  369. case visibility
  370. of None: discard
  371. of Extern:
  372. builder.add("extern ")
  373. of ExternC:
  374. builder.add("NIM_EXTERNC ")
  375. of ImportLib:
  376. builder.add("N_LIB_IMPORT ")
  377. of ExportLib:
  378. builder.add("N_LIB_EXPORT ")
  379. of ExportLibVar:
  380. builder.add("N_LIB_EXPORT_VAR ")
  381. of Private:
  382. builder.add("N_LIB_PRIVATE ")
  383. of StaticProc:
  384. builder.add("static ")
  385. template addDeclWithVisibility(builder: var Builder, visibility: DeclVisibility, declBody: typed) =
  386. ## adds a declaration as in `declBody` with the given visibility
  387. builder.addVisibilityPrefix(visibility)
  388. declBody
  389. type ProcParamBuilder = object
  390. needsComma: bool
  391. proc initProcParamBuilder(builder: var Builder): ProcParamBuilder =
  392. result = ProcParamBuilder(needsComma: false)
  393. builder.add("(")
  394. proc finishProcParamBuilder(builder: var Builder, params: ProcParamBuilder) =
  395. if params.needsComma:
  396. builder.add(")")
  397. else:
  398. builder.add("void)")
  399. template cgDeclFrmt*(s: PSym): string =
  400. s.constraint.strVal
  401. proc addParam(builder: var Builder, params: var ProcParamBuilder, name: string, typ: Snippet) =
  402. if params.needsComma:
  403. builder.add(", ")
  404. else:
  405. params.needsComma = true
  406. builder.add(typ)
  407. builder.add(" ")
  408. builder.add(name)
  409. proc addParam(builder: var Builder, params: var ProcParamBuilder, param: PSym, typ: Snippet) =
  410. if params.needsComma:
  411. builder.add(", ")
  412. else:
  413. params.needsComma = true
  414. var modifiedTyp = typ
  415. if sfNoalias in param.flags:
  416. modifiedTyp.add(" NIM_NOALIAS")
  417. if sfCodegenDecl notin param.flags:
  418. builder.add(modifiedTyp)
  419. builder.add(" ")
  420. builder.add(param.loc.snippet)
  421. else:
  422. builder.add runtimeFormat(param.cgDeclFrmt, [modifiedTyp, param.loc.snippet])
  423. proc addUnnamedParam(builder: var Builder, params: var ProcParamBuilder, typ: Snippet) =
  424. if params.needsComma:
  425. builder.add(", ")
  426. else:
  427. params.needsComma = true
  428. builder.add(typ)
  429. proc addProcTypedParam(builder: var Builder, paramBuilder: var ProcParamBuilder, callConv: TCallingConvention, name: string, rettype, params: Snippet) =
  430. if paramBuilder.needsComma:
  431. builder.add(", ")
  432. else:
  433. paramBuilder.needsComma = true
  434. builder.add(CallingConvToStr[callConv])
  435. builder.add("_PTR(")
  436. builder.add(rettype)
  437. builder.add(", ")
  438. builder.add(name)
  439. builder.add(")")
  440. builder.add(params)
  441. proc addVarargsParam(builder: var Builder, params: var ProcParamBuilder) =
  442. # does not exist in NIFC, needs to be proc pragma
  443. if params.needsComma:
  444. builder.add(", ")
  445. else:
  446. params.needsComma = true
  447. builder.add("...")
  448. template addProcParams(builder: var Builder, params: out ProcParamBuilder, body: typed) =
  449. params = initProcParamBuilder(builder)
  450. body
  451. finishProcParamBuilder(builder, params)
  452. type SimpleProcParam = tuple
  453. name, typ: string
  454. proc cProcParams(params: varargs[SimpleProcParam]): Snippet =
  455. if params.len == 0: return "(void)"
  456. result = "("
  457. for i in 0 ..< params.len:
  458. if i != 0: result.add(", ")
  459. result.add(params[i].typ)
  460. if params[i].name.len != 0:
  461. result.add(" ")
  462. result.add(params[i].name)
  463. result.add(")")
  464. template addProcHeaderWithParams(builder: var Builder, callConv: TCallingConvention,
  465. name: string, rettype: Snippet, paramBuilder: typed) =
  466. # on nifc should build something like (proc name params type pragmas
  467. # with no body given
  468. # or enforce this with secondary builder object
  469. builder.add(CallingConvToStr[callConv])
  470. builder.add("(")
  471. builder.add(rettype)
  472. builder.add(", ")
  473. builder.add(name)
  474. builder.add(")")
  475. paramBuilder
  476. proc addProcHeader(builder: var Builder, callConv: TCallingConvention,
  477. name: string, rettype, params: Snippet) =
  478. # on nifc should build something like (proc name params type pragmas
  479. # with no body given
  480. # or enforce this with secondary builder object
  481. addProcHeaderWithParams(builder, callConv, name, rettype):
  482. builder.add(params)
  483. proc addProcHeader(builder: var Builder, name: string, rettype, params: Snippet, isConstructor = false) =
  484. # no callconv
  485. builder.add(rettype)
  486. builder.add(" ")
  487. if isConstructor:
  488. builder.add("__attribute__((constructor)) ")
  489. builder.add(name)
  490. builder.add(params)
  491. proc addProcHeader(builder: var Builder, m: BModule, prc: PSym, name: string, params, rettype: Snippet, addAttributes: bool) =
  492. # on nifc should build something like (proc name params type pragmas
  493. # with no body given
  494. # or enforce this with secondary builder object
  495. let noreturn = isNoReturn(m, prc)
  496. if sfPure in prc.flags and hasDeclspec in extccomp.CC[m.config.cCompiler].props:
  497. builder.add("__declspec(naked) ")
  498. if noreturn and hasDeclspec in extccomp.CC[m.config.cCompiler].props:
  499. builder.add("__declspec(noreturn) ")
  500. builder.add(CallingConvToStr[prc.typ.callConv])
  501. builder.add("(")
  502. builder.add(rettype)
  503. builder.add(", ")
  504. builder.add(name)
  505. builder.add(")")
  506. builder.add(params)
  507. if addAttributes:
  508. if sfPure in prc.flags and hasAttribute in extccomp.CC[m.config.cCompiler].props:
  509. builder.add(" __attribute__((naked))")
  510. if noreturn and hasAttribute in extccomp.CC[m.config.cCompiler].props:
  511. builder.add(" __attribute__((noreturn))")
  512. proc finishProcHeaderAsProto(builder: var Builder) =
  513. builder.addLineEnd(";")
  514. template finishProcHeaderWithBody(builder: var Builder, body: typed) =
  515. builder.addLineEndIndent(" {")
  516. body
  517. builder.addLineEndDedent("}")
  518. builder.addNewline
  519. proc addProcVar(builder: var Builder, m: BModule, prc: PSym, name: string, params, rettype: Snippet,
  520. isStatic = false, ignoreAttributes = false) =
  521. # on nifc, builds full variable
  522. if isStatic:
  523. builder.add("static ")
  524. let noreturn = isNoReturn(m, prc)
  525. if not ignoreAttributes:
  526. if sfPure in prc.flags and hasDeclspec in extccomp.CC[m.config.cCompiler].props:
  527. builder.add("__declspec(naked) ")
  528. if noreturn and hasDeclspec in extccomp.CC[m.config.cCompiler].props:
  529. builder.add("__declspec(noreturn) ")
  530. builder.add(CallingConvToStr[prc.typ.callConv])
  531. builder.add("_PTR(")
  532. builder.add(rettype)
  533. builder.add(", ")
  534. builder.add(name)
  535. builder.add(")")
  536. builder.add(params)
  537. if not ignoreAttributes:
  538. if sfPure in prc.flags and hasAttribute in extccomp.CC[m.config.cCompiler].props:
  539. builder.add(" __attribute__((naked))")
  540. if noreturn and hasAttribute in extccomp.CC[m.config.cCompiler].props:
  541. builder.add(" __attribute__((noreturn))")
  542. # ensure we are just adding a variable:
  543. builder.addLineEnd(";")
  544. proc addProcVar(builder: var Builder, callConv: TCallingConvention,
  545. name: string, params, rettype: Snippet,
  546. isStatic = false, isVolatile = false) =
  547. # on nifc, builds full variable
  548. if isStatic:
  549. builder.add("static ")
  550. builder.add(CallingConvToStr[callConv])
  551. builder.add("_PTR(")
  552. builder.add(rettype)
  553. builder.add(", ")
  554. if isVolatile:
  555. builder.add("volatile ")
  556. builder.add(name)
  557. builder.add(")")
  558. builder.add(params)
  559. # ensure we are just adding a variable:
  560. builder.addLineEnd(";")
  561. proc addProcVar(builder: var Builder,
  562. name: string, params, rettype: Snippet,
  563. isStatic = false, isVolatile = false) =
  564. # no callconv
  565. if isStatic:
  566. builder.add("static ")
  567. builder.add(rettype)
  568. builder.add(" (*")
  569. if isVolatile:
  570. builder.add("volatile ")
  571. builder.add(name)
  572. builder.add(")")
  573. builder.add(params)
  574. # ensure we are just adding a variable:
  575. builder.addLineEnd(";")
  576. type VarInitializerKind = enum
  577. Assignment, CppConstructor
  578. proc addVar(builder: var Builder, m: BModule, s: PSym, name: string, typ: Snippet, kind = Local, visibility: DeclVisibility = None, initializer: Snippet = "", initializerKind: VarInitializerKind = Assignment) =
  579. if sfCodegenDecl in s.flags:
  580. builder.add(runtimeFormat(s.cgDeclFrmt, [typ, name]))
  581. if initializer.len != 0:
  582. if initializerKind == Assignment:
  583. builder.add(" = ")
  584. builder.add(initializer)
  585. builder.addLineEnd(";")
  586. return
  587. if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0:
  588. builder.add("NIM_ALIGN(" & $s.alignment & ") ")
  589. builder.addVisibilityPrefix(visibility)
  590. if kind == Threadvar:
  591. if optThreads in m.config.globalOptions:
  592. let sym = s.typ.sym
  593. if sym != nil and sfCppNonPod in sym.flags:
  594. builder.add("NIM_THREAD_LOCAL ")
  595. else: builder.add("NIM_THREADVAR ")
  596. else:
  597. builder.addVarHeader(kind)
  598. builder.add(typ)
  599. if sfRegister in s.flags: builder.add(" register")
  600. if sfVolatile in s.flags: builder.add(" volatile")
  601. if sfNoalias in s.flags: builder.add(" NIM_NOALIAS")
  602. builder.add(" ")
  603. builder.add(name)
  604. if initializer.len != 0:
  605. if initializerKind == Assignment:
  606. builder.add(" = ")
  607. builder.add(initializer)
  608. builder.addLineEnd(";")
  609. proc addInclude(builder: var Builder, value: Snippet) =
  610. builder.addLineEnd("#include " & value)