2
0

njvmtcon.pas 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. {
  2. Copyright (c) 2011 by Jonas Maebe
  3. Generates nodes for typed constant declarations
  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 njvmtcon;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,
  22. node,
  23. symtype,symdef,
  24. ngtcon;
  25. type
  26. tarrstringdata = record
  27. arrstring: ansistring;
  28. arrdatastart, arrdatalen: asizeint;
  29. arraybase: tnode;
  30. end;
  31. tjvmtypedconstbuilder = class(tnodetreetypedconstbuilder)
  32. private
  33. procedure tc_flush_arr_strconst(def: tdef);
  34. procedure tc_emit_arr_strconst_ele(val: int64; def: torddef);
  35. protected
  36. arrstringdata: tarrstringdata;
  37. parsingordarray: boolean;
  38. procedure parse_arraydef(def: tarraydef); override;
  39. procedure tc_emit_setdef(def: tsetdef; var node: tnode);override;
  40. procedure tc_emit_orddef(def: torddef; var node: tnode); override;
  41. end;
  42. implementation
  43. uses
  44. globals,widestr,verbose,constexp,
  45. tokens,scanner,pexpr,
  46. defutil,
  47. nbas,ncal,ncon,ncnv,njvmcon;
  48. procedure init_arrstringdata(out data: tarrstringdata);
  49. begin
  50. data.arrstring:='';
  51. data.arrdatastart:=0;
  52. data.arrdatalen:=0;
  53. data.arraybase:=nil;
  54. end;
  55. procedure tjvmtypedconstbuilder.tc_flush_arr_strconst(def: tdef);
  56. var
  57. wstr: pcompilerwidestring;
  58. wc: tcompilerwidechar;
  59. i: longint;
  60. procvariant: string[8];
  61. begin
  62. // convert ansistring to packed unicodestring
  63. initwidestring(wstr);
  64. for i:=1 to length(arrstringdata.arrstring) div 2 do
  65. begin
  66. wc:=tcompilerwidechar(ord(arrstringdata.arrstring[i*2-1]) shl 8 or
  67. ord(arrstringdata.arrstring[i*2]));
  68. concatwidestringchar(wstr,wc);
  69. end;
  70. if odd(length(arrstringdata.arrstring)) then
  71. concatwidestringchar(wstr,
  72. tcompilerwidechar(ord(arrstringdata.arrstring[length(arrstringdata.arrstring)]) shl 8));
  73. if is_char(def) then
  74. procvariant:='ansichar'
  75. else if is_signed(def) then
  76. case def.size of
  77. 1: procvariant:='shortint';
  78. 2: procvariant:='smallint';
  79. 4: procvariant:='longint';
  80. 8: procvariant:='int64';
  81. else
  82. internalerror(2011111301);
  83. end
  84. else
  85. case def.size of
  86. 1: procvariant:='byte';
  87. 2: procvariant:='word';
  88. 4: procvariant:='cardinal';
  89. 8: procvariant:='qword';
  90. else
  91. internalerror(2011111302);
  92. end;
  93. // (const s: unicodestring; var arr: array of shortint; startintdex, len: longint);
  94. addstatement(statmnt,ccallnode.createintern('fpc_tcon_'+procvariant+'_array_from_string',
  95. ccallparanode.create(genintconstnode(arrstringdata.arrdatalen),
  96. ccallparanode.create(genintconstnode(arrstringdata.arrdatastart),
  97. ccallparanode.create(arrstringdata.arraybase.getcopy,
  98. ccallparanode.create(cstringconstnode.createunistr(wstr),nil))))));
  99. inc(arrstringdata.arrdatastart,arrstringdata.arrdatalen);
  100. arrstringdata.arrstring:='';
  101. arrstringdata.arrdatalen:=0;
  102. donewidestring(wstr);
  103. end;
  104. procedure tjvmtypedconstbuilder.tc_emit_arr_strconst_ele(val: int64; def: torddef);
  105. var
  106. elesize: longint;
  107. begin
  108. elesize:=def.size;
  109. inc(arrstringdata.arrdatalen);
  110. case elesize of
  111. 1:
  112. arrstringdata.arrstring:=arrstringdata.arrstring+char(val);
  113. 2:
  114. arrstringdata.arrstring:=arrstringdata.arrstring+char(val shr 8)+char(val and $ff);
  115. 4:
  116. arrstringdata.arrstring:=arrstringdata.arrstring+char((val shr 24))+
  117. char((val shr 16) and $ff)+
  118. char((val shr 8) and $ff)+
  119. char(val and $ff);
  120. 8:
  121. arrstringdata.arrstring:=arrstringdata.arrstring+char((val shr 56))+
  122. char((val shr 48) and $ff)+
  123. char((val shr 40) and $ff)+
  124. char((val shr 32) and $ff)+
  125. char((val shr 24) and $ff)+
  126. char((val shr 16) and $ff)+
  127. char((val shr 8) and $ff)+
  128. char(val and $ff);
  129. end;
  130. { we can't use the full 64kb, because inside the Java class file the
  131. string constant is actually encoded using UTF-8 and it's this UTF-8
  132. encoding that has to fit inside 64kb (and utf-8 encoding of random
  133. data can easily blow up its size by about a third) }
  134. if length(arrstringdata.arrstring)>40000 then
  135. tc_flush_arr_strconst(def);
  136. end;
  137. procedure tjvmtypedconstbuilder.parse_arraydef(def: tarraydef);
  138. var
  139. n: tnode;
  140. i, len: longint;
  141. ca: pbyte;
  142. ch: array[0..1] of char;
  143. old_arrstringdata: tarrstringdata;
  144. old_parsingordarray: boolean;
  145. begin
  146. if is_dynamic_array(def) or
  147. (not is_char(def.elementdef) and
  148. (not is_integer(def.elementdef) or
  149. not(ts_compact_int_array_init in current_settings.targetswitches))) then
  150. begin
  151. inherited;
  152. exit;
  153. end;
  154. old_arrstringdata:=arrstringdata;
  155. init_arrstringdata(arrstringdata);
  156. arrstringdata.arraybase:=basenode.getcopy;
  157. old_parsingordarray:=parsingordarray;
  158. parsingordarray:=true;
  159. if (token=_LKLAMMER) or
  160. not is_char(def.elementdef) then
  161. inherited
  162. else
  163. begin
  164. { array of ansichar -> can be constant char/string; can't use plain
  165. assignment in this case, because it will result in a codepage
  166. conversion }
  167. n:=comp_expr([ef_accept_equal]);
  168. if n.nodetype=stringconstn then
  169. begin
  170. len:=tstringconstnode(n).len;
  171. if (tstringconstnode(n).cst_type in [cst_unicodestring,cst_widestring]) then
  172. inserttypeconv(n,getansistringdef);
  173. if n.nodetype<>stringconstn then
  174. internalerror(2010033003);
  175. ca:=pbyte(tstringconstnode(n).value_str);
  176. { For tp7 the maximum lentgh can be 255 }
  177. if (m_tp7 in current_settings.modeswitches) and
  178. (len>255) then
  179. len:=255;
  180. end
  181. else if is_constcharnode(n) then
  182. begin
  183. ch[0]:=chr(tordconstnode(n).value.uvalue and $ff);
  184. ca:=@ch;
  185. len:=1;
  186. end
  187. else if is_constwidecharnode(n) and (current_settings.sourcecodepage<>CP_UTF8) then
  188. begin
  189. inserttypeconv(n,cansichartype);
  190. if not is_constcharnode(n) then
  191. internalerror(2010033001);
  192. ch[0]:=chr(tordconstnode(n).value.uvalue and $ff);
  193. ca:=@ch;
  194. len:=1;
  195. end
  196. else
  197. begin
  198. Message(parser_e_illegal_expression);
  199. len:=0;
  200. { avoid crash later on }
  201. ch[0]:=#0;
  202. ca:=@ch;
  203. end;
  204. if len>(def.highrange-def.lowrange+1) then
  205. Message(parser_e_string_larger_array);
  206. for i:=0 to def.highrange-def.lowrange do
  207. begin
  208. if i<len then
  209. begin
  210. tc_emit_arr_strconst_ele(pbyte(ca)^,torddef(cansichartype));
  211. inc(ca);
  212. end
  213. else
  214. {Fill the remaining positions with #0.}
  215. tc_emit_arr_strconst_ele(0,torddef(cansichartype));
  216. end;
  217. n.free;
  218. end;
  219. if length(arrstringdata.arrstring)<>0 then
  220. tc_flush_arr_strconst(def.elementdef);
  221. arrstringdata.arraybase.free;
  222. parsingordarray:=old_parsingordarray;
  223. arrstringdata:=old_arrstringdata;
  224. end;
  225. procedure tjvmtypedconstbuilder.tc_emit_setdef(def: tsetdef; var node: tnode);
  226. begin
  227. { indicate that set constant nodes have to be transformed into
  228. constructors here }
  229. if node.nodetype=setconstn then
  230. tjvmsetconstnode(node).setconsttype:=sct_construct;
  231. inherited tc_emit_setdef(def,node);
  232. end;
  233. procedure tjvmtypedconstbuilder.tc_emit_orddef(def: torddef; var node: tnode);
  234. begin
  235. if not parsingordarray then
  236. begin
  237. inherited;
  238. exit;
  239. end;
  240. if node.nodetype<>ordconstn then
  241. internalerror(2011111101);
  242. tc_emit_arr_strconst_ele(tordconstnode(node).value.svalue,def);
  243. basenode.free;
  244. basenode:=nil;
  245. node.free;
  246. node:=nil;
  247. end;
  248. begin
  249. ctypedconstbuilder:=tjvmtypedconstbuilder;
  250. end.