diff options
Diffstat (limited to 'lib/edoc/src/edoc_parser.yrl')
-rw-r--r-- | lib/edoc/src/edoc_parser.yrl | 124 |
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]}}). |