aboutsummaryrefslogtreecommitdiffstats
path: root/lib/edoc/src/edoc_parser.yrl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/edoc/src/edoc_parser.yrl')
-rw-r--r--lib/edoc/src/edoc_parser.yrl124
1 files changed, 85 insertions, 39 deletions
diff --git a/lib/edoc/src/edoc_parser.yrl b/lib/edoc/src/edoc_parser.yrl
index 0eea8ae66f..4d6428f75b 100644
--- a/lib/edoc/src/edoc_parser.yrl
+++ b/lib/edoc/src/edoc_parser.yrl
@@ -22,23 +22,21 @@
%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
%% USA
%%
-%% Author contact: [email protected]
-%%
-%% $Id$
-%%
+%% Author contact: [email protected]
%% =====================================================================
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 +50,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 +64,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 +90,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 +116,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 +163,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 +187,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 +229,7 @@ etype -> utype: '$1'.
throws -> etype where_defs:
#t_throws{type = '$1',
- defs = lists:reverse('$2')}.
+ defs = '$2'}.
%% (commented out for now)
%% Header
@@ -221,7 +255,7 @@ throws -> etype where_defs:
%% "%% USA"
%% "%%"
%% "%% @private"
-%% "%% @author Richard Carlsson <[email protected]>"
+%% "%% @author Richard Carlsson <[email protected]>"
%% "%% ===================================================================="
%% .
@@ -297,7 +331,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
@@ -310,10 +359,10 @@ parse_spec(S, L) ->
{ok, Spec} ->
Spec;
{error, E} ->
- throw_error(E, L)
+ throw_error({parse_spec, E}, L)
end;
{error, E, _} ->
- throw_error(E, L)
+ throw_error({parse_spec, E}, L)
end.
%% ---------------------------------------------------------------------
@@ -379,7 +428,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.
@@ -404,8 +453,8 @@ parse_throws(S, L) ->
%% ---------------------------------------------------------------------
-throw_error({L, M, D}, _L0) ->
- throw({error,L,{format_error,M,D}});
+-spec throw_error(term(), erl_scan:line()) -> no_return().
+
throw_error({parse_spec, E}, L) ->
throw_error({"specification", E}, L);
throw_error({parse_typedef, E}, L) ->
@@ -417,7 +466,4 @@ throw_error({parse_throws, E}, L) ->
throw_error(parse_param, L) ->
throw({error, L, "missing parameter name"});
throw_error({Where, E}, L) when is_list(Where) ->
- throw({error,L,{"unknown error parsing ~s: ~P.",[Where,E,15]}});
-throw_error(E, L) ->
- %% Just in case.
- throw({error,L,{"unknown parse error: ~P.",[E,15]}}).
+ throw({error,L,{"unknown error parsing ~s: ~P.",[Where,E,15]}}).