aboutsummaryrefslogtreecommitdiffstats
path: root/lib/edoc/src/edoc_parser.yrl
diff options
context:
space:
mode:
authorHans Bolinder <[email protected]>2010-06-22 09:42:44 +0200
committerHans Bolinder <[email protected]>2011-03-10 12:57:37 +0100
commit8052b98f596db048467c0c57cbaac1d3a27687ad (patch)
tree144fcf14894c8a5c7df3778d7b1d91fa6a72a1cb /lib/edoc/src/edoc_parser.yrl
parentcc5885e81da81dc52bd7890ff3612a48d2f4a9f2 (diff)
downloadotp-8052b98f596db048467c0c57cbaac1d3a27687ad.tar.gz
otp-8052b98f596db048467c0c57cbaac1d3a27687ad.tar.bz2
otp-8052b98f596db048467c0c57cbaac1d3a27687ad.zip
Make Erlang specifications and types available in EDoc
It is now possible to use Erlang specifications and types in EDoc documentation. Erlang specifications and types will be used unless there is also a function specification (@spec) or a type alias (@type) with the same name. In the current implementation the placement of -spec matters: it should be placed where the @spec would otherwise have been placed. Not all Erlang types are included in the documentation, but only those exported by some export_type declaration or used by some documented Erlang specification (-spec). There is currently no support for overloaded Erlang specifications. The syntax definitions of EDoc have been augmented to cope with most of the Erlang types. (But we recommend that Erlang types should be used instead.) edoc:read_source() takes one new option, report_missing_types. edoc_layout:module() takes one new option, pretty_printer.
Diffstat (limited to 'lib/edoc/src/edoc_parser.yrl')
-rw-r--r--lib/edoc/src/edoc_parser.yrl106
1 files changed, 79 insertions, 27 deletions
diff --git a/lib/edoc/src/edoc_parser.yrl b/lib/edoc/src/edoc_parser.yrl
index 91ee5a1b2b..6943f1bdb8 100644
--- a/lib/edoc/src/edoc_parser.yrl
+++ b/lib/edoc/src/edoc_parser.yrl
@@ -24,21 +24,22 @@
%%
%% Author contact: [email protected]
%%
-%% $Id$
+%% $Id $
%%
%% =====================================================================
Nonterminals
start spec func_type utype_list utype_tuple utypes utype ptypes ptype
-nutype function_name where_defs defs def typedef etype throws qname ref
-aref mref lref pref var_list vars fields field.
+nutype function_name where_defs defs defs2 def typedef etype
+throws qname ref aref mref lref pref var_list vars fields field
+futype_list bin_base_type bin_unit_type.
Terminals
-atom float integer var string start_spec start_typedef start_throws
+atom float integer var an_var string start_spec start_typedef start_throws
start_ref
'(' ')' ',' '.' '->' '{' '}' '[' ']' '|' '+' ':' '::' '=' '/' '//' '*'
-'#' 'where'.
+'#' 'where' '<<' '>>' '..' '...'.
Rootsymbol start.
@@ -52,9 +53,9 @@ qname -> atom: [tok_val('$1')].
qname -> qname '.' atom: [tok_val('$3') | '$1'].
spec -> func_type where_defs:
- #t_spec{type = '$1', defs = lists:reverse('$2')}.
+ #t_spec{type = '$1', defs = '$2'}.
spec -> function_name func_type where_defs:
- #t_spec{name = '$1', type = '$2', defs = lists:reverse('$3')}.
+ #t_spec{name = '$1', type = '$2', defs = '$3'}.
where_defs -> 'where' defs: '$2'.
where_defs -> defs: '$1'.
@@ -66,13 +67,15 @@ func_type -> utype_list '->' utype:
%% Paired with line number, for later error reporting
-utype_list -> '(' ')' : {[], tok_line('$1')}.
utype_list -> '(' utypes ')' : {lists:reverse('$2'), tok_line('$1')}.
-utype_tuple -> '{' '}' : [].
+futype_list -> utype_list : '$1'.
+futype_list -> '(' '...' ')' : {[#t_var{name = '...'}], tok_line('$1')}.
+
utype_tuple -> '{' utypes '}' : lists:reverse('$2').
%% Produced in reverse order.
+utypes -> '$empty' : [].
utypes -> utype : ['$1'].
utypes -> utypes ',' utype : ['$3' | '$1'].
@@ -90,20 +93,25 @@ ptypes -> ptypes '|' ptype : ['$3' | '$1'].
ptype -> var : #t_var{name = tok_val('$1')}.
ptype -> atom : #t_atom{val = tok_val('$1')}.
ptype -> integer: #t_integer{val = tok_val('$1')}.
+ptype -> integer '..' integer: #t_integer_range{from = tok_val('$1'),
+ to = tok_val('$3')}.
ptype -> float: #t_float{val = tok_val('$1')}.
ptype -> utype_tuple : #t_tuple{types = '$1'}.
ptype -> '[' ']' : #t_nil{}.
ptype -> '[' utype ']' : #t_list{type = '$2'}.
+ptype -> '[' utype ',' '...' ']' : #t_nonempty_list{type = '$2'}.
ptype -> utype_list:
- if length(element(1, '$1')) == 1 ->
+ if length(element(1, '$1')) == 1 ->
%% there must be exactly one utype in the list
hd(element(1, '$1'));
+ %% Replace last line when releasing next major release:
+ %% #t_paren{type = hd(element(1, '$1'))};
length(element(1, '$1')) == 0 ->
return_error(element(2, '$1'), "syntax error before: ')'");
true ->
return_error(element(2, '$1'), "syntax error before: ','")
end.
-ptype -> utype_list '->' ptype:
+ptype -> futype_list '->' ptype:
#t_fun{args = element(1, '$1'), range = '$3'}.
ptype -> '#' atom '{' '}' :
#t_record{name = #t_atom{val = tok_val('$2')}}.
@@ -111,17 +119,45 @@ ptype -> '#' atom '{' fields '}' :
#t_record{name = #t_atom{val = tok_val('$2')},
fields = lists:reverse('$4')}.
ptype -> atom utype_list:
- #t_type{name = #t_name{name = tok_val('$1')},
- args = element(1, '$2')}.
-ptype -> qname ':' atom utype_list :
+ case {tok_val('$1'), element(1, '$2')} of
+ {nil, []} ->
+ %% Prefer '[]' before 'nil(). Due to
+ %% compatibility with Erlang types, which do not
+ %% separate '[]' from 'nil()'.
+ #t_nil{};
+ {list, [T]} ->
+ %% Prefer '[T]' before 'list(T). Due to
+ %% compatibility with Erlang types, which do not
+ %% separate '[T]' from 'list(T)'.
+ #t_list{type = T};
+ {'fun', [#t_fun{}=Fun]} ->
+ %% An incompatible change as compared to EDOc 0.7.6.6.
+ %% Due to compatibility with Erlang types.
+ Fun;
+ {'fun', []} ->
+ #t_type{name = #t_name{name = function}};
+ {Name, Args} ->
+ #t_type{name = #t_name{name = Name},
+ args = Args}
+ end.
+ptype -> qname ':' atom utype_list :
#t_type{name = #t_name{module = qname('$1'),
name = tok_val('$3')},
args = element(1, '$4')}.
-ptype -> '//' atom '/' qname ':' atom utype_list :
+ptype -> '//' atom '/' qname ':' atom utype_list :
#t_type{name = #t_name{app = tok_val('$2'),
module = qname('$4'),
name = tok_val('$6')},
args = element(1, '$7')}.
+ptype -> '<<' '>>' : #t_binary{}.
+ptype -> '<<' bin_base_type '>>' : #t_binary{base_size = '$2'}.
+ptype -> '<<' bin_unit_type '>>' : #t_binary{unit_size = '$2'}.
+ptype -> '<<' bin_base_type ',' bin_unit_type '>>' :
+ #t_binary{base_size = '$2', unit_size = '$4'}.
+
+bin_base_type -> an_var ':' integer: tok_val('$3').
+
+bin_unit_type -> an_var ':' an_var '*' integer : tok_val('$5').
%% Produced in reverse order.
fields -> field : ['$1'].
@@ -130,18 +166,19 @@ fields -> fields ',' field : ['$3' | '$1'].
field -> atom '=' utype :
#t_field{name = #t_atom{val = tok_val('$1')}, type = '$3'}.
-%% Produced in reverse order.
defs -> '$empty' : [].
-defs -> defs def : ['$2' | '$1'].
-defs -> defs ',' def : ['$3' | '$1'].
+defs -> def defs2 : ['$1' | lists:reverse('$2')].
+
+%% Produced in reverse order.
+defs2 -> '$empty' : [].
+defs2 -> defs2 def : ['$2' | '$1'].
+defs2 -> defs2 ',' def : ['$3' | '$1'].
def -> var '=' utype:
#t_def{name = #t_var{name = tok_val('$1')},
type = '$3'}.
-def -> atom var_list '=' utype:
- #t_def{name = #t_type{name = #t_name{name = tok_val('$1')},
- args = '$2'},
- type = '$4'}.
+def -> atom '(' utypes ')' '=' utype:
+ build_def(tok_val('$1'), '$2', '$3', '$6').
var_list -> '(' ')' : [].
var_list -> '(' vars ')' : lists:reverse('$2').
@@ -153,12 +190,12 @@ vars -> vars ',' var : [#t_var{name = tok_val('$3')} | '$1'].
typedef -> atom var_list where_defs:
#t_typedef{name = #t_name{name = tok_val('$1')},
args = '$2',
- defs = lists:reverse('$3')}.
+ defs = '$3'}.
typedef -> atom var_list '=' utype where_defs:
#t_typedef{name = #t_name{name = tok_val('$1')},
args = '$2',
type = '$4',
- defs = lists:reverse('$5')}.
+ defs = '$5'}.
%% References
@@ -195,7 +232,7 @@ etype -> utype: '$1'.
throws -> etype where_defs:
#t_throws{type = '$1',
- defs = lists:reverse('$2')}.
+ defs = '$2'}.
%% (commented out for now)
%% Header
@@ -297,7 +334,22 @@ union(Ts) ->
end.
annotate(T, A) -> ?add_t_ann(T, A).
-
+
+build_def(S, P, As, T) ->
+ case all_vars(As) of
+ true ->
+ #t_def{name = #t_type{name = #t_name{name = S},
+ args = lists:reverse(As)},
+ type = T};
+ false ->
+ return_error(element(2, P), "variable expected after '('")
+ end.
+
+all_vars([#t_var{} | As]) ->
+ all_vars(As);
+all_vars(As) ->
+ As =:= [].
+
%% ---------------------------------------------------------------------
%% @doc EDoc type specification parsing. Parses the content of
@@ -379,7 +431,7 @@ parse_param(S, L) ->
{S1, S2} = edoc_lib:split_at_space(edoc_lib:strip_space(S)),
case edoc_lib:strip_space(S1) of
"" -> throw_error(parse_param, L);
- Name ->
+ Name ->
Text = edoc_lib:strip_space(S2),
{list_to_atom(Name), edoc_wiki:parse_xml(Text, L)}
end.