Move remaining functions to elixir_env

This commit is contained in:
José Valim
2013-11-22 23:13:26 +01:00
parent 4e251b10b9
commit 7d26bfbfad
10 changed files with 88 additions and 101 deletions
+1 -1
View File
@@ -620,7 +620,7 @@ defmodule Macro do
# Anything else is just returned
defp expand_once(other, _env, cache), do: { other, false, cache }
defp to_erl_env(env, nil), do: :elixir_scope.to_erl_env(env)
defp to_erl_env(env, nil), do: :elixir_env.ex_to_scope(env)
defp to_erl_env(_env, cache), do: cache
defp is_partial?(args) do
+5 -5
View File
@@ -70,7 +70,7 @@ delete_definition(Module, Tuple) ->
%% before evaluating the function body), we would see both definitions.
wrap_definition(Kind, Call, Expr, Context, ExEnv) ->
Env = elixir_env:from_ex(ExEnv),
Env = elixir_env:ex_to_env(ExEnv),
{ EscapedCall, QC } = elixir_quote:escape(Call, true),
{ EscapedExpr, QE } = elixir_quote:escape(Expr, true),
@@ -78,14 +78,14 @@ wrap_definition(Kind, Call, Expr, Context, ExEnv) ->
(not QC#elixir_quote.unquoted) andalso
(not QE#elixir_quote.unquoted),
Args = [Kind, CheckClauses, EscapedCall, EscapedExpr, elixir_env:to_quote(Env)],
Args = [Kind, CheckClauses, EscapedCall, EscapedExpr, elixir_env:serialize(Env)],
{ { '.', [], [elixir_def, store_definition] }, [], Args }.
% Invoked by the wrap definition with the function abstract tree.
% Each function is then added to the function table.
store_definition(Kind, CheckClauses, Call, Body, #elixir_env{line=Line} = Env) ->
S = elixir_env:to_scope(Env),
S = elixir_env:env_to_scope(Env),
{ NameAndArgs, Guards } = elixir_clauses:extract_guards(Call),
{ Name, Args } = case elixir_clauses:extract_args(NameAndArgs) of
@@ -135,7 +135,7 @@ run_on_definition_callbacks(Kind, Line, Module, Name, Args, Guards, Expr, S, CO)
true ->
ok;
_ ->
Env = elixir_scope:to_ex_env({ Line, S }),
Env = elixir_env:scope_to_ex({ Line, S }),
Callbacks = 'Elixir.Module':get_attribute(Module, on_definition),
[Mod:Fun(Env, Kind, Name, Args, Guards, Expr) || { Mod, Fun } <- Callbacks]
end.
@@ -201,7 +201,7 @@ translate_clause(Line, Kind, Unpacked, Guards, Body, S) ->
true ->
FBody = { 'match', Line,
{ 'var', Line, '__CALLER__' },
?wrap_call(Line, elixir_scope, to_ex_env, [{ var, Line, '_@CALLER' }])
?wrap_call(Line, elixir_env, scope_to_ex, [{ var, Line, '_@CALLER' }])
},
setelement(5, TClause, [FBody|element(5, TClause)]);
false -> TClause
+60
View File
@@ -0,0 +1,60 @@
-module(elixir_env).
-include("elixir.hrl").
-export([ex_to_env/1, env_to_scope/1, env_to_scope_with_vars/2,
ex_to_scope/1, scope_to_ex/1, serialize/1, serialize_with_vars/1]).
%% Conversion in between #elixir_env, #elixir_scope and Macro.Env
ex_to_env(Env) when element(1, Env) == 'Elixir.Macro.Env' ->
erlang:setelement(1, Env, elixir_env).
env_to_scope(#elixir_env{module=Module,file=File,
function=Function,aliases=Aliases,context=Context,
requires=Requires,macros=Macros,functions=Functions,
macro_functions=MacroFunctions,macro_macros=MacroMacros,
context_modules=ContextModules,macro_aliases=MacroAliases,
lexical_tracker=Lexical}) ->
#elixir_scope{module=Module,file=File,
function=Function,aliases=Aliases,context=Context,
requires=Requires,macros=Macros,functions=Functions,
macro_functions=MacroFunctions,macro_macros=MacroMacros,
context_modules=ContextModules,macro_aliases=MacroAliases,
lexical_tracker=Lexical}.
env_to_scope_with_vars(#elixir_env{} = Env, Vars) ->
(env_to_scope(Env))#elixir_scope{
vars=orddict:from_list(Vars),
counter=[{'',length(Vars)}]
}.
scope_to_ex({ Line, #elixir_scope{module=Module,file=File,
function=Function,aliases=Aliases,context=Context,
requires=Requires,macros=Macros,functions=Functions,
context_modules=ContextModules,macro_aliases=MacroAliases,
macro_functions=MacroFunctions, macro_macros=MacroMacros,
vars=Vars,lexical_tracker=Lexical} }) when is_integer(Line) ->
{ 'Elixir.Macro.Env', Module, File, Line, Function, Context, Requires, Aliases,
Functions, Macros, MacroAliases, MacroFunctions, MacroMacros, ContextModules,
[Pair || { Pair, _ } <- Vars], Lexical }.
ex_to_scope(Env) ->
env_to_scope(ex_to_env(Env)).
%% Serialization
serialize(#elixir_env{lexical_tracker=nil} = Env) ->
{ '{}', [], tuple_to_list(Env) };
serialize(#elixir_env{lexical_tracker=Lexical} = Env) ->
Expr = { { '.', [], [erlang, binary_to_term] }, [], [term_to_binary(Lexical)] },
{ '{}', [], tuple_to_list(Env#elixir_env{lexical_tracker=Expr}) }.
serialize_with_vars(#elixir_env{} = Env) ->
{ Vars, _ } = lists:mapfoldl(fun var_to_tuple/2, 0, Env#elixir_env.vars),
{ serialize(Env), Vars }.
var_to_tuple({ Key, Kind }, Counter) ->
Var = if is_atom(Kind) -> { Key, [], Kind };
is_integer(Kind) -> { Key, [{ counter, Kind }], nil }
end,
Args = [Key, Kind, ?atom_concat(["_@", Counter]), Var],
{ { '{}', [], Args }, Counter + 1 }.
+1 -1
View File
@@ -80,7 +80,7 @@ capture_import(Meta, { Atom, ImportMeta, Args } = Expr, S, Sequential) ->
end.
capture_require(Meta, { { '.', _, [Left, Right] }, RequireMeta, Args } = Expr, S, Sequential) ->
{ Mod, SE } = 'Elixir.Macro':expand_all(Left, elixir_scope:to_ex_env({ ?line(Meta), S }), S),
{ Mod, SE } = 'Elixir.Macro':expand_all(Left, elixir_env:scope_to_ex({ ?line(Meta), S }), S),
case Sequential andalso is_atom(Mod) andalso
elixir_dispatch:require_function(RequireMeta, Mod, Right, length(Args), SE) of
+2 -2
View File
@@ -145,7 +145,7 @@ extract_bit_values(Meta, [Size|T], default, Types, S) when is_integer(Size) anda
extract_bit_values(Meta, T, {integer, Meta, Size}, Types, S);
extract_bit_values(Meta, [{ '|', _, [Left, Right] }], Size, Types, S) ->
{ Expanded, ES } = 'Elixir.Macro':expand_all(Right, elixir_scope:to_ex_env({ ?line(Meta), S }), S),
{ Expanded, ES } = 'Elixir.Macro':expand_all(Right, elixir_env:scope_to_ex({ ?line(Meta), S }), S),
extract_bit_values(Meta, [Left|join_expansion(Expanded,[])], Size, Types, ES);
extract_bit_values(Meta, [_|_] = All, Size, Types, S) ->
@@ -187,7 +187,7 @@ extract_bit_type_or_size(_Value, _Args, _Other, _Types) ->
{ error, unknown }.
handle_unknown_specifier(Meta, [H|T], Size, Types, S) ->
case 'Elixir.Macro':expand_all(H, elixir_scope:to_ex_env({ ?line(Meta), S }), S) of
case 'Elixir.Macro':expand_all(H, elixir_env:scope_to_ex({ ?line(Meta), S }), S) of
{ H, ES } ->
elixir_errors:syntax_error(Meta, ES#elixir_scope.file, "unknown bitstring specifier ~ts", ['Elixir.Macro':to_string(H)]);
{ E, ES } ->
+2 -2
View File
@@ -95,7 +95,7 @@ translate({defmodule, Meta, [Ref, KV]}, S) when is_list(KV) ->
{ Ref, S }
end,
Env = elixir_scope:to_ex_env({ ?line(Meta), FS }),
Env = elixir_env:scope_to_ex({ ?line(Meta), FS }),
translate_each(elixir_module:translate(FRef, Block, Env), FS);
translate({Kind, Meta, [Call]}, S) when ?defs(Kind) ->
@@ -104,7 +104,7 @@ translate({Kind, Meta, [Call]}, S) when ?defs(Kind) ->
translate({Kind, Meta, [Call, Expr]}, S) when ?defs(Kind) ->
assert_module_scope(Meta, Kind, S),
assert_no_function_scope(Meta, Kind, S),
Env = elixir_scope:to_ex_env({ ?line(Meta), S }),
Env = elixir_env:scope_to_ex({ ?line(Meta), S }),
Ctx = lists:keymember(context, 1, Meta),
translate_each(elixir_def:wrap_definition(Kind, Call, Expr, Ctx, Env), S);
+5 -5
View File
@@ -41,7 +41,7 @@ docs_table(Module) ->
%% will be passed to the invoked function.
translate(Ref, Block, ExEnv) ->
Env = elixir_env:from_ex(ExEnv),
Env = elixir_env:ex_to_env(ExEnv),
%% In case we are generating a module from inside a function,
%% we get rid of the lexical tracker information as, at this
@@ -52,7 +52,7 @@ translate(Ref, Block, ExEnv) ->
end,
{ Escaped, _ } = elixir_quote:escape(Block, false),
{ QuotedEnv, QuotedVars } = elixir_env:to_quote_with_vars(LexEnv),
{ QuotedEnv, QuotedVars } = elixir_env:serialize_with_vars(LexEnv),
Args = [Ref, Escaped, QuotedVars, QuotedEnv],
{ { '.', [], [elixir_module, compile] }, [], Args }.
@@ -61,7 +61,7 @@ translate(Ref, Block, ExEnv) ->
compile(Module, Block, Vars, #elixir_env{line=Line} = Env) ->
Dict = [{ { Name, Kind }, Value } || { Name, Kind, Value, _ } <- Vars],
compile(Line, Module, Block, Vars, elixir_env:to_scope_with_vars(Env, Dict)).
compile(Line, Module, Block, Vars, elixir_env:env_to_scope_with_vars(Env, Dict)).
compile(Line, Module, Block, Vars, #elixir_scope{context_modules=FileModules} = RawS) when is_atom(Module) ->
C = elixir_compiler:get_opts(),
@@ -151,7 +151,7 @@ eval_form(Line, Module, Block, Vars, S) ->
KV = [{ K, V } || { _, _, K, V } <- Vars],
{ Value, NewS } = elixir_compiler:eval_forms([Block], Line, KV, S),
elixir_def_overridable:store_pending(Module),
Env = elixir_scope:to_ex_env({ Line, S }),
Env = elixir_env:scope_to_ex({ Line, S }),
eval_callbacks(Line, Module, before_compile, [Env], NewS),
elixir_def_overridable:store_pending(Module),
Value.
@@ -278,7 +278,7 @@ compile_opts(Module) ->
load_form(Line, Forms, Opts, #elixir_scope{file=File} = S) ->
elixir_compiler:module(Forms, File, Opts, fun(Module, Binary) ->
EvalS = scope_for_eval(Module, S),
Env = elixir_scope:to_ex_env({ Line, EvalS }),
Env = elixir_env:scope_to_ex({ Line, EvalS }),
eval_callbacks(Line, Module, after_compile, [Env, Binary], EvalS),
case get(elixir_compiled) of
-81
View File
@@ -2,9 +2,6 @@
-module(elixir_scope).
-export([translate_var/5,
build_erl_var/2, build_ex_var/2,
serialize/1, deserialize/1, to_erl/1,
serialize_with_vars/2, deserialize_with_vars/2,
to_erl_env/1, to_ex_env/1,
load_binding/2, dump_binding/2,
umergev/2, umergec/2, umergea/2, merge_clause_vars/2
]).
@@ -81,84 +78,6 @@ build_ex_var(Line, Key, Name, S) when is_integer(Line) ->
Var = { ?atom_concat([Name, "@", Counter]), [{line,Line}], Context },
{ Var, NS }.
%% Macro.Env <-> #elixir_scope conversion
to_erl_env({ 'Elixir.Macro.Env', Module, File, _Line, Function, Context, Requires,
Aliases, Functions, Macros, MacroAliases, MacroFunctions, MacroMacros,
ContextModules, _Vars, Lexical }) ->
#elixir_scope{module=Module,file=File,
function=Function,aliases=Aliases,context=Context,
requires=Requires,macros=Macros,functions=Functions,
macro_functions=MacroFunctions, macro_macros=MacroMacros,
context_modules=ContextModules,macro_aliases=MacroAliases,
lexical_tracker=Lexical}.
to_ex_env({ Line, #elixir_scope{module=Module,file=File,
function=Function,aliases=Aliases,context=Context,
requires=Requires,macros=Macros,functions=Functions,
context_modules=ContextModules,macro_aliases=MacroAliases,
macro_functions=MacroFunctions, macro_macros=MacroMacros,
vars=Vars,lexical_tracker=Lexical} }) when is_integer(Line) ->
{ 'Elixir.Macro.Env', Module, File, Line, Function, Context, Requires, Aliases,
Functions, Macros, MacroAliases, MacroFunctions, MacroMacros, ContextModules,
list_vars(Vars), Lexical }.
list_vars(Vars) -> [Pair || { { _, K } = Pair, _ } <- Vars, is_atom(K)].
%% SERIALIZATION
%% When serializing scopes, we support serialization of pids.
to_erl(Structure) ->
elixir_utils:elixir_to_erl(Structure, fun
(X) when is_pid(X) ->
?wrap_call(0, erlang, binary_to_term, [elixir_utils:elixir_to_erl(term_to_binary(X))]);
(Other) ->
error({ badarg, Other })
end).
serialize(S) ->
to_erl({ S#elixir_scope.file, S#elixir_scope.functions,
S#elixir_scope.requires, S#elixir_scope.macros, S#elixir_scope.aliases,
S#elixir_scope.macro_functions, S#elixir_scope.macro_macros, S#elixir_scope.macro_aliases,
S#elixir_scope.context_modules, S#elixir_scope.lexical_tracker }).
serialize_with_vars(Line, S) when is_integer(Line) ->
{ Vars, _ } = orddict:fold(fun({ Key, Kind }, Value, { Acc, Counter }) ->
KindKey = if
is_atom(Kind) -> atom;
is_integer(Kind) -> integer
end,
{ { cons, Line, { tuple, Line, [
{ atom, Line, Key },
{ KindKey, Line, Kind },
{ atom, Line, ?atom_concat(["_@", Counter]) },
{ var, Line, Value }
] }, Acc }, Counter + 1 }
end, { { nil, Line }, 0 }, S#elixir_scope.vars),
{ serialize(S), Vars }.
% Fill in the scope with the variables serialization set in serialize_scope.
deserialize(Tuple) -> deserialize_with_vars(Tuple, []).
deserialize_with_vars({ File, Functions, Requires, Macros, Aliases, MacroFunctions,
MacroMacros, MacroAliases, FileModules, LexicalTracker }, Vars) ->
#elixir_scope{
file=File,
functions=Functions,
requires=Requires,
macros=Macros,
aliases=Aliases,
macro_functions=MacroFunctions,
macro_macros=MacroMacros,
macro_aliases=MacroAliases,
context_modules=FileModules,
vars=orddict:from_list(Vars),
lexical_tracker=LexicalTracker,
counter=[{'',length(Vars)}]
}.
%% SCOPE MERGING
%% Receives two scopes and return a new scope based on the second
+11 -3
View File
@@ -136,8 +136,8 @@ translate_each({ '__DIR__', _Meta, Atom }, S) when is_atom(Atom) ->
translate_each(filename:dirname(S#elixir_scope.file), S);
translate_each({ '__ENV__', Meta, Atom }, S) when is_atom(Atom) ->
Env = elixir_scope:to_ex_env({ ?line(Meta), S }),
{ elixir_scope:to_erl(Env), S };
Env = elixir_env:scope_to_ex({ ?line(Meta), S }),
{ ex_env_to_erl(Env), S };
translate_each({ '__CALLER__', Meta, Atom }, S) when is_atom(Atom) ->
{ { var, ?line(Meta), '__CALLER__' }, S#elixir_scope{caller=true} };
@@ -461,12 +461,20 @@ var_kind(Meta, Kind) ->
false -> Kind
end.
ex_env_to_erl(Structure) ->
elixir_utils:elixir_to_erl(Structure, fun
(X) when is_pid(X) ->
?wrap_call(0, erlang, binary_to_term, [elixir_utils:elixir_to_erl(term_to_binary(X))]);
(Other) ->
error({ badarg, Other })
end).
%% Opts
translate_opts(Meta, Kind, Allowed, Opts, S) ->
{ Expanded, TS } = case literal_opts(Opts) orelse skip_expansion(S#elixir_scope.module) of
true -> { Opts, S };
false -> 'Elixir.Macro':expand_all(Opts, elixir_scope:to_ex_env({ ?line(Meta), S }), S)
false -> 'Elixir.Macro':expand_all(Opts, elixir_env:scope_to_ex({ ?line(Meta), S }), S)
end,
validate_opts(Meta, Kind, Allowed, Expanded, TS),
{ Expanded, TS }.
+1 -1
View File
@@ -79,7 +79,7 @@ normalize_rescue(_, { in, Meta, [Left, Right] }, S) ->
_ when is_list(Right) ->
is_valid_rescue_list(Right, S) andalso { Left, Right };
_ ->
{ Expanded, ES } = 'Elixir.Macro':expand_all(Right, elixir_scope:to_ex_env({ ?line(Meta), S }), S),
{ Expanded, ES } = 'Elixir.Macro':expand_all(Right, elixir_env:scope_to_ex({ ?line(Meta), S }), S),
case is_valid_rescue_list(Expanded, ES) of
true -> { Left, Expanded };
false ->