~ubuntu-branches/debian/squeeze/erlang/squeeze

« back to all changes in this revision

Viewing changes to lib/hipe/cerl/cerl_pmatch.erl

  • Committer: Bazaar Package Importer
  • Author(s): Erlang Packagers, Sergei Golovan
  • Date: 2006-12-03 17:07:44 UTC
  • mfrom: (2.1.11 feisty)
  • Revision ID: james.westby@ubuntu.com-20061203170744-rghjwupacqlzs6kv
Tags: 1:11.b.2-4
[ Sergei Golovan ]
Fixed erlang-base and erlang-base-hipe prerm scripts.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
%% =====================================================================
2
 
%% @doc Core Erlang pattern matching compiler.
3
 
%%
4
 
%% <p>For reference, see Simon L. Peyton Jones "The Implementation of
5
 
%% Functional Programming Languages", chapter 5 (by Phil Wadler).</p>
6
 
%% @end
7
 
%%
8
 
%% Copyright (C) 1999-2002 Richard Carlsson
 
2
%% Copyright (C) 1999-2004 Richard Carlsson
9
3
%%
10
4
%% This library is free software; you can redistribute it and/or modify
11
5
%% it under the terms of the GNU Lesser General Public License as
22
16
%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23
17
%% USA
24
18
%%
25
 
%% Author contact: richardc@csd.uu.se
26
 
%%
27
19
%% $Id$
28
20
%%
 
21
%% @author Richard Carlsson <richardc@it.uu.se>
 
22
%% @copyright 2000-2006 Richard Carlsson
 
23
%%
 
24
%% @doc Core Erlang pattern matching compiler.
 
25
%%
 
26
%% <p>For reference, see Simon L. Peyton Jones "The Implementation of
 
27
%% Functional Programming Languages", chapter 5 (by Phil Wadler).</p>
 
28
%%
29
29
%% @type cerl() = cerl:cerl().
30
30
%%     Abstract Core Erlang syntax trees.
31
31
%% @type cerl_records() = cerl:cerl_records().
32
32
%%     An explicit record representation of Core Erlang syntax trees.
33
33
 
34
 
%% TODO: Binary-patterns
35
 
 
36
34
-module(cerl_pmatch).
37
35
 
38
 
-export([clauses/2, module/2, expr/2, core_transform/2]).
 
36
-define(NO_UNUSED, true).
 
37
 
 
38
-export([clauses/2]).
 
39
-ifndef(NO_UNUSED).
 
40
-export([transform/2, core_transform/2, expr/2]).
 
41
-endif.
39
42
 
40
43
-import(lists, [all/2, splitwith/2, foldr/3, keysort/2, foldl/3,
41
44
                mapfoldl/3]).
42
45
 
 
46
-define(binary_id, {binary}).
 
47
-define(cons_id, {cons}).
 
48
-define(tuple_id, {tuple}).
 
49
-define(literal_id(V), V).
 
50
 
 
51
 
43
52
%% @spec core_transform(Module::cerl_records(), Options::[term()]) ->
44
53
%%           cerl_records()
45
54
%%
46
55
%% @doc Transforms a module represented by records. See
47
 
%% <code>module/2</code> for details.
 
56
%% <code>transform/2</code> for details.
48
57
%%
49
58
%% <p>Use the compiler option <code>{core_transform, cerl_pmatch}</code>
50
59
%% to insert this function as a compilation pass.</p>
51
60
%%
52
 
%% @see module/2
 
61
%% @see transform/2
53
62
 
 
63
-ifndef(NO_UNUSED).
54
64
core_transform(M, Opts) ->
55
 
    cerl:to_records(module(cerl:from_records(M), Opts)).
56
 
 
57
 
 
58
 
%% @spec module(Module::cerl(), Options::[term()]) -> cerl()
 
65
    cerl:to_records(transform(cerl:from_records(M), Opts)).
 
66
-endif. % NO_UNUSED
 
67
%% @clear
 
68
 
 
69
 
 
70
%% @spec transform(Module::cerl(), Options::[term()]) -> cerl()
59
71
%%
60
72
%% @doc Rewrites all <code>case</code>-clauses in <code>Module</code>.
61
73
%% <code>receive</code>-clauses are not affected. Currently, no options
65
77
%% @see expr/2
66
78
%% @see core_transform/2
67
79
 
68
 
module(M, _Opts) ->
69
 
    expr(M, env__empty()).
 
80
-ifndef(NO_UNUSED).
 
