Permalink
Browse files

Ensure quoted variables are properly carried in clauses

  • Loading branch information...
1 parent bd09818 commit bc4918ee0de69971b740a25b036348a51c2cbce4 @josevalim josevalim committed Aug 17, 2012
Showing with 29 additions and 19 deletions.
  1. +3 −0 CHANGELOG.md
  2. +2 −3 lib/eex/lib/eex/engine.ex
  3. +16 −11 lib/elixir/src/elixir_clauses.erl
  4. +8 −5 lib/elixir/src/elixir_scope.erl
View
@@ -4,6 +4,9 @@
* [Kernel] Better error messages when invalid options are given to `import`, `alias` or `require`
* [Binary] Add support to `part` and `split` functions
+* bug fix
+ * [Macro] Fixed a bug where quoted expressions were not behaving the same as their non-quoted counterparts
+
# v0.6.0 (2012-08-01)
* incompatible changes
@@ -37,9 +37,8 @@ defmodule EEx.Engine do
"""
def handle_expr(buffer, '=', expr) do
quote do
- tmp_1 = unquote(buffer)
- tmp_2 = to_binary(unquote(expr))
- tmp_1 <> tmp_2
+ tmp = unquote(buffer)
+ tmp <> to_binary(unquote(expr))
end
end
@@ -119,7 +119,7 @@ match(Line, DecoupledClauses, RawS) ->
{ FinalVars, FS } = lists:mapfoldl(fun normalize_vars/2, TS, NewVars),
% Defines a tuple that will be used as left side of the match operator
- LeftVars = [{var, Line, NewValue} || {_, NewValue,_} <- FinalVars],
+ LeftVars = [{var, Line, NewValue} || { _, _, NewValue, _ } <- FinalVars],
% Expand all clauses by adding a match operation at the end
% that assigns variables missing in one clause to the others.
@@ -128,7 +128,7 @@ match(Line, DecoupledClauses, RawS) ->
end.
expand_clauses(Line, [Clause|T], [ClauseVars|V], LeftVars, FinalVars, Acc, S) ->
- RightVars = [normalize_clause_var(Var, OldValue, ClauseVars) || {Var, _, OldValue} <- FinalVars],
+ RightVars = [normalize_clause_var(Var, Kind, OldValue, ClauseVars) || { Var, Kind, _, OldValue } <- FinalVars],
AssignExpr = generate_match(Line, LeftVars, RightVars),
ClauseExprs = element(5, Clause),
@@ -199,26 +199,31 @@ has_match_tuple(_) -> false.
% Normalize the given var checking its existence in the scope var dictionary.
-normalize_vars(Var, #elixir_scope{vars=Vars, clause_vars=ClauseVars} = S) ->
- { { _, _, NewValue }, NS } = elixir_scope:build_erl_var(0, S),
+normalize_vars({ Var, quoted }, S) ->
+ normalize_vars(Var, quoted, #elixir_scope.quote_vars, S);
- FS = NS#elixir_scope{
- vars=orddict:store(Var, NewValue, Vars),
- clause_vars=orddict:store(Var, NewValue, ClauseVars)
- },
+normalize_vars({ Var, Kind }, S) ->
+ normalize_vars(Var, Kind, #elixir_scope.vars, S).
+
+normalize_vars(Var, Kind, Index, #elixir_scope{clause_vars=ClauseVars} = S) ->
+ Vars = element(Index, S),
+ { { _, _, NewValue }, S1 } = elixir_scope:build_erl_var(0, S),
+
+ S2 = setelement(Index, S1, orddict:store(Var, NewValue, Vars)),
+ S3 = S2#elixir_scope{clause_vars=orddict:store({ Var, Kind }, NewValue, ClauseVars)},
Expr = case orddict:find(Var, Vars) of
{ ok, OldValue } -> { var, 0, OldValue };
error -> { atom, 0, nil }
end,
- { { Var, NewValue, Expr }, FS }.
+ { { Var, Kind, NewValue, Expr }, S3 }.
% Normalize a var by checking if it was defined in the clause.
% If so, use it, otherwise use from main scope.
-normalize_clause_var(Var, OldValue, ClauseVars) ->
- case orddict:find(Var, ClauseVars) of
+normalize_clause_var(Var, Kind, OldValue, ClauseVars) ->
+ case orddict:find({ Var, Kind }, ClauseVars) of
{ ok, ClauseValue } -> { var, 0, ClauseValue };
error -> OldValue
end.
@@ -32,7 +32,7 @@ translate_var(Line, Name, Kind, S) ->
{ NewVar, NS#elixir_scope{
vars=orddict:store(Name, RealName, Vars),
temp_vars=orddict:store(Name, Kind, TempVars),
- clause_vars=orddict:store(Name, RealName, ClauseVars)
+ clause_vars=orddict:store({ Name, Kind }, RealName, ClauseVars)
} }
end;
_ ->
@@ -110,7 +110,7 @@ umergev(S1, S2) ->
S2#elixir_scope{
vars=orddict:merge(fun var_merger/3, V1, V2),
quote_vars=orddict:merge(fun var_merger/3, Q1, Q2),
- clause_vars=orddict:merge(fun var_merger/3, C1, C2)
+ clause_vars=orddict:merge(fun clause_var_merger/3, C1, C2)
}.
% Receives two scopes and return a new scope based on the first
@@ -127,13 +127,16 @@ umergec(S1, S2) ->
% Merge variables trying to find the most recently created.
+clause_var_merger({ Var, _ }, K1, K2) ->
+ var_merger(Var, K1, K2).
+
var_merger(Var, Var, K2) -> K2;
var_merger(Var, K1, Var) -> K1;
var_merger(_Var, K1, K2) ->
- V1 = list_to_integer(var_number(atom_to_list(K1))),
- V2 = list_to_integer(var_number(atom_to_list(K2))),
+ V1 = var_number(atom_to_list(K1)),
+ V2 = var_number(atom_to_list(K2)),
if V1 > V2 -> K1;
true -> K2
end.
-var_number([_,_|T]) -> T.
+var_number([_,_|T]) -> list_to_integer(T).

0 comments on commit bc4918e

Please sign in to comment.