PageRenderTime 43ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/src/boss_db_pmod_pt.erl

http://github.com/evanmiller/boss_db
Erlang | 471 lines | 372 code | 44 blank | 55 comment | 10 complexity | 2e817db7d8cf30a9ca69f8bd0e53793e MD5 | raw file
Possible License(s): MIT
  1. %%
  2. %% %CopyrightBegin%
  3. %%
  4. %% Copyright Ericsson AB 2013. All Rights Reserved.
  5. %%
  6. %% The contents of this file are subject to the Erlang Public License,
  7. %% Version 1.1, (the "License"); you may not use this file except in
  8. %% compliance with the License. You should have received a copy of the
  9. %% Erlang Public License along with this software. If not, it can be
  10. %% retrieved online at http://www.erlang.org/.
  11. %%
  12. %% Software distributed under the License is distributed on an "AS IS"
  13. %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  14. %% the License for the specific language governing rights and limitations
  15. %% under the License.
  16. %%
  17. %% %CopyrightEnd%
  18. %%
  19. -module(boss_db_pmod_pt).
  20. -export([parse_transform/2,
  21. format_error/1]).
  22. %% Expand function definition forms of parameterized module.
  23. %% The code is based on the code in sys_expand_pmod which used to be
  24. %% included in the compiler, but details are different because
  25. %% sys_pre_expand has not been run. In particular:
  26. %%
  27. %% * Record definitions are still present and must be handled.
  28. %%
  29. %% * (Syntatic) local calls may actually be calls to an imported
  30. %% funtion or a BIF. It is a local call if and only if there
  31. %% is a definition for the function in the module.
  32. %%
  33. %% * When we introduce the module parameters and 'THIS' in each
  34. %% function, we must artificially use it to avoid a warning for
  35. %% unused variables.
  36. %%
  37. %% * On the other hand, we don't have to worry about module_info/0,1
  38. %% because they have not been added yet.
  39. -record(pmod, {parameters,
  40. defined
  41. }).
  42. parse_transform(Forms0, _Options) ->
  43. put(?MODULE, []),
  44. Forms = transform(Forms0),
  45. case erase(?MODULE) of
  46. [] ->
  47. Forms;
  48. [_|_]=Errors ->
  49. File = get_file(Forms),
  50. {error,[{File,Errors}],[]}
  51. end.
  52. format_error(extends_self) ->
  53. "cannot extend from self";
  54. format_error(define_instance) ->
  55. "defining instance function not allowed in parameterized module".
  56. add_error(Line, Error) ->
  57. put(?MODULE, get(?MODULE) ++ [{Line,?MODULE,Error}]).
  58. get_file([{attribute,_,file,{File,_}}|_]) -> File;
  59. get_file([_|T]) -> get_file(T).
  60. transform(Forms0) ->
  61. Def = collect_defined(Forms0),
  62. {Base,ModAs,Forms1} = attribs(Forms0, [], undefined, []),
  63. {Mod,Ps0} = case ModAs of
  64. {M0,P0} -> {M0,P0};
  65. M0 -> {M0,undefined}
  66. end,
  67. Forms2 = case Ps0 of
  68. undefined ->
  69. Forms1;
  70. _ ->
  71. pmod_expand(Forms1, Mod, Base, Ps0, Def)
  72. end,
  73. %% Add new functions.
  74. NewFs0 = maybe_extend(Base, Mod, Ps0),
  75. NewExps = collect_defined(NewFs0),
  76. Forms3 = add_attributes(Forms2, [{attribute,0,export,NewExps}]),
  77. add_new_funcs(Forms3, NewFs0).
  78. pmod_expand(Forms0, Mod, Base, Ps0, Def) ->
  79. Ps = if is_atom(Base) ->
  80. ['BASE' | Ps0];
  81. true ->
  82. Ps0
  83. end,
  84. St0 = #pmod{parameters=Ps,defined=gb_sets:from_list(Def)},
  85. {Forms1,_} = forms(Forms0, St0),
  86. Forms2 = update_exps(Forms1),
  87. Forms3 = update_forms(Forms2),
  88. NewFs0 = add_instance(Mod, Ps, []),
  89. NewFs = ensure_new(Base, Ps0, NewFs0),
  90. Forms = add_new_funcs(Forms3, NewFs),
  91. NewExps = collect_defined(NewFs),
  92. add_attributes(Forms, [{attribute,0,export,NewExps}]).
  93. add_attributes([{attribute,_,module,_}=F|Fs], Attrs) ->
  94. [F|Attrs++Fs];
  95. add_attributes([F|Fs], Attrs) ->
  96. [F|add_attributes(Fs, Attrs)].
  97. add_new_funcs([{eof,_}|_]=Fs, NewFs) ->
  98. NewFs ++ Fs;
  99. add_new_funcs([F|Fs], Es) ->
  100. [F|add_new_funcs(Fs, Es)].
  101. maybe_extend([], _, _) ->
  102. %% No 'extends' attribute.
  103. [];
  104. maybe_extend(Base, _Mod, undefined) ->
  105. %% There is a an 'extends' attribute; the module is not parameterized.
  106. Name = '$handle_undefined_function',
  107. Args = [{var,0,'Func'},{var,0,'Args'}],
  108. Body = [make_apply({atom,0,Base}, {var,0,'Func'}, {var,0,'Args'})],
  109. F = {function,0,Name,2,[{clause,0,Args,[],Body}]},
  110. [F];
  111. maybe_extend(Base, Mod, Ps) ->
  112. %% There is a an 'extends' attribute; the module is parameterized.
  113. Name = '$handle_undefined_function',
  114. Args = [{var,0,'Func'},{var,0,'Args'}],
  115. DontCares = [{var,0,'_'} || _ <- Ps],
  116. TuplePs = {tuple,0,[{atom,0,Mod},{var,0,'BaseVars'}|DontCares]},
  117. G = [{call,0,{atom,0,is_atom},
  118. [{call,0,{atom,0,element},
  119. [{integer,0,1},{var,0,'BaseVars'}]}]}],
  120. FixedArgs = make_lists_rev([{var,0,'Rs'},
  121. {cons,0,{var,0,'BaseVars'},{nil,0}}]),
  122. Body = [{'case',0,make_lists_rev([{var,0,'Args'}]),
  123. [{clause,0,[{cons,0,TuplePs,{var,0,'Rs'}}],[G],
  124. [make_apply({atom,0,Base}, {var,0,'Func'}, FixedArgs)]},
  125. {clause,0,[{var,0,'_'}],[],
  126. [make_apply({atom,0,Base}, {var,0,'Func'}, {var,0,'Args'})]}
  127. ]}],
  128. F = {function,0,Name,2,[{clause,0,Args,[],Body}]},
  129. [F].
  130. make_apply(M, F, A) ->
  131. {call,0,{remote,0,{atom,0,erlang},{atom,0,apply}},[M,F,A]}.
  132. make_lists_rev(As) ->
  133. {call,0,{remote,0,{atom,0,lists},{atom,0,reverse}},As}.
  134. ensure_new(Base, Ps, Fs) ->
  135. case has_new(Fs) of
  136. true ->
  137. Fs;
  138. false ->
  139. add_new(Base, Ps, Fs)
  140. end.
  141. has_new([{function,_L,new,_A,_Cs} | _Fs]) ->
  142. true;
  143. has_new([_ | Fs]) ->
  144. has_new(Fs);
  145. has_new([]) ->
  146. false.
  147. add_new(Base, Ps, Fs) ->
  148. Vs = [{var,0,V} || V <- Ps],
  149. As = if is_atom(Base) ->
  150. [{call,0,{remote,0,{atom,0,Base},{atom,0,new}},Vs} | Vs];
  151. true ->
  152. Vs
  153. end,
  154. Body = [{call,0,{atom,0,instance},As}],
  155. add_func(new, Vs, Body, Fs).
  156. add_instance(Mod, Ps, Fs) ->
  157. Vs = [{var,0,V} || V <- Ps],
  158. AbsMod = [{tuple,0,[{atom,0,Mod}|Vs]}],
  159. add_func(instance, Vs, AbsMod, Fs).
  160. add_func(Name, Args, Body, Fs) ->
  161. A = length(Args),
  162. F = {function,0,Name,A,[{clause,0,Args,[],Body}]},
  163. [F|Fs].
  164. collect_defined(Fs) ->
  165. [{N,A} || {function,_,N,A,_} <- Fs].
  166. attribs([{attribute,Line,module,{Mod,_}=ModAs}|T], Base, _, Acc) ->
  167. attribs(T, Base, ModAs, [{attribute,Line,module,Mod}|Acc]);
  168. attribs([{attribute,_,module,Mod}=H|T], Base, _, Acc) ->
  169. attribs(T, Base, Mod, [H|Acc]);
  170. attribs([{attribute,Line,extends,Base}|T], Base0, Ps, Acc) when is_atom(Base) ->
  171. Mod = case Ps of
  172. {Mod0,_} -> Mod0;
  173. Mod0 -> Mod0
  174. end,
  175. case Mod of
  176. Base ->
  177. add_error(Line, extends_self),
  178. attribs(T, Base0, Ps, Acc);
  179. _ ->
  180. attribs(T, Base, Ps, Acc)
  181. end;
  182. attribs([H|T], Base, Ps, Acc) ->
  183. attribs(T, Base, Ps, [H|Acc]);
  184. attribs([], Base, Ps, Acc) ->
  185. {Base,Ps,lists:reverse(Acc)}.
  186. %% This is extremely simplistic for now; all functions get an extra
  187. %% parameter, whether they need it or not, except for static functions.
  188. update_function_name({F,A}) when F =/= new ->
  189. {F,A+1};
  190. update_function_name(E) ->
  191. E.
  192. update_forms([{function,L,N,A,Cs}|Fs]) when N =/= new ->
  193. [{function,L,N,A+1,Cs}|update_forms(Fs)];
  194. update_forms([F|Fs]) ->
  195. [F|update_forms(Fs)];
  196. update_forms([]) ->
  197. [].
  198. update_exps([{attribute,Line,export,Es0}|T]) ->
  199. Es = [update_function_name(E) || E <- Es0],
  200. [{attribute,Line,export,Es}|update_exps(T)];
  201. update_exps([H|T]) ->
  202. [H|update_exps(T)];
  203. update_exps([]) ->
  204. [].
  205. %% Process the program forms.
  206. forms([F0|Fs0],St0) ->
  207. {F1,St1} = form(F0,St0),
  208. {Fs1,St2} = forms(Fs0,St1),
  209. {[F1|Fs1],St2};
  210. forms([], St0) ->
  211. {[], St0}.
  212. %% Only function definitions are of interest here. State is not updated.
  213. form({function,Line,instance,_Arity,_Clauses}=F,St) ->
  214. add_error(Line, define_instance),
  215. {F,St};
  216. form({function,Line,Name0,Arity0,Clauses0},St) when Name0 =/= new ->
  217. {Name,Arity,Clauses} = function(Name0, Arity0, Clauses0, St),
  218. {{function,Line,Name,Arity,Clauses},St};
  219. %% Pass anything else through
  220. form(F,St) -> {F,St}.
  221. function(Name, Arity, Clauses0, St) ->
  222. Clauses1 = clauses(Clauses0,St),
  223. {Name,Arity,Clauses1}.
  224. clauses([C|Cs],#pmod{parameters=Ps}=St) ->
  225. {clause,L,H,G,B0} = clause(C,St),
  226. T = {tuple,L,[{var,L,V} || V <- ['_'|Ps]]},
  227. B = [{match,L,{var,L,'_'},{var,L,V}} || V <- ['THIS'|Ps]] ++ B0,
  228. [{clause,L,H++[{match,L,T,{var,L,'THIS'}}],G,B}|clauses(Cs,St)];
  229. clauses([],_St) -> [].
  230. clause({clause,Line,H,G,B0},St) ->
  231. %% We never update H and G, so we will just copy them.
  232. B1 = exprs(B0,St),
  233. {clause,Line,H,G,B1}.
  234. pattern_grp([{bin_element,L1,E1,S1,T1} | Fs],St) ->
  235. S2 = case S1 of
  236. default ->
  237. default;
  238. _ ->
  239. expr(S1,St)
  240. end,
  241. T2 = case T1 of
  242. default ->
  243. default;
  244. _ ->
  245. bit_types(T1)
  246. end,
  247. [{bin_element,L1,expr(E1,St),S2,T2} | pattern_grp(Fs,St)];
  248. pattern_grp([],_St) ->
  249. [].
  250. bit_types([]) ->
  251. [];
  252. bit_types([Atom | Rest]) when is_atom(Atom) ->
  253. [Atom | bit_types(Rest)];
  254. bit_types([{Atom, Integer} | Rest]) when is_atom(Atom), is_integer(Integer) ->
  255. [{Atom, Integer} | bit_types(Rest)].
  256. exprs([E0|Es],St) ->
  257. E1 = expr(E0,St),
  258. [E1|exprs(Es,St)];
  259. exprs([],_St) -> [].
  260. expr({var,_L,_V}=Var,_St) ->
  261. Var;
  262. expr({integer,_Line,_I}=Integer,_St) -> Integer;
  263. expr({float,_Line,_F}=Float,_St) -> Float;
  264. expr({atom,_Line,_A}=Atom,_St) -> Atom;
  265. expr({string,_Line,_S}=String,_St) -> String;
  266. expr({char,_Line,_C}=Char,_St) -> Char;
  267. expr({nil,_Line}=Nil,_St) -> Nil;
  268. expr({cons,Line,H0,T0},St) ->
  269. H1 = expr(H0,St),
  270. T1 = expr(T0,St),
  271. {cons,Line,H1,T1};
  272. expr({lc,Line,E0,Qs0},St) ->
  273. Qs1 = lc_bc_quals(Qs0,St),
  274. E1 = expr(E0,St),
  275. {lc,Line,E1,Qs1};
  276. expr({bc,Line,E0,Qs0},St) ->
  277. Qs1 = lc_bc_quals(Qs0,St),
  278. E1 = expr(E0,St),
  279. {bc,Line,E1,Qs1};
  280. expr({tuple,Line,Es0},St) ->
  281. Es1 = expr_list(Es0,St),
  282. {tuple,Line,Es1};
  283. expr({map, Line, Es0}, St) ->
  284. Es1 = expr_list(Es0, St),
  285. {map, Line, Es1};
  286. expr({map, Line, Name, Es0}, St) ->
  287. Es1 = expr_list(Es0, St),
  288. {map, Line, Name, Es1};
  289. expr({map_field_assoc, Line, Key, E0}, St) ->
  290. E = expr(E0, St),
  291. {map_field_assoc, Line, Key, E};
  292. expr({record,Line,Name,Is0},St) ->
  293. Is = record_fields(Is0,St),
  294. {record,Line,Name,Is};
  295. expr({record,Line,E0,Name,Is0},St) ->
  296. E = expr(E0,St),
  297. Is = record_fields(Is0,St),
  298. {record,Line,E,Name,Is};
  299. expr({record_field,Line,E0,Name,Key},St) ->
  300. E = expr(E0,St),
  301. {record_field,Line,E,Name,Key};
  302. expr({block,Line,Es0},St) ->
  303. Es1 = exprs(Es0,St),
  304. {block,Line,Es1};
  305. expr({'if',Line,Cs0},St) ->
  306. Cs1 = icr_clauses(Cs0,St),
  307. {'if',Line,Cs1};
  308. expr({'case',Line,E0,Cs0},St) ->
  309. E1 = expr(E0,St),
  310. Cs1 = icr_clauses(Cs0,St),
  311. {'case',Line,E1,Cs1};
  312. expr({'receive',Line,Cs0},St) ->
  313. Cs1 = icr_clauses(Cs0,St),
  314. {'receive',Line,Cs1};
  315. expr({'receive',Line,Cs0,To0,ToEs0},St) ->
  316. To1 = expr(To0,St),
  317. ToEs1 = exprs(ToEs0,St),
  318. Cs1 = icr_clauses(Cs0,St),
  319. {'receive',Line,Cs1,To1,ToEs1};
  320. expr({'try',Line,Es0,Scs0,Ccs0,As0},St) ->
  321. Es1 = exprs(Es0,St),
  322. Scs1 = icr_clauses(Scs0,St),
  323. Ccs1 = icr_clauses(Ccs0,St),
  324. As1 = exprs(As0,St),
  325. {'try',Line,Es1,Scs1,Ccs1,As1};
  326. expr({'fun',_,{function,_,_,_}}=ExtFun,_St) ->
  327. ExtFun;
  328. expr({'fun',Line,Body},St) ->
  329. case Body of
  330. {clauses,Cs0} ->
  331. Cs1 = fun_clauses(Cs0,St),
  332. {'fun',Line,{clauses,Cs1}};
  333. {function,F,A} = Function ->
  334. {F1,A1} = update_function_name({F,A}),
  335. if A1 =:= A ->
  336. {'fun',Line,Function};
  337. true ->
  338. %% Must rewrite local fun-name to a fun that does a
  339. %% call with the extra THIS parameter.
  340. As = make_vars(A, Line),
  341. As1 = As ++ [{var,Line,'THIS'}],
  342. Call = {call,Line,{atom,Line,F1},As1},
  343. Cs = [{clause,Line,As,[],[Call]}],
  344. {'fun',Line,{clauses,Cs}}
  345. end;
  346. {function,_M,_F,_A} = Fun4 -> %This is an error in lint!
  347. {'fun',Line,Fun4}
  348. end;
  349. expr({call,Lc,{atom,_,instance}=Name,As0},St) ->
  350. %% All local functions 'instance(...)' are static by definition,
  351. %% so they do not take a 'THIS' argument when called
  352. As1 = expr_list(As0,St),
  353. {call,Lc,Name,As1};
  354. expr({call,Lc,{atom,_,new}=Name,As0},St) ->
  355. %% All local functions 'new(...)' are static by definition,
  356. %% so they do not take a 'THIS' argument when called
  357. As1 = expr_list(As0,St),
  358. {call,Lc,Name,As1};
  359. expr({call,Lc,{atom,_Lf,F}=Atom,As0}, #pmod{defined=Def}=St) ->
  360. As1 = expr_list(As0,St),
  361. case gb_sets:is_member({F,length(As0)}, Def) of
  362. false ->
  363. %% BIF or imported function.
  364. {call,Lc,Atom,As1};
  365. true ->
  366. %% Local function call - needs THIS parameter.
  367. {call,Lc,Atom,As1 ++ [{var,0,'THIS'}]}
  368. end;
  369. expr({call,Line,F0,As0},St) ->
  370. %% Other function call
  371. F1 = expr(F0,St),
  372. As1 = expr_list(As0,St),
  373. {call,Line,F1,As1};
  374. expr({'catch',Line,E0},St) ->
  375. E1 = expr(E0,St),
  376. {'catch',Line,E1};
  377. expr({match,Line,P,E0},St) ->
  378. E1 = expr(E0,St),
  379. {match,Line,P,E1};
  380. expr({bin,Line,Fs},St) ->
  381. Fs2 = pattern_grp(Fs,St),
  382. {bin,Line,Fs2};
  383. expr({op,Line,Op,A0},St) ->
  384. A1 = expr(A0,St),
  385. {op,Line,Op,A1};
  386. expr({op,Line,Op,L0,R0},St) ->
  387. L1 = expr(L0,St),
  388. R1 = expr(R0,St),
  389. {op,Line,Op,L1,R1};
  390. %% The following are not allowed to occur anywhere!
  391. expr({remote,Line,M0,F0},St) ->
  392. M1 = expr(M0,St),
  393. F1 = expr(F0,St),
  394. {remote,Line,M1,F1}.
  395. expr_list([E0|Es],St) ->
  396. E1 = expr(E0,St),
  397. [E1|expr_list(Es,St)];
  398. expr_list([],_St) -> [].
  399. record_fields([{record_field,L,K,E0}|T],St) ->
  400. E = expr(E0,St),
  401. [{record_field,L,K,E}|record_fields(T,St)];
  402. record_fields([],_) -> [].
  403. icr_clauses([C0|Cs],St) ->
  404. C1 = clause(C0,St),
  405. [C1|icr_clauses(Cs,St)];
  406. icr_clauses([],_St) -> [].
  407. lc_bc_quals([{generate,Line,P,E0}|Qs],St) ->
  408. E1 = expr(E0,St),
  409. [{generate,Line,P,E1}|lc_bc_quals(Qs,St)];
  410. lc_bc_quals([{b_generate,Line,P,E0}|Qs],St) ->
  411. E1 = expr(E0,St),
  412. [{b_generate,Line,P,E1}|lc_bc_quals(Qs,St)];
  413. lc_bc_quals([E0|Qs],St) ->
  414. E1 = expr(E0,St),
  415. [E1|lc_bc_quals(Qs,St)];
  416. lc_bc_quals([],_St) -> [].
  417. fun_clauses([C0|Cs],St) ->
  418. C1 = clause(C0,St),
  419. [C1|fun_clauses(Cs,St)];
  420. fun_clauses([],_St) -> [].
  421. make_vars(N, L) ->
  422. make_vars(1, N, L).
  423. make_vars(N, M, L) when N =< M ->
  424. V = list_to_atom("X"++integer_to_list(N)),
  425. [{var,L,V} | make_vars(N + 1, M, L)];
  426. make_vars(_, _, _) ->
  427. [].