81
transform(M, _Opts) ->
 
82
  expr(M, env__empty()).
 
83
-endif. % NO_UNUSED
 
84
%% @clear
70
85
 
71
86
 
72
87
%% @spec clauses(Clauses::[Clause], Env) -> {Expr, Vars}
94
109
%% 
95
110
%% @see rec_env
96
111
%% @see expr/2
97
 
%% @see module/2
 
112
%% @see transform/2
98
113
 
99
114
clauses(Cs, Env) ->
100
115
    clauses(Cs, none, Env).
112
127
    %% If the "default action" is the atom 'none', it is simply not
113
128
    %% added; otherwise it is put in the body of a final catch-all
114
129
    %% clause (which is often removed by the below optimization).
115
 
    Cs1 = if Else == none -> Cs;
 
130
    Cs1 = if Else =:= none -> Cs;
116
131
             true -> Cs ++ [cerl:c_clause([], Else)]
117
132
          end,
118
133
    %% This clause reduction is an important optimization. It selects a
136
151
group([X | _] = Xs, F) ->
137
152
    group(Xs, F, F(X)).
138
153
 
139
 
group([], _F, _P) ->
140
 
    [];
141
154
group(Xs, F, P) ->
142
 
    {First, Rest} = splitwith(fun (X) -> F(X) == P end, Xs),
 
155
    {First, Rest} = splitwith(fun (X) -> F(X) =:= P end, Xs),
143
156
    [First | group(Rest, F)].
144
157
 
145
158
is_var_clause(C) ->
189
202
%% body of a final catch-all clause.
190
203
 
191
204
match_con([V | Vs], Cs, Else, Env) ->
192
 
 
193
 
    case group_con(Cs) of
194
 
        [{_, _, Gs}] ->
 
205
    case group_con(Cs) of 
 
206
      [{_, _, Gs}] ->
195
207
            %% Don't create a group type switch if there is only one
196
 
            %% such group.
197
 
 
 
208
            %% such group
198
209
            make_switch(V, [match_congroup(D, Vs, Cs, Else, Env)
199
 
                            ||  {_, D, Cs} <- Gs],
 
210
                            ||  {D, _, Cs} <- Gs],
200
211
                        Else, Env);
201
212
        Ts ->
202
213
            Cs1 = [match_typegroup(T, V, Vs, Gs, Else, Env)
203
 
                   || {_, T, Gs} <- Ts],
 
214
                   || {T, _, Gs} <- Ts],
204
215
            make_switch(V, Cs1, Else, Env)
205
216
    end.
206
217
 
207
 
match_typegroup(_T, _V, Vs, [{_, D, Cs}], Else, Env) ->
 
218
 
 
219
match_typegroup(_T, _V, Vs, [{D, _, Cs}], Else, Env) when element(1, D) /= ?binary_id ->
208
220
    %% Don't create a group type switch if there is only one constructor
209
 
    %% in the group. (Note that this always happens for the empty list.)
 
221
    %% in the group. (Note that this always happens for '[]'.)  
 
222
    %% Special case for binaries which always get a group switch
210
223
    match_congroup(D, Vs, Cs, Else, Env);
211
224
match_typegroup(T, V, Vs, Gs, Else, Env) ->
212
225
    Body = make_switch(V, [match_congroup(D, Vs, Cs, Else, Env)
213
 
                           ||  {_, D, Cs} <- Gs],
 
226
                         ||  {D, _, Cs} <- Gs],
214
227
                       Else, Env),
215
228
    typetest_clause(T, V, Body, Env).
216
229
 
217
 
match_congroup({<<0>>, Segs}, Vs, Cs, Else, Env) ->
218
 
    Body = match(Vs, Cs, Else, Env),
219
 
    cerl:c_clause([make_pat(<<0>>, Segs)], Body);
 
230
match_congroup({?binary_id, Segs}, Vs, Cs, _Else, Env) -> 
 
231
    Ref = get_unique(),
 
232
    Guard = cerl:c_primop(cerl:c_atom(set_label), [cerl:c_int(Ref)]),
 
233
    NewElse = cerl:c_primop(cerl:c_atom(goto_label), [cerl:c_int(Ref)]),
 
234
    Body = match(Vs, Cs, NewElse, Env),
 
235
    cerl:c_clause([make_pat(?binary_id, Segs)], Guard, Body);
220
236
 
221
237
match_congroup({D, A}, Vs, Cs, Else, Env) ->
222
238
    Vs1 = new_vars(A, Env),
