Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 326523ebe4
Fetching contributors…

Cannot retrieve contributors at this time

104 lines (83 sloc) 3.396 kb
%
% reia_ivars: Convert Reia implicit state instance variables to explicit state
% Copyright (C)2010 Tony Arcieri
%
% Redistribution is permitted under the MIT license. See LICENSE for details.
%
-module(reia_ivars).
-export([mutable_method/1, immutable_method/1]).
-include("reia_nodes.hrl").
-include("reia_object.hrl").
-define(ivar_placeholder(Line, Name),
#var{line=Line, name=list_to_atom("__ivar_placeholder_" ++ atom_to_list(Name))}
).
% Transform for methods that are allowed to alter instance variables
mutable_method(Method) ->
Line = Method#function.line,
% Transform all ivars in function arguments into placeholder variables
{Args, ArgIvars} = lists:mapfoldl(fun(Arg, Ivars) ->
{[Arg2], Ivars2} = reia_syntax:mapfold_subtrees(fun mutable_args_ivars/2, Ivars, [Arg]),
{Arg2, Ivars2}
end, [], Method#function.args),
% Extract instance variable dictionary
Ivars = #native_call{
line = Line,
module = erlang,
function = element,
args = [#integer{line=Line, value=3}, ?self(Line)]
},
BindIvars = #match{line=Line, left=?ivars(Line), right=Ivars},
Body = case ArgIvars of
[] -> Method#function.body;
_ ->
Placeholders = [?ivar_placeholder(Line, Name) || #ivar{name=Name} <- ArgIvars],
BindArgs = #match{
line = Line,
left = #tuple{line=Line, elements=ArgIvars},
right = #tuple{line=Line, elements=Placeholders}
},
[BindArgs|Method#function.body]
end,
Body2 = reia_syntax:map_subtrees(fun mutable_method_ivars/1, Body),
Method#function{args=Args, body = [BindIvars|Body2]}.
mutable_args_ivars(#ivar{line=Line, name=Name} = Ivar, Ivars) ->
{?ivar_placeholder(Line, Name), [Ivar|Ivars]};
mutable_args_ivars(Expr, Ivars) ->
reia_syntax:mapfold_subtrees(fun mutable_args_ivars/2, Ivars, Expr).
mutable_method_ivars(#ivar{} = Ivar) -> remap_ivar(Ivar);
mutable_method_ivars(Expr) ->
reia_syntax:map_subtrees(fun mutable_method_ivars/1, Expr).
% Methods which are not allowed to make changes to instance variables
immutable_method(Method) ->
Line = Method#function.line,
IvarPattern = #tuple{line=Line, elements=[
#atom{line=Line, name=reia_object},
#var{line=Line, name='_'},
?ivars(Line)
 ]},
Ivars = #'case'{line=Line, expr=?self(Line), clauses=[
#clause{line=Line, patterns=[IvarPattern], exprs=[#nil{}]},
#clause{line=Line, patterns=[#var{line=Line, name='_'}], exprs=[
#match{line=Line, left=?ivars(Line), right=#nil{}}
]}
]},
Body = reia_syntax:map_subtrees(fun immutable_method_ivars/1, Method#function.body),
Method#function{body=[Ivars|Body]}.
immutable_method_ivars(#match{} = Expr) ->
[Left] = reia_syntax:map_subtrees(fun immutable_match_context/1, [Expr#match.left]),
[Right] = reia_syntax:map_subtrees(fun immutable_method_ivars/1, [Expr#match.right]),
Expr#match{left=Left, right=Right};
immutable_method_ivars(#ivar{} = Ivar) -> remap_ivar(Ivar);
immutable_method_ivars(Expr) ->
reia_syntax:map_subtrees(fun immutable_method_ivars/1, Expr).
immutable_match_context(#ivar{line=Line}) ->
reia:throw('SyntaxError', Line, "illegal instance variable match");
immutable_match_context(Expr) ->
reia_syntax:map_subtrees(fun immutable_match_context/1, Expr).
remap_ivar(#ivar{line=Line, name=Name}) ->
#binary_op{
line = Line,
type = '[]',
left = ?ivars(Line),
right = #atom{line=Line, name=Name}
}.
Jump to Line
Something went wrong with that request. Please try again.