cbuilderstmts.nim 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. template addAssignmentWithValue(builder: var Builder, lhs: Snippet, valueBody: typed) =
  2. builder.add(lhs)
  3. builder.add(" = ")
  4. valueBody
  5. builder.addLineEnd(";")
  6. template addFieldAssignmentWithValue(builder: var Builder, lhs: Snippet, name: string, valueBody: typed) =
  7. builder.add(lhs)
  8. builder.add("." & name & " = ")
  9. valueBody
  10. builder.addLineEnd(";")
  11. template addAssignment(builder: var Builder, lhs, rhs: Snippet) =
  12. builder.addAssignmentWithValue(lhs):
  13. builder.add(rhs)
  14. template addFieldAssignment(builder: var Builder, lhs: Snippet, name: string, rhs: Snippet) =
  15. builder.addFieldAssignmentWithValue(lhs, name):
  16. builder.add(rhs)
  17. template addMutualFieldAssignment(builder: var Builder, lhs, rhs: Snippet, name: string) =
  18. builder.addFieldAssignmentWithValue(lhs, name):
  19. builder.add(rhs)
  20. builder.add("." & name)
  21. template addAssignment(builder: var Builder, lhs: Snippet, rhs: int | int64 | uint64 | Int128) =
  22. builder.addAssignmentWithValue(lhs):
  23. builder.addIntValue(rhs)
  24. template addFieldAssignment(builder: var Builder, lhs: Snippet, name: string, rhs: int | int64 | uint64 | Int128) =
  25. builder.addFieldAssignmentWithValue(lhs, name):
  26. builder.addIntValue(rhs)
  27. template addDerefFieldAssignment(builder: var Builder, lhs: Snippet, name: string, rhs: Snippet) =
  28. builder.add(lhs)
  29. builder.add("->" & name & " = ")
  30. builder.add(rhs)
  31. builder.addLineEnd(";")
  32. template addSubscriptAssignment(builder: var Builder, lhs: Snippet, index: Snippet, rhs: Snippet) =
  33. builder.add(lhs)
  34. builder.add("[" & index & "] = ")
  35. builder.add(rhs)
  36. builder.addLineEnd(";")
  37. template addStmt(builder: var Builder, stmtBody: typed) =
  38. ## makes an expression built by `stmtBody` into a statement
  39. stmtBody
  40. builder.addLineEnd(";")
  41. proc addCallStmt(builder: var Builder, callee: Snippet, args: varargs[Snippet]) =
  42. builder.addStmt():
  43. builder.addCall(callee, args)
  44. # XXX blocks need indent tracker in `Builder` object
  45. template addSingleIfStmt(builder: var Builder, cond: Snippet, body: typed) =
  46. builder.add("if (")
  47. builder.add(cond)
  48. builder.addLineEndIndent(") {")
  49. body
  50. builder.addLineEndDedent("}")
  51. template addSingleIfStmtWithCond(builder: var Builder, condBody: typed, body: typed) =
  52. builder.add("if (")
  53. condBody
  54. builder.addLineEndIndent(") {")
  55. body
  56. builder.addLineEndDedent("}")
  57. proc initIfStmt(builder: var Builder): IfBuilder =
  58. IfBuilder(state: WaitingIf)
  59. proc finishIfStmt(builder: var Builder, stmt: IfBuilder) =
  60. assert stmt.state != InBlock
  61. builder.addNewline()
  62. template addIfStmt(builder: var Builder, stmt: out IfBuilder, body: typed) =
  63. stmt = initIfStmt(builder)
  64. body
  65. finishIfStmt(builder, stmt)
  66. proc initElifBranch(builder: var Builder, stmt: var IfBuilder, cond: Snippet) =
  67. case stmt.state
  68. of WaitingIf:
  69. builder.add("if (")
  70. of WaitingElseIf:
  71. builder.add(" else if (")
  72. else: assert false, $stmt.state
  73. builder.add(cond)
  74. builder.addLineEndIndent(") {")
  75. stmt.state = InBlock
  76. proc initElseBranch(builder: var Builder, stmt: var IfBuilder) =
  77. assert stmt.state == WaitingElseIf, $stmt.state
  78. builder.addLineEndIndent(" else {")
  79. stmt.state = InBlock
  80. proc finishBranch(builder: var Builder, stmt: var IfBuilder) =
  81. builder.addDedent("}")
  82. stmt.state = WaitingElseIf
  83. template addElifBranch(builder: var Builder, stmt: var IfBuilder, cond: Snippet, body: typed) =
  84. initElifBranch(builder, stmt, cond)
  85. body
  86. finishBranch(builder, stmt)
  87. template addElseBranch(builder: var Builder, stmt: var IfBuilder, body: typed) =
  88. initElseBranch(builder, stmt)
  89. body
  90. finishBranch(builder, stmt)
  91. proc initForRange(builder: var Builder, i, start, bound: Snippet, inclusive: bool = false) =
  92. builder.add("for (")
  93. builder.add(i)
  94. builder.add(" = ")
  95. builder.add(start)
  96. builder.add("; ")
  97. builder.add(i)
  98. if inclusive:
  99. builder.add(" <= ")
  100. else:
  101. builder.add(" < ")
  102. builder.add(bound)
  103. builder.add("; ")
  104. builder.add(i)
  105. builder.addLineEndIndent("++) {")
  106. proc initForStep(builder: var Builder, i, start, bound, step: Snippet, inclusive: bool = false) =
  107. builder.add("for (")
  108. builder.add(i)
  109. builder.add(" = ")
  110. builder.add(start)
  111. builder.add("; ")
  112. builder.add(i)
  113. if inclusive:
  114. builder.add(" <= ")
  115. else:
  116. builder.add(" < ")
  117. builder.add(bound)
  118. builder.add("; ")
  119. builder.add(i)
  120. builder.add(" += ")
  121. builder.add(step)
  122. builder.addLineEndIndent(") {")
  123. proc finishFor(builder: var Builder) {.inline.} =
  124. builder.addLineEndDedent("}")
  125. template addForRangeExclusive(builder: var Builder, i, start, bound: Snippet, body: typed) =
  126. initForRange(builder, i, start, bound, false)
  127. body
  128. finishFor(builder)
  129. template addForRangeInclusive(builder: var Builder, i, start, bound: Snippet, body: typed) =
  130. initForRange(builder, i, start, bound, true)
  131. body
  132. finishFor(builder)
  133. template addSwitchStmt(builder: var Builder, val: Snippet, body: typed) =
  134. builder.add("switch (")
  135. builder.add(val)
  136. builder.addLineEnd(") {") # no indent
  137. body
  138. builder.addLineEnd("}")
  139. template addSingleSwitchCase(builder: var Builder, val: Snippet, body: typed) =
  140. builder.add("case ")
  141. builder.add(val)
  142. builder.addLineEndIndent(":")
  143. body
  144. builder.addLineEndDedent("")
  145. type
  146. SwitchCaseState = enum
  147. None, Of, Else, Finished
  148. SwitchCaseBuilder = object
  149. state: SwitchCaseState
  150. proc addCase(builder: var Builder, info: var SwitchCaseBuilder, val: Snippet) =
  151. if info.state != Of:
  152. assert info.state == None
  153. info.state = Of
  154. builder.add("case ")
  155. builder.add(val)
  156. builder.addLineEndIndent(":")
  157. proc addCaseRange(builder: var Builder, info: var SwitchCaseBuilder, first, last: Snippet) =
  158. if info.state != Of:
  159. assert info.state == None
  160. info.state = Of
  161. builder.add("case ")
  162. builder.add(first)
  163. builder.add(" ... ")
  164. builder.add(last)
  165. builder.addLineEndIndent(":")
  166. proc addCaseElse(builder: var Builder, info: var SwitchCaseBuilder) =
  167. assert info.state == None
  168. info.state = Else
  169. builder.addLineEndIndent("default:")
  170. template addSwitchCase(builder: var Builder, info: out SwitchCaseBuilder, caseBody, body: typed) =
  171. info = SwitchCaseBuilder(state: None)
  172. caseBody
  173. info.state = Finished
  174. body
  175. builder.addLineEndDedent("")
  176. template addSwitchElse(builder: var Builder, body: typed) =
  177. builder.addLineEndIndent("default:")
  178. body
  179. builder.addLineEndDedent("")
  180. proc addBreak(builder: var Builder) =
  181. builder.addLineEnd("break;")
  182. type ScopeBuilder = object
  183. inside: bool
  184. proc initScope(builder: var Builder): ScopeBuilder =
  185. builder.addLineEndIndent("{")
  186. result = ScopeBuilder(inside: true)
  187. proc finishScope(builder: var Builder, scope: var ScopeBuilder) =
  188. assert scope.inside, "scope not inited"
  189. builder.addLineEndDedent("}")
  190. scope.inside = false
  191. template addScope(builder: var Builder, body: typed) =
  192. builder.addLineEndIndent("{")
  193. body
  194. builder.addLineEndDedent("}")
  195. type WhileBuilder = object
  196. inside: bool
  197. proc initWhileStmt(builder: var Builder, cond: Snippet): WhileBuilder =
  198. builder.add("while (")
  199. builder.add(cond)
  200. builder.addLineEndIndent(") {")
  201. result = WhileBuilder(inside: true)
  202. proc finishWhileStmt(builder: var Builder, stmt: var WhileBuilder) =
  203. assert stmt.inside, "while stmt not inited"
  204. builder.addLineEndDedent("}")
  205. stmt.inside = false
  206. template addWhileStmt(builder: var Builder, cond: Snippet, body: typed) =
  207. builder.add("while (")
  208. builder.add(cond)
  209. builder.addLineEndIndent(") {")
  210. body
  211. builder.addLineEndDedent("}")
  212. proc addLabel(builder: var Builder, name: TLabel) =
  213. builder.add(name)
  214. builder.addLineEnd(": ;")
  215. proc addReturn(builder: var Builder) =
  216. builder.addLineEnd("return;")
  217. proc addReturn(builder: var Builder, value: Snippet) =
  218. builder.add("return ")
  219. builder.add(value)
  220. builder.addLineEnd(";")
  221. proc addGoto(builder: var Builder, label: TLabel) =
  222. builder.add("goto ")
  223. builder.add(label)
  224. builder.addLineEnd(";")
  225. proc addComputedGoto(builder: var Builder, value: Snippet) =
  226. builder.add("goto *")
  227. builder.add(value)
  228. builder.addLineEnd(";")
  229. proc addIncr(builder: var Builder, val: Snippet) =
  230. builder.add(val)
  231. builder.addLineEnd("++;")
  232. proc addDecr(builder: var Builder, val: Snippet) =
  233. builder.add(val)
  234. builder.addLineEnd("--;")
  235. proc addInPlaceOp(builder: var Builder, binOp: TypedBinaryOp, t: Snippet, a, b: Snippet) =
  236. builder.add(a)
  237. builder.add(' ')
  238. builder.add(typedBinaryOperators[binOp])
  239. builder.add("= ")
  240. builder.add(b)
  241. builder.addLineEnd(";")
  242. proc addInPlaceOp(builder: var Builder, binOp: UntypedBinaryOp, a, b: Snippet) =
  243. builder.add(a)
  244. builder.add(' ')
  245. builder.add(untypedBinaryOperators[binOp])
  246. builder.add("= ")
  247. builder.add(b)
  248. builder.addLineEnd(";")
  249. proc cInPlaceOp(binOp: TypedBinaryOp, t: Snippet, a, b: Snippet): Snippet =
  250. result = ""
  251. result.add(a)
  252. result.add(' ')
  253. result.add(typedBinaryOperators[binOp])
  254. result.add("= ")
  255. result.add(b)
  256. result.add(";\n")
  257. proc cInPlaceOp(binOp: UntypedBinaryOp, a, b: Snippet): Snippet =
  258. result = ""
  259. result.add(a)
  260. result.add(' ')
  261. result.add(untypedBinaryOperators[binOp])
  262. result.add("= ")
  263. result.add(b)
  264. result.add(";\n")
  265. template addCPragma(builder: var Builder, val: Snippet) =
  266. builder.addNewline()
  267. builder.add("#pragma ")
  268. builder.add(val)
  269. builder.addNewline()
  270. proc addDiscard(builder: var Builder, val: Snippet) =
  271. builder.add("(void)")
  272. builder.add(val)
  273. builder.addLineEnd(";")