1%% Licensed under the Apache License, Version 2.0 (the "License");
2%% you may not use this file except in compliance with the License.
3%% You may obtain a copy of the License at
4%%
5%%     http://www.apache.org/licenses/LICENSE-2.0
6%%
7%% Unless required by applicable law or agreed to in writing, software
8%% distributed under the License is distributed on an "AS IS" BASIS,
9%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10%% See the License for the specific language governing permissions and
11%% limitations under the License.
12%%
13%% @copyright 2000-2006 Richard Carlsson
14%% @author Richard Carlsson <carlsson.richard@gmail.com>
15%%
16%% @doc Core Erlang pattern matching compiler.
17%%
18%% <p>For reference, see Simon L. Peyton Jones "The Implementation of
19%% Functional Programming Languages", chapter 5 (by Phil Wadler).</p>
20%%
21%% @type cerl() = cerl:cerl().
22%%     Abstract Core Erlang syntax trees.
23%% @type cerl_records() = cerl:cerl_records().
24%%     An explicit record representation of Core Erlang syntax trees.
25
26-module(cerl_pmatch).
27
28%%-define(NO_UNUSED, true).
29
30-export([clauses/2]).
31-ifndef(NO_UNUSED).
32-export([transform/2, core_transform/2, expr/2]).
33-endif.
34
35-import(lists, [all/2, splitwith/2, foldr/3, keysort/2, foldl/3,
36		mapfoldl/3]).
37
38-define(binary_id, {binary}).
39-define(cons_id, {cons}).
40-define(tuple_id, {tuple}).
41-define(literal_id(V), V).
42
43
44%% @spec core_transform(Module::cerl_records(), Options::[term()]) ->
45%%           cerl_records()
46%%
47%% @doc Transforms a module represented by records. See
48%% <code>transform/2</code> for details.
49%%
50%% <p>Use the compiler option <code>{core_transform, cerl_pmatch}</code>
51%% to insert this function as a compilation pass.</p>
52%%
53%% @see transform/2
54
55-ifndef(NO_UNUSED).
56-spec core_transform(cerl:c_module(), [_]) -> cerl:c_module().
57
58core_transform(M, Opts) ->
59    cerl:to_records(transform(cerl:from_records(M), Opts)).
60-endif.	% NO_UNUSED
61%% @clear
62
63
64%% @spec transform(Module::cerl(), Options::[term()]) -> cerl()
65%%
66%% @doc Rewrites all <code>case</code>-clauses in <code>Module</code>.
67%% <code>receive</code>-clauses are not affected. Currently, no options
68%% are available.
69%%
70%% @see clauses/2
71%% @see expr/2
72%% @see core_transform/2
73
74-ifndef(NO_UNUSED).
75-spec transform(cerl:cerl(), [_]) -> cerl:cerl().
76
77transform(M, _Opts) ->
78  expr(M, env__empty()).
79-endif.	% NO_UNUSED
80%% @clear
81
82
83%% @spec clauses(Clauses::[Clause], Env) -> {Expr, Vars}
84%%    Clause = cerl()
85%%    Expr = cerl()
86%%    Vars = [cerl()]
87%%    Env = rec_env:environment()
88%%
89%% @doc Rewrites a sequence of clauses to an equivalent expression,
90%% removing as much repeated testing as possible. Returns a pair
91%% <code>{Expr, Vars}</code>, where <code>Expr</code> is the resulting
92%% expression, and <code>Vars</code> is a list of new variables (i.e.,
93%% not already in the given environment) to be bound to the arguments to
94%% the switch. The following is a typical example (assuming
95%% <code>E</code> is a Core Erlang case expression):
96%% <pre>
97%%   handle_case(E, Env) ->
98%%       Cs = case_clauses(E),
99%%       {E1, Vs} = cerl_pmatch(Cs, Env),
100%%       c_let(Vs, case_arg(E), E1).
101%% </pre>
102%%
103%% <p>The environment is used for generating new variables which do not
104%% shadow existing bindings.</p>
105%%
106%% @see rec_env
107%% @see expr/2
108%% @see transform/2
109
110-spec clauses([cerl:cerl(),...], rec_env:environment()) ->
111          {cerl:cerl(), [cerl:cerl()]}.
112
113clauses(Cs, Env) ->
114    clauses(Cs, none, Env).
115
116clauses([C | _] = Cs, Else, Env) ->
117    Vs = new_vars(cerl:clause_arity(C), Env),
118    E = match(Vs, Cs, Else, add_vars(Vs, Env)),
119    {E, Vs}.
120
121%% The implementation very closely follows that described in the book.
122
123match([], Cs, Else, _Env) ->
124    %% If the "default action" is the atom 'none', it is simply not
125    %% added; otherwise it is put in the body of a final catch-all
126    %% clause (which is often removed by the below optimization).
127    Cs1 = if Else =:= none -> Cs;
128	     true -> Cs ++ [cerl:c_clause([], Else)]
129	  end,
130    %% This clause reduction is an important optimization. It selects a
131    %% clause body if possible, and otherwise just removes dead clauses.
132    case cerl_clauses:reduce(Cs1) of
133 	{true, {C, []}} ->    % if we get bindings, something is wrong!
134 	    cerl:clause_body(C);
135 	{false, Cs2} ->
136	    %% This happens when guards are nontrivial.
137 	    cerl:c_case(cerl:c_values([]), Cs2)
138    end;
139match([V | _] = Vs, Cs, Else, Env) ->
140    foldr(fun (CsF, ElseF) ->
141		  match_var_con(Vs, CsF, ElseF, Env)
142	  end,
143	  Else,
144	  group([unalias(C, V) || C <- Cs], fun is_var_clause/1)).
145
146group([], _F) ->
147    [];
148group([X | _] = Xs, F) ->
149    group(Xs, F, F(X)).
150
151group(Xs, F, P) ->
152    {First, Rest} = splitwith(fun (X) -> F(X) =:= P end, Xs),
153    [First | group(Rest, F)].
154
155is_var_clause(C) ->
156    cerl:is_c_var(hd(cerl:clause_pats(C))).
157
158%% To avoid code duplication, if the 'Else' expression is too big, we
159%% put it in a local function definition instead, and replace it with a
160%% call. (Note that it is important that 'is_lightweight' does not yield
161%% 'true' for a simple function application, or we will create a lot of
162%% unnecessary extra functions.)
163
164match_var_con(Vs, Cs, none = Else, Env) ->
165    match_var_con_1(Vs, Cs, Else, Env);
166match_var_con(Vs, Cs, Else, Env) ->
167    case is_lightweight(Else) of
168	true ->
169	    match_var_con_1(Vs, Cs, Else, Env);
170	false ->
171	    F = new_fvar("match_", 0, Env),
172	    Else1 = cerl:c_apply(F, []),
173	    Env1 = add_vars([F], Env),
174	    cerl:c_letrec([{F, cerl:c_fun([], Else)}],
175			  match_var_con_1(Vs, Cs, Else1, Env1))
176    end.
177
178match_var_con_1(Vs, Cs, Else, Env) ->
179    case is_var_clause(hd(Cs)) of
180	true ->
181	    match_var(Vs, Cs, Else, Env);
182	false ->
183	    match_con(Vs, Cs, Else, Env)
184    end.
185
186match_var([V | Vs], Cs, Else, Env) ->
187    Cs1 = [begin
188	       [P | Ps] = cerl:clause_pats(C),
189	       G = make_let([P], V, cerl:clause_guard(C)),
190	       B = make_let([P], V, cerl:clause_body(C)),
191	       cerl:update_c_clause(C, Ps, G, B)
192	   end
193	   || C <- Cs],
194    match(Vs, Cs1, Else, Env).
195
196%% Since Erlang is dynamically typed, we must include the possibility
197%% that none of the constructors in the group will match, and in that
198%% case the "Else" code will be executed (unless it is 'none'), in the
199%% body of a final catch-all clause.
200
201match_con([V | Vs], Cs, Else, Env) ->
202    case group_con(Cs) of
203      [{_, _, Gs}] ->
204 	    %% Don't create a group type switch if there is only one
205 	    %% such group
206	    make_switch(V, [match_congroup(DG, Vs, CsG, Else, Env)
207 			    || {DG, _, CsG} <- Gs],
208 			Else, Env);
209	Ts ->
210	    Cs1 = [match_typegroup(T, V, Vs, Gs, Else, Env)
211		   || {T, _, Gs} <- Ts],
212	    make_switch(V, Cs1, Else, Env)
213    end.
214
215
216match_typegroup(_T, _V, Vs, [{D, _, Cs}], Else, Env) when element(1, D) /= ?binary_id ->
217    %% Don't create a group type switch if there is only one constructor
218    %% in the group. (Note that this always happens for '[]'.)
219    %% Special case for binaries which always get a group switch
220    match_congroup(D, Vs, Cs, Else, Env);
221match_typegroup(T, V, Vs, Gs, Else, Env) ->
222    Body = make_switch(V, [match_congroup(D, Vs, Cs, Else, Env)
223			 ||  {D, _, Cs} <- Gs],
224		       Else, Env),
225    typetest_clause(T, V, Body, Env).
226
227match_congroup({?binary_id, Segs}, Vs, Cs, Else, Env) ->
228    Body = match(Vs, Cs, Else, Env),
229    cerl:c_clause([make_pat(?binary_id, Segs)], Body);
230
231match_congroup({D, A}, Vs, Cs, Else, Env) ->
232    Vs1 = new_vars(A, Env),
233    Body = match(Vs1 ++ Vs, Cs, Else, add_vars(Vs1, Env)),
234    cerl:c_clause([make_pat(D, Vs1)], Body).
235
236make_switch(V, Cs, Else, Env) ->
237    cerl:c_case(V, if Else =:= none -> Cs;
238		      true -> Cs ++ [cerl:c_clause([new_var(Env)],
239						   Else)]
240		   end).
241
242%% We preserve the relative order of different-type constructors as they
243%% were originally listed. This is done by tracking the clause numbers.
244
245group_con(Cs) ->
246    {Cs1, _} = mapfoldl(fun (C, N) ->
247				[P | Ps] = cerl:clause_pats(C),
248				Ps1 = sub_pats(P) ++ Ps,
249				G = cerl:clause_guard(C),
250				B = cerl:clause_body(C),
251				C1 = cerl:update_c_clause(C, Ps1, G, B),
252				D = con_desc(P),
253				{{D, N, C1}, N + 1}
254			end,
255			0, Cs),
256    %% Sort and group constructors.
257    Css = group(keysort(1, Cs1), fun ({D,_,_}) -> D end),
258    %% Sort each group "back" by line number, and move the descriptor
259    %% and line number to the wrapper for the group.
260    Gs = [finalize_congroup(C) || C <- Css],
261    %% Group by type only (put e.g. different-arity tuples together).
262    Gss = group(Gs, fun ({D,_,_}) -> con_desc_type(D) end),
263    %% Sort and wrap the type groups.
264    Ts = [finalize_typegroup(G) || G <- Gss],
265    %% Sort type-groups by first clause order
266    keysort(2, Ts).
267
268finalize_congroup(Cs) ->
269    [{D,N,_}|_] = Cs1 = keysort(2, Cs),
270    {D, N, [C || {_,_,C} <- Cs1]}.
271
272finalize_typegroup(Gs) ->
273    [{D,N,_}|_] = Gs1 = keysort(2, Gs),
274    {con_desc_type(D), N, Gs1}.
275
276%% Since Erlang clause patterns can contain "alias patterns", we must
277%% eliminate these, by turning them into let-definitions in the guards
278%% and bodies of the clauses.
279
280unalias(C, V) ->
281    [P | Ps] = cerl:clause_pats(C),
282    B = cerl:clause_body(C),
283    G = cerl:clause_guard(C),
284    unalias(P, V, Ps, B, G, C).
285
286unalias(P, V, Ps, B, G, C) ->
287    case cerl:type(P) of
288	alias ->
289	    V1 = cerl:alias_var(P),
290	    B1 = make_let([V1], V, B),
291	    G1 = make_let([V1], V, G),
292	    unalias(cerl:alias_pat(P), V, Ps, B1, G1, C);
293	_ ->
294	    cerl:update_c_clause(C, [P | Ps], G, B)
295    end.
296
297%% Generating a type-switch clause
298
299typetest_clause([], _V, E, _Env) ->
300    cerl:c_clause([cerl:c_nil()], E);
301typetest_clause(atom, V, E, _Env) ->
302    typetest_clause_1(is_atom, V, E);
303typetest_clause(integer, V, E, _Env) ->
304    typetest_clause_1(is_integer, V, E);
305typetest_clause(float, V, E, _Env) ->
306    typetest_clause_1(is_float, V, E);
307typetest_clause(cons, _V, E, Env) ->
308    [V1, V2] = new_vars(2, Env),
309    cerl:c_clause([cerl:c_cons(V1, V2)], E);  % there is no 'is cons'
310typetest_clause(tuple, V, E, _Env) ->
311    typetest_clause_1(is_tuple, V, E);
312typetest_clause(binary, V, E, _Env) ->
313    typetest_clause_1(is_binary, V, E).
314
315typetest_clause_1(T, V, E) ->
316    cerl:c_clause([V], cerl:c_call(cerl:c_atom('erlang'),
317				   cerl:c_atom(T), [V]), E).
318
319%% This returns a constructor descriptor, to be used for grouping and
320%% pattern generation. It consists of an identifier term and the arity.
321
322con_desc(E) ->
323    case cerl:type(E) of
324	cons -> {?cons_id, 2};
325	tuple -> {?tuple_id, cerl:tuple_arity(E)};
326	binary -> {?binary_id, cerl:binary_segments(E)};
327	literal ->
328	    case cerl:concrete(E) of
329		[_|_] -> {?cons_id, 2};
330		T when is_tuple(T) -> {?tuple_id, tuple_size(T)};
331		V -> {?literal_id(V), 0}
332	    end;
333	_ ->
334	    throw({bad_constructor, E})
335    end.
336
337%% This returns the type class for a constructor descriptor, for
338%% grouping of clauses. It does not distinguish between tuples of
339%% different arity, nor between different values of atoms, integers and
340%% floats.
341
342con_desc_type({?literal_id([]), _}) -> [];
343con_desc_type({?literal_id(V), _}) when is_atom(V) -> atom;
344con_desc_type({?literal_id(V), _}) when is_integer(V) -> integer;
345con_desc_type({?literal_id(V), _}) when is_float(V) -> float;
346con_desc_type({?cons_id, 2}) -> cons;
347con_desc_type({?tuple_id, _}) -> tuple;
348con_desc_type({?binary_id, _}) -> binary.
349
350%% This creates a new constructor pattern from a type descriptor and a
351%% list of variables.
352
353make_pat(?cons_id, [V1, V2]) -> cerl:c_cons(V1, V2);
354make_pat(?tuple_id, Vs) -> cerl:c_tuple(Vs);
355make_pat(?binary_id, Segs) -> cerl:c_binary(Segs);
356make_pat(?literal_id(Val), []) -> cerl:abstract(Val).
357
358%% This returns the list of subpatterns of a constructor pattern.
359
360sub_pats(E) ->
361    case cerl:type(E) of
362	cons ->
363	    [cerl:cons_hd(E), cerl:cons_tl(E)];
364	tuple ->
365	    cerl:tuple_es(E);
366	binary ->
367	    [];
368	literal ->
369	    case cerl:concrete(E) of
370		[H|T] -> [cerl:abstract(H), cerl:abstract(T)];
371		T when is_tuple(T) -> [cerl:abstract(X)
372				       || X <- tuple_to_list(T)];
373		_ -> []
374	    end;
375	_ ->
376	    throw({bad_constructor_pattern, E})
377    end.
378
379%% This avoids generating stupid things like "let X = ... in 'true'",
380%% and "let X = Y in X", keeping the generated code cleaner. It also
381%% prevents expressions from being considered "non-lightweight" when
382%% code duplication is disallowed (see is_lightweight for details).
383
384make_let(Vs, A, B) ->
385    cerl_lib:reduce_expr(cerl:c_let(Vs, A, B)).
386
387%% ---------------------------------------------------------------------
388%% Rewriting a module or other expression:
389
390%% @spec expr(Expression::cerl(), Env) -> cerl()
391%%    Env = rec_env:environment()
392%%
393%% @doc Rewrites all <code>case</code>-clauses in
394%% <code>Expression</code>. <code>receive</code>-clauses are not
395%% affected.
396%%
397%% <p>The environment is used for generating new variables which do not
398%% shadow existing bindings.</p>
399%%
400%% @see clauses/2
401%% @see rec_env
402
403-ifndef(NO_UNUSED).
404-spec expr(cerl:cerl(), rec_env:environment()) -> cerl:cerl().
405
406expr(E, Env) ->
407    case cerl:type(E) of
408        binary ->
409            Es = expr_list(cerl:binary_segments(E), Env),
410            cerl:update_c_binary(E, Es);
411        bitstr ->
412            V = expr(cerl:bitstr_val(E), Env),
413            Sz = expr(cerl:bitstr_size(E), Env),
414            Unit = expr(cerl:bitstr_unit(E), Env),
415            Type = expr(cerl:bitstr_type(E), Env),
416            cerl:update_c_bitstr(E, V, Sz, Unit, Type, cerl:bitstr_flags(E));
417 	literal ->
418	    E;
419	var ->
420	    E;
421	values ->
422	    Es = expr_list(cerl:values_es(E), Env),
423 	    cerl:update_c_values(E, Es);
424	cons ->
425	    H = expr(cerl:cons_hd(E), Env),
426	    T = expr(cerl:cons_tl(E), Env),
427	    cerl:update_c_cons(E, H, T);
428 	tuple ->
429	    Es = expr_list(cerl:tuple_es(E), Env),
430	    cerl:update_c_tuple(E, Es);
431 	'let' ->
432	    A = expr(cerl:let_arg(E), Env),
433	    Vs = cerl:let_vars(E),
434	    Env1 = add_vars(Vs, Env),
435	    B = expr(cerl:let_body(E), Env1),
436	    cerl:update_c_let(E, Vs, A, B);
437	seq ->
438	    A = expr(cerl:seq_arg(E), Env),
439	    B = expr(cerl:seq_body(E), Env),
440 	    cerl:update_c_seq(E, A, B);
441 	apply ->
442	    Op = expr(cerl:apply_op(E), Env),
443	    As = expr_list(cerl:apply_args(E), Env),
444 	    cerl:update_c_apply(E, Op, As);
445 	call ->
446	    M = expr(cerl:call_module(E), Env),
447	    N = expr(cerl:call_name(E), Env),
448	    As = expr_list(cerl:call_args(E), Env),
449 	    cerl:update_c_call(E, M, N, As);
450 	primop ->
451	    As = expr_list(cerl:primop_args(E), Env),
452	    cerl:update_c_primop(E, cerl:primop_name(E), As);
453 	'case' ->
454	    A = expr(cerl:case_arg(E), Env),
455	    Cs = expr_list(cerl:case_clauses(E), Env),
456	    {E1, Vs} = clauses(Cs, Env),
457 	    make_let(Vs, A, E1);
458 	clause ->
459	    Vs = cerl:clause_vars(E),
460	    Env1 = add_vars(Vs, Env),
461	    G = expr(cerl:clause_guard(E), Env1),
462	    B = expr(cerl:clause_body(E), Env1),
463	    cerl:update_c_clause(E, cerl:clause_pats(E), G, B);
464 	'fun' ->
465	    Vs = cerl:fun_vars(E),
466	    Env1 = add_vars(Vs, Env),
467	    B = expr(cerl:fun_body(E), Env1),
468	    cerl:update_c_fun(E, Vs, B);
469 	'receive' ->
470	    %% NOTE: No pattern matching compilation is done here! The
471	    %% receive-clauses and patterns cannot be staged as long as
472	    %% we are working with "normal" Core Erlang.
473	    Cs = expr_list(cerl:receive_clauses(E), Env),
474	    T = expr(cerl:receive_timeout(E), Env),
475	    A = expr(cerl:receive_action(E), Env),
476	    cerl:update_c_receive(E, Cs, T, A);
477	'try' ->
478	    A = expr(cerl:try_arg(E), Env),
479	    Vs = cerl:try_vars(E),
480	    B = expr(cerl:try_body(E), add_vars(Vs, Env)),
481	    Evs = cerl:try_evars(E),
482	    H = expr(cerl:try_handler(E), add_vars(Evs, Env)),
483	    cerl:update_c_try(E, A, Vs, B, Evs, H);
484 	'catch' ->
485	    B = expr(cerl:catch_body(E), Env),
486	    cerl:update_c_catch(E, B);
487	letrec ->
488	    Ds = cerl:letrec_defs(E),
489	    Env1 = add_defs(Ds, Env),
490	    Ds1 = defs(Ds, Env1),
491	    B = expr(cerl:letrec_body(E), Env1),
492	    cerl:update_c_letrec(E, Ds1, B);
493	module ->
494	    Ds = cerl:module_defs(E),
495	    Env1 = add_defs(Ds, Env),
496	    Ds1 = defs(Ds, Env1),
497	    cerl:update_c_module(E, cerl:module_name(E),
498				 cerl:module_exports(E),
499				 cerl:module_attrs(E), Ds1)
500    end.
501
502expr_list(Es, Env) ->
503    [expr(E, Env) || E <- Es].
504
505defs(Ds, Env) ->
506    [{V, expr(F, Env)} || {V, F} <- Ds].
507-endif.	% NO_UNUSED
508%% @clear
509
510%% ---------------------------------------------------------------------
511%%	Support functions
512
513new_var(Env) ->
514    Name = env__new_vname(Env),
515    cerl:c_var(Name).
516
517new_vars(N, Env) ->
518    [cerl:c_var(V) || V <- env__new_vnames(N, Env)].
519
520new_fvar(A, N, Env) ->
521    Name = env__new_fname(A, N, Env),
522    cerl:c_var(Name).
523
524add_vars(Vs, Env) ->
525    foldl(fun (V, E) -> env__bind(cerl:var_name(V), [], E) end, Env, Vs).
526
527-ifndef(NO_UNUSED).
528add_defs(Ds, Env) ->
529    foldl(fun ({V, _F}, E) ->
530		  env__bind(cerl:var_name(V), [], E)
531	  end, Env, Ds).
532-endif.	% NO_UNUSED
533
534%% This decides whether an expression is worth lifting out to a separate
535%% function instead of duplicating the code. In other words, whether its
536%% cost is about the same or smaller than that of a local function call.
537%% Note that variables must always be "lightweight"; otherwise, they may
538%% get lifted out of the case switch that introduces them.
539
540is_lightweight(E) ->
541    case get('cerl_pmatch_duplicate_code') of
542	never -> cerl:type(E) =:= var;    % Avoids all code duplication
543	always -> true;    % Does not lift code to new functions
544	_ -> is_lightweight_1(E)
545    end.
546
547is_lightweight_1(E) ->
548    case cerl:type(E) of
549	var -> true;
550   	literal -> true;
551   	'fun' -> true;
552   	values -> all(fun is_simple/1, cerl:values_es(E));
553   	cons -> is_simple(cerl:cons_hd(E))
554   		    andalso is_simple(cerl:cons_tl(E));
555   	tuple -> all(fun is_simple/1, cerl:tuple_es(E));
556   	'let' -> (is_simple(cerl:let_arg(E)) andalso
557   		  is_lightweight_1(cerl:let_body(E)));
558   	seq -> (is_simple(cerl:seq_arg(E)) andalso
559   		is_lightweight_1(cerl:seq_body(E)));
560   	primop ->
561   	    all(fun is_simple/1, cerl:primop_args(E));
562   	apply ->
563   	    is_simple(cerl:apply_op(E))
564   		andalso all(fun is_simple/1, cerl:apply_args(E));
565   	call ->
566   	    is_simple(cerl:call_module(E))
567   		andalso is_simple(cerl:call_name(E))
568   		andalso all(fun is_simple/1, cerl:call_args(E));
569   	_ ->
570	    %% The default is to lift the code to a new function.
571	    false
572    end.
573
574%% "Simple" things have no (or negligible) runtime cost and are free
575%% from side effects.
576
577is_simple(E) ->
578    case cerl:type(E) of
579	var -> true;
580	literal -> true;
581	values -> all(fun is_simple/1, cerl:values_es(E));
582	_ -> false
583    end.
584
585
586%% ---------------------------------------------------------------------
587%% Abstract datatype: environment()
588
589env__bind(Key, Val, Env) ->
590    rec_env:bind(Key, Val, Env).
591
592-ifndef(NO_UNUSED).
593%% env__bind_recursive(Ks, Vs, F, Env) ->
594%%     rec_env:bind_recursive(Ks, Vs, F, Env).
595
596%% env__lookup(Key, Env) ->
597%%     rec_env:lookup(Key, Env).
598
599%% env__get(Key, Env) ->
600%%     rec_env:get(Key, Env).
601
602%% env__is_defined(Key, Env) ->
603%%     rec_env:is_defined(Key, Env).
604
605env__empty() ->
606    rec_env:empty().
607-endif.	% NO_UNUSED
608
609env__new_vname(Env) ->
610    rec_env:new_key(Env).
611
612env__new_vnames(N, Env) ->
613    rec_env:new_keys(N, Env).
614
615env__new_fname(F, A, Env) ->
616    rec_env:new_key(fun (X) ->
617			    S = integer_to_list(X),
618			    {list_to_atom(F ++ S), A}
619		    end,
620		    Env).
621