ccgcalls.nim 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2015 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. #
  10. # included from cgen.nim
  11. proc leftAppearsOnRightSide(le, ri: PNode): bool =
  12. if le != nil:
  13. for i in 1 ..< ri.len:
  14. let r = ri[i]
  15. if isPartOf(le, r) != arNo: return true
  16. proc hasNoInit(call: PNode): bool {.inline.} =
  17. result = call.sons[0].kind == nkSym and sfNoInit in call.sons[0].sym.flags
  18. proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
  19. callee, params: Rope) =
  20. genLineDir(p, ri)
  21. var pl = callee & ~"(" & params
  22. # getUniqueType() is too expensive here:
  23. var typ = skipTypes(ri.sons[0].typ, abstractInst)
  24. if typ.sons[0] != nil:
  25. if isInvalidReturnType(p.config, typ.sons[0]):
  26. if params != nil: pl.add(~", ")
  27. # beware of 'result = p(result)'. We may need to allocate a temporary:
  28. if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
  29. # Great, we can use 'd':
  30. if d.k == locNone: getTemp(p, typ.sons[0], d, needsInit=true)
  31. elif d.k notin {locTemp} and not hasNoInit(ri):
  32. # reset before pass as 'result' var:
  33. discard "resetLoc(p, d)"
  34. add(pl, addrLoc(p.config, d))
  35. add(pl, ~");$n")
  36. line(p, cpsStmts, pl)
  37. else:
  38. var tmp: TLoc
  39. getTemp(p, typ.sons[0], tmp, needsInit=true)
  40. add(pl, addrLoc(p.config, tmp))
  41. add(pl, ~");$n")
  42. line(p, cpsStmts, pl)
  43. genAssignment(p, d, tmp, {}) # no need for deep copying
  44. else:
  45. add(pl, ~")")
  46. if p.module.compileToCpp:
  47. if lfSingleUse in d.flags:
  48. # do not generate spurious temporaries for C++! For C we're better off
  49. # with them to prevent undefined behaviour and because the codegen
  50. # is free to emit expressions multiple times!
  51. d.k = locCall
  52. d.r = pl
  53. excl d.flags, lfSingleUse
  54. else:
  55. if d.k == locNone and p.splitDecls == 0:
  56. getTempCpp(p, typ.sons[0], d, pl)
  57. else:
  58. if d.k == locNone: getTemp(p, typ.sons[0], d)
  59. var list: TLoc
  60. initLoc(list, locCall, d.lode, OnUnknown)
  61. list.r = pl
  62. genAssignment(p, d, list, {}) # no need for deep copying
  63. else:
  64. if d.k == locNone: getTemp(p, typ.sons[0], d)
  65. assert(d.t != nil) # generate an assignment to d:
  66. var list: TLoc
  67. initLoc(list, locCall, d.lode, OnUnknown)
  68. list.r = pl
  69. genAssignment(p, d, list, {}) # no need for deep copying
  70. else:
  71. add(pl, ~");$n")
  72. line(p, cpsStmts, pl)
  73. proc genBoundsCheck(p: BProc; arr, a, b: TLoc)
  74. proc openArrayLoc(p: BProc, n: PNode): Rope =
  75. var a: TLoc
  76. var q = skipConv(n)
  77. var skipped = false
  78. while q.kind == nkStmtListExpr and q.len > 0:
  79. skipped = true
  80. q = q.lastSon
  81. if getMagic(q) == mSlice:
  82. # magic: pass slice to openArray:
  83. if skipped:
  84. q = skipConv(n)
  85. while q.kind == nkStmtListExpr and q.len > 0:
  86. for i in 0..q.len-2:
  87. genStmts(p, q[i])
  88. q = q.lastSon
  89. var b, c: TLoc
  90. initLocExpr(p, q[1], a)
  91. initLocExpr(p, q[2], b)
  92. initLocExpr(p, q[3], c)
  93. # but first produce the required index checks:
  94. if optBoundsCheck in p.options:
  95. genBoundsCheck(p, a, b, c)
  96. let ty = skipTypes(a.t, abstractVar+{tyPtr})
  97. let dest = getTypeDesc(p.module, n.typ.sons[0])
  98. case ty.kind
  99. of tyArray:
  100. let first = toInt64(firstOrd(p.config, ty))
  101. if first == 0:
  102. result = "($4*)(($1)+($2)), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dest]
  103. else:
  104. result = "($5*)($1)+(($2)-($4)), ($3)-($2)+1" %
  105. [rdLoc(a), rdLoc(b), rdLoc(c), intLiteral(first), dest]
  106. of tyOpenArray, tyVarargs, tyUncheckedArray, tyCString:
  107. result = "($4*)($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dest]
  108. of tyString, tySequence:
  109. if skipTypes(n.typ, abstractInst).kind == tyVar and
  110. not compileToCpp(p.module):
  111. result = "($5*)(*$1)$4+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dataField(p), dest]
  112. else:
  113. result = "($5*)$1$4+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dataField(p), dest]
  114. else:
  115. internalError(p.config, "openArrayLoc: " & typeToString(a.t))
  116. else:
  117. initLocExpr(p, n, a)
  118. case skipTypes(a.t, abstractVar).kind
  119. of tyOpenArray, tyVarargs:
  120. result = "$1, $1Len_0" % [rdLoc(a)]
  121. of tyString, tySequence:
  122. if skipTypes(n.typ, abstractInst).kind == tyVar and
  123. not compileToCpp(p.module):
  124. var t: TLoc
  125. t.r = "(*$1)" % [a.rdLoc]
  126. result = "(*$1)$3, $2" % [a.rdLoc, lenExpr(p, t), dataField(p)]
  127. else:
  128. result = "$1$3, $2" % [a.rdLoc, lenExpr(p, a), dataField(p)]
  129. of tyArray:
  130. result = "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))]
  131. of tyPtr, tyRef:
  132. case lastSon(a.t).kind
  133. of tyString, tySequence:
  134. var t: TLoc
  135. t.r = "(*$1)" % [a.rdLoc]
  136. result = "(*$1)$3, $2" % [a.rdLoc, lenExpr(p, t), dataField(p)]
  137. of tyArray:
  138. result = "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, lastSon(a.t)))]
  139. else:
  140. internalError(p.config, "openArrayLoc: " & typeToString(a.t))
  141. else: internalError(p.config, "openArrayLoc: " & typeToString(a.t))
  142. proc genArgStringToCString(p: BProc, n: PNode): Rope {.inline.} =
  143. var a: TLoc
  144. initLocExpr(p, n.sons[0], a)
  145. result = ropecg(p.module, "#nimToCStringConv($1)", [a.rdLoc])
  146. proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): Rope =
  147. var a: TLoc
  148. if n.kind == nkStringToCString:
  149. result = genArgStringToCString(p, n)
  150. elif skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs}:
  151. var n = if n.kind != nkHiddenAddr: n else: n.sons[0]
  152. result = openArrayLoc(p, n)
  153. elif ccgIntroducedPtr(p.config, param, call[0].typ[0]):
  154. initLocExpr(p, n, a)
  155. result = addrLoc(p.config, a)
  156. elif p.module.compileToCpp and param.typ.kind == tyVar and
  157. n.kind == nkHiddenAddr:
  158. initLocExprSingleUse(p, n.sons[0], a)
  159. # if the proc is 'importc'ed but not 'importcpp'ed then 'var T' still
  160. # means '*T'. See posix.nim for lots of examples that do that in the wild.
  161. let callee = call.sons[0]
  162. if callee.kind == nkSym and
  163. {sfImportc, sfInfixCall, sfCompilerProc} * callee.sym.flags == {sfImportc} and
  164. {lfHeader, lfNoDecl} * callee.sym.loc.flags != {}:
  165. result = addrLoc(p.config, a)
  166. else:
  167. result = rdLoc(a)
  168. else:
  169. initLocExprSingleUse(p, n, a)
  170. result = rdLoc(a)
  171. proc genArgNoParam(p: BProc, n: PNode): Rope =
  172. var a: TLoc
  173. if n.kind == nkStringToCString:
  174. result = genArgStringToCString(p, n)
  175. else:
  176. initLocExprSingleUse(p, n, a)
  177. result = rdLoc(a)
  178. template genParamLoop(params) {.dirty.} =
  179. if i < len(typ):
  180. assert(typ.n.sons[i].kind == nkSym)
  181. let paramType = typ.n.sons[i]
  182. if not paramType.typ.isCompileTimeOnly:
  183. if params != nil: add(params, ~", ")
  184. add(params, genArg(p, ri.sons[i], paramType.sym, ri))
  185. else:
  186. if params != nil: add(params, ~", ")
  187. add(params, genArgNoParam(p, ri.sons[i]))
  188. proc addActualSuffixForHCR(res: var Rope, module: PSym, sym: PSym) =
  189. if sym.flags * {sfImportc, sfNonReloadable} == {} and sym.loc.k == locProc and
  190. (sym.typ.callConv == ccInline or sym.owner.id == module.id):
  191. res = res & "_actual".rope
  192. proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
  193. var op: TLoc
  194. # this is a hotspot in the compiler
  195. initLocExpr(p, ri.sons[0], op)
  196. var params: Rope
  197. # getUniqueType() is too expensive here:
  198. var typ = skipTypes(ri.sons[0].typ, abstractInstOwned)
  199. assert(typ.kind == tyProc)
  200. assert(len(typ) == len(typ.n))
  201. var length = len(ri)
  202. for i in 1 ..< length:
  203. genParamLoop(params)
  204. var callee = rdLoc(op)
  205. if p.hcrOn and ri.sons[0].kind == nkSym:
  206. callee.addActualSuffixForHCR(p.module.module, ri.sons[0].sym)
  207. fixupCall(p, le, ri, d, callee, params)
  208. proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
  209. proc getRawProcType(p: BProc, t: PType): Rope =
  210. result = getClosureType(p.module, t, clHalf)
  211. proc addComma(r: Rope): Rope =
  212. result = if r == nil: r else: r & ~", "
  213. const PatProc = "$1.ClE_0? $1.ClP_0($3$1.ClE_0):(($4)($1.ClP_0))($2)"
  214. const PatIter = "$1.ClP_0($3$1.ClE_0)" # we know the env exists
  215. var op: TLoc
  216. initLocExpr(p, ri.sons[0], op)
  217. var pl: Rope
  218. var typ = skipTypes(ri.sons[0].typ, abstractInst)
  219. assert(typ.kind == tyProc)
  220. var length = len(ri)
  221. for i in 1 ..< length:
  222. assert(len(typ) == len(typ.n))
  223. genParamLoop(pl)
  224. template genCallPattern {.dirty.} =
  225. if tfIterator in typ.flags:
  226. lineF(p, cpsStmts, PatIter & ";$n", [rdLoc(op), pl, pl.addComma, rawProc])
  227. else:
  228. lineF(p, cpsStmts, PatProc & ";$n", [rdLoc(op), pl, pl.addComma, rawProc])
  229. let rawProc = getRawProcType(p, typ)
  230. if typ.sons[0] != nil:
  231. if isInvalidReturnType(p.config, typ.sons[0]):
  232. if len(ri) > 1: add(pl, ~", ")
  233. # beware of 'result = p(result)'. We may need to allocate a temporary:
  234. if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
  235. # Great, we can use 'd':
  236. if d.k == locNone:
  237. getTemp(p, typ.sons[0], d, needsInit=true)
  238. elif d.k notin {locTemp} and not hasNoInit(ri):
  239. # reset before pass as 'result' var:
  240. discard "resetLoc(p, d)"
  241. add(pl, addrLoc(p.config, d))
  242. genCallPattern()
  243. else:
  244. var tmp: TLoc
  245. getTemp(p, typ.sons[0], tmp, needsInit=true)
  246. add(pl, addrLoc(p.config, tmp))
  247. genCallPattern()
  248. genAssignment(p, d, tmp, {}) # no need for deep copying
  249. else:
  250. if d.k == locNone: getTemp(p, typ.sons[0], d)
  251. assert(d.t != nil) # generate an assignment to d:
  252. var list: TLoc
  253. initLoc(list, locCall, d.lode, OnUnknown)
  254. if tfIterator in typ.flags:
  255. list.r = PatIter % [rdLoc(op), pl, pl.addComma, rawProc]
  256. else:
  257. list.r = PatProc % [rdLoc(op), pl, pl.addComma, rawProc]
  258. genAssignment(p, d, list, {}) # no need for deep copying
  259. else:
  260. genCallPattern()
  261. proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
  262. if i < len(typ):
  263. # 'var T' is 'T&' in C++. This means we ignore the request of
  264. # any nkHiddenAddr when it's a 'var T'.
  265. let paramType = typ.n.sons[i]
  266. assert(paramType.kind == nkSym)
  267. if paramType.typ.isCompileTimeOnly:
  268. result = nil
  269. elif typ.sons[i].kind == tyVar and ri.sons[i].kind == nkHiddenAddr:
  270. result = genArgNoParam(p, ri.sons[i][0])
  271. else:
  272. result = genArgNoParam(p, ri.sons[i]) #, typ.n.sons[i].sym)
  273. else:
  274. if tfVarargs notin typ.flags:
  275. localError(p.config, ri.info, "wrong argument count")
  276. result = nil
  277. else:
  278. result = genArgNoParam(p, ri.sons[i])
  279. discard """
  280. Dot call syntax in C++
  281. ======================
  282. so c2nim translates 'this' sometimes to 'T' and sometimes to 'var T'
  283. both of which are wrong, but often more convenient to use.
  284. For manual wrappers it can also be 'ptr T'
  285. Fortunately we know which parameter is the 'this' parameter and so can fix this
  286. mess in the codegen.
  287. now ... if the *argument* is a 'ptr' the codegen shall emit -> and otherwise .
  288. but this only depends on the argument and not on how the 'this' was declared
  289. however how the 'this' was declared affects whether we end up with
  290. wrong 'addr' and '[]' ops...
  291. Since I'm tired I'll enumerate all the cases here:
  292. var
  293. x: ptr T
  294. y: T
  295. proc t(x: T)
  296. x[].t() --> (*x).t() is correct.
  297. y.t() --> y.t() is correct
  298. proc u(x: ptr T)
  299. x.u() --> needs to become x->u()
  300. (addr y).u() --> needs to become y.u()
  301. proc v(x: var T)
  302. --> first skip the implicit 'nkAddr' node
  303. x[].v() --> (*x).v() is correct, but might have been eliminated due
  304. to the nkAddr node! So for this case we need to generate '->'
  305. y.v() --> y.v() is correct
  306. """
  307. proc skipAddrDeref(node: PNode): PNode =
  308. var n = node
  309. var isAddr = false
  310. case n.kind
  311. of nkAddr, nkHiddenAddr:
  312. n = n.sons[0]
  313. isAddr = true
  314. of nkDerefExpr, nkHiddenDeref:
  315. n = n.sons[0]
  316. else: return n
  317. if n.kind == nkObjDownConv: n = n.sons[0]
  318. if isAddr and n.kind in {nkDerefExpr, nkHiddenDeref}:
  319. result = n.sons[0]
  320. elif n.kind in {nkAddr, nkHiddenAddr}:
  321. result = n.sons[0]
  322. else:
  323. result = node
  324. proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
  325. # for better or worse c2nim translates the 'this' argument to a 'var T'.
  326. # However manual wrappers may also use 'ptr T'. In any case we support both
  327. # for convenience.
  328. internalAssert p.config, i < len(typ)
  329. assert(typ.n.sons[i].kind == nkSym)
  330. # if the parameter is lying (tyVar) and thus we required an additional deref,
  331. # skip the deref:
  332. var ri = ri[i]
  333. while ri.kind == nkObjDownConv: ri = ri[0]
  334. let t = typ.sons[i].skipTypes({tyGenericInst, tyAlias, tySink})
  335. if t.kind == tyVar:
  336. let x = if ri.kind == nkHiddenAddr: ri[0] else: ri
  337. if x.typ.kind == tyPtr:
  338. result = genArgNoParam(p, x)
  339. result.add("->")
  340. elif x.kind in {nkHiddenDeref, nkDerefExpr} and x[0].typ.kind == tyPtr:
  341. result = genArgNoParam(p, x[0])
  342. result.add("->")
  343. else:
  344. result = genArgNoParam(p, x)
  345. result.add(".")
  346. elif t.kind == tyPtr:
  347. if ri.kind in {nkAddr, nkHiddenAddr}:
  348. result = genArgNoParam(p, ri[0])
  349. result.add(".")
  350. else:
  351. result = genArgNoParam(p, ri)
  352. result.add("->")
  353. else:
  354. ri = skipAddrDeref(ri)
  355. if ri.kind in {nkAddr, nkHiddenAddr}: ri = ri[0]
  356. result = genArgNoParam(p, ri) #, typ.n.sons[i].sym)
  357. result.add(".")
  358. proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): Rope =
  359. var i = 0
  360. var j = 1
  361. while i < pat.len:
  362. case pat[i]
  363. of '@':
  364. var first = true
  365. for k in j ..< ri.len:
  366. let arg = genOtherArg(p, ri, k, typ)
  367. if arg.len > 0:
  368. if not first:
  369. result.add(~", ")
  370. first = false
  371. result.add arg
  372. inc i
  373. of '#':
  374. if i+1 < pat.len and pat[i+1] in {'+', '@'}:
  375. let ri = ri[j]
  376. if ri.kind in nkCallKinds:
  377. let typ = skipTypes(ri.sons[0].typ, abstractInst)
  378. if pat[i+1] == '+': result.add genArgNoParam(p, ri.sons[0])
  379. result.add(~"(")
  380. if 1 < ri.len:
  381. result.add genOtherArg(p, ri, 1, typ)
  382. for k in j+1 ..< ri.len:
  383. result.add(~", ")
  384. result.add genOtherArg(p, ri, k, typ)
  385. result.add(~")")
  386. else:
  387. localError(p.config, ri.info, "call expression expected for C++ pattern")
  388. inc i
  389. elif i+1 < pat.len and pat[i+1] == '.':
  390. result.add genThisArg(p, ri, j, typ)
  391. inc i
  392. elif i+1 < pat.len and pat[i+1] == '[':
  393. var arg = ri.sons[j].skipAddrDeref
  394. while arg.kind in {nkAddr, nkHiddenAddr, nkObjDownConv}: arg = arg[0]
  395. result.add genArgNoParam(p, arg)
  396. #result.add debugTree(arg, 0, 10)
  397. else:
  398. result.add genOtherArg(p, ri, j, typ)
  399. inc j
  400. inc i
  401. of '\'':
  402. var idx, stars: int
  403. if scanCppGenericSlot(pat, i, idx, stars):
  404. var t = resolveStarsInCppType(typ, idx, stars)
  405. if t == nil: result.add(~"void")
  406. else: result.add(getTypeDesc(p.module, t))
  407. else:
  408. let start = i
  409. while i < pat.len:
  410. if pat[i] notin {'@', '#', '\''}: inc(i)
  411. else: break
  412. if i - 1 >= start:
  413. add(result, substr(pat, start, i - 1))
  414. proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
  415. var op: TLoc
  416. initLocExpr(p, ri.sons[0], op)
  417. # getUniqueType() is too expensive here:
  418. var typ = skipTypes(ri.sons[0].typ, abstractInst)
  419. assert(typ.kind == tyProc)
  420. var length = len(ri)
  421. assert(len(typ) == len(typ.n))
  422. # don't call '$' here for efficiency:
  423. let pat = ri.sons[0].sym.loc.r.data
  424. internalAssert p.config, pat.len > 0
  425. if pat.contains({'#', '(', '@', '\''}):
  426. var pl = genPatternCall(p, ri, pat, typ)
  427. # simpler version of 'fixupCall' that works with the pl+params combination:
  428. var typ = skipTypes(ri.sons[0].typ, abstractInst)
  429. if typ.sons[0] != nil:
  430. if p.module.compileToCpp and lfSingleUse in d.flags:
  431. # do not generate spurious temporaries for C++! For C we're better off
  432. # with them to prevent undefined behaviour and because the codegen
  433. # is free to emit expressions multiple times!
  434. d.k = locCall
  435. d.r = pl
  436. excl d.flags, lfSingleUse
  437. else:
  438. if d.k == locNone: getTemp(p, typ.sons[0], d)
  439. assert(d.t != nil) # generate an assignment to d:
  440. var list: TLoc
  441. initLoc(list, locCall, d.lode, OnUnknown)
  442. list.r = pl
  443. genAssignment(p, d, list, {}) # no need for deep copying
  444. else:
  445. add(pl, ~";$n")
  446. line(p, cpsStmts, pl)
  447. else:
  448. var pl: Rope = nil
  449. #var param = typ.n.sons[1].sym
  450. if 1 < ri.len:
  451. add(pl, genThisArg(p, ri, 1, typ))
  452. add(pl, op.r)
  453. var params: Rope
  454. for i in 2 ..< length:
  455. if params != nil: params.add(~", ")
  456. assert(len(typ) == len(typ.n))
  457. add(params, genOtherArg(p, ri, i, typ))
  458. fixupCall(p, le, ri, d, pl, params)
  459. proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
  460. # generates a crappy ObjC call
  461. var op: TLoc
  462. initLocExpr(p, ri.sons[0], op)
  463. var pl = ~"["
  464. # getUniqueType() is too expensive here:
  465. var typ = skipTypes(ri.sons[0].typ, abstractInst)
  466. assert(typ.kind == tyProc)
  467. var length = len(ri)
  468. assert(len(typ) == len(typ.n))
  469. # don't call '$' here for efficiency:
  470. let pat = ri.sons[0].sym.loc.r.data
  471. internalAssert p.config, pat.len > 0
  472. var start = 3
  473. if ' ' in pat:
  474. start = 1
  475. add(pl, op.r)
  476. if length > 1:
  477. add(pl, ~": ")
  478. add(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri))
  479. start = 2
  480. else:
  481. if length > 1:
  482. add(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri))
  483. add(pl, ~" ")
  484. add(pl, op.r)
  485. if length > 2:
  486. add(pl, ~": ")
  487. add(pl, genArg(p, ri.sons[2], typ.n.sons[2].sym, ri))
  488. for i in start ..< length:
  489. assert(len(typ) == len(typ.n))
  490. if i >= len(typ):
  491. internalError(p.config, ri.info, "varargs for objective C method?")
  492. assert(typ.n.sons[i].kind == nkSym)
  493. var param = typ.n.sons[i].sym
  494. add(pl, ~" ")
  495. add(pl, param.name.s)
  496. add(pl, ~": ")
  497. add(pl, genArg(p, ri.sons[i], param, ri))
  498. if typ.sons[0] != nil:
  499. if isInvalidReturnType(p.config, typ.sons[0]):
  500. if len(ri) > 1: add(pl, ~" ")
  501. # beware of 'result = p(result)'. We always allocate a temporary:
  502. if d.k in {locTemp, locNone}:
  503. # We already got a temp. Great, special case it:
  504. if d.k == locNone: getTemp(p, typ.sons[0], d, needsInit=true)
  505. add(pl, ~"Result: ")
  506. add(pl, addrLoc(p.config, d))
  507. add(pl, ~"];$n")
  508. line(p, cpsStmts, pl)
  509. else:
  510. var tmp: TLoc
  511. getTemp(p, typ.sons[0], tmp, needsInit=true)
  512. add(pl, addrLoc(p.config, tmp))
  513. add(pl, ~"];$n")
  514. line(p, cpsStmts, pl)
  515. genAssignment(p, d, tmp, {}) # no need for deep copying
  516. else:
  517. add(pl, ~"]")
  518. if d.k == locNone: getTemp(p, typ.sons[0], d)
  519. assert(d.t != nil) # generate an assignment to d:
  520. var list: TLoc
  521. initLoc(list, locCall, ri, OnUnknown)
  522. list.r = pl
  523. genAssignment(p, d, list, {}) # no need for deep copying
  524. else:
  525. add(pl, ~"];$n")
  526. line(p, cpsStmts, pl)
  527. proc genCall(p: BProc, e: PNode, d: var TLoc) =
  528. if e.sons[0].typ.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).callConv == ccClosure:
  529. genClosureCall(p, nil, e, d)
  530. elif e.sons[0].kind == nkSym and sfInfixCall in e.sons[0].sym.flags:
  531. genInfixCall(p, nil, e, d)
  532. elif e.sons[0].kind == nkSym and sfNamedParamCall in e.sons[0].sym.flags:
  533. genNamedParamCall(p, e, d)
  534. else:
  535. genPrefixCall(p, nil, e, d)
  536. postStmtActions(p)
  537. proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) =
  538. if ri.sons[0].typ.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).callConv == ccClosure:
  539. genClosureCall(p, le, ri, d)
  540. elif ri.sons[0].kind == nkSym and sfInfixCall in ri.sons[0].sym.flags:
  541. genInfixCall(p, le, ri, d)
  542. elif ri.sons[0].kind == nkSym and sfNamedParamCall in ri.sons[0].sym.flags:
  543. genNamedParamCall(p, ri, d)
  544. else:
  545. genPrefixCall(p, le, ri, d)
  546. postStmtActions(p)