1%% ``Licensed under the Apache License, Version 2.0 (the "License"); 2%% you may not use this file except in compliance with the License. 3%% You may obtain a copy of the License at 4%% 5%% http://www.apache.org/licenses/LICENSE-2.0 6%% 7%% Unless required by applicable law or agreed to in writing, software 8%% distributed under the License is distributed on an "AS IS" BASIS, 9%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10%% See the License for the specific language governing permissions and 11%% limitations under the License. 12%% 13%% The Initial Developer of the Original Code is Ericsson Utvecklings AB. 14%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings 15%% AB. All Rights Reserved.'' 16%% 17%% $Id: sys_pre_expand.erl,v 1.1 2008/12/17 09:53:42 mikpe Exp $ 18%% 19%% Purpose : Expand some source Erlang constructions. This is part of the 20%% pre-processing phase. 21 22%% N.B. Although structs (tagged tuples) are not yet allowed in the 23%% language there is code included in pattern/2 and expr/3 (commented out) 24%% that handles them by transforming them to tuples. 25 26-module(sys_pre_expand). 27 28%% Main entry point. 29-export([module/2]). 30 31-import(ordsets, [from_list/1,add_element/2, 32 union/1,union/2,intersection/1,intersection/2,subtract/2]). 33-import(lists, [member/2,map/2,foldl/3,foldr/3,sort/1,reverse/1,duplicate/2]). 34 35-include("../my_include/erl_bits.hrl"). 36 37-record(expand, {module=[], %Module name 38 parameters=undefined, %Module parameters 39 package="", %Module package 40 exports=[], %Exports 41 imports=[], %Imports 42 mod_imports, %Module Imports 43 compile=[], %Compile flags 44 records=dict:new(), %Record definitions 45 attributes=[], %Attributes 46 defined=[], %Defined functions 47 vcount=0, %Variable counter 48 func=[], %Current function 49 arity=[], %Arity for current function 50 fcount=0, %Local fun count 51 fun_index=0, %Global index for funs 52 bitdefault, 53 bittypes 54 }). 55 56%% module(Forms, CompileOptions) 57%% {ModuleName,Exports,TransformedForms} 58%% Expand the forms in one module. N.B.: the lists of predefined 59%% exports and imports are really ordsets! 60 61module(Fs, Opts) -> 62 %% Set pre-defined exported functions. 63 PreExp = [{module_info,0},{module_info,1}], 64 65 %% Set pre-defined module imports. 66 PreModImp = [{erlang,erlang},{packages,packages}], 67 68 %% Build initial expand record. 69 St0 = #expand{exports=PreExp, 70 mod_imports=dict:from_list(PreModImp), 71 compile=Opts, 72 defined=PreExp, 73 bitdefault = erl_bits:system_bitdefault(), 74 bittypes = erl_bits:system_bittypes() 75 }, 76 %% Expand the functions. 77 {Tfs,St1} = forms(Fs, foldl(fun define_function/2, St0, Fs)), 78 {Efs,St2} = expand_pmod(Tfs, St1), 79 %% Get the correct list of exported functions. 80 Exports = case member(export_all, St2#expand.compile) of 81 true -> St2#expand.defined; 82 false -> St2#expand.exports 83 end, 84 %% Generate all functions from stored info. 85 {Ats,St3} = module_attrs(St2#expand{exports = Exports}), 86 {Mfs,St4} = module_predef_funcs(St3), 87 {St4#expand.module, St4#expand.exports, Ats ++ Efs ++ Mfs, 88 St4#expand.compile}. 89 90expand_pmod(Fs0, St) -> 91 case St#expand.parameters of 92 undefined -> 93 {Fs0,St}; 94 Ps -> 95 {Fs1,Xs,Ds} = sys_expand_pmod:forms(Fs0, Ps, 96 St#expand.exports, 97 St#expand.defined), 98 A = length(Ps), 99 Vs = [{var,0,V} || V <- Ps], 100 N = {atom,0,St#expand.module}, 101 B = [{tuple,0,[N|Vs]}], 102 F = {function,0,new,A,[{clause,0,Vs,[],B}]}, 103 As = St#expand.attributes, 104 {[F|Fs1],St#expand{exports=add_element({new,A}, Xs), 105 defined=add_element({new,A}, Ds), 106 attributes = [{abstract, true} | As]}} 107 end. 108 109%% -type define_function(Form, State) -> State. 110%% Add function to defined if form a function. 111 112define_function({function,_,N,A,_Cs}, St) -> 113 St#expand{defined=add_element({N,A}, St#expand.defined)}; 114define_function(_, St) -> St. 115 116module_attrs(St) -> 117 {[{attribute,0,Name,Val} || {Name,Val} <- St#expand.attributes],St}. 118 119module_predef_funcs(St) -> 120 PreDef = [{module_info,0},{module_info,1}], 121 PreExp = PreDef, 122 {[{function,0,module_info,0, 123 [{clause,0,[],[], 124 [{call,0,{remote,0,{atom,0,erlang},{atom,0,get_module_info}}, 125 [{atom,0,St#expand.module}]}]}]}, 126 {function,0,module_info,1, 127 [{clause,0,[{var,0,'X'}],[], 128 [{call,0,{remote,0,{atom,0,erlang},{atom,0,get_module_info}}, 129 [{atom,0,St#expand.module},{var,0,'X'}]}]}]}], 130 St#expand{defined=union(from_list(PreDef), St#expand.defined), 131 exports=union(from_list(PreExp), St#expand.exports)}}. 132 133%% forms(Forms, State) -> 134%% {TransformedForms,State'} 135%% Process the forms. Attributes are lost and just affect the state. 136%% Ignore uninteresting forms like eof and type. 137 138forms([{attribute,_,Name,Val}|Fs0], St0) -> 139 St1 = attribute(Name, Val, St0), 140 forms(Fs0, St1); 141forms([{function,L,N,A,Cs}|Fs0], St0) -> 142 {Ff,St1} = function(L, N, A, Cs, St0), 143 {Fs,St2} = forms(Fs0, St1), 144 {[Ff|Fs],St2}; 145forms([_|Fs], St) -> forms(Fs, St); 146forms([], St) -> {[],St}. 147 148%% -type attribute(Attribute, Value, State) -> 149%% State. 150%% Process an attribute, this just affects the state. 151 152attribute(module, {Module, As}, St) -> 153 true = is_atom(Module), 154 St#expand{module=Module, 155 parameters=As}; 156attribute(module, Module, St) -> 157 true = is_atom(Module), 158 St#expand{module=Module}; 159attribute(export, Es, St) -> 160 St#expand{exports=union(from_list(Es), St#expand.exports)}; 161attribute(import, Is, St) -> 162 import(Is, St); 163attribute(compile, C, St) when list(C) -> 164 St#expand{compile=St#expand.compile ++ C}; 165attribute(compile, C, St) -> 166 St#expand{compile=St#expand.compile ++ [C]}; 167attribute(record, {Name,Defs}, St) -> 168 St#expand{records=dict:store(Name, normalise_fields(Defs), 169 St#expand.records)}; 170attribute(file, _File, St) -> St; %This is ignored 171attribute(Name, Val, St) when list(Val) -> 172 St#expand{attributes=St#expand.attributes ++ [{Name,Val}]}; 173attribute(Name, Val, St) -> 174 St#expand{attributes=St#expand.attributes ++ [{Name,[Val]}]}. 175 176function(L, N, A, Cs0, St0) -> 177 {Cs,St} = clauses(Cs0, St0#expand{func=N,arity=A,fcount=0}), 178 {{function,L,N,A,Cs},St}. 179 180%% -type clauses([Clause], State) -> 181%% {[TransformedClause],State}. 182%% Expand function clauses. 183 184clauses([{clause,Line,H0,G0,B0}|Cs0], St0) -> 185 {H,Hvs,_Hus,St1} = head(H0, St0), 186 {G,Gvs,_Gus,St2} = guard(G0, Hvs, St1), 187 {B,_Bvs,_Bus,St3} = exprs(B0, union(Hvs, Gvs), St2), 188 {Cs,St4} = clauses(Cs0, St3), 189 {[{clause,Line,H,G,B}|Cs],St4}; 190clauses([], St) -> {[],St}. 191 192%% head(HeadPatterns, State) -> 193%% {TransformedPatterns,Variables,UsedVariables,State'} 194 195head(As, St) -> pattern_list(As, St). 196 197%% pattern(Pattern, State) -> 198%% {TransformedPattern,Variables,UsedVariables,State'} 199%% BITS: added used variables for bit patterns with varaible length 200%% 201 202pattern({var,_,'_'}=Var, St) -> %Ignore anonymous variable. 203 {Var,[],[],St}; 204pattern({var,_,V}=Var, St) -> 205 {Var,[V],[],St}; 206pattern({char,_,_}=Char, St) -> 207 {Char,[],[],St}; 208pattern({integer,_,_}=Int, St) -> 209 {Int,[],[],St}; 210pattern({float,_,_}=Float, St) -> 211 {Float,[],[],St}; 212pattern({atom,_,_}=Atom, St) -> 213 {Atom,[],[],St}; 214pattern({string,_,_}=String, St) -> 215 {String,[],[],St}; 216pattern({nil,_}=Nil, St) -> 217 {Nil,[],[],St}; 218pattern({cons,Line,H,T}, St0) -> 219 {TH,THvs,Hus,St1} = pattern(H, St0), 220 {TT,TTvs,Tus,St2} = pattern(T, St1), 221 {{cons,Line,TH,TT},union(THvs, TTvs),union(Hus,Tus),St2}; 222pattern({tuple,Line,Ps}, St0) -> 223 {TPs,TPsvs,Tus,St1} = pattern_list(Ps, St0), 224 {{tuple,Line,TPs},TPsvs,Tus,St1}; 225%%pattern({struct,Line,Tag,Ps}, St0) -> 226%% {TPs,TPsvs,St1} = pattern_list(Ps, St0), 227%% {{tuple,Line,[{atom,Line,Tag}|TPs]},TPsvs,St1}; 228pattern({record_index,Line,Name,Field}, St) -> 229 {index_expr(Line, Field, Name, record_fields(Name, St)),[],[],St}; 230pattern({record,Line,Name,Pfs}, St0) -> 231 Fs = record_fields(Name, St0), 232 {TMs,TMsvs,Us,St1} = pattern_list(pattern_fields(Fs, Pfs), St0), 233 {{tuple,Line,[{atom,Line,Name}|TMs]},TMsvs,Us,St1}; 234pattern({bin,Line,Es0}, St0) -> 235 {Es1,Esvs,Esus,St1} = pattern_bin(Es0, St0), 236 {{bin,Line,Es1},Esvs,Esus,St1}; 237pattern({op,_,'++',{nil,_},R}, St) -> 238 pattern(R, St); 239pattern({op,_,'++',{cons,Li,H,T},R}, St) -> 240 pattern({cons,Li,H,{op,Li,'++',T,R}}, St); 241pattern({op,_,'++',{string,Li,L},R}, St) -> 242 pattern(string_to_conses(Li, L, R), St); 243pattern({match,Line,Pat1, Pat2}, St0) -> 244 {TH,Hvt,Hus,St1} = pattern(Pat2, St0), 245 {TT,Tvt,Tus,St2} = pattern(Pat1, St1), 246 {{match,Line,TT,TH}, union(Hvt,Tvt), union(Hus,Tus), St2}; 247%% Compile-time pattern expressions, including unary operators. 248pattern({op,Line,Op,A}, St) -> 249 { erl_eval:partial_eval({op,Line,Op,A}), [], [], St}; 250pattern({op,Line,Op,L,R}, St) -> 251 { erl_eval:partial_eval({op,Line,Op,L,R}), [], [], St}. 252 253pattern_list([P0|Ps0], St0) -> 254 {P,Pvs,Pus,St1} = pattern(P0, St0), 255 {Ps,Psvs,Psus,St2} = pattern_list(Ps0, St1), 256 {[P|Ps],union(Pvs, Psvs),union(Pus, Psus),St2}; 257pattern_list([], St) -> {[],[],[],St}. 258 259%% guard(Guard, VisibleVariables, State) -> 260%% {TransformedGuard,NewVariables,UsedVariables,State'} 261%% Transform a list of guard tests. We KNOW that this has been checked 262%% and what the guards test are. Use expr for transforming the guard 263%% expressions. 264 265guard([G0|Gs0], Vs, St0) -> 266 {G,Hvs,Hus,St1} = guard_tests(G0, Vs, St0), 267 {Gs,Tvs,Tus,St2} = guard(Gs0, Vs, St1), 268 {[G|Gs],union(Hvs, Tvs),union(Hus, Tus),St2}; 269guard([], _, St) -> {[],[],[],St}. 270 271guard_tests([Gt0|Gts0], Vs, St0) -> 272 {Gt1,Gvs,Gus,St1} = guard_test(Gt0, Vs, St0), 273 {Gts1,Gsvs,Gsus,St2} = guard_tests(Gts0, union(Gvs, Vs), St1), 274 {[Gt1|Gts1],union(Gvs, Gsvs),union(Gus, Gsus),St2}; 275guard_tests([], _, St) -> {[],[],[],St}. 276 277guard_test({call,Line,{atom,_,record},[A,{atom,_,Name}]}, Vs, St) -> 278 record_test_in_guard(Line, A, Name, Vs, St); 279guard_test({call,Line,{atom,Lt,Tname},As}, Vs, St) -> 280 %% XXX This is ugly. We can remove this workaround if/when 281 %% we'll allow 'andalso' in guards. For now, we must have 282 %% different code in guards and in bodies. 283 Test = {remote,Lt, 284 {atom,Lt,erlang}, 285 {atom,Lt,normalise_test(Tname, length(As))}}, 286 put(sys_pre_expand_in_guard, yes), 287 R = expr({call,Line,Test,As}, Vs, St), 288 erase(sys_pre_expand_in_guard), 289 R; 290guard_test(Test, Vs, St) -> 291 %% XXX See the previous clause. 292 put(sys_pre_expand_in_guard, yes), 293 R = expr(Test, Vs, St), 294 erase(sys_pre_expand_in_guard), 295 R. 296 297%% record_test(Line, Term, Name, Vs, St) -> TransformedExpr 298%% Generate code for is_record/1. 299 300record_test(Line, Term, Name, Vs, St) -> 301 case get(sys_pre_expand_in_guard) of 302 undefined -> 303 record_test_in_body(Line, Term, Name, Vs, St); 304 yes -> 305 record_test_in_guard(Line, Term, Name, Vs, St) 306 end. 307 308record_test_in_guard(Line, Term, Name, Vs, St) -> 309 %% Notes: (1) To keep is_record/3 properly atomic (e.g. when inverted 310 %% using 'not'), we cannot convert it to an instruction 311 %% sequence here. It must remain a single call. 312 %% (2) Later passes assume that the last argument (the size) 313 %% is a literal. 314 %% (3) We don't want calls to erlang:is_record/3 (in the source code) 315 %% confused we the internal instruction. (Reason: (2) above + 316 %% code bloat.) 317 %% (4) Xref may be run on the abstract code, so the name in the 318 %% abstract code must be erlang:is_record/3. 319 %% (5) To achieve both (3) and (4) at the same time, set the name 320 %% here to erlang:is_record/3, but mark it as compiler-generated. 321 %% The v3_core pass will change the name to erlang:internal_is_record/3. 322 Fs = record_fields(Name, St), 323 expr({call,-Line,{remote,-Line,{atom,-Line,erlang},{atom,-Line,is_record}}, 324 [Term,{atom,Line,Name},{integer,Line,length(Fs)+1}]}, 325 Vs, St). 326 327record_test_in_body(Line, Expr, Name, Vs, St0) -> 328 %% As Expr may have side effects, we must evaluate it 329 %% first and bind the value to a new variable. 330 %% We must use also handle the case that Expr does not 331 %% evaluate to a tuple properly. 332 Fs = record_fields(Name, St0), 333 {Var,St} = new_var(Line, St0), 334 335 expr({block,Line, 336 [{match,Line,Var,Expr}, 337 {op,Line, 338 'andalso', 339 {call,Line,{atom,Line,is_tuple},[Var]}, 340 {op,Line,'andalso', 341 {op,Line,'=:=', 342 {call,Line,{atom,Line,size},[Var]}, 343 {integer,Line,length(Fs)+1}}, 344 {op,Line,'=:=', 345 {call,Line,{atom,Line,element},[{integer,Line,1},Var]}, 346 {atom,Line,Name}}}}]}, Vs, St). 347 348normalise_test(atom, 1) -> is_atom; 349normalise_test(binary, 1) -> is_binary; 350normalise_test(constant, 1) -> is_constant; 351normalise_test(float, 1) -> is_float; 352normalise_test(function, 1) -> is_function; 353normalise_test(integer, 1) -> is_integer; 354normalise_test(list, 1) -> is_list; 355normalise_test(number, 1) -> is_number; 356normalise_test(pid, 1) -> is_pid; 357normalise_test(port, 1) -> is_port; 358normalise_test(reference, 1) -> is_reference; 359normalise_test(tuple, 1) -> is_tuple; 360normalise_test(Name, _) -> Name. 361 362%% exprs(Expressions, VisibleVariables, State) -> 363%% {TransformedExprs,NewVariables,UsedVariables,State'} 364 365exprs([E0|Es0], Vs, St0) -> 366 {E,Evs,Eus,St1} = expr(E0, Vs, St0), 367 {Es,Esvs,Esus,St2} = exprs(Es0, union(Evs, Vs), St1), 368 {[E|Es],union(Evs, Esvs),union(Eus, Esus),St2}; 369exprs([], _, St) -> {[],[],[],St}. 370 371%% expr(Expression, VisibleVariables, State) -> 372%% {TransformedExpression,NewVariables,UsedVariables,State'} 373 374expr({var,_,V}=Var, _Vs, St) -> 375 {Var,[],[V],St}; 376expr({char,_,_}=Char, _Vs, St) -> 377 {Char,[],[],St}; 378expr({integer,_,_}=Int, _Vs, St) -> 379 {Int,[],[],St}; 380expr({float,_,_}=Float, _Vs, St) -> 381 {Float,[],[],St}; 382expr({atom,_,_}=Atom, _Vs, St) -> 383 {Atom,[],[],St}; 384expr({string,_,_}=String, _Vs, St) -> 385 {String,[],[],St}; 386expr({nil,_}=Nil, _Vs, St) -> 387 {Nil,[],[],St}; 388expr({cons,Line,H0,T0}, Vs, St0) -> 389 {H,Hvs,Hus,St1} = expr(H0, Vs, St0), 390 {T,Tvs,Tus,St2} = expr(T0, Vs, St1), 391 {{cons,Line,H,T},union(Hvs, Tvs),union(Hus, Tus),St2}; 392expr({lc,Line,E0,Qs0}, Vs, St0) -> 393 {E1,Qs1,_,Lvs,Lus,St1} = lc_tq(Line, E0, Qs0, {nil,Line}, Vs, St0), 394 {{lc,Line,E1,Qs1},Lvs,Lus,St1}; 395expr({tuple,Line,Es0}, Vs, St0) -> 396 {Es1,Esvs,Esus,St1} = expr_list(Es0, Vs, St0), 397 {{tuple,Line,Es1},Esvs,Esus,St1}; 398%%expr({struct,Line,Tag,Es0}, Vs, St0) -> 399%% {Es1,Esvs,Esus,St1} = expr_list(Es0, Vs, St0), 400%% {{tuple,Line,[{atom,Line,Tag}|Es1]},Esvs,Esus,St1}; 401expr({record_index,Line,Name,F}, Vs, St) -> 402 I = index_expr(Line, F, Name, record_fields(Name, St)), 403 expr(I, Vs, St); 404expr({record,Line,Name,Is}, Vs, St) -> 405 expr({tuple,Line,[{atom,Line,Name}| 406 record_inits(record_fields(Name, St), Is)]}, 407 Vs, St); 408expr({record_field,Line,R,Name,F}, Vs, St) -> 409 I = index_expr(Line, F, Name, record_fields(Name, St)), 410 expr({call,Line,{atom,Line,element},[I,R]}, Vs, St); 411expr({record,_,R,Name,Us}, Vs, St0) -> 412 {Ue,St1} = record_update(R, Name, record_fields(Name, St0), Us, St0), 413 expr(Ue, Vs, St1); 414expr({bin,Line,Es0}, Vs, St0) -> 415 {Es1,Esvs,Esus,St1} = expr_bin(Es0, Vs, St0), 416 {{bin,Line,Es1},Esvs,Esus,St1}; 417expr({block,Line,Es0}, Vs, St0) -> 418 {Es,Esvs,Esus,St1} = exprs(Es0, Vs, St0), 419 {{block,Line,Es},Esvs,Esus,St1}; 420expr({'if',Line,Cs0}, Vs, St0) -> 421 {Cs,Csvss,Csuss,St1} = icr_clauses(Cs0, Vs, St0), 422 All = new_in_all(Vs, Csvss), 423 {{'if',Line,Cs},All,union(Csuss),St1}; 424expr({'case',Line,E0,Cs0}, Vs, St0) -> 425 {E,Evs,Eus,St1} = expr(E0, Vs, St0), 426 {Cs,Csvss,Csuss,St2} = icr_clauses(Cs0, union(Evs, Vs), St1), 427 All = new_in_all(Vs, Csvss), 428 {{'case',Line,E,Cs},union(Evs, All),union([Eus|Csuss]),St2}; 429expr({'cond',Line,Cs}, Vs, St0) -> 430 {V,St1} = new_var(Line,St0), 431 expr(cond_clauses(Cs,V), Vs, St1); 432expr({'receive',Line,Cs0}, Vs, St0) -> 433 {Cs,Csvss,Csuss,St1} = icr_clauses(Cs0, Vs, St0), 434 All = new_in_all(Vs, Csvss), 435 {{'receive',Line,Cs},All,union(Csuss),St1}; 436expr({'receive',Line,Cs0,To0,ToEs0}, Vs, St0) -> 437 {To,Tovs,Tous,St1} = expr(To0, Vs, St0), 438 {ToEs,ToEsvs,_ToEsus,St2} = exprs(ToEs0, Vs, St1), 439 {Cs,Csvss,Csuss,St3} = icr_clauses(Cs0, Vs, St2), 440 All = new_in_all(Vs, [ToEsvs|Csvss]), 441 {{'receive',Line,Cs,To,ToEs},union(Tovs, All),union([Tous|Csuss]),St3}; 442expr({'fun',Line,Body}, Vs, St) -> 443 fun_tq(Line, Body, Vs, St); 444%%% expr({call,_,{atom,La,this_module},[]}, _Vs, St) -> 445%%% {{atom,La,St#expand.module}, [], [], St}; 446%%% expr({call,_,{atom,La,this_package},[]}, _Vs, St) -> 447%%% {{atom,La,list_to_atom(St#expand.package)}, [], [], St}; 448%%% expr({call,_,{atom,La,this_package},[{atom,_,Name}]}, _Vs, St) -> 449%%% M = packages:concat(St#expand.package,Name), 450%%% {{atom,La,list_to_atom(M)}, [], [], St}; 451%%% expr({call,Line,{atom,La,this_package},[A]}, Vs, St) -> 452%%% M = {call,Line,{remote,La,{atom,La,packages},{atom,La,concat}}, 453%%% [{string,La,St#expand.package}, A]}, 454%%% expr({call,Line,{atom,Line,list_to_atom},[M]}, Vs, St); 455expr({call,Line,{atom,_,is_record},[A,{atom,_,Name}]}, Vs, St) -> 456 record_test(Line, A, Name, Vs, St); 457expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,is_record}}, 458 [A,{atom,_,Name}]}, Vs, St) -> 459 record_test(Line, A, Name, Vs, St); 460expr({call,Line,{atom,La,N},As0}, Vs, St0) -> 461 {As,Asvs,Asus,St1} = expr_list(As0, Vs, St0), 462 Ar = length(As), 463 case erl_internal:bif(N, Ar) of 464 true -> 465 {{call,Line,{remote,La,{atom,La,erlang},{atom,La,N}},As}, 466 Asvs,Asus,St1}; 467 false -> 468 case imported(N, Ar, St1) of 469 {yes,Mod} -> 470 {{call,Line,{remote,La,{atom,La,Mod},{atom,La,N}},As}, 471 Asvs,Asus,St1}; 472 no -> 473 case {N,Ar} of 474 {record_info,2} -> 475 record_info_call(Line, As, St1); 476 _ -> 477 {{call,Line,{atom,La,N},As},Asvs,Asus,St1} 478 end 479 end 480 end; 481expr({call,Line,{remote,Lr,M1,F},As0}, Vs, St0) -> 482 {[M2,F1|As1],Asvs,Asus,St1} = expr_list([M1,F|As0], Vs, St0), 483 {{call,Line,{remote,Lr,M2,F1},As1},Asvs,Asus,St1}; 484expr({call,Line,{tuple,_,[{atom,_,_}=M,{atom,_,_}=F]},As}, Vs, St) -> 485 %% Rewrite {Mod,Function}(Args...) to Mod:Function(Args...). 486 expr({call,Line,{remote,Line,M,F},As}, Vs, St); 487expr({call,Line,F,As0}, Vs, St0) -> 488 {[Fun1|As1],Asvs,Asus,St1} = expr_list([F|As0], Vs, St0), 489 {{call,Line,Fun1,As1},Asvs,Asus,St1}; 490expr({'try',Line,Es0,Scs0,Ccs0,As0}, Vs, St0) -> 491 {Es1,Esvs,Esus,St1} = exprs(Es0, Vs, St0), 492 Cvs = union(Esvs, Vs), 493 {Scs1,Scsvss,Scsuss,St2} = icr_clauses(Scs0, Cvs, St1), 494 {Ccs1,Ccsvss,Ccsuss,St3} = icr_clauses(Ccs0, Cvs, St2), 495 Csvss = Scsvss ++ Ccsvss, 496 Csuss = Scsuss ++ Ccsuss, 497 All = new_in_all(Vs, Csvss), 498 {As1,Asvs,Asus,St4} = exprs(As0, Cvs, St3), 499 {{'try',Line,Es1,Scs1,Ccs1,As1}, union([Asvs,Esvs,All]), 500 union([Esus,Asus|Csuss]), St4}; 501expr({'catch',Line,E0}, Vs, St0) -> 502 %% Catch exports no new variables. 503 {E,_Evs,Eus,St1} = expr(E0, Vs, St0), 504 {{'catch',Line,E},[],Eus,St1}; 505expr({match,Line,P0,E0}, Vs, St0) -> 506 {E,Evs,Eus,St1} = expr(E0, Vs, St0), 507 {P,Pvs,Pus,St2} = pattern(P0, St1), 508 {{match,Line,P,E}, 509 union(subtract(Pvs, Vs), Evs), 510 union(intersection(Pvs, Vs), union(Eus,Pus)),St2}; 511expr({op,L,'andalso',E1,E2}, Vs, St0) -> 512 {V,St1} = new_var(L,St0), 513 E = make_bool_switch(L,E1,V, 514 make_bool_switch(L,E2,V,{atom,L,true}, 515 {atom,L,false}), 516 {atom,L,false}), 517 expr(E, Vs, St1); 518expr({op,L,'orelse',E1,E2}, Vs, St0) -> 519 {V,St1} = new_var(L,St0), 520 E = make_bool_switch(L,E1,V,{atom,L,true}, 521 make_bool_switch(L,E2,V,{atom,L,true}, 522 {atom,L,false})), 523 expr(E, Vs, St1); 524expr({op,Line,'++',{lc,Ll,E0,Qs0},M0}, Vs, St0) -> 525 {E1,Qs1,M1,Lvs,Lus,St1} = lc_tq(Ll, E0, Qs0, M0, Vs, St0), 526 {{op,Line,'++',{lc,Ll,E1,Qs1},M1},Lvs,Lus,St1}; 527expr({op,_,'++',{string,L1,S1},{string,_,S2}}, _Vs, St) -> 528 {{string,L1,S1 ++ S2},[],[],St}; 529expr({op,Ll,'++',{string,L1,S1}=Str,R0}, Vs, St0) -> 530 {R1,Rvs,Rus,St1} = expr(R0, Vs, St0), 531 E = case R1 of 532 {string,_,S2} -> {string,L1,S1 ++ S2}; 533 _Other when length(S1) < 8 -> string_to_conses(L1, S1, R1); 534 _Other -> {op,Ll,'++',Str,R1} 535 end, 536 {E,Rvs,Rus,St1}; 537expr({op,Ll,'++',{cons,Lc,H,T},L2}, Vs, St) -> 538 expr({cons,Ll,H,{op,Lc,'++',T,L2}}, Vs, St); 539expr({op,_,'++',{nil,_},L2}, Vs, St) -> 540 expr(L2, Vs, St); 541expr({op,Line,Op,A0}, Vs, St0) -> 542 {A,Avs,Aus,St1} = expr(A0, Vs, St0), 543 {{op,Line,Op,A},Avs,Aus,St1}; 544expr({op,Line,Op,L0,R0}, Vs, St0) -> 545 {L,Lvs,Lus,St1} = expr(L0, Vs, St0), 546 {R,Rvs,Rus,St2} = expr(R0, Vs, St1), 547 {{op,Line,Op,L,R},union(Lvs, Rvs),union(Lus, Rus),St2}. 548 549expr_list([E0|Es0], Vs, St0) -> 550 {E,Evs,Eus,St1} = expr(E0, Vs, St0), 551 {Es,Esvs,Esus,St2} = expr_list(Es0, Vs, St1), 552 {[E|Es],union(Evs, Esvs),union(Eus, Esus),St2}; 553expr_list([], _, St) -> 554 {[],[],[],St}. 555 556%% icr_clauses([Clause], [VisibleVariable], State) -> 557%% {[TransformedClause],[[NewVariable]],[[UsedVariable]],State'} 558%% Be very careful here to return the variables that are really used 559%% and really new. 560 561icr_clauses([], _, St) -> 562 {[],[[]],[],St}; 563icr_clauses(Clauses, Vs, St) -> 564 icr_clauses2(Clauses, Vs, St). 565 566icr_clauses2([{clause,Line,H0,G0,B0}|Cs0], Vs, St0) -> 567 {H,Hvs,Hus,St1} = head(H0, St0), %Hvs is really used! 568 {G,Gvs,Gus,St2} = guard(G0, union(Hvs, Vs), St1), 569 {B,Bvs,Bus,St3} = exprs(B0, union([Vs,Hvs,Gvs]), St2), 570 New = subtract(union([Hvs,Gvs,Bvs]), Vs), %Really new 571 Used = intersection(union([Hvs,Hus,Gus,Bus]), Vs), %Really used 572 {Cs,Csvs,Csus,St4} = icr_clauses2(Cs0, Vs, St3), 573 {[{clause,Line,H,G,B}|Cs],[New|Csvs],[Used|Csus],St4}; 574icr_clauses2([], _, St) -> 575 {[],[],[],St}. 576 577%% lc_tq(Line, Expr, Qualifiers, More, [VisibleVar], State) -> 578%% {TransExpr,[TransQual],TransMore,[NewVar],[UsedVar],State'} 579 580lc_tq(Line, E0, [{generate,Lg,P0,G0}|Qs0], M0, Vs, St0) -> 581 {G1,Gvs,Gus,St1} = expr(G0, Vs, St0), 582 {P1,Pvs,Pus,St2} = pattern(P0, St1), 583 {E1,Qs1,M1,Lvs,Lus,St3} = lc_tq(Line, E0, Qs0, M0, union(Pvs, Vs), St2), 584 {E1,[{generate,Lg,P1,G1}|Qs1],M1, 585 union(Gvs, Lvs),union([Gus,Pus,Lus]),St3}; 586lc_tq(Line, E0, [F0|Qs0], M0, Vs, St0) -> 587 %% Allow record/2 and expand out as guard test. 588 case erl_lint:is_guard_test(F0) of 589 true -> 590 {F1,Fvs,_Fus,St1} = guard_tests([F0], Vs, St0), 591 {E1,Qs1,M1,Lvs,Lus,St2} = lc_tq(Line, E0, Qs0, M0, union(Fvs, Vs), St1), 592 {E1,F1++Qs1,M1,Lvs,Lus,St2}; 593 false -> 594 {F1,Fvs,_Fus,St1} = expr(F0, Vs, St0), 595 {E1,Qs1,M1,Lvs,Lus,St2} = lc_tq(Line, E0, Qs0, M0, union(Fvs, Vs), St1), 596 {E1,[F1|Qs1],M1,Lvs,Lus,St2} 597 end; 598lc_tq(_Line, E0, [], M0, Vs, St0) -> 599 {E1,Evs,Eus,St1} = expr(E0, Vs, St0), 600 {M1,Mvs,Mus,St2} = expr(M0, Vs, St1), 601 {E1,[],M1,union(Evs, Mvs),union(Eus, Mus),St2}. 602 603%% fun_tq(Line, Body, VisibleVariables, State) -> 604%% {Fun,NewVariables,UsedVariables,State'} 605%% Transform an "explicit" fun {'fun', Line, {clauses, Cs}} into an 606%% extended form {'fun', Line, {clauses, Cs}, Info}, unless it is the 607%% name of a BIF (erl_lint has checked that it is not an import). 608%% Process the body sequence directly to get the new and used variables. 609%% "Implicit" funs {'fun', Line, {function, F, A}} are not changed. 610 611fun_tq(Lf, {function,F,A}, Vs, St0) -> 612 {As,St1} = new_vars(A, Lf, St0), 613 Cs = [{clause,Lf,As,[],[{call,Lf,{atom,Lf,F},As}]}], 614 case erl_internal:bif(F, A) of 615 true -> 616 fun_tq(Lf, {clauses,Cs}, Vs, St1); 617 false -> 618 Index = St0#expand.fun_index, 619 Uniq = erlang:hash(Cs, (1 bsl 27)-1), 620 {Fname,St2} = new_fun_name(St1), 621 {{'fun',Lf,{function,F,A},{Index,Uniq,Fname}},[],[], 622 St2#expand{fun_index=Index+1}} 623 end; 624fun_tq(Lf, {clauses,Cs0}, Vs, St0) -> 625 Uniq = erlang:hash(Cs0, (1 bsl 27)-1), 626 {Cs1,_Hvss,Frees,St1} = fun_clauses(Cs0, Vs, St0), 627 Ufrees = union(Frees), 628 Index = St1#expand.fun_index, 629 {Fname,St2} = new_fun_name(St1), 630 {{'fun',Lf,{clauses,Cs1},{Index,Uniq,Fname}},[],Ufrees, 631 St2#expand{fun_index=Index+1}}. 632 633fun_clauses([{clause,L,H0,G0,B0}|Cs0], Vs, St0) -> 634 {H,Hvs,Hus,St1} = head(H0, St0), 635 {G,Gvs,Gus,St2} = guard(G0, union(Hvs, Vs), St1), 636 {B,Bvs,Bus,St3} = exprs(B0, union([Vs,Hvs,Gvs]), St2), 637 %% Free variables cannot be new anywhere in the clause. 638 Free = subtract(union([Gus,Hus,Bus]), union([Hvs,Gvs,Bvs])), 639 %%io:format(" Gus :~p~n Bvs :~p~n Bus :~p~n Free:~p~n" ,[Gus,Bvs,Bus,Free]), 640 {Cs,Hvss,Frees,St4} = fun_clauses(Cs0, Vs, St3), 641 {[{clause,L,H,G,B}|Cs],[Hvs|Hvss],[Free|Frees],St4}; 642fun_clauses([], _, St) -> {[],[],[],St}. 643 644%% new_fun_name(State) -> {FunName,State}. 645 646new_fun_name(#expand{func=F,arity=A,fcount=I}=St) -> 647 Name = "-" ++ atom_to_list(F) ++ "/" ++ integer_to_list(A) 648 ++ "-fun-" ++ integer_to_list(I) ++ "-", 649 {list_to_atom(Name),St#expand{fcount=I+1}}. 650 651 652%% normalise_fields([RecDef]) -> [Field]. 653%% Normalise the field definitions to always have a default value. If 654%% none has been given then use 'undefined'. 655 656normalise_fields(Fs) -> 657 map(fun ({record_field,Lf,Field}) -> 658 {record_field,Lf,Field,{atom,Lf,undefined}}; 659 (F) -> F end, Fs). 660 661%% record_fields(RecordName, State) 662%% find_field(FieldName, Fields) 663 664record_fields(R, St) -> dict:fetch(R, St#expand.records). 665 666find_field(F, [{record_field,_,{atom,_,F},Val}|_]) -> {ok,Val}; 667find_field(F, [_|Fs]) -> find_field(F, Fs); 668find_field(_, []) -> error. 669 670%% field_names(RecFields) -> [Name]. 671%% Return a list of the field names structures. 672 673field_names(Fs) -> 674 map(fun ({record_field,_,Field,_Val}) -> Field end, Fs). 675 676%% index_expr(Line, FieldExpr, Name, Fields) -> IndexExpr. 677%% Return an expression which evaluates to the index of a 678%% field. Currently only handle the case where the field is an 679%% atom. This expansion must be passed through expr again. 680 681index_expr(Line, {atom,_,F}, _Name, Fs) -> 682 {integer,Line,index_expr(F, Fs, 2)}. 683 684index_expr(F, [{record_field,_,{atom,_,F},_}|_], I) -> I; 685index_expr(F, [_|Fs], I) -> 686 index_expr(F, Fs, I+1). 687 688%% pattern_fields([RecDefField], [Match]) -> [Pattern]. 689%% Build a list of match patterns for the record tuple elements. 690%% This expansion must be passed through pattern again. N.B. We are 691%% scanning the record definition field list! 692 693pattern_fields(Fs, Ms) -> 694 Wildcard = record_wildcard_init(Ms), 695 map(fun ({record_field,L,{atom,_,F},_}) -> 696 case find_field(F, Ms) of 697 {ok,Match} -> Match; 698 error when Wildcard =:= none -> {var,L,'_'}; 699 error -> Wildcard 700 end end, 701 Fs). 702 703%% record_inits([RecDefField], [Init]) -> [InitExpr]. 704%% Build a list of initialisation expressions for the record tuple 705%% elements. This expansion must be passed through expr 706%% again. N.B. We are scanning the record definition field list! 707 708record_inits(Fs, Is) -> 709 WildcardInit = record_wildcard_init(Is), 710 map(fun ({record_field,_,{atom,_,F},D}) -> 711 case find_field(F, Is) of 712 {ok,Init} -> Init; 713 error when WildcardInit =:= none -> D; 714 error -> WildcardInit 715 end end, 716 Fs). 717 718record_wildcard_init([{record_field,_,{var,_,'_'},D}|_]) -> D; 719record_wildcard_init([_|Is]) -> record_wildcard_init(Is); 720record_wildcard_init([]) -> none. 721 722%% record_update(Record, RecordName, [RecDefField], [Update], State) -> 723%% {Expr,State'} 724%% Build an expression to update fields in a record returning a new 725%% record. Try to be smart and optimise this. This expansion must be 726%% passed through expr again. 727 728record_update(R, Name, Fs, Us0, St0) -> 729 Line = element(2, R), 730 {Pre,Us,St1} = record_exprs(Us0, St0), 731 Nf = length(Fs), %# of record fields 732 Nu = length(Us), %# of update fields 733 Nc = Nf - Nu, %# of copy fields 734 735 %% We need a new variable for the record expression 736 %% to guarantee that it is only evaluated once. 737 {Var,St2} = new_var(Line, St1), 738 739 %% Try to be intelligent about which method of updating record to use. 740 {Update,St} = 741 if 742 Nu == 0 -> {R,St2}; %No fields updated 743 Nu =< Nc -> %Few fields updated 744 {record_setel(Var, Name, Fs, Us), St2}; 745 true -> %The wide area inbetween 746 record_match(Var, Name, Fs, Us, St2) 747 end, 748 {{block,element(2, R),Pre ++ [{match,Line,Var,R},Update]},St}. 749 750%% record_match(Record, RecordName, [RecDefField], [Update], State) 751%% Build a 'case' expression to modify record fields. 752 753record_match(R, Name, Fs, Us, St0) -> 754 {Ps,News,St1} = record_upd_fs(Fs, Us, St0), 755 Lr = element(2, hd(Us)), 756 {{'case',Lr,R, 757 [{clause,Lr,[{tuple,Lr,[{atom,Lr,Name}|Ps]}],[], 758 [{tuple,Lr,[{atom,Lr,Name}|News]}]}, 759 {clause,Lr,[{var,Lr,'_'}],[], 760 [call_error(Lr, {tuple,Lr,[{atom,Lr,badrecord},{atom,Lr,Name}]})]} 761 ]}, 762 St1}. 763 764record_upd_fs([{record_field,Lf,{atom,_La,F},_Val}|Fs], Us, St0) -> 765 {P,St1} = new_var(Lf, St0), 766 {Ps,News,St2} = record_upd_fs(Fs, Us, St1), 767 case find_field(F, Us) of 768 {ok,New} -> {[P|Ps],[New|News],St2}; 769 error -> {[P|Ps],[P|News],St2} 770 end; 771record_upd_fs([], _, St) -> {[],[],St}. 772 773%% record_setel(Record, RecordName, [RecDefField], [Update]) 774%% Build a nested chain of setelement calls to build the 775%% updated record tuple. 776 777record_setel(R, Name, Fs, Us0) -> 778 Us1 = foldl(fun ({record_field,Lf,Field,Val}, Acc) -> 779 I = index_expr(Lf, Field, Name, Fs), 780 [{I,Lf,Val}|Acc] 781 end, [], Us0), 782 Us = sort(Us1), 783 Lr = element(2, hd(Us)), 784 Wildcards = duplicate(length(Fs), {var,Lr,'_'}), 785 {'case',Lr,R, 786 [{clause,Lr,[{tuple,Lr,[{atom,Lr,Name}|Wildcards]}],[], 787 [foldr(fun ({I,Lf,Val}, Acc) -> 788 {call,Lf,{atom,Lf,setelement},[I,Acc,Val]} end, 789 R, Us)]}, 790 {clause,Lr,[{var,Lr,'_'}],[], 791 [call_error(Lr, {tuple,Lr,[{atom,Lr,badrecord},{atom,Lr,Name}]})]}]}. 792 793%% Expand a call to record_info/2. We have checked that it is not 794%% shadowed by an import. 795 796record_info_call(Line, [{atom,_Li,Info},{atom,_Ln,Name}], St) -> 797 case Info of 798 size -> 799 {{integer,Line,1+length(record_fields(Name, St))},[],[],St}; 800 fields -> 801 {make_list(field_names(record_fields(Name, St)), Line), 802 [],[],St} 803 end. 804 805%% Break out expressions from an record update list and bind to new 806%% variables. The idea is that we will evaluate all update expressions 807%% before starting to update the record. 808 809record_exprs(Us, St) -> 810 record_exprs(Us, St, [], []). 811 812record_exprs([{record_field,Lf,{atom,_La,_F}=Name,Val}=Field0|Us], St0, Pre, Fs) -> 813 case is_simple_val(Val) of 814 true -> 815 record_exprs(Us, St0, Pre, [Field0|Fs]); 816 false -> 817 {Var,St} = new_var(Lf, St0), 818 Bind = {match,Lf,Var,Val}, 819 Field = {record_field,Lf,Name,Var}, 820 record_exprs(Us, St, [Bind|Pre], [Field|Fs]) 821 end; 822record_exprs([], St, Pre, Fs) -> 823 {reverse(Pre),Fs,St}. 824 825is_simple_val({var,_,_}) -> true; 826is_simple_val({atom,_,_}) -> true; 827is_simple_val({integer,_,_}) -> true; 828is_simple_val({float,_,_}) -> true; 829is_simple_val({nil,_}) -> true; 830is_simple_val(_) -> false. 831 832%% pattern_bin([Element], State) -> {[Element],[Variable],[UsedVar],State}. 833 834pattern_bin(Es0, St) -> 835 Es1 = bin_expand_strings(Es0), 836 foldr(fun (E, Acc) -> pattern_element(E, Acc) end, {[],[],[],St}, Es1). 837 838pattern_element({bin_element,Line,Expr,Size,Type}, {Es,Esvs,Esus,St0}) -> 839 {Expr1,Vs1,Us1,St1} = pattern(Expr, St0), 840 {Size1,Vs2,Us2,St2} = pat_bit_size(Size, St1), 841 {Size2,Type1} = make_bit_type(Line, Size1,Type), 842 {[{bin_element,Line,Expr1,Size2,Type1}|Es], 843 union([Vs1,Vs2,Esvs]),union([Us1,Us2,Esus]),St2}. 844 845pat_bit_size(default, St) -> {default,[],[],St}; 846pat_bit_size({atom,_La,all}=All, St) -> {All,[],[],St}; 847pat_bit_size({var,_Lv,V}=Var, St) -> {Var,[],[V],St}; 848pat_bit_size(Size, St) -> 849 Line = element(2, Size), 850 {value,Sz,_} = erl_eval:expr(Size, erl_eval:new_bindings()), 851 {{integer,Line,Sz},[],[],St}. 852 853make_bit_type(Line, default, Type0) -> 854 case erl_bits:set_bit_type(default, Type0) of 855 {ok,all,Bt} -> {{atom,Line,all},erl_bits:as_list(Bt)}; 856 {ok,Size,Bt} -> {{integer,Line,Size},erl_bits:as_list(Bt)} 857 end; 858make_bit_type(_Line, Size, Type0) -> %Integer or 'all' 859 {ok,Size,Bt} = erl_bits:set_bit_type(Size, Type0), 860 {Size,erl_bits:as_list(Bt)}. 861 862%% expr_bin([Element], [VisibleVar], State) -> 863%% {[Element],[NewVar],[UsedVar],State}. 864 865expr_bin(Es0, Vs, St) -> 866 Es1 = bin_expand_strings(Es0), 867 foldr(fun (E, Acc) -> bin_element(E, Vs, Acc) end, {[],[],[],St}, Es1). 868 869bin_element({bin_element,Line,Expr,Size,Type}, Vs, {Es,Esvs,Esus,St0}) -> 870 {Expr1,Vs1,Us1,St1} = expr(Expr, Vs, St0), 871 {Size1,Vs2,Us2,St2} = if Size == default -> {default,[],[],St1}; 872 true -> expr(Size, Vs, St1) 873 end, 874 {Size2,Type1} = make_bit_type(Line, Size1, Type), 875 {[{bin_element,Line,Expr1,Size2,Type1}|Es], 876 union([Vs1,Vs2,Esvs]),union([Us1,Us2,Esus]),St2}. 877 878bin_expand_strings(Es) -> 879 foldr(fun ({bin_element,Line,{string,_,S},default,default}, Es1) -> 880 foldr(fun (C, Es2) -> 881 [{bin_element,Line,{char,Line,C},default,default}|Es2] 882 end, Es1, S); 883 (E, Es1) -> [E|Es1] 884 end, [], Es). 885 886%% new_var_name(State) -> {VarName,State}. 887 888new_var_name(St) -> 889 C = St#expand.vcount, 890 {list_to_atom("pre" ++ integer_to_list(C)),St#expand{vcount=C+1}}. 891 892%% new_var(Line, State) -> {Var,State}. 893 894new_var(L, St0) -> 895 {New,St1} = new_var_name(St0), 896 {{var,L,New},St1}. 897 898%% new_vars(Count, Line, State) -> {[Var],State}. 899%% Make Count new variables. 900 901new_vars(N, L, St) -> new_vars(N, L, St, []). 902 903new_vars(N, L, St0, Vs) when N > 0 -> 904 {V,St1} = new_var(L, St0), 905 new_vars(N-1, L, St1, [V|Vs]); 906new_vars(0, _L, St, Vs) -> {Vs,St}. 907 908%% make_list(TermList, Line) -> ConsTerm. 909 910make_list(Ts, Line) -> 911 foldr(fun (H, T) -> {cons,Line,H,T} end, {nil,Line}, Ts). 912 913string_to_conses(Line, Cs, Tail) -> 914 foldr(fun (C, T) -> {cons,Line,{char,Line,C},T} end, Tail, Cs). 915 916 917%% Create a case-switch on true/false, generating badarg for all other 918%% values. 919 920make_bool_switch(L, E, V, T, F) -> 921 make_bool_switch_1(L, E, V, [T], [F]). 922 923make_bool_switch_1(L, E, V, T, F) -> 924 case get(sys_pre_expand_in_guard) of 925 undefined -> make_bool_switch_body(L, E, V, T, F); 926 yes -> make_bool_switch_guard(L, E, V, T, F) 927 end. 928 929make_bool_switch_guard(_, E, _, [{atom,_,true}], [{atom,_,false}]) -> E; 930make_bool_switch_guard(L, E, V, T, F) -> 931 NegL = -abs(L), 932 {'case',NegL,E, 933 [{clause,NegL,[{atom,NegL,true}],[],T}, 934 {clause,NegL,[{atom,NegL,false}],[],F}, 935 {clause,NegL,[V],[],[V]} 936 ]}. 937 938make_bool_switch_body(L, E, V, T, F) -> 939 NegL = -abs(L), 940 {'case',NegL,E, 941 [{clause,NegL,[{atom,NegL,true}],[],T}, 942 {clause,NegL,[{atom,NegL,false}],[],F}, 943 {clause,NegL,[V],[], 944 [call_error(NegL,{tuple,NegL,[{atom,NegL,badarg},V]})]} 945 ]}. 946 947%% Expand a list of cond-clauses to a sequence of case-switches. 948 949cond_clauses([{clause,L,[],[[E]],B}],V) -> 950 make_bool_switch_1(L,E,V,B,[call_error(L,{atom,L,cond_clause})]); 951cond_clauses([{clause,L,[],[[E]],B} | Cs],V) -> 952 make_bool_switch_1(L,E,V,B,[cond_clauses(Cs,V)]). 953 954%% call_error(Line, Reason) -> Expr. 955%% Build a call to erlang:error/1 with reason Reason. 956 957call_error(L, R) -> 958 {call,L,{remote,L,{atom,L,erlang},{atom,L,error}},[R]}. 959 960%% new_in_all(Before, RegionList) -> NewInAll 961%% Return the variables new in all clauses. 962 963new_in_all(Before, Region) -> 964 InAll = intersection(Region), 965 subtract(InAll, Before). 966 967%% import(Line, Imports, State) -> 968%% State' 969%% imported(Name, Arity, State) -> 970%% {yes,Module} | no 971%% Handle import declarations and est for imported functions. No need to 972%% check when building imports as code is correct. 973 974import({Mod,Fs}, St) -> 975 true = is_atom(Mod), 976 Mfs = from_list(Fs), 977 St#expand{imports=add_imports(Mod, Mfs, St#expand.imports)}. 978 979add_imports(Mod, [F|Fs], Is) -> 980 add_imports(Mod, Fs, orddict:store(F, Mod, Is)); 981add_imports(_, [], Is) -> Is. 982 983imported(F, A, St) -> 984 case orddict:find({F,A}, St#expand.imports) of 985 {ok,Mod} -> {yes,Mod}; 986 error -> no 987 end. 988