cbuilderexprs.nim 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. proc constType(t: Snippet): Snippet =
  2. # needs manipulation of `t` in nifc
  3. "NIM_CONST " & t
  4. proc constPtrType(t: Snippet): Snippet =
  5. t & "* NIM_CONST"
  6. proc ptrConstType(t: Snippet): Snippet =
  7. "NIM_CONST " & t & "*"
  8. proc ptrType(t: Snippet): Snippet =
  9. t & "*"
  10. proc cppRefType(t: Snippet): Snippet =
  11. t & "&"
  12. const
  13. CallingConvToStr: array[TCallingConvention, string] = ["N_NIMCALL",
  14. "N_STDCALL", "N_CDECL", "N_SAFECALL",
  15. "N_SYSCALL", # this is probably not correct for all platforms,
  16. # but one can #define it to what one wants
  17. "N_INLINE", "N_NOINLINE", "N_FASTCALL", "N_THISCALL", "N_CLOSURE", "N_NOCONV",
  18. "N_NOCONV" #ccMember is N_NOCONV
  19. ]
  20. proc procPtrTypeUnnamed(rettype, params: Snippet): Snippet =
  21. rettype & "(*)" & params
  22. proc procPtrTypeUnnamedNimCall(rettype, params: Snippet): Snippet =
  23. rettype & "(N_RAW_NIMCALL*)" & params
  24. proc procPtrTypeUnnamed(callConv: TCallingConvention, rettype, params: Snippet): Snippet =
  25. CallingConvToStr[callConv] & "_PTR(" & rettype & ", )" & params
  26. type CppCaptureKind = enum None, ByReference, ByCopy
  27. template addCppLambda(builder: var Builder, captures: CppCaptureKind, params: Snippet, body: typed) =
  28. builder.add("[")
  29. case captures
  30. of None: discard
  31. of ByReference: builder.add("&")
  32. of ByCopy: builder.add("=")
  33. builder.add("] ")
  34. builder.add(params)
  35. builder.addLineEndIndent(" {")
  36. body
  37. builder.addLineEndDedent("}")
  38. proc cCast(typ, value: Snippet): Snippet =
  39. "((" & typ & ") " & value & ")"
  40. proc wrapPar(value: Snippet): Snippet =
  41. # used for expression group, no-op on sexp
  42. "(" & value & ")"
  43. proc removeSinglePar(value: Snippet): Snippet =
  44. # removes a single paren layer expected to exist, to silence Wparentheses-equality
  45. assert value[0] == '(' and value[^1] == ')'
  46. value[1..^2]
  47. template addCast(builder: var Builder, typ: Snippet, valueBody: typed) =
  48. ## adds a cast to `typ` with value built by `valueBody`
  49. builder.add "(("
  50. builder.add typ
  51. builder.add ") "
  52. valueBody
  53. builder.add ")"
  54. proc cAddr(value: Snippet): Snippet =
  55. "(&" & value & ")"
  56. proc cLabelAddr(value: TLabel): Snippet =
  57. "&&" & value
  58. proc cDeref(value: Snippet): Snippet =
  59. "(*" & value & ")"
  60. proc subscript(a, b: Snippet): Snippet =
  61. a & "[" & b & "]"
  62. proc dotField(a, b: Snippet): Snippet =
  63. a & "." & b
  64. proc derefField(a, b: Snippet): Snippet =
  65. a & "->" & b
  66. type CallBuilder = object
  67. needsComma: bool
  68. proc initCallBuilder(builder: var Builder, callee: Snippet): CallBuilder =
  69. result = CallBuilder(needsComma: false)
  70. builder.add(callee)
  71. builder.add("(")
  72. const cArgumentSeparator = ", "
  73. proc addArgumentSeparator(builder: var Builder) =
  74. # no-op on NIFC
  75. # used by "single argument" builders
  76. builder.add(cArgumentSeparator)
  77. template addArgument(builder: var Builder, call: var CallBuilder, valueBody: typed) =
  78. if call.needsComma:
  79. builder.addArgumentSeparator()
  80. else:
  81. call.needsComma = true
  82. valueBody
  83. proc finishCallBuilder(builder: var Builder, call: CallBuilder) =
  84. builder.add(")")
  85. template addCall(builder: var Builder, call: out CallBuilder, callee: Snippet, body: typed) =
  86. call = initCallBuilder(builder, callee)
  87. body
  88. finishCallBuilder(builder, call)
  89. proc addCall(builder: var Builder, callee: Snippet, args: varargs[Snippet]) =
  90. builder.add(callee)
  91. builder.add("(")
  92. if args.len != 0:
  93. builder.add(args[0])
  94. for i in 1 ..< args.len:
  95. builder.add(", ")
  96. builder.add(args[i])
  97. builder.add(")")
  98. proc cCall(callee: Snippet, args: varargs[Snippet]): Snippet =
  99. result = callee
  100. result.add("(")
  101. if args.len != 0:
  102. result.add(args[0])
  103. for i in 1 ..< args.len:
  104. result.add(", ")
  105. result.add(args[i])
  106. result.add(")")
  107. proc addSizeof(builder: var Builder, val: Snippet) =
  108. builder.add("sizeof(")
  109. builder.add(val)
  110. builder.add(")")
  111. proc addAlignof(builder: var Builder, val: Snippet) =
  112. builder.add("NIM_ALIGNOF(")
  113. builder.add(val)
  114. builder.add(")")
  115. proc addOffsetof(builder: var Builder, val, member: Snippet) =
  116. builder.add("offsetof(")
  117. builder.add(val)
  118. builder.add(", ")
  119. builder.add(member)
  120. builder.add(")")
  121. template cSizeof(val: Snippet): Snippet =
  122. "sizeof(" & val & ")"
  123. template cAlignof(val: Snippet): Snippet =
  124. "NIM_ALIGNOF(" & val & ")"
  125. template cOffsetof(val, member: Snippet): Snippet =
  126. "offsetof(" & val & ", " & member & ")"
  127. type TypedBinaryOp = enum
  128. Add, Sub, Mul, Div, Mod
  129. Shr, Shl, BitAnd, BitOr, BitXor
  130. const typedBinaryOperators: array[TypedBinaryOp, string] = [
  131. Add: "+",
  132. Sub: "-",
  133. Mul: "*",
  134. Div: "/",
  135. Mod: "%",
  136. Shr: ">>",
  137. Shl: "<<",
  138. BitAnd: "&",
  139. BitOr: "|",
  140. BitXor: "^"
  141. ]
  142. type TypedUnaryOp = enum
  143. Neg, BitNot
  144. const typedUnaryOperators: array[TypedUnaryOp, string] = [
  145. Neg: "-",
  146. BitNot: "~",
  147. ]
  148. type UntypedBinaryOp = enum
  149. LessEqual, LessThan, GreaterEqual, GreaterThan, Equal, NotEqual
  150. And, Or
  151. const untypedBinaryOperators: array[UntypedBinaryOp, string] = [
  152. LessEqual: "<=",
  153. LessThan: "<",
  154. GreaterEqual: ">=",
  155. GreaterThan: ">",
  156. Equal: "==",
  157. NotEqual: "!=",
  158. And: "&&",
  159. Or: "||"
  160. ]
  161. type UntypedUnaryOp = enum
  162. Not
  163. const untypedUnaryOperators: array[UntypedUnaryOp, string] = [
  164. Not: "!"
  165. ]
  166. proc addOp(builder: var Builder, binOp: TypedBinaryOp, t: Snippet, a, b: Snippet) =
  167. builder.add('(')
  168. builder.add(a)
  169. builder.add(' ')
  170. builder.add(typedBinaryOperators[binOp])
  171. builder.add(' ')
  172. builder.add(b)
  173. builder.add(')')
  174. proc addOp(builder: var Builder, unOp: TypedUnaryOp, t: Snippet, a: Snippet) =
  175. builder.add('(')
  176. builder.add(typedUnaryOperators[unOp])
  177. builder.add('(')
  178. builder.add(a)
  179. builder.add("))")
  180. proc addOp(builder: var Builder, binOp: UntypedBinaryOp, a, b: Snippet) =
  181. builder.add('(')
  182. builder.add(a)
  183. builder.add(' ')
  184. builder.add(untypedBinaryOperators[binOp])
  185. builder.add(' ')
  186. builder.add(b)
  187. builder.add(')')
  188. proc addOp(builder: var Builder, unOp: UntypedUnaryOp, a: Snippet) =
  189. builder.add('(')
  190. builder.add(untypedUnaryOperators[unOp])
  191. builder.add('(')
  192. builder.add(a)
  193. builder.add("))")
  194. template cOp(binOp: TypedBinaryOp, t: Snippet, a, b: Snippet): Snippet =
  195. '(' & a & ' ' & typedBinaryOperators[binOp] & ' ' & b & ')'
  196. template cOp(binOp: TypedUnaryOp, t: Snippet, a: Snippet): Snippet =
  197. '(' & typedUnaryOperators[binOp] & '(' & a & "))"
  198. template cOp(binOp: UntypedBinaryOp, a, b: Snippet): Snippet =
  199. '(' & a & ' ' & untypedBinaryOperators[binOp] & ' ' & b & ')'
  200. template cOp(binOp: UntypedUnaryOp, a: Snippet): Snippet =
  201. '(' & untypedUnaryOperators[binOp] & '(' & a & "))"
  202. template cIfExpr(cond, a, b: Snippet): Snippet =
  203. # XXX used for `min` and `max`, maybe add nifc primitives for these
  204. "(" & cond & " ? " & a & " : " & b & ")"
  205. template cUnlikely(val: Snippet): Snippet =
  206. "NIM_UNLIKELY(" & val & ")"