Move remaining functions to elixir_env
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 }.
|
||||
@@ -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
|
||||
|
||||
@@ -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 } ->
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 }.
|
||||
|
||||
@@ -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 ->
|
||||
|
||||
Reference in New Issue
Block a user