1%%% This file is part of PropEr. 2%%% 3%%% PropEr is free software: you can redistribute it and/or modify 4%%% it under the terms of the GNU General Public License as published by 5%%% the Free Software Foundation, either version 3 of the License, or 6%%% (at your option) any later version. 7%%% 8%%% PropEr is distributed in the hope that it will be useful, 9%%% but WITHOUT ANY WARRANTY; without even the implied warranty of 10%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11%%% GNU General Public License for more details. 12%%% 13%%% You should have received a copy of the GNU General Public License 14%%% along with PropEr. If not, see <http://www.gnu.org/licenses/>. 15%%% 16%%% Alternatively, you may use this file under the terms of the Apache 17%%% License, Version 2.0 (the "License"); you may not use this file 18%%% except in compliance with the License. You may obtain a copy of 19%%% the License at <http://www.apache.org/licenses/LICENSE-2.0> 20%%% 21%%% Unless required by applicable law or agreed to in writing, software 22%%% distributed under the License is distributed on an "AS IS" BASIS, 23%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 24%%% See the License for the specific language governing permissions and 25%%% limitations under the License. 26%%% 27%%% If you wish to allow use of your version of this file only under 28%%% the terms of the Apache License, you should delete the provisions 29%%% above and replace them with the notice and other provisions 30%%% required by the Apache License; see 31%%% <http://www.apache.org/licenses/LICENSE-2.0>. If you do not delete 32%%% the provisions above, a recipient may use your version of this 33%%% file under the terms of either the GNU General Public License or 34%%% the Apache License. 35 36%%% 37%%% @doc PropEr generator of abstract code 38%%% 39%%% <p>This module is a PropEr generator for abstract code. It 40%%% generates guards, expressions, programs (modules), and terms. It 41%%% does not generate macros or other attributes than `function', 42%%% `record', `spec', and `type'. The generated programs (guards, 43%%% expressions) can be used for testing the Compiler or other modules 44%%% traversing programs as abstract forms. Typical examples of the 45%%% latter are <code>erl_eval</code>, <code>erl_pp</code>, 46%%% <code>erl_prettypr</code> (Syntax Tools), and parse transforms. 47%%% Created modules should compile without errors, but will most likely 48%%% crash immediately when invoked.</p> 49%%% 50%%% <p>This is an example how to test the Compiler:</p> 51%%% 52%%% ``` 53%%% test() -> 54%%% ?FORALL(Abstr, proper_erlang_abstract_code:module(), 55%%% ?WHENFAIL( 56%%% begin 57%%% io:format("~ts\n", [[erl_pp:form(F) || F <- Abstr]]), 58%%% compile(Abstr, [report_errors]) 59%%% end, 60%%% case compile(Abstr, []) of 61%%% {error, _Es, _Ws} -> false; 62%%% _ -> true 63%%% end)). 64%%% 65%%% compile(Abstr, Opts) -> 66%%% compile:noenv_forms(Abstr, Opts). 67%%% ''' 68-module(proper_erlang_abstract_code). 69 70-export([module/0, module/1, guard/0, guard/1, expr/0, expr/1]). 71 72-export([term/0, term/1]). 73 74%-compile(export_all). -compile(nowarn_export_all). 75 76%-define(debug, true). 77-ifdef(debug). 78-define(DEBUG(F, As), io:format(F, As)). 79-else. 80-define(DEBUG(F, AS), ok). 81-endif. 82 83-include("proper_internal.hrl"). 84 85-type char_fun() :: fun(() -> proper_types:type()). 86%%% A function that generates characters. The default function 87%%% chooses from <code>$a..$z | $A..$Z</code>. 88 89-type atom_fun() :: fun(() -> proper_types:type()). 90%%% A function that generates atoms. The default function chooses 91%%% from 100 common English words. 92 93-type weight() :: non_neg_integer(). 94-type limit() :: non_neg_integer(). 95 96-type option() :: 97 {'variables', [atom()]} | 98 {'weight', {Key :: atom(), Weight :: weight()}} | 99 {'function', [{FunctionName :: atom(), Arity :: arity()}]} | 100 {'types', [{TypeName :: atom(), NumOfParms :: arity()}]} | 101 {'records', [{RecordName:: atom(), [FieldName :: atom()]}]} | 102 {'limit', [{Name :: atom(), Limit :: limit()}]} | 103 {'char', char_fun()} | 104 {'atom', atom_fun()} | 105 {'set_all_weights', weight()}. 106%%% See description below. 107 108-type fa() :: {atom(), arity()}. % function+arity 109-type ta() :: {atom(), arity()}. % type+arity 110-type rec() :: {RecordName :: atom(), [FieldName :: atom()]}. 111 112-record(gen_state, 113 { 114 size = 0 :: proper_gen:size(), 115 result_type = 'program' :: 'program' | 'guard' | 'expr' | 'term', 116 functions = [] :: [fa()], 117 functions_and_auto_imported = [] :: [{weight(), fa()}], 118 expr_bifs = [] :: [fa()], 119 guard_bifs = [] :: [fa()], 120 named_funs = [] :: [fa()], 121 records = [] :: [rec()], 122 guard_records = [] :: [rec()], 123 types = [] :: [ta()], 124 predef_types = [] :: [ta()], 125 module :: module(), 126 options = [] :: [option()], 127 weights = #{} :: #{Key :: atom() => Weight :: weight()}, 128 limits = #{} :: #{Key :: atom() => Limit :: limit()}, 129 variables = ordsets:new() :: ordsets:ordset(atom()), 130 simple_char = fun default_simple_char/0 :: char_fun(), 131 atom = fun default_atom/0 :: atom_fun(), 132 resize = 'false' :: boolean() 133 }). 134 135-record(post_state, 136 { 137 context = 'expr' :: 'expr' | 'type' | 'record' | 'pattern', 138 vars = ordsets:new() :: ordsets:ordset(atom()), 139 vindex = 0 :: non_neg_integer(), 140 forbidden = ordsets:new() :: ordsets:ordset(atom()), 141 known_functions = [] :: [fa()], 142 atom = fun default_atom/0 :: atom_fun() 143 }). 144 145-define(DEFAULT_SMALL_WEIGHT_PROGRAM, 50). % Needs to be quite high. 146-define(DEFAULT_SMALL_WEIGHT_TERM, 50). 147 148-define(MAX_CALL_ARGS, 2). 149-define(MAX_FUNCTION_CLAUSES, 2). 150 151-define(MAX_QUALIFIERS, 2). 152-define(MAX_IF_CLAUSES, 2). 153-define(MAX_CATCH_CLAUSES, 2). 154-define(MAX_CLAUSES, 2). 155-define(MAX_BODY, 2). 156-define(MAX_GUARD, 2). 157-define(MAX_GUARD_TESTS, 2). 158-define(MAX_MAP, 2). 159-define(MAX_TYPE_SPECIFIER, 2). 160-define(MAX_RECORD_FIELDS, 3). 161-define(MAX_TUPLE, 2). 162-define(MAX_BIN_ELEMENTS, 2). 163 164-define(MAX_FUNCTION_TYPES, 2). 165-define(MAX_FUNCTION_CONSTRAINTS, 2). 166-define(MAX_UNION_TYPES, 4). 167-define(MAX_TUPLE_TYPES, 2). 168 169-define(MAX_LIST, 4). 170-define(MAX_STRING, 4). 171 172%%% "div 2" is just a suggestion. 173-define(RESIZE(S), S#gen_state{size = S#gen_state.size div 2}). 174 175%%% @doc Returns abstract code of a term that can be handled by 176%%% <code>erl_parse:normalise/0</code>. 177 178%%% No pid() or port(). 179 180-spec term() -> proper_types:type(). 181 182term() -> 183 term([]). 184 185%%% @doc Same as {@link term/0}, but accepts a list of options. 186%%% === Options === 187%%% 188%%% Many options are the same as the ones for {@link module/1}. 189%%% <ul> 190%%% <li><code>{atom, {@link atom_fun()}}</code> - A atom generating 191%%% function to replace the default.</li> 192%%% <li><code>{char, {@link char_fun()}}</code> - A character generating 193%%% function to replace the default. The function is used when 194%%% generating strings and characters.</li> 195%%% <li><code>{limit, [{Name, Limit}]}</code> - Set the limit of 196%%% <code>Name</code> to <code>Limit</code>. The limit names are: 197%%% <ul> 198%%% <li><code>bin_elements</code> - Number of segments of a bitstring.</li> 199%%% <li><code>list</code> - Number of elements of a plain list.</li> 200%%% <li><code>map</code> - Number of associations of a map.</li> 201%%% <li><code>string</code> - Number of characters of a string.</li> 202%%% <li><code>tuple</code> - Number of elements of a tuple.</li> 203%%% </ul> 204%%% </li> 205%%% <li><code>{resize, boolean()}</code> - Use <code>?SIZED</code> 206%%% to limit the size of the generated abstract code. With this 207%%% option set to <code>false</code> (the default) big code 208%%% may be generated among the first instances.</li> 209%%% <li><code>{set_all_weights, Weight}</code> - Set the weight of 210%%% all keys to <code>Weight</code>.</li> 211%%% <li><code>{weight, {Key, Weight}}</code> - Set the weight of 212%%% <code>Key</code> to weight <code>Weight</code>. A weight of zero 213%%% means that a construct is not generated. Higher weights means that 214%%% a construct i generated relatively often. Groups of weight keys 215%%% follow. Notice that the weight of a key is relative to other 216%%% keys of the same group. The weight of <code>small</code> needs 217%%% to quite high to avoid generating too deeply nested abstract 218%%% code.</li> <ul> 219%%% <li>Atomic expressions (<code>small</code>): <code>atom, boolean, 220%%% integer, string, char, float, nil</code></li> 221%%% <li>Compound terms: <code>small, bitstring, list, tuple, 222%%% map, 'fun'</code></li> 223%%% <li>Map expressions (<code>map</code>): <code>build_map</code></li> 224%%% <li>List expressions (<code>list</code>): <code>plain_list, 225%%% cons</code></li> 226%%% <li>Bitstrings (<code>bitstring</code>): <code>bits, bytes</code></li> 227%%% <li>Function expressions (<code>'fun'</code>): 228%%% <code>ext_mfa</code></li> 229%%% </ul> 230%%% </ul> 231 232-spec term(Options :: [option()]) -> proper_types:type(). 233 234term(Opts) -> 235 PreOpts = [{set_all_weights, 0}], 236 Tags = [compound, small, bitstring, list, tuple, map, 'fun', 237 atom, boolean, integer, string, char, float, nil, 238 bits, bytes, 239 plain_list, cons, 240 build_map, 241 ext_mfa], 242 WOpts = ([{weight, {small, ?DEFAULT_SMALL_WEIGHT_TERM}}] 243 ++ [{weight, {T, 1}} || T <- Tags]), 244 BadOpts = [Opt || 245 {weight, {T, _}} = Opt <- Opts, 246 not lists:member(T, Tags)], 247 case BadOpts =:= [] andalso options(PreOpts ++ WOpts ++ Opts) of 248 false -> 249 erlang:error(badarg); 250 S0 -> 251 S1 = S0#gen_state{result_type = term}, 252 S = eval_dependencies(S1), 253 ?LET(E, 254 ?SIZED(Size, compound(S#gen_state{size = Size})), 255 begin 256 #gen_state{functions = Funs, atom = AtomGen} = S, 257 [Term] = post_process([E], Funs, AtomGen, []), 258 Term 259 end) 260 end. 261 262%%% @doc Returns abstract code of a module. 263%%% The module has type declarations, functions, function specifications, 264%%% and record declarations. 265 266-spec module() -> proper_types:type(). 267 268module() -> 269 module([]). 270 271%%% @doc Same as {@link module/0}, but accepts a list of options. 272%%% === Options === 273%%% 274%%% <ul> 275%%% <li><code>{atom, {@link atom_fun()}}</code> - A atom generating 276%%% function to replace the default.</li> 277%%% <li><code>{char, {@link char_fun()}}</code> - A character generating 278%%% function to replace the default. The function is used when 279%%% generating strings and characters.</li> 280%%% <li><code>{functions, [{Name, Arity}]}</code> - A list of FAs to 281%%% be used as names of generated functions. The default is a small 282%%% number of functions with a small number of arguments.</li> 283%%% <li><code>{limit, [{Name, Limit}]}</code> - Set the limit of 284%%% <code>Name</code> to <code>Limit</code>. The limit names are: 285%%% <ul> 286%%% <li><code>bin_elements</code> - Number of segments of a bitstring.</li> 287%%% <li><code>list</code> - Number of elements of a plain list.</li> 288%%% <li><code>map</code> - Number of associations of a map.</li> 289%%% <li><code>string</code> - Number of characters of a string.</li> 290%%% <li><code>tuple</code> - Number of elements of a tuple.</li> 291%%% <li><code>body</code> - Number of clauses of a body.</li> 292%%% <li><code>call_args</code> - Number of arguments of function call.</li> 293%%% <li><code>catch_clauses</code> - Number of clauses of the 294%%% <code>catch</code> part of a <code>try/catch</code>.</li> 295%%% <li><code>clauses</code> - Number of clauses of <code>case</code>, 296%%% the <code>of</code> part of <code>try/catch</code>, and 297%%% <code>receive</code>.</li> 298%%% <li><code>function_clauses</code> - Number of clauses of 299%%% a function.</li> 300%%% <li><code>function_constraints</code> - Number of constraints of 301%%% a function specification.</li> 302%%% <li><code>function_constraints</code> - Number of constraints of 303%%% a function specification.</li> 304%%% <li><code>function_types</code> - Number of types of 305%%% an overloaded function specification.</li> 306%%% <li><code>guard</code> - Number of guards of a clause.</li> 307%%% <li><code>guard_tests</code> - Number of guard tests of a guard.</li> 308%%% <li><code>if_clauses</code> - Number of clauses of 309%%% <code>if</code>.</li> 310%%% <li><code>tuple_types</code> - Number of types (elements) 311%%% of tuple types.</li> 312%%% <li><code>qualifiers</code> - Number of qualifiers 313%%% of comprehensions.</li> 314%%% <li><code>record_fields</code> - Number of fields of record 315%%% declarations.</li> 316%%% <li><code>tsl</code> - Number of elements of 317%%% type specifier lists (of segments of bit syntax expressions).</li> 318%%% <li><code>union_types</code> - Number of types of type 319%%% union.s</li> 320%%% </ul> 321%%% </li> 322%%% <li><code>{records, [{Name, [Field]}]}</code> - A list 323%%% of record names with field names to be used as names of 324%%% generated records. The default is a small number of records 325%%% with a small number of fields.</li> 326%%% <li><code>{types, [{Name, NumOfParameters}]}</code> - A list 327%%% of TAs to be used as names of generated types. The default 328%%% is a small number of types.</li> 329%%% <li><code>{resize, boolean()}</code> - Use <code>?SIZED</code> 330%%% to limit the size of the generated abstract code. With this 331%%% option set to <code>false</code> (the default) big code 332%%% may be generated among the first instances.</li> 333%%% <li><code>{set_all_weights, Weight}</code> - Set the weight of 334%%% all keys to <code>Weight</code>.</li> 335%%% <li><code>{weight, {Key, Weight}}</code> - Set the weight of 336%%% <code>Key</code> to weight <code>Weight</code>. A weight of zero 337%%% means that a construct is not generated. Higher weights means that 338%%% a construct i generated relatively often. Groups of weight keys 339%%% follow. Notice that the weight of a key is relative to other 340%%% keys of the same group. Also notice that some keys occur in 341%%% more than one group, which makes it all more complicated. The 342%%% weight of <code>small</code> needs to be quite high to avoid 343%%% generating too deeply nested abstract code.</li> 344%%% <ul> 345%%% <li>Declarations: <code>record_decl, type_decl, function_decl, 346%%% function_spec</code> (<code>type_decl</code> and 347%%% <code>function_spec</code> are off by default)</li> 348%%% <li>Atomic expressions (<code>small</code>): <code>atom, boolean, 349%%% integer, string, char, float, nil, pat_var, var</code></li> 350%%% <li>Compound expressions: <code>small, bitstring, list, tuple, 351%%% map, match, binop, unop, record, 'case', block, 'if', 'fun', 352%%% 'receive', 'try', 'catch', try_of, termcall, varcall, localcall, 353%%% extcall</code> (<code>termcall</code> is off by default)</li> 354%%% <li>Map expressions (<code>map</code>): <code>build_map, 355%%% update_map</code></li> 356%%% <li>List expressions (<code>list</code>): <code>plain_list, cons, 357%%% lc</code></li> 358%%% <li>Qualifiers (of <code>lc</code>): <code>lc_gen, blc_gen, 359%%% lc_any_filter, lc_guard_filter</code></li> 360%%% <li>Bitstrings (<code>bitstring</code>): <code>bits, blc, 361%%% literal_bits</code></li> 362%%% <li>Try after (<code>'try', try_of</code>): <code>no_try_after, 363%%% try_after</code></li> 364%%% <li>Catch clause exception types (<code>'catch'</code>): 365%%% <code>no_eclass, any_eclass, lit_eclass, var_eclass, 366%%% bad_eclass</code></li> 367%%% <li>Receive timouts (<code>'receive'</code>): <code> 368%%% lit_timeout, inf_timeout, var_timeout</code></li> 369%%% <li>Function expressions (<code>'fun'</code>): <code> 370%%% lambda, rec_lambda, local_mfa, ext_mfa, any_mfa</code></li> 371%%% <li>Guards: <code>no_guard, yes_guard</code></li> 372%%% <li>Guard test: <code>small, tuple, map, cons, plain_list, bits, 373%%% binop, unop, record, guard_call, remote_guard_call</code></li> 374%%% <li>Pattern: <code>small, match, tuple, cons, plain_list, bits, 375%%% unop, binop, record, map_pattern, string_prefix</code></li> 376%%% <li>Pattern variables (<code>pat_var</code>): 377%%% <code>fresh_var, bound_var</code></li> 378%%% <li>Record field initialization (the <code>_ = V</code> syntax): 379%%% <code>yes_multi_field_init, no_multi_field_init</code></li> 380%%% <li>String prefix (<code>string_prefix</code>): <code> 381%%% nil, string, string_prefix_list</code></li> 382%%% <li>Types: <code>annotated_type, atom, bitstring, 'fun', 383%%% integer_range_type, nil, map, predefined_type, record, 384%%% remote_type, singleton_integer_type, tuple, type_union, 385%%% type_variable, user_defined_type</code></li> 386%%% <li>Function specifications: <code>yes_constrained_function_type, 387%%% no_constrained_function_type</code></li> 388%%% <li>Overloaded function specifications: <code> 389%%% no_overloaded, yes_overloaded</code></li> 390%%% <li>Singleton integer type (<code>singleton_integer_type</code>): 391%%% <code>integer, char, unop, binop</code></li> 392%%% </ul> 393%%% </ul> 394 395-spec module(Options :: [option()]) -> proper_types:type(). 396 397module(Opts) when is_list(Opts) -> 398 case options(Opts) of 399 false -> 400 erlang:error(badarg); 401 State0 -> 402 TopTags = [record_decl, type_decl, function_decl, function_spec], 403 TagWeights = get_weights(TopTags, State0), 404 ?DEBUG(" TagWeights ~p\n", [TagWeights]), 405 State = set_up(State0), 406 FormsL = [form(TW, TagWeights, State) || TW <- TagWeights], 407 Fs = ([{attribute, anno(), module, State#gen_state.module}] 408 ++ lists:append(FormsL)), 409 #gen_state{functions = Funs, atom = AtomGen} = State, 410 true = length(Funs) > 0, 411 ?SUCHTHAT(T, 412 ?LET(P, 413 Fs, 414 post_process(P, Funs, AtomGen, [])), 415 ok_by_the_linter(forms, T)) 416 end. 417 418%%% @doc Returns abstract code of a guard. A guard is a sequence 419%%% of guard tests. 420 421-spec guard() -> proper_types:type(). 422 423guard() -> 424 guard([]). 425 426%%% @doc Same as {@link guard/0}, but accepts a list of options. See 427%%% {@link module/1} for a description of the options. 428 429-spec guard(Options :: [option()]) -> proper_types:type(). 430 431guard(Opts) when is_list(Opts) -> 432 case options(Opts) of 433 false -> 434 erlang:error(badarg); 435 State0 -> 436 State1 = State0#gen_state{result_type = guard}, 437 State = set_up(State1), 438 ?LET(G, 439 ?SIZED(Size, a_guard(State#gen_state{size = Size})), 440 begin 441 #gen_state{functions = Funs, 442 atom = AtomGen, 443 variables = Vars} = State, 444 [Guard] = post_process([G], Funs, AtomGen, Vars), 445 Guard 446 end) 447 end. 448 449%%% @doc Returns abstract code of an expression. 450 451-spec expr() -> proper_types:type(). 452 453expr() -> 454 expr([]). 455 456%%% @doc Same as {@link expr/0}, but accepts a list of options. See 457%%% {@link module/1} for a description of the options. 458 459-spec expr(Options :: list()) -> proper_types:type(). 460 461expr(Opts) when is_list(Opts) -> 462 case options(Opts) of 463 false -> 464 erlang:error(badarg); 465 State0 -> 466 State1 = State0#gen_state{result_type = expr, 467 functions = []}, 468 State2 = set_up(State1), 469 ?SUCHTHAT(Expr, 470 ?LET(E1, 471 ?SIZED(Size, 472 begin 473 State = State2#gen_state{size = Size}, 474 abstract_expr(State) 475 end), 476 begin 477 #gen_state{functions = Funs, 478 atom = AtomGen, 479 variables = Vars} = State2, 480 [E2] = post_process([E1], Funs, AtomGen, Vars), 481 E2 482 end), 483 ok_by_the_linter(expr, Expr)) 484 end. 485 486set_up(S0) -> 487 #gen_state{functions = Fs, records = Rs, types = Ts} = S0, 488 GRs = guard_records(Rs), 489 case {Fs, Rs, Ts} of 490 {[], [], []} -> 491 erlang:error(nothing_to_work_with); 492 _ -> 493 %% Give local functions higher weight. 494 AutoImported = auto_imported(), 495 FW = case length(Fs) of 496 0 -> 497 0; % not used 498 NumFs -> 499 max(1, round(length(AutoImported) / NumFs)) 500 end, 501 FAWs = ([{FW, FA} || FA <- Fs] 502 ++ [{1, FA} || FA <- AutoImported]), 503 S1 = S0#gen_state{functions_and_auto_imported = FAWs, 504 expr_bifs = guard_bifs() ++ expr_ops(), 505 guard_bifs = guard_bifs() ++ guard_ops(), 506 guard_records = GRs}, 507 State = eval_dependencies(S1), 508 ?DEBUG(" records: ~p\n", [State#gen_state.records]), 509 ?DEBUG(" types: ~p\n", [State#gen_state.types]), 510 ?DEBUG(" functions: ~p\n", [State#gen_state.functions]), 511 ?DEBUG(" weights: ~p\n", [State#gen_state.weights]), 512 ?DEBUG(" limits: ~p\n", [State#gen_state.limits]), 513 ?DEBUG(" resize: ~p\n", [State#gen_state.resize]), 514 State 515 end. 516 517%%% The fields of the chosen record are initiated with guard 518%%% expressions, which means that the record can occur in a guard 519%%% expression. 520guard_records([]) -> 521 []; 522guard_records([R | _]) -> 523 [R]. 524 525form({_Tag, 0}, _, _State) -> 526 []; 527form({type_decl, _}, _, State) -> 528 TypeNames = State#gen_state.types, 529 Exports = [{attribute, anno(), export_type, TypeNames}], 530 Decls = [type_decl(State, TN) || TN <- TypeNames], 531 Exports ++ Decls; 532form({record_decl, _}, _, State) -> 533 RecordNames = State#gen_state.records, 534 State = State#gen_state{records = RecordNames}, 535 State1 = exclude_tags([fresh_var], State), 536 State2 = State1#gen_state{records = []}, 537 declare_recs(RecordNames, State2); 538form({function_decl, _}, TagWeights, State) -> 539 FunctionNames = State#gen_state.functions, 540 Exports = [{attribute, anno(), export, FunctionNames}], 541 State = State#gen_state{functions = FunctionNames}, 542 {function_spec, SpecW} = lists:keyfind(function_spec, 1, TagWeights), 543 Decls = [begin 544 FD = function_decl(State, FN), 545 case SpecW of 546 0 -> 547 [FD]; 548 _ -> 549 [function_spec(State, FN), FD] 550 end 551 end || 552 FN <- FunctionNames], 553 Exports ++ lists:append(Decls); 554form({function_spec, _}, _, _State) -> 555 []. 556 557declare_recs([], _) -> 558 []; 559declare_recs([Rec|Recs], S0) -> 560 S0_1 = exclude_tags([record], S0), 561 R = record_decl(S0_1, Rec), 562 S = S0#gen_state{records = [Rec|S0#gen_state.records]}, 563 [R | declare_recs1(Recs, S)]. 564 565declare_recs1([], _S) -> 566 []; 567declare_recs1([Rec|Recs], S0) -> 568 R = record_decl(S0, Rec), 569 S = S0#gen_state{records = [Rec|S0#gen_state.records]}, 570 [R | declare_recs1(Recs, S)]. 571 572record_decl(S0, {RecName, Fs}=R) -> 573 ?SIZED(Size, 574 begin 575 S = S0#gen_state{size = Size}, 576 {'attribute', anno(), 'record', 577 {RecName, field_decls(S, R, Fs)}} 578 end). 579 580field_decls(S, R, Fs) -> 581 [field_decl(S, R, F) || F <- Fs]. 582 583field_decl(S0, R, F) -> 584 S = case rec_init_guard_expr(S0, R) of 585 true -> 586 exclude_tags([complex_field_init], S0); 587 false -> 588 S0 589 end, 590 ?LET(Field, 591 wunion([field_no_type, field_yes_type], S, ?FUNCTION_NAME), 592 set_field_name(Field, F)). 593 594rec_init_guard_expr(S, R) -> 595 lists:member(R, S#gen_state.guard_records). 596 597set_field_name({'typed_record_field', Field, AbstractType}, F) -> 598 {'typed_record_field', set_field_name(Field, F), AbstractType}; 599set_field_name({'record_field', A, field_name}, F) -> 600 {'record_field', A, lit_atom(F)}; 601set_field_name({'record_field', A, field_name, AbstractExpr}, F) -> 602 {'record_field', A, lit_atom(F), AbstractExpr}. 603 604field_yes_type(S) -> 605 {'typed_record_field', field_no_type(S), abstract_type(S)}. 606 607field_no_type(S) -> 608 wunion([field_no_init, field_yes_init], S, ?FUNCTION_NAME). 609 610field_no_init(_S) -> 611 {'record_field', anno(), field_name()}. 612 613field_yes_init(S) -> 614 {'record_field', 615 anno(), 616 field_name(), 617 case get_weight(complex_field_init, S) of 618 0 -> 619 guard_test(S); 620 1 -> 621 abstract_expr(S) 622 end}. 623 624field_name() -> 625 field_name. 626 627type_decl(S0, {TypeName, N}) -> 628 ?SIZED(Size, 629 begin 630 S = S0#gen_state{size = Size}, 631 Parms = list_of_gen2(N, type_parameter()), 632 {'attribute', anno(), type_attr(), 633 %% Not affected by weight of 'variable'. 634 {TypeName, abstract_type(S), Parms}} 635 end). 636 637type_parameter() -> 638 a_variable(type_parameter). 639 640type_attr() -> 641 proper_types:oneof(['type', 'opaque']). 642 643function_spec(S0, {F, N}) -> 644 ?SIZED(Size, 645 begin 646 S = S0#gen_state{size = Size}, 647 {'attribute', anno(), spec_attr(), 648 {{F, N}, function_type_list(S, N)}} 649 end). 650 651spec_attr() -> 652 'spec'. 653 %% oneof(['callback', 'spec']). 654 655function_decl(S0, {F, N}) -> 656 ?SIZED(Size, 657 begin 658 S = S0#gen_state{size = Size}, 659 {'function', anno(), F, N, function_clause_seq(S, N)} 660 end). 661 662abstract_expr(S) -> 663 compound(S). 664 665compound(#gen_state{size = 0}=S) -> 666 wunion([small], S, ?FUNCTION_NAME); % assume weight(small) > 0 667compound(S) -> 668 Tags = [small, bitstring, list, tuple, map, match, binop, unop, 669 record, 'case', block, 'if', 'fun', 'receive', 'try', 670 'catch', try_of, termcall, varcall, localcall, extcall], 671 wunion(Tags, resize(S), ?FUNCTION_NAME). 672 673a_map(S, abstract_type) -> 674 map_type(S); 675a_map(S, Where) -> 676 wunion([build_map, update_map], S, Where). 677 678a_list(S, Where) -> 679 wunion([plain_list, cons, lc], S, Where). 680 681%%% Assume 'plain' means 'proper' (see eqc:eqc_erlang_program). 682plain_list(S, T) -> 683 ?LET(L, 684 list_of_gen(T, get_limit(list, S)), 685 lists:foldr(fun(E, A) -> 686 {'cons', anno(), E, A} 687 end, nil(), L)). 688 689cons(_S, T) -> 690 {'cons', anno(), T, T}. 691 692nil(_S, abstract_type) -> 693 empty_list_type(); 694nil(_S, _Where) -> 695 nil(). 696 697nil() -> 698 {'nil', anno()}. 699 700update_record(S, T) -> 701 ?LET({RecName, Fields}, 702 known_record(S), 703 {'record', 704 anno(), 705 abstract_expr(S), 706 RecName, 707 record_field_seq(S, T, Fields, update)}). 708 709'catch'(S) -> 710 {'catch', anno(), abstract_expr(S)}. 711 712termcall(_S, T) -> 713 {'tuple', anno(), [T, T]}. 714 715varcall(S, T) -> 716 {'call', anno(), T, args(S)}. 717 718localcall(S) -> 719 ?LET({F, N}, 720 local_function_or_auto_imported(S), 721 {'call', anno(), F, n_args(S, N)}). 722 723extcall(S) -> 724 proper_types:weighted_union( 725 [{1, ?LAZY(any_extcall(S))}, 726 {1, ?LAZY(known_extcall(S))}]). 727 728any_extcall(S) -> 729 N = random_n_args(S), 730 {'call', anno(), remote_function(S), n_args(S, N)}. 731 732known_extcall(S) -> 733 ?LET({F, N}, 734 expr_bif(S), 735 {'call', anno(), 736 {'remote', anno(), lit_atom('erlang'), lit_atom(F)}, 737 n_args(S, N)}). 738 739expr_bif(S) -> 740 proper_types:oneof(S#gen_state.expr_bifs). 741 742n_args(S, N) -> 743 list_of_gen2(N, abstract_expr(S)). 744 745args(S) -> 746 N = random_n_args(S), 747 list_of_gen2(N, abstract_expr(S)). 748 749local_function_or_auto_imported(S) -> 750 ?LET({F, N}, 751 proper_types:weighted_union(S#gen_state.functions_and_auto_imported), 752 case lists:member({F, N}, S#gen_state.named_funs) of 753 true -> 754 {a_variable(F), N}; 755 false -> 756 {lit_atom(F), N} 757 end). 758 759remote_function(S) -> 760 {'remote', anno(), abstract_expr(S), abstract_expr(S)}. 761 762lc(S) -> 763 {'lc', anno(), template(S), qualifier_seq(S)}. 764 765blc(S) -> 766 LiteralW = get_weight(literal_bits, S), 767 wunion1( 768 [{1, ?LAZY({'bc', anno(), template(S), qualifier_seq(S)})}, 769 {LiteralW, ?LAZY(literal_bc(S))} 770 ]). 771 772literal_bc(S) -> 773 %% The weight of `literal_bits' is not zero. 774 SBC = set_tag_weights([{in_literal_bc, 1}], S), 775 {'bc', anno(), bits(SBC, compound), qualifier_seq(SBC)}. 776 777template(S) -> 778 abstract_expr(S). 779 780qualifier_seq(S) -> 781 non_empty_list_of_gen(qualifier(S), get_limit(qualifiers, S)). 782 783qualifier(S) -> 784 Tags = [lc_gen, blc_gen, lc_any_filter, lc_guard_filter], 785 wunion(Tags, S, ?FUNCTION_NAME). 786 787lc_gen(S) -> 788 {'generate', anno(), pattern(S), abstract_expr(S)}. 789 790blc_gen(S) -> 791 LiteralW = get_weight(literal_bits, S), 792 WildBitsW = wild_bits_weight(S), 793 ?LET({Pattern, Expr}, 794 {bits(S, pattern), 795 wunion1( 796 [{WildBitsW, ?LAZY(abstract_expr(S))}, 797 {LiteralW, ?LAZY(bits(S, compound))} 798 ])}, 799 {'b_generate', anno(), Pattern, Expr}). 800 801lc_any_filter(S) -> 802 abstract_expr(S). 803 804lc_guard_filter(S) -> 805 guard_test(S). 806 807block(S) -> 808 {'block', anno(), body(S)}. 809 810'if'(S) -> 811 {'if', anno(), if_clause_seq(S)}. 812 813if_clause_seq(S) -> 814 non_empty_list_of_gen(if_clause(S), get_limit(if_clauses, S)). 815 816if_clause(S) -> 817 {'clause', anno(), [], if_guard_seq(S), body(S)}. 818 819if_guard_seq(S) -> 820 list_of_gen(a_guard(S), get_limit(guard, S)). 821 822'case'(S) -> 823 {'case', anno(), abstract_expr(S), clause_seq(S)}. 824 825'try'(S) -> 826 NESeq = non_empty_catch_clause_seq(S), 827 Seq = catch_clause_seq(S), 828 ?LET(After, 829 wunion([no_try_after, try_after], S, ?FUNCTION_NAME), 830 case After of 831 [] -> 832 {'try', anno(), body(S), [], NESeq, After}; 833 _ -> 834 {'try', anno(), body(S), [], Seq, After} 835 end). 836 837try_of(S) -> 838 NESeq = non_empty_catch_clause_seq(S), 839 Seq = catch_clause_seq(S), 840 ?LET(After, 841 wunion([no_try_after, try_after], S, ?FUNCTION_NAME), 842 case After of 843 [] -> 844 {'try', anno(), body(S), clause_seq(S), NESeq, After}; 845 _ -> 846 {'try', anno(), body(S), clause_seq(S), Seq, After} 847 end). 848 849no_try_after(_S) -> 850 []. 851 852try_after(S) -> 853 body(S). 854 855catch_clause_seq(S) -> 856 list_of_gen(catch_clause(S), get_limit(catch_clauses, S)). 857 858non_empty_catch_clause_seq(S) -> 859 non_empty_list_of_gen(catch_clause(S), get_limit(catch_clauses, S)). 860 861catch_clause(S) -> 862 Tags = [no_eclass, any_eclass, lit_eclass, var_eclass, bad_eclass], 863 ?LET({EClass, St}, 864 {wunion(Tags, S, ?FUNCTION_NAME), stacktrace_variable(S)}, 865 {'clause', anno(), 866 [{'tuple', anno(), [EClass, pattern(S), St]}], 867 clause_guard_seq(S), 868 body(S)}). 869 870no_eclass(_S) -> 871 a_variable('_'). 872 873any_eclass(_S) -> 874 a_variable('_'). 875 876lit_eclass(_S) -> 877 proper_types:oneof([lit_atom('exit'), 878 lit_atom('error'), 879 lit_atom('throw')]). 880 881var_eclass(S) -> 882 var(S). % atom is fallback 883 884bad_eclass(_S) -> 885 lit_atom(bad_eclass). 886 887stacktrace_variable(S) -> 888 %% weight(fresh_var) = 0 results in an anonymous variable. 889 fresh_var(S). 890 891'receive'(S) -> 892 Ws = sum_weights([lit_timeout, inf_timeout, var_timeout], S), 893 AfterW = min(Ws, 1), 894 proper_types:weighted_union( 895 [{1, ?LAZY(receive_no_after(S))}, 896 {AfterW, ?LAZY(receive_yes_after(S))} 897 ]). 898 899receive_no_after(S) -> 900 {'receive', anno(), clause_seq(S)}. 901 902receive_yes_after(S) -> 903 ?LET(Timeout, 904 wunion([lit_timeout, inf_timeout, var_timeout], S, ?FUNCTION_NAME), 905 {'receive', anno(), receive_after_clause_seq(S), Timeout, body(S)}). 906 907receive_after_clause_seq(S) -> 908 list_of_gen(clause(S), get_limit(clauses, S)). 909 910clause_seq(S) -> 911 non_empty_list_of_gen(clause(S), get_limit(clauses, S)). 912 913lit_timeout(S) -> 914 an_integer(S). 915 916inf_timeout(_S) -> 917 lit_atom('infinity'). 918 919var_timeout(S) -> 920 abstract_expr(S). 921 922'fun'(S, abstract_type) -> 923 fun_type(S); 924'fun'(S, Where) -> 925 Tags = [lambda, rec_lambda, local_mfa, ext_mfa, any_mfa], 926 wunion(Tags, S, Where). 927 928lambda(S) -> 929 ?LET({_F, N}, 930 proper_types:oneof(S#gen_state.named_funs), 931 {'fun', anno(), {'clauses', function_clause_seq(S, N)}}). 932 933rec_lambda(S) -> 934 ?LET({F, N}, 935 proper_types:oneof(S#gen_state.named_funs), 936 begin 937 FNW = {1, {F, N}}, % too low? 938 Functions = [FNW | S#gen_state.functions_and_auto_imported], 939 S1 = S#gen_state{functions_and_auto_imported = Functions}, 940 {'named_fun', anno(), F, function_clause_seq(S1, N)} 941 end). 942 943function_clause_seq(S, N) -> 944 NCl = random_n_clauses(S), 945 list_of_gen2(NCl, function_clause(S, N)). 946 947random_n_clauses(S) -> 948 uniform(get_limit(function_clauses, S)). 949 950function_clause(S, N) -> 951 {'clause', anno(), pattern_seq(S, N), clause_guard_seq(S), body(S)}. 952 953local_mfa(S) -> 954 ?LET({F, N}, 955 local_function(S), 956 {'fun', anno(), {'function', F, N}}). 957 958ext_mfa(S) -> 959 LW = 960 case 961 (S#gen_state.result_type =:= term orelse 962 get_weight(function_decl, S) > 0) 963 of 964 true -> 965 1; 966 false -> 967 0 968 end, 969 wunion1( 970 [{LW, ?LAZY(?LET({F, N}, 971 local_function(S), 972 {'fun', anno(), 973 {'function', lit_atom(S#gen_state.module), 974 lit_atom(F), 975 lit_integer(N)}}))}, 976 {1, ?LAZY({'fun', anno(), 977 {'function', any_module(S), 978 any_function(), 979 lit_integer(proper_types:arity())}})} 980 ]). 981 982any_mfa(S) -> 983 ?SUCHTHAT(Fun_MFA, 984 ?LET({M, F, A}, 985 {var_or_atom(S), var_or_atom(S), var_or_arity(S)}, 986 {'fun', anno(), {'function', M, F, A}}), 987 begin 988 {'fun', _, {'function', M, F, A}} = Fun_MFA, 989 is_var(M) orelse is_var(F) orelse is_var(A) 990 end). 991 992var_or_atom(S) -> 993 var(S). % atom is fallback 994 995var_or_arity(_S) -> 996 proper_types:oneof([a_variable(bound_var_or_an_arity), 997 lit_integer(proper_types:arity())]). 998 999is_var({'var', _, _}) -> true; 1000is_var(_) -> false. 1001 1002local_function(S) -> 1003 one_of(S#gen_state.functions, no_functions). 1004 1005clause(S) -> 1006 {'clause', anno(), [pattern(S)], clause_guard_seq(S), body(S)}. 1007 1008pattern_seq(S, N) -> 1009 list_of_gen2(N, pattern(S)). 1010 1011body(S) -> 1012 non_empty_list_of_gen(abstract_expr(S), get_limit(body, S)). 1013 1014clause_guard_seq(S) -> 1015 wunion([no_guard, yes_guard], S, ?FUNCTION_NAME). 1016 1017no_guard(_S) -> 1018 []. 1019 1020yes_guard(S) -> 1021 non_empty_list_of_gen(a_guard(S), get_limit(guard, S)). 1022 1023a_guard(S) -> 1024 non_empty_list_of_gen(guard_test(S), get_limit(guard_tests, S)). 1025 1026guard_test(#gen_state{size = 0}=S) -> 1027 wunion([small], S, ?FUNCTION_NAME); % assume weight(small) > 0 1028guard_test(S) -> 1029 Tags = [small, tuple, map, cons, plain_list, bits, binop, 1030 unop, record, guard_call, remote_guard_call], 1031 wunion(Tags, resize(S), ?FUNCTION_NAME). 1032 1033build_map(S, T) -> 1034 {'map', anno(), assoc_seq(S, 0, T)}. 1035 1036update_map(S, T) -> 1037 {'map', anno(), T, assoc_seq(S, 1, T)}. 1038 1039assoc_seq(S, ExactWeight, T) -> 1040 list_of_gen(assoc(ExactWeight, T), get_limit(map, S)). 1041 1042assoc(ExactWeight, T) -> 1043 wunion1( 1044 [{1, ?LAZY({'map_field_assoc', anno(), T, T})}, 1045 {ExactWeight, ?LAZY(assoc_exact(T))}]). 1046 1047assoc_exact(T) -> 1048 {'map_field_exact', anno(), T, T}. 1049 1050%%% The type test is_record() is not handled well. 1051guard_call(S) -> 1052 case has_fields(S) of 1053 false -> 1054 guard_call_1(S); 1055 true -> 1056 proper_types:weighted_union([{10, ?LAZY(guard_call_1(S))}, 1057 {1, ?LAZY(guard_call_2(S))}, 1058 {1, ?LAZY(guard_call_3(S))}]) 1059 end. 1060 1061guard_call_1(S) -> 1062 ?LET({F, N}, 1063 guard_bif(S), 1064 {'call', anno(), lit_atom(F), guard_call_args(N, S)}). 1065 1066guard_call_2(S) -> 1067 ?LET({RecName, _Fields}, 1068 known_record_with_fields(S), 1069 {'call', anno(), lit_atom('is_record'), 1070 guard_call_args(1, S) ++ [lit_atom(RecName)]}). 1071 1072guard_call_3(S) -> 1073 ?LET({RecName, Fields}, 1074 known_record_with_fields(S), 1075 {'call', anno(), 1076 {'remote', anno(), lit_atom('erlang'), lit_atom('is_record')}, 1077 (guard_call_args(1, S) ++ 1078 [lit_atom(RecName), lit_integer(length(Fields))])}). 1079 1080remote_guard_call(S) -> 1081 ?LET({F, N}, 1082 guard_bif(S), 1083 {'call', anno(), 1084 {'remote', anno(), lit_atom('erlang'), lit_atom(F)}, 1085 guard_call_args(N, S)}). 1086 1087guard_bif(S) -> 1088 proper_types:oneof(S#gen_state.guard_bifs). 1089 1090%%% Guard BIFs with arity greater than than the limit of call_args are 1091%%% not excluded. 1092guard_call_args(N, S) -> 1093 list_of_gen2(N, guard_test(S)). 1094 1095pattern(#gen_state{size = 0}=S) -> 1096 wunion([small], S, ?FUNCTION_NAME); % assume weight(small) > 0 1097pattern(S) -> 1098 Tags = [small, match, tuple, cons, plain_list, bits, unop, binop, 1099 record, map_pattern, string_prefix], 1100 wunion(Tags, resize(S), ?FUNCTION_NAME). 1101 1102a_record(S, abstract_type) -> 1103 record_type(S); 1104a_record(S, compound=Where) -> 1105 a_record2([build_record, record_field_access, record_index, 1106 update_record], S, Where); 1107a_record(S, guard_test=Where) -> 1108 a_record2([build_record, record_field_access, record_index], S, Where); 1109a_record(S, pattern=Where) -> 1110 a_record2([record_pattern, record_index], S, Where). 1111 1112a_record2(Tags, S0, Where) -> 1113 S = maybe_exclude_field_access(S0), 1114 wunion(Tags, S, Where). 1115 1116maybe_exclude_field_access(S) -> 1117 %% Maybe the user should fix this kind of issues. 1118 case has_fields(S) of 1119 false -> 1120 exclude_tags([record_field_access, record_index], S); 1121 true -> 1122 S 1123 end. 1124 1125has_fields(S) -> 1126 lists:any(fun({_, Fields}) -> Fields =/= [] end, S#gen_state.records). 1127 1128record_field_access(S, T) -> 1129 ?LET({RecName, Fields}, 1130 known_record_with_fields(S), 1131 begin 1132 Field = lit_atom(proper_types:oneof(Fields)), 1133 {'record_field', anno(), T, RecName, Field} 1134 end). 1135 1136record_index(S) -> 1137 ?LET({RecName, Fields}, 1138 known_record_with_fields(S), 1139 begin 1140 Field = lit_atom(proper_types:oneof(Fields)), 1141 {'record_index', anno(), RecName, Field} 1142 end). 1143 1144record_pattern(S) -> 1145 ?LET({RecName, Fields}, 1146 known_guard_record(S), 1147 {'record', 1148 anno(), 1149 RecName, 1150 record_field_seq(S, pattern(S), Fields, build)}). 1151 1152build_record(S, guard_test) -> 1153 ?LET({RecName, Fields}, 1154 known_guard_record(S), 1155 {'record', 1156 anno(), 1157 RecName, 1158 record_field_seq(S, guard_test(S), Fields, build)}); 1159build_record(S, compound) -> 1160 ?LET({RecName, Fields}, 1161 known_record(S), 1162 {'record', 1163 anno(), 1164 RecName, 1165 record_field_seq(S, abstract_expr(S), Fields, build)}). 1166 1167record_field_seq(_S, _T, [], _Context) -> 1168 []; 1169record_field_seq(S, T, Fs0, build) -> 1170 ?LET(IF, 1171 wunion([yes_multi_field_init, no_multi_field_init], S, anywhere), 1172 begin 1173 Fs = IF ++ Fs0, 1174 record_field_seq2(S, T, Fs) 1175 end); 1176record_field_seq(S, T, Fs, update) -> 1177 record_field_seq2(S, T, Fs). 1178 1179record_field_seq2(S, T, Fs) -> 1180 N = uniform(min(length(Fs), get_limit(record_fields, S))), 1181 record_field(N, T, Fs). 1182 1183yes_multi_field_init(_S) -> 1184 ['_']. 1185 1186no_multi_field_init(_S) -> 1187 []. 1188 1189record_field(0, _T, _Fs) -> 1190 []; 1191record_field(N, T, Fs0) -> 1192 ?LET(F, 1193 proper_types:oneof(Fs0), 1194 begin 1195 Name = case F of 1196 '_' -> a_variable(F); 1197 _ -> lit_atom(F) 1198 end, 1199 Field = {'record_field', anno(), Name, T}, 1200 Fs = lists:delete(F, Fs0), 1201 [Field | record_field(N - 1, T, Fs)] 1202 end). 1203 1204map_pattern(S0) -> 1205 S = exclude_tags([record_index, string_prefix, pat_var], S0), 1206 {'map', anno(), assoc_pattern_seq(S)}. 1207 1208assoc_pattern_seq(S) -> 1209 KeyW = get_weight(map_pattern_assoc, S), 1210 ValueW = get_weight(map_pattern_exact, S), 1211 %% Note that when excluding tags, more zero_weights errors are 1212 %% possible. 1213 InKey = [{fresh_var, 0}, 1214 {map_pattern_assoc, 1}, 1215 {map_pattern_exact, 0}, 1216 {match, 0}], 1217 SKey = set_tag_weights(InKey, S), % only => in key; no =/2 in key 1218 G = proper_types:weighted_union( 1219 [{KeyW, 1220 %% EEP 52. 1221 ?LAZY({'map_field_assoc', anno(), guard_test(SKey), pattern(S)})}, 1222 {ValueW, 1223 ?LAZY({'map_field_exact', anno(), pattern(SKey), pattern(S)})}]), 1224 non_empty_list_of_gen(G, ?MAX_MAP). 1225 1226string_prefix(S) -> 1227 StringPrefix = wunion([nil, string, string_prefix_list], S, pattern), 1228 S1 = exclude_tags([record_index, string_prefix], S), 1229 {'op', anno(), '++', StringPrefix, pattern(S1)}. 1230 1231string_prefix_list(S) -> 1232 plain_list(S, proper_types:union([a_char(S), an_integer(S)])). 1233 1234%%% Maybe something like 'small'. Should obey S.size. 1235abstract_type(S) -> 1236 Tags = [annotated_type, atom, bitstring, 'fun', 1237 integer_range_type, nil, map, predefined_type, record, 1238 remote_type, singleton_integer_type, tuple, type_union, 1239 type_variable, user_defined_type], 1240 wunion(Tags, S, ?FUNCTION_NAME). 1241 1242annotated_type(S) -> 1243 ?LET({Var, Type}, 1244 {annotation(S), abstract_type(S)}, 1245 {'ann_type', anno(), [Var, Type]}). 1246 1247annotation(S) -> 1248 proper_types:weighted_union( 1249 [{20, ?LAZY(type_variable(S))}, 1250 {1, ?LAZY(anonymous_var(S))}]). 1251 1252empty_list_type() -> 1253 {'type', anno(), 'nil', []}. 1254 1255fun_type(S) -> 1256 proper_types:weighted_union( 1257 [{1, ?LAZY({'type', anno(), 'fun', []})}, 1258 {1, ?LAZY({'type', anno(), 'fun', [{'type', anno(), 'any'}, 1259 abstract_type(S)]})}, 1260 {2, ?LAZY(fun_type_n(S))}]). 1261 1262fun_type_n(S) -> 1263 N = random_n_args(S), 1264 function_type(S, N). 1265 1266random_n_args(S) -> 1267 uniform(get_limit(call_args, S) + 1) - 1. 1268 1269integer_range_type(S) -> 1270 ?LET({T1, T2}, 1271 {singleton_integer_type(S), singleton_integer_type(S)}, 1272 {'type', anno(), 'range', [T1, T2]}). 1273 1274map_type(S) -> 1275 proper_types:weighted_union( 1276 [{1, ?LAZY({'type', anno(), 'map', 'any'})}, 1277 {1, ?LAZY({'type', anno(), 'map', assoc_type_seq(S)})}]). 1278 1279assoc_type_seq(S) -> 1280 list_of_gen(assoc_type(S), ?MAX_MAP). 1281 1282assoc_type(S) -> 1283 proper_types:weighted_union( 1284 [{1, ?LAZY({'type', anno(), 'map_field_assoc', 1285 [abstract_type(S), abstract_type(S)]})}, 1286 {1, ?LAZY({'type', anno(), 'map_field_exact', 1287 [abstract_type(S), abstract_type(S)]})}]). 1288 1289predefined_type(S) -> 1290 ?LET({TypeName, N}, 1291 proper_types:oneof(S#gen_state.predef_types), 1292 {'type', 1293 anno(), 1294 TypeName, 1295 list_of_gen2(N, abstract_type(S))}). 1296 1297record_type(S) -> 1298 ?LET({RecName, Fields}, 1299 known_record(S), 1300 {'type', 1301 anno(), 1302 'record', 1303 [lit_atom(RecName) | record_field_types(S, Fields)]}). 1304 1305record_field_types(_S, []) -> 1306 []; 1307record_field_types(S, Fs) -> 1308 N = uniform(min(length(Fs), get_limit(record_fields, S))), 1309 Type = abstract_type(S), 1310 record_field_type(N, Type, Fs). 1311 1312record_field_type(0, _T, _Fs) -> 1313 []; 1314record_field_type(N, T, Fs0) -> 1315 ?LET(FieldName, 1316 proper_types:oneof(Fs0), 1317 begin 1318 Name = lit_atom(FieldName), 1319 Field = {'type', anno(), 'field_type', [Name, T]}, 1320 Fs = lists:delete(FieldName, Fs0), 1321 [Field | record_field_type(N - 1, T, Fs)] 1322 end). 1323 1324remote_type(S) -> 1325 ?LET({Module, Name, T}, 1326 {an_atom(S), an_atom(S), abstract_type(S)}, 1327 {'remote_type', anno(), [Module, Name, [T]]}). 1328 1329tuple_type(S) -> 1330 proper_types:weighted_union( 1331 [{1, ?LAZY({'type', anno(), 'tuple', abstract_type_seq(S)})}, 1332 {1, ?LAZY({'type', anno(), 'tuple', 'any'})}]). 1333 1334abstract_type_seq(S) -> 1335 list_of_gen(abstract_type(S), get_limit(tuple_types, S)). 1336 1337type_union(S) -> 1338 N = uniform(get_limit(union_types, S) - 2) + 2, 1339 {'type', 1340 anno(), 1341 'union', 1342 list_of_gen2(N, abstract_type(S))}. 1343 1344user_defined_type(S) -> 1345 ?LET({TypeName, N}, 1346 local_type(S), 1347 {'user_type', anno(), TypeName, list_of_gen2(N, abstract_type(S))}). 1348 1349function_type_list(S, N) -> 1350 ?LET({Ft, {MinTypes, MaxTypes}}, 1351 {function_type(S, N), n_function_types(S)}, 1352 begin 1353 Tags = [yes_constrained_function_type, 1354 no_constrained_function_type], 1355 G = wunion(Tags, S, ?FUNCTION_NAME), 1356 NTypes = MinTypes + uniform(MaxTypes - MinTypes + 1) - 1, 1357 ?LET(Ts, 1358 list_of_gen2(NTypes, G), 1359 [case T of 1360 no_function_constraint -> 1361 Ft; 1362 Fc -> 1363 {'type', anno(), 'bounded_fun', [Ft, Fc]} 1364 end || T <- Ts]) 1365 end). 1366 1367function_type(S, N) -> 1368 {'type', anno(), 'fun', 1369 [{'type', anno(), 1370 'product', 1371 list_of_gen2(N, abstract_type(S))}, 1372 abstract_type(S)]}. 1373 1374no_constrained_function_type(_S) -> 1375 no_function_constraint. 1376 1377yes_constrained_function_type(S) -> 1378 function_constraint(S). 1379 1380function_constraint(S) -> 1381 non_empty_list_of_gen(constraint(S), get_limit(function_constraints, S)). 1382 1383constraint(S) -> 1384 ?LET({IsSubtype, V, T}, 1385 {lit_atom('is_subtype'), type_variable(S), abstract_type(S)}, 1386 {'type', anno(), 'constraint', [IsSubtype, [V, T]]}). 1387 1388n_function_types(S) -> 1389 wunion([no_overloaded, yes_overloaded], S, ?FUNCTION_NAME). 1390 1391%%% Maybe function_types-limit is enough? 1392no_overloaded(_S) -> 1393 {1, 1}. 1394 1395yes_overloaded(S) -> 1396 {2, max(get_limit(function_types, S), 2)}. 1397 1398type_variable(_S) -> 1399 a_variable(type_variable). 1400 1401singleton_integer_type(S) -> 1402 wunion([integer, char, unop, binop], S, abstract_type). 1403 1404small(S, pattern) -> 1405 Tags = [atom, boolean, integer, string, char, float, nil, pat_var], 1406 wunion(Tags, S, ?FUNCTION_NAME); 1407small(S, _Where) -> 1408 Tags = [atom, boolean, integer, string, char, float, nil, var], 1409 wunion(Tags, S, ?FUNCTION_NAME). 1410 1411a_boolean(_S) -> 1412 proper_types:union([lit_atom('true'), lit_atom('false')]). 1413 1414an_integer(_S) -> 1415 lit_integer(proper_types:non_neg_integer()). 1416 1417a_string(S) -> 1418 {'string', anno(), simple_string(S)}. 1419 1420simple_string(S) -> 1421 N = uniform(get_limit(string, S) + 1) - 1, 1422 simple_string1(S, N). 1423 1424simple_string1(_S, 0) -> 1425 []; 1426simple_string1(S, N) -> 1427 [simple_char(S) | simple_string1(S, N - 1)]. 1428 1429a_char(S) -> 1430 {'char', anno(), simple_char(S)}. 1431 1432simple_char(S) -> 1433 (S#gen_state.simple_char)(). 1434 1435default_simple_char() -> 1436 proper_types:union([proper_types:integer($a, $z), 1437 proper_types:integer($A, $Z)]). 1438 1439default_atom() -> 1440 any_of(some_atoms()). 1441 1442a_float(_S) -> 1443 ?LET(Float, 1444 proper_types:float(), 1445 {'float', anno(), abs(Float)}). 1446 1447var(_S) -> 1448 a_variable(bound_var_or_an_atom). 1449 1450pat_var(S) -> 1451 wunion([fresh_var, bound_var], S, ?FUNCTION_NAME). 1452 1453fresh_var(S) -> 1454 case get_weight(fresh_var, S) of 1455 0 -> 1456 anonymous_var(S); 1457 _ -> 1458 proper_types:weighted_union( 1459 [{20, ?LAZY(a_variable(fresh_var))}, 1460 {1, ?LAZY(anonymous_var(S))}]) 1461 end. 1462 1463bound_var(_S) -> 1464 a_variable(bound_var_or_an_integer). 1465 1466anonymous_var(_S) -> 1467 a_variable('_'). 1468 1469a_variable(Name) -> 1470 {'var', anno(), Name}. 1471 1472match(S, pattern) -> 1473 {'match', anno(), pattern(S), pattern(S)}; 1474match(S, compound) -> 1475 {'match', anno(), pattern(S), abstract_expr(S)}. 1476 1477tuple(S, abstract_type) -> 1478 tuple_type(S); 1479tuple(S, Where) -> 1480 T = where(S, Where), 1481 {'tuple', anno(), list_of_gen(T, get_limit(tuple, S))}. 1482 1483non_empty_list_of_gen(G, Max) -> 1484 N = uniform(Max), 1485 list_of_gen2(N, G). 1486 1487list_of_gen(G, Max) -> 1488 N = uniform(Max + 1) - 1, 1489 list_of_gen2(N, G). 1490 1491list_of_gen2(0, _G) -> 1492 []; 1493list_of_gen2(N, G) -> 1494 [G | list_of_gen2(N - 1, G)]. 1495 1496bitstring(S, abstract_type) -> 1497 {'type', anno(), 'binary', [singleton_integer_type(S), 1498 singleton_integer_type(S)]}; 1499bitstring(S, Where) -> 1500 case S#gen_state.result_type of 1501 term -> 1502 wunion([bits, bytes], S, Where); 1503 ResType when ResType =:= program; 1504 ResType =:= guard; 1505 ResType =:= expr -> 1506 wunion([bits, blc], S, Where) 1507 end. 1508 1509bytes(S) -> 1510 {'bin', anno(), binelement_seq_term(S, bytes)}. 1511 1512bits(#gen_state{result_type = term} = S, compound) -> 1513 {'bin', anno(), binelement_seq_term(S, bits)}; 1514bits(S, compound=Where) -> 1515 LiteralW = get_weight(literal_bits, S), 1516 WildBitsW = wild_bits_weight(S), 1517 proper_types:weighted_union( 1518 [{WildBitsW, 1519 ?LAZY({'bin', anno(), binelement_seq(S, abstract_expr(S), Where)})}, 1520 {LiteralW, ?LAZY(literal_bits(S, Where))} 1521 ]); 1522bits(S, guard_test=Where) -> 1523 {'bin', anno(), binelement_seq(S, guard_test(S), Where)}; 1524bits(S, pattern=Where) -> 1525 LiteralW = get_weight(literal_bits, S), 1526 WildBitsW = wild_bits_weight(S), 1527 proper_types:weighted_union( 1528 [{WildBitsW, 1529 ?LAZY({'bin', anno(), binelement_seq(S, bin_pattern(S), Where)})}, 1530 {LiteralW, ?LAZY(literal_bits(S, Where))} 1531 ]). 1532 1533wild_bits_weight(S) -> 1534 case get_weight(in_literal_bc, S) of 1535 1 -> 0; 1536 _ -> 1 1537 end. 1538 1539binelement_seq_term(S, B) -> 1540 N = uniform(get_limit(bin_elements, S)), 1541 binelements_term(N, B). 1542 1543binelements_term(0, _) -> 1544 []; 1545binelements_term(N, B) -> 1546 Expr = lit_integer(uniform(1 bsl 32) - 1), 1547 Size = case B of 1548 bits -> 1549 lit_integer(8 * uniform(4) - uniform(7)); 1550 bytes -> 1551 lit_integer(8 * uniform(4)) 1552 end, 1553 TSL = default, 1554 [{'bin_element', anno(), Expr, Size, TSL} | binelements_term(N - 1, B)]. 1555 1556bin_pattern(S) -> 1557 Tags = [pat_var, string, integer, char, float, atom, unop, binop], 1558 wunion(Tags, S, pattern). 1559 1560binelement_seq(S, T, Where) -> 1561 N = uniform(get_limit(bin_elements, S)), 1562 binelements(N, S, T, Where). 1563 1564binelements(0, _S, _T, _W) -> 1565 []; 1566binelements(N, S, T, Where) -> 1567 [binelement(S, T, Where, N =:= 1) | binelements(N - 1, S, T, Where)]. 1568 1569binelement(S, T, Where, IsLast) -> 1570 ?LET(Expr, 1571 T, 1572 case {Where, Expr} of 1573 {pattern, {string, _, _}} -> 1574 {'bin_element', 1575 anno(), 1576 Expr, 1577 'default', 1578 proper_types:union(['default', 1579 [proper_types:union(['utf8', 1580 'utf16', 1581 'utf32'])]])}; 1582 _ -> 1583 %% If HasUnit then Size =/= default. 1584 %% If HasUtf then Size =:= default and not HasUnit 1585 ?LET(TSL0, 1586 type_specifier_list(S, IsLast), 1587 begin 1588 HasUtf = TSL0 =/= 'default' 1589 andalso TSL0 -- [utf8, utf16, utf32] =/= TSL0, 1590 {TSL, Size} = 1591 case HasUtf of 1592 true -> 1593 {[TS || TS <- TSL0, 1594 (not is_tuple(TS) orelse 1595 element(1, TS) =/= 'unit')], 1596 'default'}; 1597 false -> 1598 HasUnit = 1599 TSL0 =/= 'default' 1600 andalso 1601 lists:keymember('unit', 1, TSL0), 1602 case HasUnit of 1603 true when Where =:= pattern -> 1604 {TSL0, 1605 %% not 'default': 1606 binelement_size_pattern(S)}; 1607 true -> 1608 {TSL0, 1609 T}; % not 'default' 1610 false when Where =:= pattern -> 1611 {TSL0, 1612 binelement_size 1613 (binelement_size_pattern(S))}; 1614 false -> 1615 {TSL0, 1616 binelement_size(T)} % any size 1617 end 1618 end, 1619 {'bin_element', anno(), Expr, Size, TSL} 1620 end) 1621 end). 1622 1623binelement_size_pattern(S0) -> 1624 S = exclude_tags([fresh_var], S0), 1625 guard_test(S). %% EEP 52 1626 1627binelement_size(T) -> 1628 proper_types:weighted_union( 1629 [{1, ?LAZY('default')}, 1630 {2, ?LAZY(T)}]). 1631 1632%%% Generate simple and--most of the time--correct binary and 1633%%% bitstring expressions. The purpose is to cover more of the 1634%%% Compiler as the random code seldom passes the many tests of binary 1635%%% lists comprehensions. 1636literal_bits(S, Where) -> 1637 N = uniform(get_limit(bin_elements, S)), 1638 {'bin', anno(), literal_binelements(N, S, Where)}. 1639 1640literal_binelements(0, _S, _Where) -> 1641 []; 1642literal_binelements(N, S, Where) -> 1643 [literal_binelement(S, N =:= 1, Where) | 1644 literal_binelements(N - 1, S, Where)]. 1645 1646literal_binelement(S, IsLast, Where) -> 1647 ?LET(Type, 1648 a_type(IsLast andalso Where =/= pattern), 1649 if 1650 Type =:= integer -> 1651 %% Strings? 1652 ?LET({Size, Unit}, 1653 {proper_types:integer(0, 8), 1654 proper_types:integer(1, 32)}, % not too big... 1655 {'bin_element', 1656 anno(), 1657 case Where of 1658 compound -> 1659 singleton_integer_type(S); % A bit sloppy. 1660 pattern -> 1661 singleton_integer_type(S) % More? 1662 end, 1663 lit_integer(Size), 1664 [Type, {'unit', Unit}, signedness(), endianness()]}); 1665 Type =:= utf8; Type =:= utf16; Type =:= utf32 -> 1666 ?LET(CharOrString, 1667 literal_unicode(S), 1668 {'bin_element', 1669 anno(), 1670 CharOrString, 1671 default, 1672 [Type, signedness(), endianness()]}); 1673 Type =:= float -> 1674 ?LET({Size, Unit}, 1675 proper_types:oneof([{16, 1}, {32, 1}, {64, 1}]), 1676 {'bin_element', 1677 anno(), 1678 a_float(S), 1679 lit_integer(Size), 1680 [Type, {'unit', Unit}, signedness(), endianness()]}); 1681 true -> 1682 ?LET({Bin, Unit0}, 1683 {literal_bits(S, Where), unit()}, 1684 begin 1685 BitSize = 1686 %% This could be slow if deeply nested. 1687 try 1688 {value, B, _} = erl_eval:expr(Bin, []), 1689 bit_size(B) 1690 catch 1691 _:_ -> 1692 1000 1693 end, 1694 {Unit, MaxSize} = 1695 if 1696 Type =:= bytes -> 1697 {8, BitSize div 8}; 1698 Type =:= binary -> 1699 Unit1 = max(min(Unit0, BitSize), 1), 1700 {Unit1, BitSize div Unit1}; 1701 Type =:= bitstring; Type =:= bits -> 1702 {1, BitSize} 1703 end, 1704 Size = proper_types:integer(0, MaxSize), 1705 {'bin_element', 1706 anno(), 1707 Bin, 1708 lit_integer(Size), 1709 [Type, {'unit', Unit}, signedness(), endianness()]} 1710 end) 1711 end). 1712 1713%%% Does not use #gen_state.simple_char. Perhaps it should. 1714literal_unicode(S) -> 1715 StringW = get_weight(string, S), 1716 S1 = S#gen_state{simple_char = fun unicode/0}, 1717 wunion1([{3, ?LAZY(lit_integer(unicode()))}, 1718 {StringW, ?LAZY(a_string(S1))}]). 1719 1720unicode() -> 1721 proper_types:oneof([proper_types:integer(0, 16#D7FF), 1722 proper_types:integer(16#E000, 16#10FFFF)]). 1723 1724binop(S, abstract_type) -> 1725 T = singleton_integer_type(S), 1726 {'op', anno(), type_binop(), T, T}; 1727binop(S, compound=Where) -> 1728 wunion([any_op, guard_op], S, Where); 1729binop(S, guard_test) -> 1730 guard_binop(S, guard_test(S)); 1731binop(S, pattern) -> 1732 pattern_binop(pattern_expr_operand(S)). 1733 1734any_binop(_S, T) -> 1735 {'op', anno(), any_binop(), T, T}. 1736 1737guard_binop(_S, T) -> 1738 {'op', anno(), guard_binop(), T, T}. 1739 1740pattern_binop(T) -> 1741 {'op', anno(), pattern_binop(), T, T}. 1742 1743%%% The operators according to erl_internal. orelse/andalso added. 1744any_binop() -> 1745 proper_types:oneof( 1746 ['+', '-', '*', '/', 'div', 'rem', 'band', 'bor', 'bxor', 'bsl', 'bsr', 1747 'and', 'or', 'xor', 1748 '=:=', '=/=', '==', '/=', '=<', '<', '>=', '>', 1749 'orelse', 'andalso', % not proper operators, but handled as such 1750 '++', '--', '!']). % not in guards 1751 1752guard_binop() -> 1753 proper_types:oneof( 1754 ['+', '-', '*', '/', 'div', 'rem', 'band', 'bor', 'bxor', 'bsl', 'bsr', 1755 'and', 'or', 'xor', 1756 '=:=', '=/=', '==', '/=', '=<', '<', '>=', '>', 1757 'orelse', 'andalso']). % not proper operators, but handled as such 1758 1759pattern_binop() -> 1760 proper_types:oneof( 1761 ['+', '-', '*', '/', 'div', 'rem', 'band', 'bor', 'bxor', 'bsl', 1762 'bsr']). 1763 1764type_binop() -> 1765 proper_types:oneof( 1766 ['+', '-', '*', 'div', 'rem', 'band', 'bor', 'bxor', 'bsl', 'bsr']). 1767 1768unop(S, abstract_type) -> 1769 {'op', anno(), type_unop(), singleton_integer_type(S)}; 1770unop(S, compound) -> 1771 %% any_op and guard_op: they are the same for unary operators 1772 {'op', anno(), any_unop(), abstract_expr(S)}; 1773unop(S, guard_test) -> 1774 {'op', anno(), any_unop(), guard_test(S)}; 1775unop(S, pattern) -> 1776 {'op', anno(), pattern_unop(), pattern_expr_operand(S)}. 1777 1778pattern_expr_operand(S0) -> 1779 S = exclude_tags([record_index, string_prefix], S0), 1780 %% Simplified. Evaluates to an integer. 1781 wunion([char, float, integer, unop, binop], S, pattern). 1782 1783any_unop() -> 1784 proper_types:oneof(['+', '-', 'bnot', 'not']). 1785 1786pattern_unop() -> 1787 proper_types:oneof(['+', '-']). 1788 1789type_unop() -> 1790 proper_types:oneof(['+', '-', 'bnot']). 1791 1792type_specifier_list(S, IsLast) -> 1793 proper_types:weighted_union( 1794 [{1, 'default'}, 1795 {1, ?LAZY(type_specifiers(S, IsLast))}]). 1796 1797type_specifiers(S, IsLast) -> 1798 N = uniform(get_limit(tsl, S)), 1799 type_specifier(N, IsLast, []). 1800 1801type_specifier(0, _IsLast, _L) -> 1802 []; 1803type_specifier(N, IsLast, L) -> 1804 ?LET({Tag, TS}, 1805 ?SUCHTHAT({Tag, _}, 1806 a_type_specifier(IsLast, L), 1807 not is_chosen(Tag, L)), 1808 [TS | type_specifier(N - 1, IsLast, [Tag, TS | L])]). 1809 1810a_type_specifier(IsLast0, L) -> 1811 %% A bit sloppy. Cannot generate [{unit, 8}, binary], for example. 1812 %% Maybe do nothing here and everyting in post_process()? 1813 IsLast = IsLast0 andalso not is_chosen(unit, L), 1814 UnitWeight = case is_member([bitstring, bits, bytes, binary], L) of 1815 true -> 0; 1816 false -> 1 1817 end, 1818 wunion1( 1819 [{1, ?LAZY({'type', a_type(IsLast)})}, 1820 {1, ?LAZY({'signedness', signedness()})}, 1821 {1, ?LAZY({'endianness', endianness()})}, 1822 {UnitWeight, ?LAZY({unit, {'unit', unit()}})}]). 1823 1824is_member([], _) -> 1825 false; 1826is_member([E|Es], L) -> 1827 lists:member(E, L) orelse is_member(Es, L). 1828 1829is_chosen(Tag, L) -> 1830 lists:member(Tag, L). 1831 1832a_type(IsLast) -> 1833 wunion1(bit_segment_types(IsLast)). 1834 1835bit_segment_types(false) -> 1836 [{3, 'integer'}, 1837 {2, 'float'}, 1838 {1, 'utf8'}, 1839 {1, 'utf16'}, 1840 {1, 'utf32'}]; 1841bit_segment_types(true) -> 1842 [{3, 'integer'}, 1843 {2, 'float'}, 1844 {3, 'binary'}, 1845 {3, 'bytes'}, 1846 {3, 'bitstring'}, 1847 {3, 'bits'}, 1848 {1, 'utf8'}, 1849 {1, 'utf16'}, 1850 {1, 'utf32'}]. 1851 1852signedness() -> 1853 proper_types:oneof(['signed', 'unsigned']). 1854 1855endianness() -> 1856 proper_types:oneof(['big', 'little', 'native']). 1857 1858unit() -> 1859 wunion1( 1860 [{10, ?LAZY(proper_types:oneof([1, 8, 16, 32]))}, 1861 {1, proper_types:integer(1, 256)}]). 1862 1863known_record_with_fields(S) -> 1864 ?SUCHTHAT(R, known_record(S), element(2, R) =/= []). 1865 1866known_record(S) -> 1867 one_of(S#gen_state.records, no_records). 1868 1869known_guard_record(S) -> 1870 [R|_] = S#gen_state.guard_records, 1871 R. 1872 1873local_type(S) -> 1874 one_of(S#gen_state.types, no_types). 1875 1876one_of([], Err) -> 1877 erlang:error(Err); 1878one_of(L, _Err) -> 1879 proper_types:oneof(L). 1880 1881an_atom(_S) -> 1882 lit_atom(any_atom()). 1883 1884any_atom() -> 1885 any_atom. 1886 1887any_module(_S) -> 1888 lit_atom(any_module). 1889 1890any_function() -> 1891 lit_atom(any_function). 1892 1893lit_atom(A) -> 1894 {'atom', anno(), A}. 1895 1896lit_integer(I) -> 1897 {'integer', anno(), I}. 1898 1899anno() -> 1900 erl_anno:new(0). 1901 1902resize(#gen_state{resize = false} = S) -> 1903 S; 1904resize(#gen_state{resize = true} = S) -> 1905 ?RESIZE(S). 1906 1907%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1908 1909eval_dependencies(State0) -> 1910 State = case State0#gen_state.functions of 1911 [] -> 1912 exclude_tags([function_decl], State0); 1913 _ -> 1914 State0 1915 end, 1916 Deps = deps(State#gen_state.result_type), 1917 Fun = fun(Dep, S) -> 1918 {Tags, AffectedTags} = Dep, 1919 eval_dep(S, Tags, AffectedTags) 1920 end, 1921 lists:foldl(Fun, State, Deps). 1922 1923%%% The list is not exhaustive. Maybe the user should fix this kind of 1924%%% issues. 1925deps(term) -> 1926 [{[nil, string, char, integer], [string_prefix]}, 1927 {[bits, bytes], [bitstring]}, 1928 {[bitstring], [bits, bytes]}, 1929 {[build_map], [map]}, 1930 {[plain_list, cons], [list]}]; 1931deps(ResType) when ResType =:= program; ResType =:= guard; ResType =:= expr -> 1932 [{[type_decl], [user_defined_type]}, 1933 {[record_decl], [record]}, 1934 {[nil, string, char, integer], [string_prefix]}, 1935 {[bits, blc], [bitstring]}, 1936 {[function_decl], [local_mfa]}, 1937 {[bitstring], [bits, blc]}, 1938 {[build_map, update_map], [map]}, 1939 {[fresh_var, bound_var], [pat_var]}, 1940 {[plain_list, cons, lc], [list]}]. 1941 1942eval_dep(S, Tags, AffectedTags) -> 1943 case sum_weights(Tags, S) of 1944 0 -> 1945 exclude_tags(AffectedTags, S); 1946 _ -> 1947 S 1948 end. 1949 1950sum_weights(Tags, State) -> 1951 Ws = get_weights(Tags, State), 1952 lists:sum([W || {_, W} <- Ws]). 1953 1954get_weights(Tags, State) -> 1955 [{Tag, get_weight(Tag, State)} || Tag <- Tags]. 1956 1957get_weight(Tag, State) -> 1958 maps:get(Tag, State#gen_state.weights). 1959 1960exclude_tags(Tags, State) -> 1961 TagWeights = [{Tag, 0} || Tag <- Tags], 1962 set_tag_weights(TagWeights, State). 1963 1964set_tag_weights(TagWeights, State) -> 1965 Weights = State#gen_state.weights, 1966 Fun = fun({Tag, Weight}, Ws) -> 1967 maps:put(Tag, Weight, Ws) 1968 end, 1969 NewWeights = lists:foldl(Fun, Weights, TagWeights), 1970 State#gen_state{weights = NewWeights}. 1971 1972%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1973 1974wunion(Tags, State, Where) -> 1975 FreqTypes = weights(Tags, State, Where), 1976 wunion2(FreqTypes, Tags). 1977 1978wunion1(FreqTypes) -> 1979 wunion2(FreqTypes, []). 1980 1981wunion2(FreqTypes0, Tags) -> 1982 FreqTypes = non_zero(FreqTypes0), 1983 case FreqTypes of 1984 [] -> 1985 erlang:error({zero_weights, Tags}); 1986 _ -> 1987 ok 1988 end, 1989 proper_types:weighted_union(FreqTypes). 1990 1991non_zero(FreqTypes) -> 1992 [FT || {F, _} = FT <- FreqTypes, F =/= 0]. 1993 1994weights(Tags, State, Where) -> 1995 Weights = State#gen_state.weights, 1996 [{maps:get(Tag, Weights), 1997 ?LAZY((pfun(Tag, Where))(State))} 1998 || Tag <- Tags]. 1999 2000pfun(annotated_type, _) -> fun annotated_type/1; 2001pfun(atom, _) -> fun an_atom/1; 2002pfun(integer_range_type, _) -> fun integer_range_type/1; 2003pfun(no_constrained_function_type, _) -> fun no_constrained_function_type/1; 2004pfun(no_overloaded, _) -> fun no_overloaded/1; 2005pfun(predefined_type, _) -> fun predefined_type/1; 2006pfun(remote_type, _) -> fun remote_type/1; 2007pfun(singleton_integer_type, _) -> fun singleton_integer_type/1; 2008pfun(type_union, _) -> fun type_union/1; 2009pfun(type_variable, _) -> fun type_variable/1; 2010pfun(user_defined_type, _) -> fun user_defined_type/1; 2011pfun(yes_constrained_function_type, _) -> fun yes_constrained_function_type/1; 2012pfun(yes_overloaded, _) -> fun yes_overloaded/1; 2013%%pfun(anonymous_var, _) -> fun anonymous_var/1; 2014pfun(any_eclass, _) -> fun any_eclass/1; 2015pfun(any_mfa, _) -> fun any_mfa/1; 2016pfun(any_op, Where) -> pfun1(fun any_binop/2, Where); 2017pfun(boolean, _) -> fun a_boolean/1; 2018pfun(bad_eclass, _) -> fun bad_eclass/1; 2019pfun(bitstring, Where) -> fun(S) -> bitstring(S, Where) end; 2020pfun(bits, Where) -> fun(S) -> bits(S, Where) end; 2021pfun(blc, _) -> fun blc/1; 2022pfun(blc_gen, _) -> fun blc_gen/1; 2023pfun(binop, Where) -> fun(S) -> binop(S, Where) end; 2024pfun(block, _) -> fun block/1; 2025pfun(bound_var, _) -> fun bound_var/1; 2026pfun(bytes, _) -> fun bytes/1; 2027pfun('case', _) -> fun 'case'/1; 2028pfun('catch', _) -> fun 'catch'/1; 2029pfun(char, _) -> fun a_char/1; 2030pfun(cons, Where) -> pfun1(fun cons/2, Where); 2031pfun(ext_mfa, _) -> fun ext_mfa/1; 2032pfun(field_no_init, _) -> fun field_no_init/1; 2033pfun(field_no_type, _) -> fun field_no_type/1; 2034pfun(field_yes_init, _) -> fun field_yes_init/1; 2035pfun(field_yes_type, _) -> fun field_yes_type/1; 2036pfun(float, _) -> fun a_float/1; 2037pfun(fresh_var, _) -> fun fresh_var/1; 2038pfun('fun', Where) -> fun(S) -> 'fun'(S, Where) end; 2039pfun(guard_call, _) -> fun guard_call/1; 2040pfun(guard_op, Where) -> pfun1(fun guard_binop/2, Where); 2041pfun('if', _) -> fun 'if'/1; 2042pfun(inf_timeout, _) -> fun inf_timeout/1; 2043pfun(integer, _) -> fun an_integer/1; 2044pfun(lambda, _) -> fun lambda/1; 2045pfun(lc, _) -> fun lc/1; 2046pfun(lc_any_filter, _) -> fun lc_any_filter/1; 2047pfun(lc_guard_filter, _) -> fun lc_guard_filter/1; 2048pfun(lc_gen, _) -> fun lc_gen/1; 2049pfun(list, Where) -> fun(S) -> a_list(S, Where) end; 2050pfun(lit_eclass, _) -> fun lit_eclass/1; 2051pfun(lit_timeout, _) -> fun lit_timeout/1; 2052pfun(localcall, _) -> fun localcall/1; 2053pfun(local_mfa, _) -> fun local_mfa/1; 2054pfun(map, Where) -> fun(S) -> a_map(S, Where) end; 2055pfun(build_map, Where) -> pfun1(fun build_map/2, Where); 2056pfun(map_pattern, _) -> fun map_pattern/1; 2057pfun(string_prefix, _) -> fun string_prefix/1; 2058pfun(string_prefix_list, _) -> fun string_prefix_list/1; % internal 2059pfun(match, Where) -> fun(S) -> match(S, Where) end; 2060pfun(nil, Where) -> fun(S) -> nil(S, Where) end; 2061pfun(no_eclass, _) -> fun no_eclass/1; 2062pfun(no_guard, _) -> fun no_guard/1; 2063pfun(no_multi_field_init,_) -> fun no_multi_field_init/1; 2064pfun(no_try_after, _) -> fun no_try_after/1; 2065pfun(pat_var, _) -> fun pat_var/1; 2066pfun(plain_list, Where) -> pfun1(fun plain_list/2, Where); 2067pfun('receive', _) -> fun 'receive'/1; 2068pfun(rec_lambda, _) -> fun rec_lambda/1; 2069pfun(record, Where) -> fun(S) -> a_record(S, Where) end; 2070pfun(build_record, Where) -> fun(S) -> build_record(S, Where) end; 2071pfun(record_pattern, _) -> fun record_pattern/1; 2072pfun(update_record, Where) -> pfun1(fun update_record/2, Where); 2073pfun(record_index, _) -> fun(S) -> record_index(S) end; 2074pfun(record_field_access, Where) -> pfun1(fun record_field_access/2, Where); 2075pfun(extcall, _) -> fun extcall/1; 2076pfun(remote_guard_call, _) -> fun remote_guard_call/1; 2077pfun(small, Where) -> fun(S) -> small(S, Where) end; 2078pfun(string, _) -> fun a_string/1; 2079pfun(termcall, Where) -> pfun1(fun termcall/2, Where); 2080pfun(tuple, Where) -> fun(S) -> tuple(S, Where) end; 2081pfun('try', _) -> fun 'try'/1; 2082pfun(try_of, _) -> fun try_of/1; 2083pfun(try_after, _) -> fun try_after/1; 2084pfun(unop, Where) -> fun(S) -> unop(S, Where) end; 2085pfun(update_map, Where) -> pfun1(fun update_map/2, Where); 2086pfun(var, _) -> fun var/1; 2087pfun(varcall, Where) -> pfun1(fun varcall/2, Where); 2088pfun(var_eclass, _) -> fun var_eclass/1; 2089pfun(var_timeout, _) -> fun var_timeout/1; 2090pfun(yes_guard, _) -> fun yes_guard/1; 2091pfun(yes_multi_field_init, _) -> fun yes_multi_field_init/1. 2092 2093pfun1(F, Where) -> fun(S) -> F(S, where(S, Where)) end. 2094 2095where(S, compound) -> abstract_expr(S); 2096where(S, guard_test) -> guard_test(S); 2097where(S, pattern) -> pattern(S). 2098 2099%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2100 2101options(Options) -> 2102 State = create_template(), 2103 #gen_state{weights = Weights, limits = Limits} = State, 2104 (check_options(Weights, Limits, Options) 2105 andalso eval_options(Options, State)). 2106 2107check_options(Weights, Limits, Options) -> 2108 lists:all(fun ({K, {V1, V2}}) -> check_option2(Weights, Limits, K, V1, V2) 2109 ; ({K, V}) -> check_option(K, V) 2110 end, Options). 2111 2112check_option(set_all_weights, Value) -> 2113 is_integer(Value) andalso Value >= 0; 2114check_option(variables, Term) -> 2115 try 2116 %% true = length(Term) > 0, 2117 lists:all(fun(V) -> is_variable(V) end, Term) 2118 catch 2119 _:_ -> 2120 false 2121 end; 2122check_option(functions, Term) -> 2123 try 2124 lists:all(fun(F) -> is_fa(F) end, Term) 2125 catch 2126 _:_ -> 2127 false 2128 end; 2129check_option(types, Term) -> 2130 try 2131 lists:all(fun(T) -> is_fa(T) end, Term) 2132 catch 2133 _:_ -> 2134 false 2135 end; 2136check_option(records, Term) -> 2137 try 2138 lists:all(fun(R) -> is_record(R) end, Term) 2139 catch 2140 _:_ -> 2141 false 2142 end; 2143check_option(char, Term) when is_function(Term, 0) -> 2144 true; 2145check_option(atom, Term) when is_function(Term, 0) -> 2146 true; 2147check_option(resize, Term) when is_boolean(Term) -> 2148 true; 2149check_option(_, _) -> 2150 false. 2151 2152check_option2(Weights, _Limits, weight, Term1, W) -> 2153 is_integer(W) andalso W >= 0 andalso 2154 is_map(Weights) andalso maps:is_key(Term1, Weights); 2155check_option2(_Weights, Limits, limit, Term1, L) -> 2156 %% A limit equal to zero would mean the same as setting the weight 2157 %% to zero. 2158 is_integer(L) andalso L > 0 andalso 2159 is_map(Limits) andalso maps:is_key(Term1, Limits) andalso 2160 (Term1 =/= tsl orelse L =< 3); 2161check_option2(_, _, _, _, _) -> 2162 false. 2163 2164is_variable(T) -> 2165 case atom_to_list(T) of 2166 [C|_Cs] when C >= $A, C =< $Z -> 2167 true; 2168 [C|_Cs] when C =:= $_ -> 2169 true 2170 end. 2171 2172is_fa({F, A}) when is_atom(F), is_integer(A), A >= 0, A < 256 -> true. 2173 2174is_record({R, Fs}) when is_atom(R) -> 2175 true = lists:all(fun erlang:is_atom/1, Fs). 2176 2177eval_options([], State) -> 2178 State; 2179eval_options([{weight, {K, V}}|Options], State0) -> 2180 State = set_weight(State0, K, V), 2181 eval_options(Options, State); 2182eval_options([{set_all_weights, V}|Options], State0) -> 2183 Weights = maps:map(fun (termcall, V0) -> V0 2184 ; (map_pattern_assoc, V0) -> V0 2185 ; (map_pattern_exact, V0) -> V0 2186 ; (complex_field_init, V0) -> V0 2187 ; (string_prefix_list, V0) -> V0 2188 ; (in_literal_bc, V0) -> V0 2189 ; (_, _) -> V 2190 end, State0#gen_state.weights), 2191 State = State0#gen_state{weights = Weights}, 2192 eval_options(Options, State); 2193eval_options([{limit, {K, W}}|Options], State0) -> 2194 State = set_limit(State0, K, W), 2195 eval_options(Options, State); 2196eval_options([{variables, Vars}|Options], State0) -> 2197 State = State0#gen_state{variables = ordsets:from_list(Vars)}, 2198 eval_options(Options, State); 2199eval_options([{functions, Funcs}|Options], State) -> 2200 State1 = State#gen_state{functions = Funcs}, 2201 eval_options(Options, State1); 2202eval_options([{types, Types}|Options], State) -> 2203 State1 = State#gen_state{types = Types}, 2204 eval_options(Options, State1); 2205eval_options([{records, Records}|Options], State) -> 2206 State1 = State#gen_state{records = Records}, 2207 eval_options(Options, State1); 2208eval_options([{char, CharGen}|Options], State) -> 2209 State1 = State#gen_state{simple_char = CharGen}, 2210 eval_options(Options, State1); 2211eval_options([{atom, AtomGen}|Options], State) -> 2212 State1 = State#gen_state{atom = AtomGen}, 2213 eval_options(Options, State1); 2214eval_options([{resize, Boolean}|Options], State) -> 2215 State1 = State#gen_state{resize = Boolean}, 2216 eval_options(Options, State1). 2217 2218set_weight(State, K, V) -> 2219 Weights = State#gen_state.weights, 2220 State#gen_state{weights = maps:update(K, V, Weights)}. 2221 2222set_limit(State, Name, Value) -> 2223 Limits = State#gen_state.limits, 2224 State#gen_state{limits = maps:update(Name, Value, Limits)}. 2225 2226get_limit(Tag, State) -> 2227 maps:get(Tag, State#gen_state.limits). 2228 2229create_template() -> 2230 NamedFunctions = some_named_functions(), 2231 PredefTypes = predef_types(), 2232 #gen_state{module = module_name, 2233 functions = some_functions(), 2234 records = some_records(), 2235 types = some_types(), 2236 named_funs = NamedFunctions, 2237 predef_types = PredefTypes, 2238 weights = default_weights(), 2239 limits = default_limits()}. 2240 2241default_weights() -> 2242 #{ 2243 'case' => 1, 2244 'catch' => 1, 2245 'fun' => 1, 2246 'if' => 1, 2247 'receive' => 1, 2248 'try' => 1, 2249 annotated_type => 1, 2250 %% anonymous_var => 1, 2251 any_eclass => 1, 2252 any_mfa => 1, 2253 any_op => 1, 2254 atom => 1, 2255 bad_eclass => 1, 2256 bitstring => 1, 2257 bits => 1, 2258 bytes => 1, % term only 2259 blc => 1, 2260 blc_gen => 1, 2261 binop => 1, 2262 block => 1, 2263 boolean => 1, 2264 bound_var => 1, 2265 char => 1, 2266 compound => 1, 2267 cons => 1, 2268 default => 1, 2269 ext_mfa => 1, 2270 field => 1, 2271 field_no_init => 1, 2272 field_no_type => 1, 2273 field_yes_init => 1, 2274 field_yes_type => 1, 2275 file => 1, 2276 float => 1, 2277 fresh_var => 1, 2278 function_decl => 1, 2279 function_spec => 0, 2280 generate => 1, 2281 guard_op => 1, 2282 guard_call => 1, 2283 inf_timeout => 1, 2284 integer => 3, 2285 integer_range_type => 1, 2286 lambda => 1, 2287 lc => 1, 2288 lc_any_filter => 10, 2289 lc_guard_filter => 5, 2290 lc_gen => 5, 2291 list => 1, 2292 lit_eclass => 1, 2293 lit_timeout => 1, 2294 localcall => 1, 2295 local_mfa => 1, 2296 map => 1, 2297 build_map => 1, 2298 map_pattern => 1, 2299 string_prefix => 1, 2300 match => 1, 2301 nil => 1, 2302 no_constrained_function_type => 1, 2303 no_eclass => 1, 2304 no_guard => 1, 2305 no_multi_field_init => 1, 2306 no_overloaded => 1, 2307 no_try_after => 1, 2308 pat_var => 1, 2309 plain_list => 1, 2310 predefined_type => 1, 2311 rec_lambda => 1, 2312 record => 1, 2313 build_record => 1, 2314 record_pattern => 1, 2315 record_decl => 1, 2316 record_field_access => 1, 2317 record_index => 1, 2318 update_record => 1, 2319 extcall => 1, 2320 remote_guard_call => 1, 2321 remote_type => 1, 2322 signedness => 1, 2323 singleton_integer_type => 1, 2324 size => 1, 2325 small => ?DEFAULT_SMALL_WEIGHT_PROGRAM, 2326 string => 1, 2327 termcall => 0, 2328 try_of => 1, 2329 try_after => 1, 2330 tuple => 1, 2331 type => 1, 2332 type_decl => 0, 2333 type_union => 1, 2334 type_variable => 1, 2335 unop => 1, 2336 update_map => 1, 2337 user_defined_type => 1, 2338 varcall => 1, 2339 var_eclass => 1, 2340 var_timeout => 1, 2341 var => 1, 2342 yes_constrained_function_type => 1, 2343 yes_guard => 1, 2344 yes_multi_field_init => 1, 2345 yes_overloaded => 1, 2346 2347 literal_bits => 1, 2348 %% See also eval_options(). 2349 %% Used internally, see literal_bc(). 2350 in_literal_bc => 0, 2351 2352 %% Used internally, see assoc_pattern_seq(). 2353 map_pattern_exact => 1, 2354 map_pattern_assoc => 0, 2355 2356 %% Also used internally: 2357 complex_field_init => 1, 2358 string_prefix_list => 1 2359 }. 2360 2361default_limits() -> 2362 #{ 2363 %% term and program 2364 bin_elements => ?MAX_BIN_ELEMENTS, 2365 list => ?MAX_LIST, 2366 map => ?MAX_MAP, 2367 string => ?MAX_STRING, 2368 tuple => ?MAX_TUPLE, 2369 %% program 2370 body => ?MAX_BODY, 2371 call_args => ?MAX_CALL_ARGS, 2372 catch_clauses => ?MAX_CATCH_CLAUSES, 2373 clauses => ?MAX_CLAUSES, 2374 function_clauses => ?MAX_FUNCTION_CLAUSES, 2375 function_constraints => ?MAX_FUNCTION_CONSTRAINTS, 2376 function_types => ?MAX_FUNCTION_TYPES, 2377 guard => ?MAX_GUARD, 2378 guard_tests => ?MAX_GUARD_TESTS, 2379 if_clauses => ?MAX_IF_CLAUSES, 2380 tuple_types => ?MAX_TUPLE_TYPES, 2381 qualifiers => ?MAX_QUALIFIERS, 2382 record_fields => ?MAX_RECORD_FIELDS, 2383 tsl => ?MAX_TYPE_SPECIFIER, 2384 union_types => ?MAX_UNION_TYPES 2385 }. 2386 2387%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2388 2389%%% Postprocess generated abstract format. 2390 2391post_process(Abstracts, Functions, AtomGen, Variables) -> 2392 Known = (Functions ++ auto_imported() ++ 2393 guard_bifs() ++ other_bifs()), 2394 State = #post_state{known_functions = Known, 2395 atom = AtomGen, 2396 vars = Variables}, 2397 ?DEBUG("\n\n<original>\n~p\n</original>\n", [Abstracts]), 2398 [post1(Abstr, State) || Abstr <- Abstracts]. 2399 2400post1(AbstrL, State) when is_list(AbstrL) -> 2401 {AbstrL1, _} = post_list(AbstrL, State), 2402 AbstrL1; 2403post1(Abstr, State) -> 2404 {Abstr1, _} = post(Abstr, State), 2405 Abstr1. 2406 2407%%% - unbound/unsafe linter errors are avoided, but the code is 2408%%% probably a bit too complex... 2409 2410post({var, A, fresh_var}, S) -> 2411 new_var(A, S); 2412post({var, A, bound_var_or_an_atom}, S) -> 2413 any_var(A, S, atom); 2414post({var, A, bound_var_or_an_integer}, S) -> 2415 any_var(A, S, integer); 2416post({var, A, bound_var_or_an_arity}, S) -> 2417 any_var(A, S, arity); 2418post({var, A, type_variable}, S) -> 2419 any_var(A, S, fresh_var); 2420post({var, A, type_parameter}, S) -> 2421 new_var(A, S); 2422post({atom, A, any_function}, S) -> 2423 {{atom, A, create_atom(S)}, S}; 2424post({atom, A, any_module}, S) -> 2425 {{atom, A, create_atom(S)}, S}; 2426post({atom, A, create_atom}, S) -> 2427 {{atom, A, create_atom(S)}, S}; 2428post({atom, A, bad_eclass}, S) -> 2429 {{atom, A, create_atom(S)}, S}; 2430post({cons, A, H, T}, S) -> 2431 {[H1,T1], S1} = post_expr_list([H, T], S), 2432 {{cons, A, H1, T1}, S1}; 2433post({call, A1, {remote, A2, M, F}, As}, S) -> 2434 {[M1, F1|As1], S1} = post_expr_list([M, F|As], S), 2435 {{call, A1, {remote, A2, M1, F1}, As1}, S1}; 2436post({call, A, F, As}, S) -> 2437 {[F1|As1], S1} = post_expr_list([F|As], S), 2438 case F1 of 2439 {atom, _, Name} = Atom -> 2440 KnownFunctions = S#post_state.known_functions, 2441 case lists:member({Name, length(As)}, KnownFunctions) of 2442 true -> 2443 {{call, A, F1, As1}, S1}; 2444 false -> 2445 {Atom, S} 2446 end; 2447 _ -> % named fun or other 2448 {{call, A, F1, As1}, S1} 2449 end; 2450post({match, A, P, E}, S) -> 2451 {[P2, E2], S3} = 2452 case S#post_state.context of 2453 pattern -> % alias 2454 post_expr_list([P, E], S); 2455 _ -> 2456 {E1, S1} = post(E, S), 2457 {[P1], S2} = post_patterns([P], S1), 2458 {[P1, E1], S2} 2459 end, 2460 {{match, A, P2, E2}, S3}; 2461post({lc, A, E, Qs}, S) -> 2462 {Qs1, S1} = post_qualifiers(Qs, S), 2463 {E1, _} = post(E, S1), 2464 {{lc, A, E1, Qs1}, S}; 2465post({bc, A, E, Qs}, S) -> 2466 {Qs1, S1} = post_qualifiers(Qs, S), 2467 {E1, _} = post(E, S1), 2468 {{bc, A, E1, Qs1}, S}; 2469post({op, A, Op, E}, S) -> 2470 {E1, S1} = post(E, S), 2471 E3 = case S#post_state.context of 2472 pattern -> 2473 {E2, _} = post_round(E1, A), 2474 E2; 2475 _ -> 2476 E1 2477 end, 2478 {{op, A, Op, E3}, S1}; 2479post({op, A, Op, L, R}, S) when Op =:= 'bsl'; Op =:= 'bsr' -> 2480 %% bsl and bsr can create huge integers, which is not what we want 2481 %% to test here. 2482 {[L1, R1], S1} = post_expr_list([L, R], S), 2483 {L3, R3} = 2484 case S1#post_state.context of 2485 expr -> 2486 {L1, R1}; 2487 pattern -> 2488 {L2, _} = post_round(L1, A), 2489 {R2, V} = post_round(R1, A), 2490 case V of % can be slow... 2491 {integer, _, I} when I > 30 -> 2492 {L2, {integer, A, 30}}; 2493 {integer, _, I} when I < -30 -> 2494 {L2, {integer, A, -30}}; 2495 _ -> 2496 {L2, R2} 2497 end; 2498 type -> 2499 case erl_eval:partial_eval(R1) of % can be slow... 2500 {integer, _, I} when I > 30 -> 2501 {L1, {integer, A, 30}}; 2502 {integer, _, I} when I < -30 -> 2503 {L1, {integer, A, -30}}; 2504 _ -> 2505 {L1, R1} 2506 end 2507 end, 2508 {{op, A, Op, L3, R3}, S1}; 2509post({op, A, Op, L, R}, S) when Op =:= 'rem'; Op =:= 'div'; % type and pattern 2510 Op =:= '/' -> % pattern 2511 {[L1, R1], S1} = post_expr_list([L, R], S), 2512 {L3, R3} = 2513 case S1#post_state.context of 2514 expr -> 2515 {L1, R1}; 2516 pattern -> 2517 {L2, _} = post_round(L1, A), 2518 {R2, V} = post_round(R1, A), 2519 case V of % can be slow... 2520 {integer, _, 0} -> % division by zero 2521 {L2, {op, A, '+', R2, {integer, A, 1}}}; 2522 _ -> 2523 {L2, R2} 2524 end; 2525 type -> 2526 case erl_eval:partial_eval(R1) of % can be slow... 2527 {integer, _, 0} -> % division by zero 2528 {L1, {op, A, '+', R1, {integer, A, 1}}}; 2529 _ -> 2530 {L1, R1} 2531 end 2532 end, 2533 {{op, A, Op, L3, R3}, S1}; 2534post({op, A, Op, L, R}, S) when Op =:= 'orelse'; Op =:= 'andalso' -> 2535 {L1, S1} = post(L, S), 2536 {R1, S2} = post(R, S1), 2537 IntroducedVariables = introduced_variables(S1, S2), 2538 S3 = forbidden_variables(S2, IntroducedVariables), 2539 {{op, A, Op, L1, R1}, S3}; 2540post({op, A, Op, L, R}, S) -> 2541 {[L1, R1], S1} = post_expr_list([L, R], S), 2542 {L3, R3} = 2543 case S1#post_state.context of 2544 pattern -> 2545 {L2, _} = post_round(L1, A), 2546 {R2, _} = post_round(R1, A), 2547 {L2, R2}; 2548 _ -> 2549 {L1, R1} 2550 end, 2551 {{op, A, Op, L3, R3}, S1}; 2552post({map, A, Es}, S) -> 2553 {Es1, S1} = post_expr_list(Es, S), 2554 {{map, A, Es1}, S1}; 2555post({map, A, B, Es}, S) -> 2556 {[B1|Es1], S1} = post_expr_list([B|Es], S), 2557 {{map, A, B1, Es1}, S1}; 2558post({map_field_assoc, A, K, V}, S) -> 2559 {[K2, V2], S1} = 2560 case S#post_state.context of 2561 pattern -> 2562 %% K is any guard expression, which the linter accepts. 2563 L = [post_expr(K, S), post(V, S)], 2564 expr_list2(L, S); 2565 _ -> 2566 post_expr_list([K, V], S) 2567 end, 2568 {{map_field_assoc, A, K2, V2}, S1}; 2569post({map_field_exact, A, K, V}, S) -> 2570 {[K1, V1], S1} = post_expr_list([K, V], S), 2571 {{map_field_exact, A, K1, V1}, S1}; 2572post({'if', A, Clauses}, S) -> 2573 {Clauses1, S1} = clauses(Clauses, S), 2574 {{'if', A, Clauses1}, S1}; 2575post({'case', A, E, Clauses}, S) -> 2576 {E1, S1} = post(E, S), 2577 {Clauses1, S2} = clauses(Clauses, S1), 2578 {{'case', A, E1, Clauses1}, S2}; 2579post({'try', A, B, Cls, TCls, After}, S) -> 2580 {B1, S1} = post_list(B, S), 2581 IntroVars = introduced_variables(S, S1), 2582 {Cls1, S2} = clauses_in_try(Cls, S1, clause), 2583 %% New variables in B are unsafe in TCls and After. 2584 S3 = forbidden_variables(S2, IntroVars), 2585 {TCls1, S4} = clauses_in_try(TCls, S3, catch_clause), 2586 {After1, S5} = post_list(After, S4), 2587 AllIntroVars = introduced_variables(S, S5), 2588 ForbiddenVars = ordsets:union(AllIntroVars, S#post_state.forbidden), 2589 S6 = forbidden_variables(S5, ForbiddenVars), 2590 {{'try', A, B1, Cls1, TCls1, After1}, S6}; 2591post({'receive', A, Clauses}, S) -> 2592 {Clauses1, S1} = clauses(Clauses, S), 2593 {{'receive', A, Clauses1}, S1}; 2594post({'receive', A, Clauses, E, B}, S) -> 2595 {Clauses1, S1} = clauses(Clauses, S), 2596 {E1, S2} = post(E, S), 2597 %% New variables in E are not visible in B: 2598 IntroVars0 = introduced_variables(S, S2), 2599 S3 = forbidden_variables(S2, IntroVars0), 2600 {B1, S4} = post_list(B, S3), 2601 %% New variables in receive are unsafe. 2602 IntroVars1 = introduced_variables(S, S1), 2603 IntroVars3 = introduced_variables(S, S4), 2604 IntroVars = ordsets:union(IntroVars1, IntroVars3), 2605 ForbiddenVars = ordsets:union(IntroVars, S4#post_state.forbidden), 2606 S5 = forbidden_variables(S1, ForbiddenVars), 2607 {{'receive', A, Clauses1, E1, B1}, S5}; 2608post({tuple, A, Es}, S) -> 2609 {Es1, S1} = post_expr_list(Es, S), 2610 {{tuple, A, Es1}, S1}; 2611post({'catch', A, E}, S) -> 2612 {E1, S1} = post(E, S), 2613 IntroducedVariables = introduced_variables(S, S1), 2614 S2 = forbidden_variables(S1, IntroducedVariables), 2615 {{'catch', A, E1}, S2}; 2616post({'fun', A, {clauses, Clauses}}, S) -> 2617 {Clauses1, _} = clauses(Clauses, S), 2618 {{'fun', A, {clauses, Clauses1}}, S}; 2619post({named_fun, A, F, Clauses}, S) -> 2620 {Clauses1, _} = clauses(Clauses, S), 2621 {{named_fun, A, F, Clauses1}, S}; 2622post({bin, A, Es}, S) -> 2623 {Es1, S1} = post_expr_list(Es, S), 2624 {{bin, A, Es1}, S1}; 2625post({bin_element, A, Expr, default, TSL}, S) -> 2626 {[Expr1], S1} = post_expr_list([Expr], S), 2627 {{bin_element, A, Expr1, default, TSL}, S1}; 2628post({bin_element, A, Expr, Size, TSL}, S) -> 2629 {[Expr2, Size2], S1} = 2630 case S#post_state.context of 2631 pattern -> 2632 %% Size is any guard expression, which the linter accepts. 2633 L = [post(Expr, S), post_expr(Size, S)], 2634 expr_list2(L, S); 2635 _ -> 2636 post_expr_list([Expr, Size], S) 2637 end, 2638 {{bin_element, A, Expr2, Size2, TSL}, S1}; 2639post({record, A, E, RecName, Fields}, S) -> 2640 {[E1|Fields1], S1} = post_expr_list([E|Fields], S), 2641 {{record, A, E1, RecName, Fields1}, S1}; 2642post({record, A, RecName, Fields}, S) -> 2643 {Fields1, S1} = post_expr_list(Fields, S), 2644 {{record, A, RecName, Fields1}, S1}; 2645post({type, A, binary, [_B, _U]=BU}, S) -> 2646 {[B1, U1], S1} = post_expr_list(BU, S), 2647 Check = fun(E) -> 2648 case erl_eval:partial_eval(E) of 2649 {integer, _, V} when V >= 0 -> 2650 E; 2651 {integer, _, V} when V < 0 -> 2652 {op, A, '-', E}; 2653 (_) -> % cannot happen 2654 E 2655 end 2656 end, 2657 {{type, A, binary, [Check(B1), Check(U1)]}, S1}; 2658post({type, A, range, [_L, _H]=LH}, S) -> 2659 {[L1, H1] = LH1, S1} = post_expr_list(LH, S), 2660 Low = erl_eval:partial_eval(L1), 2661 High = erl_eval:partial_eval(H1), 2662 case {Low, High} of 2663 {{integer, _, V}, {integer, _, V}} -> 2664 {{type, A, range, [L1, {op, A, '+', H1, {integer, A, 1}}]}, S1}; 2665 {{integer, _, V1}, {integer, _, V2}} when V1 >= V2 -> 2666 {{type, A, range, [H1, L1]}, S1}; 2667 {{integer, _, V1}, {integer, _, V2}} when V1 < V2 -> 2668 {{type, A, range, LH1}, S1}; 2669 _ -> % cannot happen 2670 {{type, A, range, LH1}, S1} 2671 end; 2672post({attribute, A, Type, {TypeName, AbstrType, Parms}}, S) 2673 when Type =:= 'opaque'; Type =:= 'type' -> 2674 in_context 2675 (type, S, 2676 fun(State) -> 2677 {Parms1, S1} = post_list(Parms, State), 2678 {AbstrType1, S2} = post(AbstrType, S1), 2679 {{attribute, A, Type, {TypeName, AbstrType1, Parms1}}, S2} 2680 end); 2681post({function, A, F, N, ClauseSeq}, S) -> 2682 in_context 2683 (expr, S, 2684 fun(State) -> 2685 {ClauseSeq1, State1} = function_clauses(ClauseSeq, State), 2686 {{function, A, F, N, ClauseSeq1}, State1} 2687 end); 2688post({attribute, A, Spec, {{_F, _N}=FN, FuncTypeList}}, S) -> 2689 in_context 2690 (type, S, 2691 fun(State) -> 2692 {FuncTypeList1, State1} = post_list(FuncTypeList, State), 2693 {{attribute, A, Spec, {FN, FuncTypeList1}}, State1} 2694 end); 2695post({attribute, A, record, {Name, Fields}}, S) -> 2696 in_context 2697 (record, S, 2698 fun(State) -> 2699 {Fields1, State1} = post_list(Fields, State), 2700 {{attribute, A, record, {Name, Fields1}}, State1} 2701 end); 2702post({record_field, A, Name, Expr}, #post_state{context = record} = S) -> 2703 in_context 2704 (expr, S, 2705 fun(State) -> 2706 {Expr1, State1} = post(Expr, State), 2707 {{record_field, A, Name, Expr1}, State1} 2708 end); 2709post({typed_record_field, Field, Type}, S) -> 2710 in_context 2711 (type, S, 2712 fun(State) -> 2713 {Field1, State1} = post(Field, State), 2714 {Type1, State2} = post(Type, State1), 2715 {{typed_record_field, Field1, Type1}, State2} 2716 end); 2717%%% No special handling of the following cases: 2718post({ann_type, A, T}, S) -> 2719 {T1, S1} = post_list(T, S), 2720 {{ann_type, A, T1}, S1}; 2721post({atom, _, _}=A, S) -> 2722 {A, S}; 2723post({attribute, _, _, _}=A, S) -> 2724 {A, S}; 2725post({block, A, Body}, S) -> 2726 {Body1, S1} = post_list(Body, S), 2727 {{block, A, Body1}, S1}; 2728post({char, _, _}=C, S) -> 2729 {C, S}; 2730post({float, _, _}=F, S) -> 2731 {F, S}; 2732post({'fun', _A, {function, M, N, Arity}}=F, S) when is_atom(M), 2733 is_atom(N), 2734 is_integer(Arity) -> 2735 %% cannot happen 2736 {F, S}; 2737post({'fun', A, {function, M, N, Arity}}, S) -> 2738 {[M1, N1, Arity1], S1} = post_list([M, N, Arity], S), 2739 {{'fun', A, {function, M1, N1, Arity1}}, S1}; 2740post({'fun', _A, {function, N, Arity}}=F, S) when is_atom(N), 2741 is_integer(Arity) -> 2742 {F, S}; 2743post({integer, _, _}=I, S) -> 2744 {I, S}; 2745post({nil, _}=N, S) -> 2746 {N, S}; 2747post({record_field, A, N}, S) -> 2748 {N1, S1} = post(N, S), 2749 {{record_field, A, N1}, S1}; 2750post({record_field, A, F, E}, S) -> 2751 {[F1, E1], S1} = post_list([F, E], S), 2752 {{record_field, A, F1, E1}, S1}; 2753post({record_field, A, E0, N, F}, S) -> 2754 {[E1, F1], S1} = post_list([E0, F], S), 2755 {{record_field, A, E1, N, F1}, S1}; 2756post({record_index, A, N, F}, S) -> 2757 {F1, S1} = post(F, S), 2758 {{record_index, A, N, F1}, S1}; 2759post({remote_type, A, [M, N, Ts]}, S) -> 2760 {[M1, N1], S1} = post_list([M, N], S), 2761 {Ts1, S2} = post_list(Ts, S1), 2762 {{remote_type, A, [M1, N1, Ts1]}, S2}; 2763post({string, _, _}=Str, S) -> 2764 {Str, S}; 2765post({type, _A, any}=Any, S) -> 2766 {Any, S}; 2767post({type, _A, _N, any}=Any, S) -> 2768 {Any, S}; 2769post({type, A, 'fun', Ts}, S) -> 2770 {Ts1, S1} = post_list(Ts, S), 2771 {{type, A, 'fun', Ts1}, S1}; 2772post({type, A, constraint, [C, [V, T]]}, S) -> 2773 {[C1, V1, T1], S1} = post_list([C, V, T], S), 2774 {{type, A, constraint, [C1, [V1, T1]]}, S1}; 2775post({type, A, bounded_fun, [Ft, Fcs]}, S) -> 2776 {Ft1, S1} = post(Ft, S), 2777 {Fcs1, S2} = post_list(Fcs, S1), 2778 {{type, A, bounded_fun, [Ft1, Fcs1]}, S2}; 2779post({type, A, N, Ts}, S) -> 2780 {Ts1, S1} = post_list(Ts, S), 2781 {{type, A, N, Ts1}, S1}; 2782post({user_type, A, N, Ts}, S) -> 2783 {Ts1, S1} = post_list(Ts, S), 2784 {{user_type, A, N, Ts1}, S1}; 2785post({var, _A, '_'}=VarU, S) -> 2786 {VarU, S}; 2787post({var, _A, _NamedFun}=VarNF, S) -> 2788 {VarNF, S}. 2789 2790in_context(Context, S, Fun) -> 2791 S1 = S#post_state{context = Context, 2792 vars = [], 2793 vindex = 0, 2794 forbidden = []}, 2795 {T, _} = Fun(S1), 2796 {T, S}. 2797 2798post_round(E, A) -> 2799 case erl_eval:partial_eval(E) of % can be slow if E is deep 2800 {float, _, F} -> 2801 %% Very crude. A pity guard BIFs cannot be evaluated by 2802 %% erl_eval:partial_eval/1 (for example erlang:guard/1). 2803 I = {integer, A, round(F)}, 2804 {I, I}; 2805 V -> 2806 {E, V} 2807 end. 2808 2809post_qualifiers([], S) -> 2810 {[], S}; 2811post_qualifiers([{Gen, A, P, E}|Qs], S) when Gen =:= generate; 2812 Gen =:= b_generate -> 2813 %% Variables introduced in E can only be used in E, and can be 2814 %% introduced in subsequent generators. 2815 {E1, _} = post(E, S), 2816 {[P1], S1} = post_patterns([P], S), 2817 {Qs1, S2} = post_qualifiers(Qs, S1), 2818 {[{Gen, A, P1, E1}|Qs1], S2}; 2819post_qualifiers([F|Qs], S) -> 2820 {F1, S1} = post(F, S), 2821 {Qs1, S2} = post_qualifiers(Qs, S1), 2822 {[F1|Qs1], S2}. 2823 2824function_clauses(Clauses, S) -> 2825 L = [post_clause(Cl, S) || Cl <- Clauses], 2826 {Clauses1, _} = lists:unzip(L), 2827 {Clauses1, S}. 2828 2829clauses([], S) -> 2830 {[], S}; % receive after T -> E end 2831clauses(Clauses, S) -> 2832 L = [post_clause(Cl, S) || Cl <- Clauses], 2833 {Clauses1, Ss} = lists:unzip(L), 2834 VarsInCls = [introduced_variables(S, S1) || S1 <- Ss], 2835 NewVars = ordsets:union(VarsInCls), 2836 ExportedVars = ordsets:intersection(VarsInCls), 2837 ForbiddenVars = ordsets:subtract(NewVars, ExportedVars), 2838 ForbiddenVarsInCls = [S1#post_state.forbidden || S1 <- Ss], 2839 AllForbiddenVars = ordsets:union([ForbiddenVars|ForbiddenVarsInCls]), 2840 S1 = forbidden_variables(S, AllForbiddenVars), 2841 S2 = S1#post_state{vars = ordsets:union(ExportedVars, S#post_state.vars)}, 2842 {Clauses1, S2}. 2843 2844clauses_in_try([], S, _Kind) -> 2845 {[], S}; 2846clauses_in_try(Clauses, S, Kind) -> 2847 L = [post_try_clause(Cl, S, Kind) || Cl <- Clauses], 2848 {Clauses1, Ss} = lists:unzip(L), 2849 VarsInCls = [introduced_variables(S, S1) || S1 <- Ss], 2850 ForbiddenVars = ordsets:union(VarsInCls), 2851 ForbiddenVarsInCls = [S1#post_state.forbidden || S1 <- Ss], 2852 AllForbiddenVars = ordsets:union([ForbiddenVars|ForbiddenVarsInCls]), 2853 S1 = forbidden_variables(S, AllForbiddenVars), 2854 {Clauses1, S1}. 2855 2856post_try_clause(Clause, S, clause) -> 2857 post_clause(Clause, S); 2858post_try_clause(Clause, S, catch_clause) -> 2859 {clause, A1, [{'tuple', A2, [EClass, P, St]}], GuardSeq, Body} = Clause, 2860 {EClass1, S1} = post(EClass, S), 2861 {[P1], S2} = post_patterns([P], S1), 2862 %% Stacktrace variable must not be bound: 2863 SSt = forbidden_variables(S2, S2#post_state.vars), 2864 {St1, S3} = post(St, SSt), 2865 StackVars = introduced_variables(SSt, S3), 2866 %% The stacktrace variable cannot be used in the catch clause guard: 2867 S4 = forbidden_variables(S3, StackVars), 2868 {GuardSeq1, S5} = post_guard_seq(GuardSeq, S4), 2869 %% Should simplify this... 2870 S6 = allowed_variables(S5, StackVars), 2871 {Body1, S7} = post_list(Body, S6), 2872 S8 = forbidden_variables(S7, StackVars), 2873 {{clause, A1, [{'tuple', A2, [EClass1, P1, St1]}], GuardSeq1, Body1}, 2874 S8}. 2875 2876post_clause({clause, A, Patterns, GuardSeq, Body}, S0) -> 2877 {Patterns1, S1} = post_patterns(Patterns, S0), 2878 {GuardSeq1, S2} = post_guard_seq(GuardSeq, S1), 2879 {Body1, S3} = post_list(Body, S2), 2880 {{clause, A, Patterns1, GuardSeq1, Body1}, S3}. 2881 2882post_patterns(Patterns, S0) -> 2883 Ctxt = S0#post_state.context, 2884 S1 = S0#post_state{context = pattern}, 2885 {Patterns1, S2} = post_expr_list(Patterns, S1), 2886 {Patterns1, S2#post_state{context = Ctxt}}. 2887 2888post_guard_seq(GuardSeq, S) -> 2889 GuardSeq1 = [post_list(G, S) || G <- GuardSeq], 2890 expr_list2(GuardSeq1, S). 2891 2892post_list([], S) -> 2893 {[], S}; 2894post_list([E|Es], S) -> 2895 {E1, S1} = post(E, S), 2896 {Es1, S2} = post_list(Es, S1), 2897 {[E1|Es1], S2}. 2898 2899post_expr_list(Es, S) -> 2900 L = [post(E, S) || E <- Es], 2901 expr_list2(L, S). 2902 2903expr_list2(L, S) -> 2904 {Es1, Ss} = lists:unzip(L), 2905 VsInEs = [S1#post_state.vars || S1 <- Ss], 2906 Vs = ordsets:union([S#post_state.vars|VsInEs]), 2907 Forbidden = ordsets:union([S1#post_state.forbidden || S1 <- Ss]), 2908 S1 = S#post_state{vars = Vs}, 2909 S2 = forbidden_variables(S1, Forbidden), 2910 {Es1, S2}. 2911 2912post_expr(Expr, S0) -> 2913 Ctxt = S0#post_state.context, 2914 S1 = S0#post_state{context = expr}, 2915 {Expr1, S2} = post(Expr, S1), 2916 {Expr1, S2#post_state{context = Ctxt}}. 2917 2918introduced_variables(S0, S1) -> 2919 ordsets:from_list(S1#post_state.vars -- S0#post_state.vars). 2920 2921forbidden_variables(S, Vs) -> 2922 S#post_state{forbidden = ordsets:union(S#post_state.forbidden, Vs)}. 2923 2924allowed_variables(S, Vs) -> 2925 S#post_state{forbidden = ordsets:subtract(S#post_state.forbidden, Vs)}. 2926 2927any_var(Anno, State, Fallback) -> 2928 #post_state{vars = Vs, forbidden = NoNo} = State, 2929 case find_var(Vs, NoNo, length(Vs)) of 2930 no -> 2931 case Fallback of 2932 arity -> 2933 {{integer, Anno, uniform(256) - 1}, State}; 2934 atom -> 2935 {{atom, Anno, create_atom(State)}, State}; 2936 fresh_var -> 2937 new_var(Anno, State); 2938 integer -> 2939 {{integer, Anno, uniform(1024) - 1}, State} % smallish 2940 end; 2941 {yes, Var} -> 2942 {{var, Anno, Var}, State} 2943 end. 2944 2945find_var([], _NoNo, 0) -> 2946 no; 2947find_var(Vs, NoNo, N) -> 2948 V = lists:nth(uniform(N), Vs), 2949 case ordsets:is_element(V, NoNo) of 2950 true -> 2951 find_var(Vs -- [V], NoNo, N - 1); 2952 false -> 2953 {yes, V} 2954 end. 2955 2956create_atom(S) -> 2957 (S#post_state.atom)(). 2958 2959any_of(L) -> 2960 lists:nth(uniform(length(L)), L). 2961 2962new_var(Anno, S) -> 2963 #post_state{vars = Vs, forbidden = NoNo, vindex = I} = S, 2964 Seed = case S#post_state.context of 2965 type -> 2966 '_V'; % avoid singleton_typevar error.. 2967 expr -> 2968 'V'; 2969 pattern -> 2970 'V' 2971 end, 2972 NewVar = list_to_atom(lists:concat([Seed, I])), 2973 S1 = S#post_state{vindex = I + 1}, 2974 case ordsets:is_element(NewVar, NoNo) of 2975 true -> 2976 new_var(Anno, S1); 2977 false -> 2978 NewVars = ordsets:add_element(NewVar, Vs), 2979 S2 = S#post_state{vars = NewVars}, 2980 {{var, Anno, NewVar}, S2} 2981 end. 2982 2983%%% Some errors detected by the linter are not compensated for in this 2984%%% module. However, such errors should not occur very often, which 2985%%% means that bad instances can be discarded without (almost) any 2986%%% slow-down. But check that the errors returned are expected as 2987%%% unexpected errors can slow down the generator. 2988ok_by_the_linter(What, T) -> 2989 case call_linter(What, T) of 2990 {ok, _Ws} -> 2991 true; 2992 {error, [{_File,Errors}], _Ws} -> 2993 ?DEBUG("LINT ~p\n", [Errors]), 2994 ?DEBUG("HARD? ~p\n", [all_hard_to_fix_errors(Errors)]), 2995 case all_hard_to_fix_errors(Errors) of 2996 true -> 2997 ?DEBUG("DISCARD!\n", []), 2998 false % discard; try again 2999 %% ; false -> 3000 %% io:format("The linter found an error that should not " 3001 %% "have occurred:\n ~p\n ~p\n", [Errors, T]), 3002 %% exit({bug, Errors, T}) 3003 end 3004 end. 3005 3006call_linter(expr, Expr) -> 3007 erl_lint:exprs([Expr], []); 3008call_linter(forms, Forms) -> 3009 erl_lint:module(Forms). 3010 3011all_hard_to_fix_errors(Errors) -> 3012 lists:all(fun hard_error/1, Errors). 3013 3014%%% After some testing it seems harmless to treat all linter errors 3015%%% as "hard". The "leakage" is negligible. 3016 3017%%% hard_error({_, erl_lint, illegal_bin_pattern}) -> true; 3018%%% hard_error({_, erl_lint, {error, bittype_unit}}) -> true; 3019%%% hard_error({_, erl_lint, illegal_map_key}) -> true; 3020%%% hard_error({_, erl_lint, unsized_binary_in_bin_gen_pattern}) -> true; 3021%%% Not yet seen: 3022%%% illegal_guard_expr 3023%%% utf_bittype_size_or_unit 3024%%% {undefined_bittype, _} 3025%%% unsized_binary_in_bin_gen_pattern 3026%%% illegal_pattern_end 3027%%% and probably more... 3028%%% Not so hard errors, should have been taken care of: 3029%%% ({_, erl_lint, {bittype_mismatch, _, _, _}}) 3030%%% ({_, erl_lint, unsized_binary_not_at_end}) 3031%%% hard_error({_, erl_lint, unsized_binary_in_bin_gen_pattern}) -> true; 3032hard_error({_, erl_lint, _}) -> true. 3033 3034some_atoms() -> 3035 ['', air, area, art, back, body, book, business, car, change, 3036 child, city, community, company, country, day, door, education, 3037 eye, face, fact, family, father, force, friend, game, girl, 3038 government, group, guy, hand, head, health, history, home, hour, 3039 house, idea, information, issue, job, kid, kind, law, level, 3040 life, line, lot, man, member, minute, moment, money, month, 3041 morning, mother, name, night, number, office, others, parent, 3042 part, party, people, person, place, point, power, president, 3043 problem, program, question, reason, research, result, right, 3044 room, school, service, side, state, story, student, study, 3045 system, teacher, team, thing, time, war, water, way, week, woman, 3046 word, work, world, year]. 3047 3048some_named_functions() -> 3049 %% Do not include {'_', ...} since "fun _() -> _() end" 3050 %% results in unbound variable. 3051 [{'F1',1}, {'F2',0}, {'F3',2}, {'F3',3}]. 3052 3053some_functions() -> 3054 [{f1,1}, {f1,2}, {f2,0}]. 3055 3056some_records() -> 3057 %% The first one is chosen as "guard record", which means that 3058 %% all field initializations are guard expressions. 3059 [{r1,[f1,f2]}, {r2,[]}, {r3,[f1]}]. 3060 3061%%% An arbitrary, small, collection of BIFs. 3062auto_imported() -> 3063 [{abs,1}, {atom_to_list,1}, {ceil,1}, {erase,1}, 3064 {exit,1}, {group_leader,2}, {is_function,2}, 3065 %% Old BIFs: 3066 {check_process_code,2}, {get,0}, {is_atom,1}]. 3067 3068some_types() -> 3069 [{t1,0}, {t2,1}]. 3070 3071predef_types() -> 3072 [{any,0}, {arity,0}, {atom,0}, {binary,0}, {bitstring,0}, 3073 {boolean,0}, {byte,0}, {char,0}, {float,0}, {function,0}, 3074 {identifier,0}, {integer,0}, {iodata,0}, {iolist,0}, {list,0}, 3075 {list,1}, {map,0}, {maybe_improper_list,0}, 3076 {maybe_improper_list,2}, {mfa,0}, {module,0}, {neg_integer,0}, 3077 {nil,0}, {no_return,0}, {node,0}, {non_neg_integer,0}, {none,0}, 3078 {nonempty_binary, 0}, {nonempty_bitstring, 0}, 3079 {nonempty_improper_list,2}, {nonempty_list,0}, {nonempty_list,1}, 3080 {nonempty_maybe_improper_list,0}, 3081 {nonempty_maybe_improper_list,2}, {nonempty_string,0}, 3082 {number,0}, {pid,0}, {port,0}, {pos_integer,0}, {reference,0}, 3083 {string,0}, {term,0}, {timeout,0}, {tuple,0}]. 3084 3085guard_bifs() -> 3086 [{abs,1}, {binary_part,2}, {binary_part,3}, {bit_size,1}, 3087 {byte_size,1}, {ceil,1}, {element,2}, {float,1}, {floor,1}, 3088 {hd,1}, {is_map_key,2}, {length,1}, {map_size,1}, {map_get,2}, 3089 {node,0}, {node,1}, {round,1}, {self,0}, {size,1}, {tl,1}, 3090 {trunc,1}, {tuple_size,1}, {is_atom,1}, {is_binary,1}, 3091 {is_bitstring,1}, {is_boolean,1}, {is_float,1}, {is_function,1}, 3092 {is_function,2}, {is_integer,1}, {is_list,1}, {is_map,1}, 3093 {is_number,1}, {is_pid,1}, {is_port,1}, {is_reference,1}, 3094 {is_tuple,1}]. 3095 3096other_bifs() -> 3097 [{is_record,2}, {is_record,3}]. 3098 3099expr_ops() -> 3100 %% Can be used in expressions with the "erlang:"-prefix. 3101 [{'++',2}, {'--',2}, {'!',2}] ++ guard_ops(). 3102 3103guard_ops() -> 3104 %% Like guard_binop() and any_unop(), but excluding 3105 %% andalso, orelse, ++, --, and !. 3106 %% Can be used in guards with the "erlang:"-prefix. 3107 [{'+',2}, {'+',1}, {'-',2}, {'-',1}, {'*',2}, {'/',2}, 3108 {'div',2}, {'rem',2}, {'band',2}, {'bnot',1}, {'bor',2}, {'bxor',2}, 3109 {'bsl',2}, {'bsr',2}, 3110 {'and',2}, {'or',2}, {'not',1}, {'xor',2}, 3111 {'=:=',2}, {'=/=',2}, {'==',2}, {'/=',2}, 3112 {'=<',2}, {'<',2}, {'>=',2}, {'>',2}]. 3113 3114uniform(N) -> 3115 rand:uniform(N). 3116