pinline.pas 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. Generates nodes for routines that need compiler support
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit pinline;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. symtype,
  22. node,
  23. globals,
  24. cpuinfo;
  25. function new_dispose_statement(is_new:boolean) : tnode;
  26. function new_function : tnode;
  27. function inline_setlength : tnode;
  28. function inline_setstring : tnode;
  29. function inline_initialize : tnode;
  30. function inline_finalize : tnode;
  31. function inline_copy : tnode;
  32. function inline_insert : tnode;
  33. function inline_delete : tnode;
  34. implementation
  35. uses
  36. { common }
  37. cutils,
  38. { global }
  39. globtype,tokens,verbose,constexp,
  40. systems,
  41. { symtable }
  42. symbase,symconst,symdef,symsym,symtable,defutil,
  43. { pass 1 }
  44. pass_1,htypechk,
  45. nmat,nadd,ncal,nmem,nset,ncnv,ninl,ncon,nld,nflw,nbas,nutils,ngenutil,
  46. { parser }
  47. scanner,
  48. pbase,pexpr,
  49. { codegen }
  50. cgbase
  51. ;
  52. function new_dispose_statement(is_new:boolean) : tnode;
  53. var
  54. newstatement : tstatementnode;
  55. temp : ttempcreatenode;
  56. para : tcallparanode;
  57. p,p2 : tnode;
  58. again : boolean; { dummy for do_proc_call }
  59. destructorname : TIDString;
  60. sym : tsym;
  61. classh : tobjectdef;
  62. callflag : tcallnodeflag;
  63. destructorpos,
  64. storepos : tfileposinfo;
  65. variantdesc : pvariantrecdesc;
  66. found : boolean;
  67. j,i : longint;
  68. variantselectsymbol : tfieldvarsym;
  69. begin
  70. if target_info.system in systems_managed_vm then
  71. message(parser_e_feature_unsupported_for_vm);
  72. consume(_LKLAMMER);
  73. p:=comp_expr([ef_accept_equal]);
  74. { calc return type }
  75. if is_new then
  76. begin
  77. set_varstate(p,vs_written,[]);
  78. valid_for_var(p,true);
  79. end
  80. else
  81. set_varstate(p,vs_readwritten,[vsf_must_be_valid]);
  82. if (m_mac in current_settings.modeswitches) and
  83. is_class(p.resultdef) then
  84. begin
  85. classh:=tobjectdef(p.resultdef);
  86. { make sure we call ObjPas.TObject.Create/Free and not a random }
  87. { create/free method in a macpas descendent object (since those }
  88. { are not supposed to be called automatically when you call }
  89. { new/dispose) }
  90. while assigned(classh.childof) do
  91. classh := classh.childof;
  92. if is_new then
  93. begin
  94. sym:=search_struct_member(classh,'CREATE');
  95. p2 := cloadvmtaddrnode.create(ctypenode.create(p.resultdef));
  96. end
  97. else
  98. begin
  99. sym:=search_struct_member(classh,'FREE');
  100. p2 := p;
  101. end;
  102. if not(assigned(sym)) then
  103. begin
  104. p.free;
  105. if is_new then
  106. p2.free;
  107. new_dispose_statement := cerrornode.create;
  108. consume_all_until(_RKLAMMER);
  109. consume(_RKLAMMER);
  110. exit;
  111. end;
  112. do_member_read(classh,false,sym,p2,again,[],nil);
  113. { we need the real called method }
  114. do_typecheckpass(p2);
  115. if (p2.nodetype=calln) and
  116. assigned(tcallnode(p2).procdefinition) then
  117. begin
  118. if is_new then
  119. begin
  120. if (tcallnode(p2).procdefinition.proctypeoption<>potype_constructor) then
  121. Message(parser_e_expr_have_to_be_constructor_call);
  122. p2.resultdef:=p.resultdef;
  123. p2:=cassignmentnode.create(p,p2);
  124. typecheckpass(p2);
  125. end
  126. else
  127. begin
  128. { Free is not a destructor
  129. if (tcallnode(p2).procdefinition.proctypeoption<>potype_destructor) then
  130. Message(parser_e_expr_have_to_be_destructor_call);
  131. }
  132. end
  133. end
  134. else
  135. internalerror(2005061202);
  136. new_dispose_statement := p2;
  137. end
  138. { constructor,destructor specified }
  139. else if (([m_mac,m_iso,m_extpas]*current_settings.modeswitches)=[]) and
  140. try_to_consume(_COMMA) then
  141. begin
  142. { extended syntax of new and dispose }
  143. { function styled new is handled in factor }
  144. { destructors have no parameters }
  145. destructorname:=pattern;
  146. destructorpos:=current_tokenpos;
  147. consume(_ID);
  148. if is_typeparam(p.resultdef) then
  149. begin
  150. p.free;
  151. p:=factor(false,[]);
  152. p.free;
  153. consume(_RKLAMMER);
  154. new_dispose_statement:=cnothingnode.create;
  155. exit;
  156. end;
  157. if (p.resultdef.typ<>pointerdef) then
  158. begin
  159. Message1(type_e_pointer_type_expected,p.resultdef.typename);
  160. p.free;
  161. p:=factor(false,[]);
  162. p.free;
  163. consume(_RKLAMMER);
  164. new_dispose_statement:=cerrornode.create;
  165. exit;
  166. end;
  167. { first parameter must be an object or class }
  168. if tpointerdef(p.resultdef).pointeddef.typ<>objectdef then
  169. begin
  170. Message(parser_e_pointer_to_class_expected);
  171. p.free;
  172. new_dispose_statement:=factor(false,[]);
  173. consume_all_until(_RKLAMMER);
  174. consume(_RKLAMMER);
  175. exit;
  176. end;
  177. { check, if the first parameter is a pointer to a _class_ }
  178. classh:=tobjectdef(tpointerdef(p.resultdef).pointeddef);
  179. if is_class(classh) then
  180. begin
  181. Message(parser_e_no_new_or_dispose_for_classes);
  182. new_dispose_statement:=factor(false,[]);
  183. consume_all_until(_RKLAMMER);
  184. consume(_RKLAMMER);
  185. exit;
  186. end;
  187. { search cons-/destructor, also in parent classes }
  188. storepos:=current_tokenpos;
  189. current_tokenpos:=destructorpos;
  190. sym:=search_struct_member(classh,destructorname);
  191. current_tokenpos:=storepos;
  192. { the second parameter of new/dispose must be a call }
  193. { to a cons-/destructor }
  194. if (not assigned(sym)) or (sym.typ<>procsym) then
  195. begin
  196. if is_new then
  197. Message(parser_e_expr_have_to_be_constructor_call)
  198. else
  199. Message(parser_e_expr_have_to_be_destructor_call);
  200. p.free;
  201. new_dispose_statement:=cerrornode.create;
  202. end
  203. else
  204. begin
  205. { For new(var,constructor) we need to take a copy because
  206. p is also used in the assignmentn below }
  207. if is_new then
  208. begin
  209. p2:=cderefnode.create(p.getcopy);
  210. include(p2.flags,nf_no_checkpointer);
  211. end
  212. else
  213. p2:=cderefnode.create(p);
  214. do_typecheckpass(p2);
  215. if is_new then
  216. callflag:=cnf_new_call
  217. else
  218. callflag:=cnf_dispose_call;
  219. if is_new then
  220. do_member_read(classh,false,sym,p2,again,[callflag],nil)
  221. else
  222. begin
  223. if not(m_fpc in current_settings.modeswitches) then
  224. do_member_read(classh,false,sym,p2,again,[callflag],nil)
  225. else
  226. begin
  227. p2:=ccallnode.create(nil,tprocsym(sym),sym.owner,p2,[callflag],nil);
  228. { support dispose(p,done()); }
  229. if try_to_consume(_LKLAMMER) then
  230. begin
  231. if not try_to_consume(_RKLAMMER) then
  232. begin
  233. Message(parser_e_no_paras_for_destructor);
  234. consume_all_until(_RKLAMMER);
  235. consume(_RKLAMMER);
  236. end;
  237. end;
  238. end;
  239. end;
  240. { we need the real called method }
  241. do_typecheckpass(p2);
  242. if (p2.nodetype=calln) and
  243. assigned(tcallnode(p2).procdefinition) then
  244. begin
  245. if is_new then
  246. begin
  247. if (tcallnode(p2).procdefinition.proctypeoption<>potype_constructor) then
  248. Message(parser_e_expr_have_to_be_constructor_call);
  249. p2.resultdef:=p.resultdef;
  250. p2:=cassignmentnode.create(p,p2);
  251. end
  252. else
  253. begin
  254. if (tcallnode(p2).procdefinition.proctypeoption<>potype_destructor) then
  255. Message(parser_e_expr_have_to_be_destructor_call);
  256. end;
  257. end
  258. else
  259. begin
  260. if is_new then
  261. CGMessage(parser_e_expr_have_to_be_constructor_call)
  262. else
  263. CGMessage(parser_e_expr_have_to_be_destructor_call);
  264. end;
  265. result:=p2;
  266. end;
  267. end
  268. else
  269. begin
  270. if (p.resultdef.typ<>pointerdef) then
  271. Begin
  272. if is_typeparam(p.resultdef) then
  273. begin
  274. p.free;
  275. consume(_RKLAMMER);
  276. new_dispose_statement:=cnothingnode.create;
  277. exit;
  278. end
  279. else
  280. begin
  281. Message1(type_e_pointer_type_expected,p.resultdef.typename);
  282. new_dispose_statement:=cerrornode.create;
  283. end;
  284. end
  285. else
  286. begin
  287. if (tpointerdef(p.resultdef).pointeddef.typ=objectdef) and
  288. (oo_has_vmt in tobjectdef(tpointerdef(p.resultdef).pointeddef).objectoptions) then
  289. Message(parser_w_use_extended_syntax_for_objects);
  290. if (tpointerdef(p.resultdef).pointeddef.typ=orddef) and
  291. (torddef(tpointerdef(p.resultdef).pointeddef).ordtype=uvoid) then
  292. begin
  293. if (m_tp7 in current_settings.modeswitches) or
  294. (m_delphi in current_settings.modeswitches) then
  295. Message(parser_w_no_new_dispose_on_void_pointers)
  296. else
  297. Message(parser_e_no_new_dispose_on_void_pointers);
  298. end;
  299. { create statements with call to getmem+initialize or
  300. finalize+freemem }
  301. new_dispose_statement:=internalstatements(newstatement);
  302. if is_new then
  303. begin
  304. { create temp for result }
  305. temp := ctempcreatenode.create(p.resultdef,p.resultdef.size,tt_persistent,true);
  306. addstatement(newstatement,temp);
  307. { create call to fpc_getmem }
  308. para := ccallparanode.create(cordconstnode.create
  309. (tpointerdef(p.resultdef).pointeddef.size,s32inttype,true),nil);
  310. addstatement(newstatement,cassignmentnode.create(
  311. ctemprefnode.create(temp),
  312. ccallnode.createintern('fpc_getmem',para)));
  313. { create call to fpc_initialize }
  314. if is_managed_type(tpointerdef(p.resultdef).pointeddef) or
  315. ((m_isolike_io in current_settings.modeswitches) and (tpointerdef(p.resultdef).pointeddef.typ=filedef)) then
  316. addstatement(newstatement,cnodeutils.initialize_data_node(cderefnode.create(ctemprefnode.create(temp)),false));
  317. { copy the temp to the destination }
  318. addstatement(newstatement,cassignmentnode.create(
  319. p,
  320. ctemprefnode.create(temp)));
  321. if (([m_iso,m_extpas]*current_settings.modeswitches)<>[]) and (is_record(tpointerdef(p.resultdef).pointeddef)) then
  322. begin
  323. variantdesc:=trecorddef(tpointerdef(p.resultdef).pointeddef).variantrecdesc;
  324. while (token=_COMMA) and assigned(variantdesc) do
  325. begin
  326. consume(_COMMA);
  327. p2:=factor(false,[]);
  328. do_typecheckpass(p2);
  329. if p2.nodetype=ordconstn then
  330. begin
  331. found:=false;
  332. { we do not have dynamic dfa, so avoid warning on variantselectsymbol below }
  333. variantselectsymbol:=nil;
  334. for i:=0 to high(variantdesc^.branches) do
  335. begin
  336. for j:=0 to high(variantdesc^.branches[i].values) do
  337. if variantdesc^.branches[i].values[j]=tordconstnode(p2).value then
  338. begin
  339. found:=true;
  340. variantselectsymbol:=tfieldvarsym(variantdesc^.variantselector);
  341. variantdesc:=variantdesc^.branches[i].nestedvariant;
  342. break;
  343. end;
  344. if found then
  345. break;
  346. end;
  347. if found then
  348. begin
  349. { if no tag-field is given, do not create an assignment statement for it }
  350. if assigned(variantselectsymbol) then
  351. { setup variant selector }
  352. addstatement(newstatement,cassignmentnode.create(
  353. csubscriptnode.create(variantselectsymbol,
  354. cderefnode.create(ctemprefnode.create(temp))),
  355. p2));
  356. end
  357. else
  358. Message(parser_e_illegal_expression);
  359. end
  360. else
  361. Message(parser_e_illegal_expression);
  362. end;
  363. end;
  364. { release temp }
  365. addstatement(newstatement,ctempdeletenode.create(temp));
  366. end
  367. else
  368. begin
  369. { create call to fpc_finalize }
  370. if is_managed_type(tpointerdef(p.resultdef).pointeddef) then
  371. addstatement(newstatement,cnodeutils.finalize_data_node(cderefnode.create(p.getcopy)));
  372. { create call to fpc_freemem }
  373. para := ccallparanode.create(p,nil);
  374. addstatement(newstatement,ccallnode.createintern('fpc_freemem',para));
  375. end;
  376. end;
  377. end;
  378. consume(_RKLAMMER);
  379. end;
  380. function new_function : tnode;
  381. var
  382. p1,p2 : tnode;
  383. classh : tobjectdef;
  384. srsym : tsym;
  385. srsymtable : TSymtable;
  386. again : boolean; { dummy for do_proc_call }
  387. begin
  388. if target_info.system in systems_managed_vm then
  389. message(parser_e_feature_unsupported_for_vm);
  390. consume(_LKLAMMER);
  391. p1:=factor(false,[]);
  392. if p1.nodetype<>typen then
  393. begin
  394. Message(type_e_type_id_expected);
  395. consume_all_until(_RKLAMMER);
  396. consume(_RKLAMMER);
  397. p1.destroy;
  398. new_function:=cerrornode.create;
  399. exit;
  400. end;
  401. if (p1.resultdef.typ<>pointerdef) then
  402. begin
  403. Message1(type_e_pointer_type_expected,p1.resultdef.typename);
  404. consume_all_until(_RKLAMMER);
  405. consume(_RKLAMMER);
  406. p1.destroy;
  407. new_function:=cerrornode.create;
  408. exit;
  409. end;
  410. if try_to_consume(_RKLAMMER) then
  411. begin
  412. if (tpointerdef(p1.resultdef).pointeddef.typ=objectdef) and
  413. (oo_has_vmt in tobjectdef(tpointerdef(p1.resultdef).pointeddef).objectoptions) then
  414. Message(parser_w_use_extended_syntax_for_objects);
  415. if p1.nodetype=typen then
  416. ttypenode(p1).allowed:=true;
  417. p1:=cinlinenode.create(in_new_x,false,p1);
  418. end
  419. else
  420. begin
  421. consume(_COMMA);
  422. if tpointerdef(p1.resultdef).pointeddef.typ<>objectdef then
  423. begin
  424. Message(parser_e_pointer_to_class_expected);
  425. consume_all_until(_RKLAMMER);
  426. consume(_RKLAMMER);
  427. p1.destroy;
  428. new_function:=cerrornode.create;
  429. exit;
  430. end;
  431. classh:=tobjectdef(tpointerdef(p1.resultdef).pointeddef);
  432. { use the objectdef for loading the VMT }
  433. p2:=p1;
  434. p1:=ctypenode.create(tpointerdef(p1.resultdef).pointeddef);
  435. do_typecheckpass(p1);
  436. { search the constructor also in the symbol tables of
  437. the parents }
  438. afterassignment:=false;
  439. searchsym_in_class(classh,classh,pattern,srsym,srsymtable,[ssf_search_helper]);
  440. consume(_ID);
  441. do_member_read(classh,false,srsym,p1,again,[cnf_new_call],nil);
  442. { we need to know which procedure is called }
  443. do_typecheckpass(p1);
  444. if not(
  445. (p1.nodetype=calln) and
  446. assigned(tcallnode(p1).procdefinition) and
  447. (tcallnode(p1).procdefinition.proctypeoption=potype_constructor)
  448. ) then
  449. Message(parser_e_expr_have_to_be_constructor_call);
  450. { constructors return boolean, update resultdef to return
  451. the pointer to the object }
  452. p1.resultdef:=p2.resultdef;
  453. p2.free;
  454. consume(_RKLAMMER);
  455. end;
  456. new_function:=p1;
  457. end;
  458. function inline_setlength : tnode;
  459. var
  460. paras: tnode;
  461. begin
  462. consume(_LKLAMMER);
  463. paras:=parse_paras(false,false,_RKLAMMER);
  464. consume(_RKLAMMER);
  465. if not assigned(paras) then
  466. begin
  467. result:=cerrornode.create;
  468. CGMessage1(parser_e_wrong_parameter_size,'SetLength');
  469. exit;
  470. end;
  471. result:=cinlinenode.create(in_setlength_x,false,paras);
  472. end;
  473. function inline_setstring : tnode;
  474. var
  475. paras, strpara, pcharpara: tnode;
  476. procname: string;
  477. cp: tstringencoding;
  478. begin
  479. consume(_LKLAMMER);
  480. paras:=parse_paras(false,false,_RKLAMMER);
  481. consume(_RKLAMMER);
  482. procname:='';
  483. if assigned(paras) and
  484. assigned(tcallparanode(paras).right) and
  485. assigned(tcallparanode(tcallparanode(paras).right).right) then
  486. begin
  487. do_typecheckpass(tcallparanode(tcallparanode(paras).right).left);
  488. do_typecheckpass(tcallparanode(tcallparanode(tcallparanode(paras).right).right).left);
  489. pcharpara:=tcallparanode(tcallparanode(paras).right).left;
  490. strpara:=tcallparanode(tcallparanode(tcallparanode(paras).right).right).left;
  491. if strpara.resultdef.typ=stringdef then
  492. begin
  493. { if there are three parameters and the first parameter
  494. ( = paras.right.right) is an ansistring, add a codepage
  495. parameter }
  496. if is_ansistring(strpara.resultdef) then
  497. begin
  498. cp:=tstringdef(strpara.resultdef).encoding;
  499. if (cp=globals.CP_NONE) then
  500. cp:=0;
  501. paras:=ccallparanode.create(genintconstnode(cp),paras);
  502. end;
  503. procname:='fpc_setstring_'+tstringdef(strpara.resultdef).stringtypname;
  504. { decide which version to call based on the second parameter }
  505. if not is_shortstring(strpara.resultdef) then
  506. if is_pwidechar(pcharpara.resultdef) or
  507. is_widechar(pcharpara.resultdef) or
  508. ((pcharpara.resultdef.typ=arraydef) and
  509. is_widechar(tarraydef(pcharpara.resultdef).elementdef)) then
  510. procname:=procname+'_pwidechar'
  511. else
  512. procname:=procname+'_pansichar';
  513. end;
  514. end;
  515. { default version (for error message) in case of missing or wrong
  516. parameters }
  517. if procname='' then
  518. if m_default_unicodestring in current_settings.modeswitches then
  519. procname:='fpc_setstring_unicodestr_pwidechar'
  520. else if m_default_ansistring in current_settings.modeswitches then
  521. procname:='fpc_setstring_ansistr_pansichar'
  522. else
  523. procname:='fpc_setstring_shortstr';
  524. result:=ccallnode.createintern(procname,paras)
  525. end;
  526. function inline_initfinal(isinit: boolean): tnode;
  527. var
  528. newblock,
  529. paras : tnode;
  530. npara,
  531. destppn,
  532. ppn : tcallparanode;
  533. begin
  534. { for easy exiting if something goes wrong }
  535. result := cerrornode.create;
  536. consume(_LKLAMMER);
  537. paras:=parse_paras(false,false,_RKLAMMER);
  538. consume(_RKLAMMER);
  539. ppn:=tcallparanode(paras);
  540. if not assigned(paras) or
  541. (assigned(ppn.right) and
  542. assigned(tcallparanode(ppn.right).right)) then
  543. begin
  544. if isinit then
  545. CGMessage1(parser_e_wrong_parameter_size,'Initialize')
  546. else
  547. CGMessage1(parser_e_wrong_parameter_size,'Finalize');
  548. exit;
  549. end;
  550. { 2 arguments? }
  551. if assigned(ppn.right) then
  552. begin
  553. destppn:=tcallparanode(ppn.right);
  554. { create call to fpc_initialize/finalize_array }
  555. npara:=ccallparanode.create(ctypeconvnode.create
  556. (ppn.left,s32inttype),
  557. ccallparanode.create(caddrnode.create_internal
  558. (crttinode.create(tstoreddef(destppn.left.resultdef),initrtti,rdt_normal)),
  559. ccallparanode.create(caddrnode.create_internal
  560. (destppn.left),nil)));
  561. if isinit then
  562. newblock:=ccallnode.createintern('fpc_initialize_array',npara)
  563. else
  564. newblock:=ccallnode.createintern('fpc_finalize_array',npara);
  565. destppn.left:=nil;
  566. end
  567. else
  568. begin
  569. if isinit then
  570. newblock:=cnodeutils.initialize_data_node(ppn.left,true)
  571. else
  572. newblock:=cnodeutils.finalize_data_node(ppn.left);
  573. end;
  574. ppn.left:=nil;
  575. paras.free;
  576. result.free;
  577. result:=newblock;
  578. end;
  579. function inline_initialize : tnode;
  580. begin
  581. result:=inline_initfinal(true);
  582. end;
  583. function inline_finalize : tnode;
  584. begin
  585. result:=inline_initfinal(false);
  586. end;
  587. function inline_copy_insert_delete(nr:byte;name:string) : tnode;
  588. var
  589. paras : tnode;
  590. { for easy exiting if something goes wrong }
  591. begin
  592. result := cerrornode.create;
  593. consume(_LKLAMMER);
  594. paras:=parse_paras(false,false,_RKLAMMER);
  595. consume(_RKLAMMER);
  596. if not assigned(paras) then
  597. begin
  598. CGMessage1(parser_e_wrong_parameter_size,name);
  599. exit;
  600. end;
  601. result.free;
  602. result:=cinlinenode.create(nr,false,paras);
  603. end;
  604. function inline_copy: tnode;
  605. begin
  606. result:=inline_copy_insert_delete(in_copy_x,'Copy');
  607. end;
  608. function inline_insert: tnode;
  609. begin
  610. result:=inline_copy_insert_delete(in_insert_x_y_z,'Insert');
  611. end;
  612. function inline_delete: tnode;
  613. begin
  614. result:=inline_copy_insert_delete(in_delete_x_y_z,'Delete');
  615. end;
  616. end.