Skip to content
Browse files

Hacked support for documentation tags @alias and @private_type

  • Loading branch information...
1 parent 5d18293 commit da5e6b34c9eae0b5926ba28709d861654adc554d @manopapad committed May 16, 2011
Showing with 413 additions and 47 deletions.
  1. +1 −1 Makefile
  2. +2 −1 README
  3. +355 −0 make_doc
  4. +0 −2 rebar.config
  5. +0 −21 src/proper_arith.erl
  6. +2 −2 src/proper_gen.erl
  7. +3 −3 src/proper_shrink.erl
  8. +31 −16 src/proper_types.erl
  9. +19 −1 src/proper_typeserver.erl
View
2 Makefile
@@ -36,7 +36,7 @@ tests:
./rebar eunit
doc:
- ./rebar doc
+ ./make_doc
clean:
./clean_temp.sh
View
3 README
@@ -25,7 +25,8 @@ Quickstart guide
--------------------------------------------------------------------------------
* Compile PropEr: run 'make' (or 'make all', if you also want to build the
- documentation).
+ documentation -- you will need the syntax_tools application and a recent
+ version of EDoc).
* Add PropEr's base directory to your Erlang code path by choosing one of the
following ways:
1. ERL_LIBS environment variable - Add the following line to your shell
View
355 make_doc
@@ -0,0 +1,355 @@
+#!/usr/bin/env escript
+%%% Copyright 2010-2011 Manolis Papadakis <manopapad@gmail.com>,
+%%% Eirini Arvaniti <eirinibob@gmail.com>
+%%% and Kostis Sagonas <kostis@cs.ntua.gr>
+%%%
+%%% This file is part of PropEr.
+%%%
+%%% PropEr is free software: you can redistribute it and/or modify
+%%% it under the terms of the GNU General Public License as published by
+%%% the Free Software Foundation, either version 3 of the License, or
+%%% (at your option) any later version.
+%%%
+%%% PropEr is distributed in the hope that it will be useful,
+%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+%%% GNU General Public License for more details.
+%%%
+%%% You should have received a copy of the GNU General Public License
+%%% along with PropEr. If not, see <http://www.gnu.org/licenses/>.
+
+%%% Author: Manolis Papadakis <manopapad@gmail.com>
+%%% Description: Documentation processing script: This script will call EDoc on
+%%% the application's source files, after inlining all types
+%%% denoted as aliases, and removing from the exported types lists
+%%% all types denoted as private.
+%%% Known Bugs: * This scipt is very hacky, it will probably break easily.
+%%% * Record declarations with no type information are discarded.
+%%% * Any text inside the same multi-line comment as an @alias or
+%%% @private_type tag will be discarded.
+%%% * Comments inside included files are not processed.
+%%% * Comments will generally be displaced, especially comments
+%%% inside type declarations or functions.
+%%% * File and line information is partially lost.
+
+
+%%------------------------------------------------------------------------------
+%% Constants
+%%------------------------------------------------------------------------------
+
+-define(SRC_FILES_RE, "^.*\\.erl$").
+-define(APP_NAME, proper).
+-define(BASE_DIR, ".").
+-define(SRC_DIR, (?BASE_DIR ++ "/src")).
+-define(INCLUDE_DIR, (?BASE_DIR ++ "/include")).
+-define(TEMP_SRC_DIR, (?BASE_DIR ++ "/temp_src")).
+-define(EDOC_OPTS, [{report_missing_type,true}, {report_type_mismatch,true},
+ {pretty_printer,erl_pp}, {preprocess,true},
+ {source_path, [?TEMP_SRC_DIR]}]).
+
+
+%%------------------------------------------------------------------------------
+%% Types
+%%------------------------------------------------------------------------------
+
+%% TODO: Replace these with the appropriate types from stdlib.
+-type abs_form() :: term().
+-type abs_clause() :: term().
+-type abs_type() :: term().
+-type abs_rec_field() :: term().
+
+-type line() :: non_neg_integer().
+-type var_name() :: atom().
+-type rec_name() :: atom().
+-type var_form() :: {'var', line(), var_name()}.
+-type type_name() :: atom().
+-type type_ref() :: {'type', type_name(), arity()}.
+-type type_def() :: {abs_type(), [var_form()]}.
+
+-type charlist() :: [char() | charlist()].
+-type charlist_with_lines() :: {[line(),...],charlist()}.
+
+
+%%------------------------------------------------------------------------------
+%% File handling
+%%------------------------------------------------------------------------------
+
+-spec main([string()]) -> 'ok'.
+main(_CmdlineArgs) ->
+ ok = file:make_dir(?TEMP_SRC_DIR),
+ Copy =
+ fun(SrcFilename, ok) ->
+ Basename = filename:basename(SrcFilename),
+ DstFilename = ?TEMP_SRC_DIR ++ "/" ++ Basename,
+ {ok,_Bytes} = file:copy(SrcFilename, DstFilename),
+ ok
+ end,
+ ok = filelib:fold_files(?SRC_DIR, ?SRC_FILES_RE, false, Copy, ok),
+ Process = fun(Filename,ok) -> process(Filename) end,
+ ok = filelib:fold_files(?TEMP_SRC_DIR, ?SRC_FILES_RE, false, Process, ok),
+ ok = edoc:application(?APP_NAME, ?BASE_DIR, ?EDOC_OPTS),
+ Delete = fun(Filename,ok) -> file:delete(Filename) end,
+ ok = filelib:fold_files(?TEMP_SRC_DIR, ?SRC_FILES_RE, false, Delete, ok),
+ ok = file:del_dir(?TEMP_SRC_DIR),
+ ok.
+
+-spec process(file:filename()) -> 'ok'.
+process(Filename) ->
+ {ok,Forms} = epp:parse_file(Filename, [?INCLUDE_DIR], []),
+ Comments = erl_comment_scan:file(Filename),
+ {NewForms,NewComments} = process_forms(Forms, Comments),
+ Code = pretty_print(NewForms, NewComments),
+ {ok,IODev} = file:open(Filename, [write]),
+ ok = io:put_chars(IODev, Code),
+ ok = file:close(IODev),
+ ok.
+
+-spec pretty_print([abs_form()], [erl_comment_scan:comment()]) -> charlist().
+pretty_print(Forms, Comments) ->
+ FormsWithLines = add_lines_to_forms(Forms),
+ CommentsWithLines =
+ [{[Line],[["%",Str,"\n"] || Str <- Text]}
+ || {Line,_Col,_Ind,Text} <- Comments],
+ CodeWithLines = lists:keymerge(1, FormsWithLines, CommentsWithLines),
+ [[S,"\n"] || {_L,S} <- CodeWithLines].
+
+-spec add_lines_to_forms([abs_form()]) -> [charlist_with_lines()].
+add_lines_to_forms(Forms) ->
+ add_lines_to_forms(Forms, [], {"",0}, []).
+
+-spec add_lines_to_forms([abs_form()], [charlist_with_lines()],
+ {file:filename(),line()},
+ [{file:filename(),line()}]) ->
+ [charlist_with_lines()].
+add_lines_to_forms([], Acc, _FilePos, _Stack) ->
+ lists:reverse(Acc);
+add_lines_to_forms([Form|Rest], Acc, {FileName,_FileLine}, Stack) ->
+ case Form of
+ {attribute,Line,file,{NewFileName,_NewFileLine} = NewFilePos} ->
+ case NewFileName of
+ "" ->
+ %% TODO: What is the meaning of an empty file name?
+ %% TODO: Why is it causing problems?
+ add_lines_to_forms(Rest, Acc, {FileName,Line}, Stack);
+ FileName ->
+ %% TODO: Can this happen?
+ add_lines_to_forms(Rest, Acc, NewFilePos, Stack);
+ _ ->
+ NewStack =
+ case Stack of
+ [{NewFileName,_}|Bottom] ->
+ Bottom;
+ _ ->
+ [{FileName,Line}|Stack]
+ end,
+ add_lines_to_forms(Rest, Acc, NewFilePos, NewStack)
+ end;
+ {attribute,Line,record,_Fields} ->
+ add_lines_to_forms(Rest, Acc, {FileName,Line}, Stack);
+ _ ->
+ PrintedForm = print_form(Form),
+ Line = get_line_from_form(Form),
+ Lines = tl(lists:reverse([Line | [L || {_F,L} <- Stack]])),
+ add_lines_to_forms(Rest, [{Lines,PrintedForm}|Acc],
+ {FileName,Line}, Stack)
+ end.
+
+-spec print_form(abs_form()) -> charlist().
+print_form({attribute,_,type,{{record,Name},Fields,[]}}) ->
+ print_record_type(Name,Fields);
+print_form(OtherForm) ->
+ erl_pp:form(OtherForm).
+
+-spec print_record_type(rec_name(), [abs_rec_field()]) -> charlist().
+print_record_type(Name, Fields) ->
+ ["-record(", atom_to_list(Name), ",{",
+ case Fields of
+ [] ->
+ [];
+ [Head|Rest] ->
+ [print_record_field(Head),
+ [[",",print_record_field(F)] || F <- Rest]]
+ end,
+ "}).\n"].
+
+-spec print_record_field(abs_rec_field()) -> charlist().
+print_record_field({record_field,_,{atom,_,Name}}) ->
+ atom_to_list(Name);
+print_record_field({record_field,_,{atom,_,Name},Initialization}) ->
+ [atom_to_list(Name), $=, erl_pp:expr(Initialization,-1,none)];
+print_record_field({typed_record_field,InnerField,FieldType}) ->
+ MyTypeDecl = {attribute,0,type,{mytype,FieldType,[]}},
+ PrintedMyType = lists:flatten(erl_pp:form(MyTypeDecl)),
+ PrintedFieldType =
+ lists:reverse(remove_from_head("\n.",
+ lists:reverse(remove_from_head("-typemytype()::", PrintedMyType)))),
+ [print_record_field(InnerField), "::", PrintedFieldType].
+
+-spec remove_from_head(string(), string()) -> string().
+remove_from_head([], Str) ->
+ Str;
+remove_from_head(ToRemove, [32|StrRest]) ->
+ remove_from_head(ToRemove, StrRest);
+remove_from_head([C|ToRemoveRest], [C|StrRest]) ->
+ remove_from_head(ToRemoveRest, StrRest).
+
+-spec get_line_from_form(abs_form()) -> line().
+get_line_from_form({attribute,Line,_Kind,_Value}) ->
+ Line;
+get_line_from_form({function,Line,_Name,_Arity,_Clauses}) ->
+ Line;
+get_line_from_form({eof,Line}) ->
+ Line.
+
+
+%%------------------------------------------------------------------------------
+%% Abstract code processing
+%%------------------------------------------------------------------------------
+
+-spec process_forms([abs_form()], [erl_comment_scan:comment()]) ->
+ {[abs_form()],[erl_comment_scan:comment()]}.
+process_forms(Forms, Comments) ->
+ process_forms([], Forms, [], Comments, []).
+
+-spec process_forms([abs_form()], [abs_form()], [erl_comment_scan:comment()],
+ [erl_comment_scan:comment()], [{type_name(),arity()}]) ->
+ {[abs_form()],[erl_comment_scan:comment()]}.
+process_forms(RevForms, Forms, RevComments, [], PrivTypes) ->
+ NewForms = lists:reverse(RevForms) ++ Forms,
+ NewComments = lists:reverse(RevComments),
+ {remove_private_types(NewForms,PrivTypes), NewComments};
+process_forms(RevForms, Forms, RevComments, [Comment|Rest], PrivTypes) ->
+ {CommLine,_Column,_Indentation,Text} = Comment,
+ IsPrivate = contains_tag(Text, "@private_type"),
+ IsAlias = contains_tag(Text, "@alias"),
+ case IsPrivate orelse IsAlias of
+ true ->
+ {MaybeType,NewRevForms,NewForms} =
+ find_next_type(CommLine, RevForms, Forms),
+ case MaybeType of
+ error ->
+ process_forms(NewRevForms, NewForms, RevComments, Rest,
+ PrivTypes);
+ {TypeRef,TypeDef} ->
+ %% TODO: Also throw away alias type forms?
+ FinalForms =
+ case IsAlias of
+ true ->
+ [replace(F,TypeRef,TypeDef) || F <- NewForms];
+ false ->
+ NewForms
+ end,
+ NewPrivTypes =
+ case IsPrivate of
+ true ->
+ {type,Name,Arity} = TypeRef,
+ [{Name,Arity} | PrivTypes];
+ false ->
+ PrivTypes
+ end,
+ process_forms(NewRevForms, FinalForms, RevComments, Rest,
+ NewPrivTypes)
+ end;
+ false ->
+ process_forms(RevForms, Forms, [Comment|RevComments], Rest,
+ PrivTypes)
+ end.
+
+-spec find_next_type(line(), [abs_form()], [abs_form()]) ->
+ {'error' | {type_ref(),type_def()}, [abs_form()], [abs_form()]}.
+find_next_type(_CommLine, RevForms, []) ->
+ {error, RevForms, []};
+find_next_type(CommLine, RevForms, [Form|Rest] = Forms) ->
+ {attribute,AttrLine,Kind,Value} = Form,
+ case AttrLine =< CommLine of
+ true ->
+ find_next_type(CommLine, [Form|RevForms], Rest);
+ false ->
+ case Kind of
+ type ->
+ {Name,TypeForm,VarForms} = Value,
+ case is_atom(Name) of
+ true ->
+ Arity = length(VarForms),
+ TypeRef = {type,Name,Arity},
+ TypeDef = {TypeForm,VarForms},
+ {{TypeRef,TypeDef}, RevForms, Forms};
+ false ->
+ {error, RevForms, Forms}
+ end;
+ _OtherKind ->
+ {error, RevForms, Forms}
+ end
+ end.
+
+-spec contains_tag([string()], string()) -> boolean().
+contains_tag(Text, Tag) ->
+ StrContainsTag = fun(Str) -> string:str(Str,Tag) =/= 0 end,
+ lists:any(StrContainsTag, Text).
+
+-spec replace(abs_form() | abs_type() | abs_rec_field() | abs_clause(),
+ var_form() | type_ref(), abs_type() | type_def()) ->
+ abs_form() | abs_type() | abs_rec_field() | abs_clause().
+%% TODO: Should we update the source lines when inlining?
+replace({attribute,Line,type,{{record,Name},Fields,[]}}, Alias, Value) ->
+ NewFields = [replace(Field,Alias,Value) || Field <- Fields],
+ {attribute, Line, type, {{record,Name},NewFields,[]}};
+replace({attribute,Line,Kind,{Name,TypeForm,VarForms}}, Alias, Value)
+ when Kind =:= type orelse Kind =:= opaque ->
+ NewTypeForm = replace(TypeForm, Alias, Value),
+ {attribute, Line, Kind, {Name,NewTypeForm,VarForms}};
+replace({attribute,Line,spec,{FunRef,Clauses}}, Alias, Value) ->
+ NewClauses = [replace(Clause,Alias,Value) || Clause <- Clauses],
+ {attribute, Line, spec, {FunRef,NewClauses}};
+replace({typed_record_field,RecField,FieldType}, Alias, Value) ->
+ {typed_record_field, RecField, replace(FieldType,Alias,Value)};
+replace({type,Line,bounded_fun,[MainClause,Constraints]}, Alias, Value) ->
+ ReplaceInConstraint =
+ fun({type,L,constraint,[ConstrKind,Args]}) ->
+ NewArgs = [replace(Arg,Alias,Value) || Arg <- Args],
+ {type, L, constraint, [ConstrKind,NewArgs]}
+ end,
+ NewConstraints = [ReplaceInConstraint(C) || C <- Constraints],
+ {type, Line, bounded_fun, [MainClause,NewConstraints]};
+replace({var,_Line1,SameName}, {var,_Line2,SameName}, Value) ->
+ Value;
+replace({Kind,Line,Args}, Alias, Value) when Kind =:= ann_type
+ orelse Kind =:= paren_type
+ orelse Kind =:= remote_type ->
+ NewArgs = [replace(Arg,Alias,Value) || Arg <- Args],
+ {Kind, Line, NewArgs};
+replace(Type = {type,_Line,tuple,any}, _Alias, _Value) ->
+ Type;
+replace({type,_Line,SameName,Args}, Alias = {type,SameName,Arity},
+ Value = {TypeForm,VarForms}) when length(Args) =:= Arity ->
+ FixedArgs = [replace(Arg,Alias,Value) || Arg <- Args],
+ ReplaceVar = fun({Var,Val},T) -> replace(T, Var, Val) end,
+ lists:foldl(ReplaceVar, TypeForm, lists:zip(VarForms,FixedArgs));
+replace({type,Line,Name,Args}, Alias, Value) ->
+ NewArgs = [replace(Arg,Alias,Value) || Arg <- Args],
+ {type, Line, Name, NewArgs};
+replace(Other, _Alias, _Value) ->
+ Other.
+
+-spec remove_private_types([abs_form()], [{type_name(),arity()}]) ->
+ [abs_form()].
+remove_private_types(Forms, PrivTypesList) ->
+ PrivTypesSet = sets:from_list(PrivTypesList),
+ [remove_from_exported(Form,PrivTypesSet) || Form <- Forms].
+
+-spec remove_from_exported(abs_form(), set()) -> abs_form().
+%% set({type_name(),arity()})
+remove_from_exported({attribute,Line,export_type,TypesList}, PrivTypesSet) ->
+ IsNotPrivate = fun(T) -> not sets:is_element(T,PrivTypesSet) end,
+ {attribute, Line, export_type, lists:filter(IsNotPrivate,TypesList)};
+remove_from_exported(OtherAttr, _PrivTypesSet) ->
+ OtherAttr.
+
+%% -spec update_line(abs_type(), line()) -> abs_type().
+%% update_line(Type, Line) ->
+%% %% TODO: Is this function necessary?
+%% %% TODO: Will this work with type declarations?
+%% UpdateNodeLine = fun(Node) -> set_pos(Node, Line) end,
+%% %% TODO: Is the 'revert' operation necessary?
+%% erl_syntax:revert(erl_syntax_lib:map(UpdateNodeLine, Type)).
+%% kate: syntax erlang;
View
2 rebar.config
@@ -35,7 +35,5 @@
report_warnings, {warn_format,1}, warn_export_vars,
warn_obsolete_guard, warn_unused_import,
warn_missing_spec, warn_untyped_record]}.
-{edoc_opts, [{report_missing_type,true}, {report_type_mismatch,true},
- {pretty_printer,erl_pp}, {preprocess,true}]}.
{dialyzer_opts, [{warnings,[unmatched_returns]}]}.
{post_hooks,[{clean,"./clean_doc.sh"}]}.
View
21 src/proper_arith.erl
@@ -28,7 +28,6 @@
-module(proper_arith).
--export([le/2]).
-export([list_remove/2, list_update/3, list_insert/3, safe_map/2, safe_foldl/3,
safe_any/2, safe_zip/2, tuple_map/2, cut_improper_tail/1,
head_length/1, find_first/2, filter/2, partition/2, remove/2, insert/3,
@@ -38,30 +37,10 @@
rand_float/1, rand_float/2, rand_non_neg_float/1,
distribute/2, jumble/1, rand_choose/1, freq_choose/1]).
--export_type([extint/0, extnum/0]).
-
-include("proper_internal.hrl").
%%-----------------------------------------------------------------------------
-%% Types
-%%-----------------------------------------------------------------------------
-
--type extint() :: integer() | 'inf'.
--type extnum() :: number() | 'inf'.
-
-
-%%-----------------------------------------------------------------------------
-%% Arithmetic functions
-%%-----------------------------------------------------------------------------
-
--spec le(extnum(), extnum()) -> boolean().
-le(inf, _B) -> true;
-le(_A, inf) -> true;
-le(A, B) -> A =< B.
-
-
-%%-----------------------------------------------------------------------------
%% List handling functions
%%-----------------------------------------------------------------------------
View
4 src/proper_gen.erl
@@ -280,7 +280,7 @@ clean_instance(ImmInstance) ->
%%-----------------------------------------------------------------------------
%% @private
--spec integer_gen(size(), proper_arith:extint(), proper_arith:extint()) ->
+-spec integer_gen(size(), proper_types:extint(), proper_types:extint()) ->
integer().
integer_gen(Size, inf, inf) ->
proper_arith:rand_int(Size);
@@ -292,7 +292,7 @@ integer_gen(_Size, Low, High) ->
proper_arith:rand_int(Low, High).
%% @private
--spec float_gen(size(), proper_arith:extnum(), proper_arith:extnum()) ->
+-spec float_gen(size(), proper_types:extnum(), proper_types:extnum()) ->
float().
float_gen(Size, inf, inf) ->
proper_arith:rand_float(Size);
View
6 src/proper_shrink.erl
@@ -401,7 +401,7 @@ elements_shrinker(Instance, Type,
%% Custom shrinkers
%%------------------------------------------------------------------------------
--spec number_shrinker(number(), proper_arith:extnum(), proper_arith:extnum(),
+-spec number_shrinker(number(), proper_types:extnum(), proper_types:extnum(),
state()) -> {[number()],state()}.
number_shrinker(X, Low, High, init) ->
{Target,Inc,OverLimit} = find_target(X, Low, High),
@@ -421,7 +421,7 @@ number_shrinker(_X, _Low, _High, {shrunk,_Pos,_State}) ->
-spec find_target(number(), number(), number()) ->
{number(),fun((number()) -> number()),fun((number()) -> boolean())}.
find_target(X, Low, High) ->
- case {proper_arith:le(Low,0), proper_arith:le(0,High)} of
+ case {proper_types:le(Low,0), proper_types:le(0,High)} of
{false, _} ->
Limit = find_limit(X, Low, High, High),
{Low, fun(Y) -> Y + 1 end, fun(Y) -> Y > Limit end};
@@ -444,7 +444,7 @@ find_target(X, Low, High) ->
-spec find_limit(number(), number(), number(), number()) -> number().
find_limit(X, Low, High, FallBack) ->
- case proper_arith:le(Low, X) andalso proper_arith:le(X, High) of
+ case proper_types:le(Low, X) andalso proper_types:le(X, High) of
true -> X;
false -> FallBack
end.
View
47 src/proper_types.erl
@@ -47,8 +47,9 @@
-export([lazy/1, sized/1, bind/3, shrinkwith/2, add_constraint/3,
native_type/2, distlist/3, with_parameter/3, with_parameters/2,
parameter/1, parameter/2]).
+-export([le/2]).
--export_type([type/0, raw_type/0]).
+-export_type([type/0, raw_type/0, extint/0, extnum/0]).
-include("proper_internal.hrl").
@@ -96,10 +97,18 @@
-type type_kind() :: 'basic' | 'wrapper' | 'constructed' | 'container' | atom().
-type instance_test() :: fun((proper_gen:imm_instance()) -> boolean()).
-type index() :: pos_integer().
+%% @alias
-type value() :: term().
+%% @private_type
+%% @alias
+-type extint() :: integer() | 'inf'.
+%% @private_type
+%% @alias
+-type extnum() :: number() | 'inf'.
-type constraint_fun() :: fun((proper_gen:instance()) -> boolean()).
-opaque type() :: {'$type', [type_prop()]}.
+%% @type raw_type()
-type raw_type() :: type() | [raw_type()] | loose_tuple(raw_type()) | term().
-type type_prop_name() :: 'kind' | 'generator' | 'reverse_gen' | 'parts_type'
| 'combine' | 'alt_gens' | 'shrink_to_parts'
@@ -159,6 +168,9 @@
%% Type manipulation functions
%%------------------------------------------------------------------------------
+%% TODO: We shouldn't need the fully qualified type name in the range of these
+%% functions.
+
%% @private
%% TODO: just cook/1 ?
-spec cook_outer(raw_type()) -> proper_types:type().
@@ -248,11 +260,13 @@ get_prop(PropName, {'$type',Props}) ->
find_prop(PropName, {'$type',Props}) ->
orddict:find(PropName, Props).
+%% @private
-spec new_type([type_prop()], type_kind()) -> proper_types:type().
new_type(PropList, Kind) ->
Type = type_from_list(PropList),
add_prop(kind, Kind, Type).
+%% @private
-spec subtype([type_prop()], proper_types:type()) -> proper_types:type().
%% TODO: should the 'is_instance' function etc. be reset for subtypes?
subtype(PropList, Type) ->
@@ -430,8 +444,7 @@ native_type(Mod, TypeStr) ->
%% Basic types
%%------------------------------------------------------------------------------
--spec integer(proper_arith:extint(), proper_arith:extint()) ->
- proper_types:type().
+-spec integer(extint(), extint()) -> proper_types:type().
integer(Low, High) ->
?BASIC([
{generator, fun(Size) -> proper_gen:integer_gen(Size, Low, High) end},
@@ -440,15 +453,13 @@ integer(Low, High) ->
[fun(X,_T,S) -> proper_shrink:number_shrinker(X, Low, High, S) end]}
]).
--spec integer_test(proper_gen:imm_instance(), proper_arith:extint(),
- proper_arith:extint()) -> boolean().
+-spec integer_test(proper_gen:imm_instance(), extint(), extint()) -> boolean().
integer_test(X, Low, High) ->
is_integer(X)
- andalso proper_arith:le(Low, X)
- andalso proper_arith:le(X, High).
+ andalso le(Low, X)
+ andalso le(X, High).
--spec float(proper_arith:extnum(), proper_arith:extnum()) ->
- proper_types:type().
+-spec float(extnum(), extnum()) -> proper_types:type().
float(Low, High) ->
?BASIC([
{generator, fun(Size) -> proper_gen:float_gen(Size, Low, High) end},
@@ -457,12 +468,16 @@ float(Low, High) ->
[fun(X,_T,S) -> proper_shrink:number_shrinker(X, Low, High, S) end]}
]).
--spec float_test(proper_gen:imm_instance(), proper_arith:extnum(),
- proper_arith:extnum()) -> boolean().
+-spec float_test(proper_gen:imm_instance(), extnum(), extnum()) -> boolean().
float_test(X, Low, High) ->
is_float(X)
- andalso proper_arith:le(Low, X)
- andalso proper_arith:le(X, High).
+ andalso le(Low, X)
+ andalso le(X, High).
+
+-spec le(extnum(), extnum()) -> boolean().
+le(inf, _B) -> true;
+le(_A, inf) -> true;
+le(A, B) -> A =< B.
-spec atom() -> proper_types:type().
atom() ->
@@ -543,6 +558,7 @@ list_test(X, ElemType) ->
is_list(X)
andalso lists:all(fun(E) -> is_instance(E, ElemType) end, X).
+%% @private
-spec list_get_indices(list()) -> [position()].
list_get_indices(List) ->
lists:seq(1, length(List)).
@@ -768,7 +784,7 @@ pos_integer() -> integer(1, inf).
-spec neg_integer() -> proper_types:type().
neg_integer() -> integer(inf, -1).
--spec range(proper_arith:extint(),proper_arith:extint()) -> proper_types:type().
+-spec range(extint(), extint()) -> proper_types:type().
range(Low, High) -> integer(Low, High).
-spec float() -> proper_types:type().
@@ -829,8 +845,7 @@ real() -> float().
-spec bool() -> proper_types:type().
bool() -> boolean().
--spec choose(proper_arith:extint(), proper_arith:extint()) ->
- proper_types:type().
+-spec choose(extint(), extint()) -> proper_types:type().
choose(Low, High) -> integer(Low, High).
-spec elements([raw_type(),...]) -> proper_types:type().
View
20 src/proper_typeserver.erl
@@ -24,7 +24,6 @@
%%% @author Manolis Papadakis <manopapad@gmail.com>
%%% @doc This module contains the subsystem responsible for integration with
%%% Erlang's built-in type system.
-%%% @private
-module(proper_typeserver).
-behaviour(gen_server).
@@ -128,8 +127,10 @@
-type pattern() :: loose_tuple(pat_field()).
-type next_step() :: 'none' | 'take_head' | {'match_with',pattern()}.
+%% @private_type
-type mod_exp_types() :: set(). %% set(imm_type_ref())
-type mod_types() :: dict(). %% dict(type_ref(),type_repr())
+%% @private_type
-type mod_exp_funs() :: set(). %% set(fun_ref())
-type mod_specs() :: dict(). %% dict(fun_ref(),fun_repr())
-record(state,
@@ -148,10 +149,13 @@
-type stack() :: [full_type_ref() | 'tuple' | 'list' | 'union' | 'fun'].
-type var_dict() :: dict(). %% dict(var_name(),ret_type())
+%% @private_type
-type imm_type() :: {mod_name(),string()}.
+%% @alias
-type fin_type() :: proper_types:type().
-type tagged_result(T) :: {'ok',T} | 'error'.
-type tagged_result2(T,S) :: {'ok',T,S} | 'error'.
+%% @alias
-type rich_result(T) :: {'ok',T} | {'error',term()}.
-type rich_result2(T,S) :: {'ok',T,S} | {'error',term()}.
@@ -169,23 +173,27 @@
%% Server interface functions
%%------------------------------------------------------------------------------
+%% @private
-spec start() -> 'ok'.
start() ->
{ok,TypeserverPid} = gen_server:start_link(?MODULE, dummy, []),
put('$typeserver_pid', TypeserverPid),
ok.
+%% @private
-spec stop() -> 'ok'.
stop() ->
TypeserverPid = get('$typeserver_pid'),
erase('$typeserver_pid'),
gen_server:cast(TypeserverPid, stop).
+%% @private
-spec create_spec_test(mfa(), timeout()) -> rich_result(proper:test()).
create_spec_test(MFA, SpecTimeout) ->
TypeserverPid = get('$typeserver_pid'),
gen_server:call(TypeserverPid, {create_spec_test,MFA,SpecTimeout}).
+%% @private
-spec get_exp_specced(mod_name()) -> rich_result([mfa()]).
get_exp_specced(Mod) ->
TypeserverPid = get('$typeserver_pid'),
@@ -197,6 +205,7 @@ get_type_repr(Mod, TypeRef, IsRemote) ->
TypeserverPid = get('$typeserver_pid'),
gen_server:call(TypeserverPid, {get_type_repr,Mod,TypeRef,IsRemote}).
+%% @private
-spec translate_type(imm_type()) -> rich_result(fin_type()).
translate_type(ImmType) ->
TypeserverPid = get('$typeserver_pid'),
@@ -237,10 +246,12 @@ demo_is_instance(X, Mod, TypeStr) ->
%% Implementation of gen_server interface
%%------------------------------------------------------------------------------
+%% @private
-spec init(_) -> {'ok',state()}.
init(_) ->
{ok, #state{}}.
+%% @private
-spec handle_call(server_call(), _, state()) ->
{'reply',server_response(),state()}.
handle_call({create_spec_test,MFA,SpecTimeout}, _From, State) ->
@@ -272,18 +283,22 @@ handle_call({translate_type,ImmType}, _From, State) ->
{reply, Error, State}
end.
+%% @private
-spec handle_cast('stop', state()) -> {'stop','normal',state()}.
handle_cast(stop, State) ->
{stop, normal, State}.
+%% @private
-spec handle_info(term(), state()) -> {'stop',{'received_info',term()},state()}.
handle_info(Info, State) ->
{stop, {received_info,Info}, State}.
+%% @private
-spec terminate(term(), state()) -> 'ok'.
terminate(_Reason, _State) ->
ok.
+%% @private
-spec code_change(term(), state(), _) -> {'ok',state()}.
code_change(_OldVsn, State, _) ->
{ok, State}.
@@ -438,6 +453,7 @@ add_module(Mod, #state{exp_types = ExpTypes} = State) ->
end
end.
+%% @private
-spec get_exp_info(mod_name()) -> rich_result2(mod_exp_types(),mod_exp_funs()).
get_exp_info(Mod) ->
case get_code_and_exports(Mod) of
@@ -909,6 +925,7 @@ add_field({atom,_,Tag}, {Left,Acc}) ->
add_field(_Type, {Left,Acc}) ->
{erlang:max(0,Left-1), [0|Acc]}.
+%% @private
-spec match(pattern(), tuple()) -> term().
match(Pattern, Term) when tuple_size(Pattern) =:= tuple_size(Term) ->
match(tuple_to_list(Pattern), tuple_to_list(Term), none, false);
@@ -1077,6 +1094,7 @@ term_to_singleton_type(Tuple) when is_tuple(Tuple) ->
{timeout, {type,0,union,[{atom,0,infinity},
{type,0,non_neg_integer,[]}]}}]).
+%% @private
%% TODO: Most of these functions accept an extended form of abs_type(), namely
%% the addition of a custom wrapper: {'from_mod',mod_name(),...}
-spec is_instance(term(), mod_name(), abs_type()) -> boolean().

0 comments on commit da5e6b3

Please sign in to comment.
Something went wrong with that request. Please try again.