224
240
    cerl:c_clause([make_pat(D, Vs1)], Body).
225
241
 
226
242
make_switch(V, Cs, Else, Env) ->
227
 
    cerl:c_case(V, if Else == none -> Cs;
 
243
    cerl:c_case(V, if Else =:= none -> Cs;
228
244
                      true -> Cs ++ [cerl:c_clause([new_var(Env)],
229
245
                                                   Else)]
230
246
                   end).
231
247
 
232
 
%% We preserve the relative order of different constructors as they were
233
 
%% originally listed. This is done by including the clause number in the
234
 
%% key used for sorting the clauses by type (this stage does not
235
 
%% distingush between different value instances of atoms, integers and
236
 
%% floats). The clauses are then grouped by type. After grouping by
237
 
%% constructor (this separates value instances), the groups are then
238
 
%% sorted again by the clause number of the first clause of each group.
 
248
%% We preserve the relative order of different-type constructors as they
 
249
%% were originally listed. This is done by tracking the clause numbers.
239
250
 
240
251
group_con(Cs) ->
241
252
    {Cs1, _} = mapfoldl(fun (C, N) ->
243
254
                                Ps1 = sub_pats(P) ++ Ps,
244
255
                                G = cerl:clause_guard(C),
245
256
                                B = cerl:clause_body(C),
246
 
                                {{{con_type(P), N}, con_desc(P),
247
 
                                  cerl:update_c_clause(C, Ps1, G, B)},
248
 
                                 N + 1}
 
257
                                C1 = cerl:update_c_clause(C, Ps1, G, B),
 
258
                                D = con_desc(P),
 
259
                                {{D, N, C1}, N + 1}
249
260
                        end,
250
261
                        0, Cs),
251
 
    %% Group by descriptor (separates different integers, atoms, etc.)
252
 
    %% Constructors that have the same descriptor have the same type.
253
 
    Css = group(keysort(1, Cs1), fun ({_,D,_}) -> D end),
254
 
    Gs = [{T, D, [C || {_,_,C} <- Cs]} || Cs=[{T,D,_}|_] <- Css],
255
 
    %% Group by type class (groups different-arity tuples together).
256
 
    Css1 = group(Gs, fun ({{T,_},_,_}) -> typeclass(T) end),
257
 
    Gs1 = [{N, T, Cs} || Cs=[{{T,N},_,_}|_] <- Css1],
258
 
    %% Sort type-groups by original clause order
259
 
    keysort(1, Gs1).
 
262
    %% Sort and group constructors.
 
263
    Css = group(keysort(1, Cs1), fun ({D,_,_}) -> D end),
 
264
    %% Sort each group "back" by line number, and move the descriptor
 
265
    %% and line number to the wrapper for the group.
 
266
    Gs = [finalize_congroup(Cs) || Cs <- Css],
 
267
    %% Group by type only (put e.g. different-arity tuples together).
 
268
    Gss = group(Gs, fun ({D,_,_}) -> con_desc_type(D) end),
 
269
    %% Sort and wrap the type groups.
 
270
    Ts = [finalize_typegroup(Gs) || Gs <- Gss],
 
271
    %% Sort type-groups by first clause order
 
272
    keysort(2, Ts).
 
273
 
 
274
finalize_congroup(Cs) ->
 
275
    [{D,N,_}|_] = Cs1 = keysort(2, Cs),
 
276
    {D, N, [C || {_,_,C} <- Cs1]}.
 
277
 
 
278
finalize_typegroup(Gs) ->
 
279
    [{D,N,_}|_] = Gs1 = keysort(2, Gs),
 
280
    {con_desc_type(D), N, Gs1}.
260
281
 
261
282
%% Since Erlang clause patterns can contain "alias patterns", we must
262
283
%% eliminate these, by turning them into let-definitions in the guards
265
286
unalias(C, V) -> 
266
287
    [P | Ps] = cerl:clause_pats(C),
267
288
    B = cerl:clause_body(C),
268
 
    unalias(P, V, Ps, B, C).
 
289
    G = cerl:clause_guard(C),
 
290
    unalias(P, V, Ps, B, G, C).
269
291
 
270
 
unalias(P, V, Ps, B, C) ->
 
292
unalias(P, V, Ps, B, G, C) ->
271
293
    case cerl:type(P) of
272
294
        alias ->
273
 
            B1 = make_let([cerl:alias_var(P)], V, B),
274
 
            unalias(cerl:alias_pat(P), V, Ps, B1, C);
275
 
        _ ->
276
 
            cerl:update_c_clause(C, [P | Ps], cerl:clause_guard(C), B)
277
 
    end.
278
 
 
279
 
%% This returns a constructor type, for sorting of clauses. It does not
280
 
%% distinguish between value instances of atoms, integers and floats.
281
 
 
282
 
con_type(E) ->
283
 
    case cerl:type(E) of
284
 
        cons ->
285
 
            cons;
286
 
        tuple ->
287
 
            {tuple, cerl:tuple_arity(E)};
288
 
        binary ->
289
 
            binary;
290
 
        literal ->
291
 
            case cerl:concrete(E) of
292
 
                V when is_atom(V) -> atom;
293
 
                V when is_integer(V) -> integer;
294
 
                V when is_float(V) -> float;
295
 
                T when is_tuple(T) -> {tuple, size(T)};
296
 
                [_|_] -> cons;
297
 
                [] -> []
298
 
            end;
299
 
        _ ->
300
 
            throw({bad_constructor, E})
301
 
    end.
302
 
 
303
 
%% Getting the generic class for type grouping.
304
 
 
305
 
typeclass({tuple, _}) -> tuple;
306
 
typeclass(X) -> X.
 
295
            V1 = cerl:alias_var(P),
 
296
            B1 = make_let([V1], V, B),
 
297
            G1 = make_let([V1], V, G),
 
298
            unalias(cerl:alias_pat(P), V, Ps, B1, G1, C);
 
299
        _ ->
 
300
            cerl:update_c_clause(C, [P | Ps], G, B)
 
301
    end.
307
302
 
308
303
%% Generating a type-switch clause
309
304
 
310
 
typetest_clause({tuple, _}, V, E, _Env) ->
311
 
    typetest_clause_1(is_tuple, V, E);
 
305
typetest_clause([], _V, E, _Env) ->
 
306
    cerl:c_clause([cerl:c_nil()], E);
312
307
typetest_clause(atom, V, E, _Env) ->
313
308
    typetest_clause_1(is_atom, V, E);
314
309
typetest_clause(integer, V, E, _Env) ->
318
313
typetest_clause(cons, _V, E, Env) ->
319
314
    [V1, V2] = new_vars(2, Env),
320
315
    cerl:c_clause([cerl:c_cons(V1, V2)], E);  % there is no 'is cons'
321
 
typetest_clause([], _V, E, _Env) ->
322
 
    cerl:c_clause([cerl:c_nil()], E);
 
316
typetest_clause(tuple, V, E, _Env) ->
 
317
    typetest_clause_1(is_tuple, V, E);
323
318
typetest_clause(binary, V, E, _Env) ->
324
319
    typetest_clause_1(is_binary, V, E).
325
320
 
330
325
%% This returns a constructor descriptor, to be used for grouping and
331
326
%% pattern generation. It consists of an identifier term and the arity.
332
327
 
333
 
-define(cons_id, [0]).
334
 
-define(tuple_id, {0}).
335
 
-define(binary_id, <<0>>).
336
 
-define(literal_id(V), V).
337
 
 
338
328
con_desc(E) ->
339
329
    case cerl:type(E) of
340
330
        cons -> {?cons_id, 2};
341
331
        tuple -> {?tuple_id, cerl:tuple_arity(E)};
342
 
        binary -> {?binary_id, cerl:binary_segs(E)};
 
332
        binary -> {?binary_id, cerl:binary_segments(E)};
343
333
        literal ->
344
334
            case cerl:concrete(E) of
345
335
                [_|_] -> {?cons_id, 2};
350
340
            throw({bad_constructor, E})
351
341
    end.
352
342
 
 
343
%% This returns the type class for a constructor descriptor, for 
 
344
%% grouping of clauses. It does not distinguish between tuples of
 
345
%% different arity, nor between different values of atoms, integers and
 
346
%% floats.
 
347
 
 
348
con_desc_type({?literal_id([]), _}) -> [];
 
349
con_desc_type({?literal_id(V), _}) when is_atom(V) -> atom;
 
350
con_desc_type({?literal_id(V), _}) when is_integer(V) -> integer;
 
351
con_desc_type({?literal_id(V), _}) when is_float(V) -> float;
 
352
con_desc_type({?cons_id, 2}) -> cons;
 
353
con_desc_type({?tuple_id, _}) -> tuple;
 
354
con_desc_type({?binary_id, _}) -> binary.
 
355
 
353
356
%% This creates a new constructor pattern from a type descriptor and a
354
357
%% list of variables.
355
358
 
380
383
    end.
381
384
 
382
385
%% This avoids generating stupid things like "let X = ... in 'true'",
383
 
%% keeping the generated code cleaner.
 
386
%% and "let X = Y in X", keeping the generated code cleaner. It also
 
387
%% prevents expressions from being considered "non-lightweight" when
 
388
%% code duplication is disallowed (see is_lightweight for details).
384
389
 
385
390
make_let(Vs, A, B) ->
386
 
    case cerl:type(B) of
387
 
        literal ->
388
 
            case is_simple(A) of
389
 
                true -> B;
390
 
                false -> cerl:c_let(Vs, A, B)
391
 
            end;
392
 
        _ -> cerl:c_let(Vs, A, B)
393
 
    end.
 
391
    cerl_lib:reduce_expr(cerl:c_let(Vs, A, B)).
394
392
 
395
 
%% ------------------------------------------------------------------------
 
393
%% ---------------------------------------------------------------------
396
394
%% Rewriting a module or other expression:
397
395
 
398
396
%% @spec expr(Expression::cerl(), Env) -> cerl()
408
406
%% @see clauses/2
409
407
%% @see rec_env
410
408
 
 
409
-ifndef(NO_UNUSED).
411
410
expr(E, Env) ->
412
411
    case cerl:type(E) of
413
412
        literal ->
463
462
            B = expr(cerl:fun_body(E), Env1),
464
463
            cerl:update_c_fun(E, Vs, B);
465
464
        'receive' ->
466
 
            %% NOTE: No pattern matching compilation done here!
 
465
            %% NOTE: No pattern matching compilation is done here! The
 
466
            %% receive-clauses and patterns cannot be staged as long as
 
467
            %% we are working with "normal" Core Erlang.
467
468
            Cs = expr_list(cerl:receive_clauses(E), Env),
468
469
            T = expr(cerl:receive_timeout(E), Env),
469
470
            A = expr(cerl:receive_action(E), Env),
498
499
 
499
500
defs(Ds, Env) ->
500
501
    [{V, expr(F, Env)} || {V, F} <- Ds].
501
 
 
502
 
 
503
 
%% ------------------------------------------------------------------------
 
502
-endif. % NO_UNUSED
 
503
%% @clear
 
504
 
 
505
%% ---------------------------------------------------------------------
504
506
%%      Support functions
505
507
 
506
508
new_var(Env) ->
518
520
    foldl(fun (V, Env) -> env__bind(cerl:var_name(V), [], Env) end,
519
521
          Env, Vs).
520
522
 
 
523
-ifndef(NO_UNUSED).
521
524
add_defs(Ds, Env) ->
522
525
    foldl(fun ({V, _F}, Env) ->
523
526
                  env__bind(cerl:var_name(V), [], Env)
524
527
          end, Env, Ds).
525
 
 
526
 
%% For now, we duplicate code without limitations, as long as lifting
527
 
%% out the code always results in a full local function call even when
528
 
%% the code is in last call context, since this causes notable slowdown
529
 
%% in tight loops.
530
 
 
531
 
is_lightweight(_) -> true.
532
 
 
533
 
%% is_lightweight(E) ->
534
 
%%     case cerl:type(E) of
535
 
%%      var -> true;
536
 
%%      literal -> true;
537
 
%%      values -> all(fun is_simple/1, cerl:values_es(E));
538
 
%%      cons -> is_simple(cerl:cons_hd(E))
539
 
%%                  andalso is_simple(cerl:cons_tl(E));
540
 
%%      tuple -> all(fun is_simple/1, cerl:tuple_es(E));
541
 
%%      'let' -> (is_simple(cerl:let_arg(E)) andalso
542
 
%%                is_lightweight(cerl:let_body(E)));
543
 
%%      seq -> (is_simple(cerl:seq_arg(E)) andalso
544
 
%%              is_lightweight(cerl:seq_body(E)));
545
 
%%      apply ->
546
 
%%          is_simple(cerl:apply_op(E))
547
 
%%              andalso all(fun is_simple/1, cerl:apply_args(E));
548
 
%%      call ->
549
 
%%          is_simple(cerl:call_module(E))
550
 
%%              andalso is_simple(cerl:call_name(E))
551
 
%%              andalso all(fun is_simple/1, cerl:call_args(E));    
552
 
%%      _ -> false
553
 
%%     end.
 
528
-endif. % NO_UNUSED
 
529
 
 
530
%% This decides whether an expression is worth lifting out to a separate
 
531
%% function instead of duplicating the code. In other words, whether its
 
532
%% cost is about the same or smaller than that of a local function call.
 
533
%% Note that variables must always be "lightweight"; otherwise, they may
 
534
%% get lifted out of the case switch that introduces them.
 
535
 
 
536
is_lightweight(E) ->
 
537
    case get('cerl_pmatch_duplicate_code') of
 
538
        never -> cerl:type(E) =:= var;    % Avoids all code duplication
 
539
        always -> true;    % Does not lift code to new functions
 
540
        _ -> is_lightweight_1(E)
 
541
    end.
 
542
 
 
543
is_lightweight_1(E) ->
 
544
    case cerl:type(E) of
 
545
        var -> true;
 
546
        literal -> true;
 
547
        'fun' -> true;
 
548
        values -> all(fun is_simple/1, cerl:values_es(E));
 
549
        cons -> is_simple(cerl:cons_hd(E))
 
550
                    andalso is_simple(cerl:cons_tl(E));
 
551
        tuple -> all(fun is_simple/1, cerl:tuple_es(E));
 
552
        'let' -> (is_simple(cerl:let_arg(E)) andalso
 
553
                  is_lightweight_1(cerl:let_body(E)));
 
554
        seq -> (is_simple(cerl:seq_arg(E)) andalso
 
555
                is_lightweight_1(cerl:seq_body(E)));
 
556
        primop ->
 
557
            all(fun is_simple/1, cerl:primop_args(E));
 
558
        apply ->
 
559
            is_simple(cerl:apply_op(E))
 
560
                andalso all(fun is_simple/1, cerl:apply_args(E));
 
561
        call ->
 
562
            is_simple(cerl:call_module(E))
 
563
                andalso is_simple(cerl:call_name(E))
 
564
                andalso all(fun is_simple/1, cerl:call_args(E));    
 
565
        _ ->
 
566
            %% The default is to lift the code to a new function.
 
567
            false
 
568
    end.
 
569
 
 
570
%% "Simple" things have no (or negligible) runtime cost and are free
 
571
%% from side effects.
554
572
 
555
573
is_simple(E) ->
556
574
    case cerl:type(E) of
561
579
    end.
562
580
 
563
581
 
564
 
%% ------------------------------------------------------------------------
 
582
get_unique() ->
 
583
  case get(unique_label) of
 
584
    undefined ->
 
585
      put(unique_label, 1),
 
586
      0;
 
587
    N ->
 
588
      put(unique_label, N+1),
 
589
      N
 
590
  end.
 
591
 
 
592
%% ---------------------------------------------------------------------
565
593
%% Abstract datatype: environment()
566
594
 
567
 
env__empty() ->
568
 
    rec_env:empty().
569
 
 
570
595
env__bind(Key, Val, Env) ->
571
596
    rec_env:bind(Key, Val, Env).
572
597
 
573
 
%% `Es' should have type `[{Key, Val}]', and `Fun' should have type
574
 
%% `(Val, Env) -> T', mapping a value together with the recursive
575
 
%% environment itself to some term `T' to be returned when the entry is
576
 
%% looked up.
577
 
 
 
598
-ifndef(NO_UNUSED).
578
599
%% env__bind_recursive(Ks, Vs, F, Env) ->
579
600
%%     rec_env:bind_recursive(Ks, Vs, F, Env).
580
601
 
587
608
%% env__is_defined(Key, Env) ->
588
609
%%     rec_env:is_defined(Key, Env).
589
610
 
 
611
env__empty() ->
 
612
    rec_env:empty().
 
613
-endif. % NO_UNUSED
 
614
 
590
615
env__new_vname(Env) ->
591
616
    rec_env:new_key(Env).
592
617
 
594
619
    rec_env:new_keys(N, Env).
595
620
 
596
621
env__new_fname(F, A, Env) ->
597
 
    rec_env:new_custom_key(fun (X) ->
598
 
                                   S = integer_to_list(X),
599
 
                                   {list_to_atom(F ++ S), A}
600
 
                           end,
601
 
                           Env).
 
622
    rec_env:new_key(fun (X) ->
 
623
                            S = integer_to_list(X),
 
624
                            {list_to_atom(F ++ S), A}
 
625
                    end,
 
626
                    Env).