~ubuntu-branches/ubuntu/saucy/rabbitmq-server/saucy

« back to all changes in this revision

Viewing changes to plugins-src/mochiweb-wrapper/mochiweb-git/src/pmod_pt.erl

  • Committer: Package Import Robot
  • Author(s): Emile Joubert
  • Date: 2012-01-31 15:28:12 UTC
  • mfrom: (0.2.20) (0.1.34 sid)
  • Revision ID: package-import@ubuntu.com-20120131152812-la0rbm603vp9s054
Tags: 3.0.2-1
New upstream release

Show diffs side-by-side

added added

removed removed

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