@@ -108,63 +108,58 @@ do_match(Meta, DecoupledClauses, S) ->
108
108
{ TX , { umergec (S , TAcc ), [TAcc # elixir_scope .clause_vars |CV ] } }
109
109
end ,
110
110
111
- { TClauses , { TS , RawCV } } = lists :mapfoldl (Transformer , {S , []}, DecoupledClauses ),
111
+ { TClauses , { TS , ReverseCV } } = lists :mapfoldl (Transformer , {S , []}, DecoupledClauses ),
112
112
113
113
% Now get all the variables defined inside each clause
114
- CV = lists :reverse (RawCV ),
115
-
116
- AllVars = lists :umerge ([orddict :fetch_keys (X ) || X <- CV ]),
117
- SharedVars = ordsets :intersection (CV ),
118
-
119
- case AllVars of
120
- [] -> { TClauses , TS };
121
- _ ->
122
- % Create a new scope that contains a list of all variables
123
- % defined inside all the clauses. It returns this new scope and
124
- % a list of tuples where the first element is the variable name,
125
- % the second one is the new pointer to the variable and the third
126
- % is the old pointer.
127
- { FinalVars , FS } = lists :mapfoldl (fun (X , Acc ) -> normalize_vars (X , SharedVars , Acc ) end , TS , AllVars ),
128
-
129
- % Defines a tuple that will be used as left side of the match operator
130
- Line = ? line (Meta ),
131
- LeftVars = [{var , Line , NewValue } || { _ , _ , NewValue , _ } <- FinalVars ],
132
-
133
- % Expand all clauses by adding a match operation at the end
134
- % that assigns variables missing in one clause to the others.
135
- expand_clauses (Meta , TClauses , CV , LeftVars , FinalVars , [], FS )
136
- end .
137
-
138
- expand_clauses (Meta , [Clause |T ], [ClauseVars |V ], LeftVars , FinalVars , Acc , S ) ->
139
- RightVars = [normalize_clause_var (Var , Kind , OldValue , ClauseVars ) ||
140
- { Var , Kind , _ , OldValue } <- FinalVars ],
141
-
142
- AssignExpr = generate_match (Meta , LeftVars , RightVars ),
143
- ClauseExprs = element (5 , Clause ),
144
- [Final |RawClauseExprs ] = lists :reverse (ClauseExprs ),
145
-
146
- % If the last sentence has a match clause, we need to assign its value
147
- % in the variable list. If not, we insert the variable list before the
148
- % final clause in order to keep it tail call optimized.
149
- { FinalClauseExprs , FS } = case has_match_tuple (Final ) of
150
- true ->
151
- case Final of
152
- { match , _ , { var , _ , UserVarName } = UserVar , _ } when UserVarName /= '_' ->
153
- { [UserVar ,AssignExpr ,Final |RawClauseExprs ], S };
154
- _ ->
155
- Line = ? line (Meta ),
156
- { StorageVar , SS } = elixir_scope :build_erl_var (Line , S ),
157
- StorageExpr = { match , Line , StorageVar , Final },
158
- { [StorageVar ,AssignExpr ,StorageExpr |RawClauseExprs ], SS }
159
- end ;
160
- false ->
161
- { [Final ,AssignExpr |RawClauseExprs ], S }
162
- end ,
163
-
164
- FinalClause = setelement (5 , Clause , lists :reverse (FinalClauseExprs )),
165
- expand_clauses (Meta , T , V , LeftVars , FinalVars , [FinalClause |Acc ], FS );
166
-
167
- expand_clauses (_Meta , [], [], _LeftVars , _FinalVars , Acc , S ) ->
114
+ CV = lists :reverse (ReverseCV ),
115
+ AllVars = lists :foldl (fun (KV , Acc ) ->
116
+ orddict :merge (fun (_ , _ , V ) -> V end , KV , Acc )
117
+ end , orddict :new (), CV ),
118
+
119
+ % Create a new scope that contains a list of all variables
120
+ % defined inside all the clauses. It returns this new scope and
121
+ % a list of tuples where the first element is the variable name,
122
+ % the second one is the new pointer to the variable and the third
123
+ % is the old pointer.
124
+ { FinalVars , FS } = lists :mapfoldl (fun ({ Key , Ref }, Acc ) ->
125
+ normalize_vars (Key , Ref , Acc )
126
+ end , TS , AllVars ),
127
+
128
+ % Expand all clauses by adding a match operation at the end
129
+ % that assigns variables missing in one clause to the others.
130
+ expand_clauses (? line (Meta ), TClauses , CV , FinalVars , [], FS ).
131
+
132
+ expand_clauses (Line , [Clause |T ], [ClauseVars |V ], FinalVars , Acc , S ) ->
133
+ case generate_match_vars (FinalVars , ClauseVars , [], []) of
134
+ { [], [] } ->
135
+ expand_clauses (Line , T , V , FinalVars , [Clause |Acc ], S );
136
+ { Left , Right } ->
137
+ MatchExpr = generate_match (Line , Left , Right ),
138
+ ClauseExprs = element (5 , Clause ),
139
+ [Final |RawClauseExprs ] = lists :reverse (ClauseExprs ),
140
+
141
+ % If the last sentence has a match clause, we need to assign its value
142
+ % in the variable list. If not, we insert the variable list before the
143
+ % final clause in order to keep it tail call optimized.
144
+ { FinalClauseExprs , FS } = case has_match_tuple (Final ) of
145
+ true ->
146
+ case Final of
147
+ { match , _ , { var , _ , UserVarName } = UserVar , _ } when UserVarName /= '_' ->
148
+ { [UserVar ,MatchExpr ,Final |RawClauseExprs ], S };
149
+ _ ->
150
+ { StorageVar , SS } = elixir_scope :build_erl_var (Line , S ),
151
+ StorageExpr = { match , Line , StorageVar , Final },
152
+ { [StorageVar ,MatchExpr ,StorageExpr |RawClauseExprs ], SS }
153
+ end ;
154
+ false ->
155
+ { [Final ,MatchExpr |RawClauseExprs ], S }
156
+ end ,
157
+
158
+ FinalClause = setelement (5 , Clause , lists :reverse (FinalClauseExprs )),
159
+ expand_clauses (Line , T , V , FinalVars , [FinalClause |Acc ], FS )
160
+ end ;
161
+
162
+ expand_clauses (_Line , [], [], _FinalVars , Acc , S ) ->
168
163
{ lists :reverse (Acc ), S }.
169
164
170
165
% Handle each key/value clause pair and translate them accordingly.
@@ -210,52 +205,44 @@ has_match_tuple(H) when is_list(H) ->
210
205
211
206
has_match_tuple (_ ) -> false .
212
207
213
- % Normalize the given var checking its existence in the scope var dictionary.
214
-
215
- normalize_vars ({ Var , Kind } = Key , Shared , # elixir_scope {vars = Vars ,clause_vars = ClauseVars } = S ) ->
216
- { NewValue , S1 } =
217
- case orddict :find (Key , Shared ) of
218
- { ok , SharedValue } ->
219
- { SharedValue , S };
220
- error ->
221
- { { _ , _ , ErlValue }, ErlS } = case (Kind /= nil ) or (S # elixir_scope .noname ) of
222
- true -> elixir_scope :build_erl_var (0 , S );
223
- false -> elixir_scope :build_erl_var (0 , Var , " _@" ++ atom_to_list (Var ), S )
224
- end ,
225
- { ErlValue , ErlS }
226
- end ,
227
-
228
- S2 = S1 # elixir_scope {
229
- vars = orddict :store (Key , NewValue , Vars ),
230
- clause_vars = orddict :store (Key , NewValue , ClauseVars )
208
+ % Normalize the given var in between clauses
209
+ % by picking one value as reference and retriving
210
+ % its previous value.
211
+
212
+ normalize_vars (Key , Value , # elixir_scope {vars = Vars ,clause_vars = ClauseVars } = S ) ->
213
+ FS = S # elixir_scope {
214
+ vars = orddict :store (Key , Value , Vars ),
215
+ clause_vars = orddict :store (Key , Value , ClauseVars )
231
216
},
232
217
233
218
Expr = case orddict :find (Key , Vars ) of
234
219
{ ok , OldValue } -> { var , 0 , OldValue };
235
220
error -> { atom , 0 , nil }
236
221
end ,
237
222
238
- { { Var , Kind , NewValue , Expr }, S2 }.
223
+ { { Key , Value , Expr }, FS }.
239
224
240
- % Normalize a var by checking if it was defined in the clause.
241
- % If so, use it, otherwise use from main scope .
225
+ % Generate match vars by checking if they were updated
226
+ % or not and assigning the previous value .
242
227
243
- normalize_clause_var (Var , Kind , OldValue , ClauseVars ) ->
244
- case orddict :find ({ Var , Kind }, ClauseVars ) of
245
- { ok , ClauseValue } -> { var , 0 , ClauseValue };
246
- error -> OldValue
247
- end .
228
+ generate_match_vars ([{ Key , NewValue , OldValue }|T ], ClauseVars , Left , Right ) ->
229
+ case orddict :find (Key , ClauseVars ) of
230
+ { ok , NewValue } ->
231
+ generate_match_vars (T , ClauseVars , Left , Right );
232
+ { ok , ClauseValue } ->
233
+ generate_match_vars (T , ClauseVars , [{ var , 0 , NewValue }|Left ], [{ var , 0 , ClauseValue }|Right ]);
234
+ error ->
235
+ generate_match_vars (T , ClauseVars , [{ var , 0 , NewValue }|Left ], [OldValue |Right ])
236
+ end ;
248
237
249
- % % generate_match
238
+ generate_match_vars ([], _ClauseVars , Left , Right ) ->
239
+ { Left , Right }.
250
240
251
- generate_match (Meta , [Left ], [Right ]) ->
252
- { match , ? line ( Meta ) , Left , Right };
241
+ generate_match (Line , [Left ], [Right ]) ->
242
+ { match , Line , Left , Right };
253
243
254
- generate_match (Meta , LeftVars , RightVars ) ->
255
- Line = ? line (Meta ),
244
+ generate_match (Line , LeftVars , RightVars ) ->
256
245
{ match , Line , { tuple , Line , LeftVars }, { tuple , Line , RightVars } }.
257
246
258
- % % Listify
259
-
260
247
listify (Expr ) when not is_list (Expr ) -> [Expr ];
261
248
listify (Expr ) -> Expr .
0 commit comments