aboutsummaryrefslogtreecommitdiffstats
path: root/lib/stdlib/src
diff options
context:
space:
mode:
authorHans Bolinder <[email protected]>2015-03-09 16:25:00 +0100
committerHans Bolinder <[email protected]>2015-04-30 08:47:11 +0200
commit3c2be863bde4965a1ac61092b1348b96397940cb (patch)
tree40f580cef20826854551e48a6c4f33085bfaf6cb /lib/stdlib/src
parent147e8b9bd0b36315f0d8bd38e39c51d93cd9f509 (diff)
downloadotp-3c2be863bde4965a1ac61092b1348b96397940cb.tar.gz
otp-3c2be863bde4965a1ac61092b1348b96397940cb.tar.bz2
otp-3c2be863bde4965a1ac61092b1348b96397940cb.zip
stdlib: Add module erl_anno
Introduce erl_anno, an abstraction of the second element of tokens and tuples in the abstract format. The convention that negative line numbers can be used for silencing compiler warnings will no longer work in OTP 19; instead the annotation 'generated' is to be used.
Diffstat (limited to 'lib/stdlib/src')
-rw-r--r--lib/stdlib/src/Makefile3
-rw-r--r--lib/stdlib/src/erl_anno.erl460
-rw-r--r--lib/stdlib/src/erl_parse.yrl160
-rw-r--r--lib/stdlib/src/stdlib.app.src3
4 files changed, 623 insertions, 3 deletions
diff --git a/lib/stdlib/src/Makefile b/lib/stdlib/src/Makefile
index 1b3744b6fb..baa178e624 100644
--- a/lib/stdlib/src/Makefile
+++ b/lib/stdlib/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2013. All Rights Reserved.
+# Copyright Ericsson AB 1996-2015. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -58,6 +58,7 @@ MODULES= \
edlin \
edlin_expand \
epp \
+ erl_anno \
erl_bits \
erl_compile \
erl_eval \
diff --git a/lib/stdlib/src/erl_anno.erl b/lib/stdlib/src/erl_anno.erl
new file mode 100644
index 0000000000..963b7278a6
--- /dev/null
+++ b/lib/stdlib/src/erl_anno.erl
@@ -0,0 +1,460 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(erl_anno).
+
+-export([new/1, is_anno/1]).
+-export([column/1, end_location/1, file/1, generated/1,
+ line/1, location/1, record/1, text/1]).
+-export([set_file/2, set_generated/2, set_line/2, set_location/2,
+ set_record/2, set_text/2]).
+
+%% To be used when necessary to avoid Dialyzer warnings.
+-export([to_term/1, from_term/1]).
+
+-export_type([anno/0, line/0, column/0, location/0, text/0]).
+
+-export_type([anno_term/0]).
+
+-define(LN(L), is_integer(L)).
+-define(COL(C), (is_integer(C) andalso C >= 1)).
+
+%% Location.
+-define(LCOLUMN(C), ?COL(C)).
+-define(LLINE(L), ?LN(L)).
+
+%% Debug: define DEBUG to make sure that annotations are handled as an
+%% opaque type. Note that all abstract code need to be compiled with
+%% DEBUG=true. See also ./erl_pp.erl.
+
+%-define(DEBUG, true).
+
+-type annotation() :: {'file', filename()}
+ | {'generated', generated()}
+ | {'location', location()}
+ | {'record', record()}
+ | {'text', string()}.
+
+-type anno() :: location() | [annotation(), ...].
+-type anno_term() :: term().
+
+-type column() :: pos_integer().
+-type generated() :: boolean().
+-type filename() :: file:filename_all().
+-type line() :: integer().
+-type location() :: line() | {line(), column()}.
+-type record() :: boolean().
+-type text() :: string().
+
+-ifdef(DEBUG).
+%% Anything 'false' accepted by the compiler.
+-define(ALINE(A), is_reference(A)).
+-define(ACOLUMN(A), is_reference(A)).
+-else.
+-define(ALINE(L), ?LN(L)).
+-define(ACOLUMN(C), ?COL(C)).
+-endif.
+
+-spec to_term(Anno) -> anno_term() when
+ Anno :: anno().
+
+-ifdef(DEBUG).
+to_term(Anno) ->
+ simplify(Anno).
+-else.
+to_term(Anno) ->
+ Anno.
+-endif.
+
+-spec from_term(Term) -> Anno when
+ Term :: anno_term(),
+ Anno :: anno().
+
+-ifdef(DEBUG).
+from_term(Term) when is_list(Term) ->
+ Term;
+from_term(Term) ->
+ [{location, Term}].
+-else.
+from_term(Term) ->
+ Term.
+-endif.
+
+-spec new(Location) -> anno() when
+ Location :: location().
+
+new(Line) when ?LLINE(Line) ->
+ new_location(Line);
+new({Line, Column}=Loc) when ?LLINE(Line), ?LCOLUMN(Column) ->
+ new_location(Loc);
+new(Term) ->
+ erlang:error(badarg, [Term]).
+
+-ifdef(DEBUG).
+new_location(Location) ->
+ [{location, Location}].
+-else.
+new_location(Location) ->
+ Location.
+-endif.
+
+-spec is_anno(Term) -> boolean() when
+ Term :: any().
+
+is_anno(Line) when ?ALINE(Line) ->
+ true;
+is_anno({Line, Column}) when ?ALINE(Line), ?ACOLUMN(Column) ->
+ true;
+is_anno(Anno) ->
+ (Anno =/= [] andalso
+ is_anno1(Anno) andalso
+ lists:keymember(location, 1, Anno)).
+
+is_anno1([{Item, Value}|Anno]) ->
+ is_anno2(Item, Value) andalso is_anno1(Anno);
+is_anno1(A) ->
+ A =:= [].
+
+is_anno2(location, Line) when ?LN(Line) ->
+ true;
+is_anno2(location, {Line, Column}) when ?LN(Line), ?COL(Column) ->
+ true;
+is_anno2(generated, true) ->
+ true;
+is_anno2(file, Filename) ->
+ is_filename(Filename);
+is_anno2(record, true) ->
+ true;
+is_anno2(text, Text) ->
+ is_string(Text);
+is_anno2(_, _) ->
+ false.
+
+is_filename(T) ->
+ is_string(T) orelse is_binary(T).
+
+is_string(T) ->
+ try lists:all(fun(C) when is_integer(C), C >= 0 -> true end, T)
+ catch _:_ -> false
+ end.
+
+-spec column(Anno) -> column() | 'undefined' when
+ Anno :: anno().
+
+column({Line, Column}) when ?ALINE(Line), ?ACOLUMN(Column) ->
+ Column;
+column(Line) when ?ALINE(Line) ->
+ undefined;
+column(Anno) ->
+ case location(Anno) of
+ {_Line, Column} ->
+ Column;
+ _Line ->
+ undefined
+ end.
+
+-spec end_location(Anno) -> location() | 'undefined' when
+ Anno :: anno().
+
+end_location(Anno) ->
+ case text(Anno) of
+ undefined ->
+ undefined;
+ Text ->
+ case location(Anno) of
+ {Line, Column} ->
+ end_location(Text, Line, Column);
+ Line ->
+ end_location(Text, Line)
+ end
+ end.
+
+-spec file(Anno) -> filename() | 'undefined' when
+ Anno :: anno().
+
+file(Line) when ?ALINE(Line) ->
+ undefined;
+file({Line, Column}) when ?ALINE(Line), ?ACOLUMN(Column) ->
+ undefined;
+file(Anno) ->
+ anno_info(Anno, file).
+
+-spec generated(Anno) -> generated() when
+ Anno :: anno().
+
+generated(Line) when ?ALINE(Line) ->
+ Line =< 0;
+generated({Line, Column}) when ?ALINE(Line), ?ACOLUMN(Column) ->
+ Line =< 0;
+generated(Anno) ->
+ _ = anno_info(Anno, generated, false),
+ {location, Location} = lists:keyfind(location, 1, Anno),
+ case Location of
+ {Line, _Column} ->
+ Line =< 0;
+ Line ->
+ Line =< 0
+ end.
+
+-spec line(Anno) -> line() when
+ Anno :: anno().
+
+line(Anno) ->
+ case location(Anno) of
+ {Line, _Column} ->
+ Line;
+ Line ->
+ Line
+ end.
+
+-spec location(Anno) -> location() when
+ Anno :: anno().
+
+location(Line) when ?ALINE(Line) ->
+ abs(Line);
+location({Line, Column}) when ?ALINE(Line), ?ACOLUMN(Column) ->
+ {abs(Line), Column};
+location(Anno) ->
+ case anno_info(Anno, location) of
+ Line when Line < 0 ->
+ -Line;
+ {Line, Column} when Line < 0 ->
+ {-Line, Column};
+ Location ->
+ Location
+ end.
+
+-spec record(Anno) -> record() when
+ Anno :: anno().
+
+record(Line) when ?ALINE(Line) ->
+ false;
+record({Line, Column}) when ?ALINE(Line), ?ACOLUMN(Column) ->
+ false;
+record(Anno) ->
+ anno_info(Anno, record, false).
+
+-spec text(Anno) -> text() | 'undefined' when
+ Anno :: anno().
+
+text(Line) when ?ALINE(Line) ->
+ undefined;
+text({Line, Column}) when ?ALINE(Line), ?ACOLUMN(Column) ->
+ undefined;
+text(Anno) ->
+ anno_info(Anno, text).
+
+-spec set_file(File, Anno) -> Anno when
+ File :: filename(),
+ Anno :: anno().
+
+set_file(File, Anno) ->
+ set(file, File, Anno).
+
+-spec set_generated(Generated, Anno) -> Anno when
+ Generated :: generated(),
+ Anno :: anno().
+
+set_generated(true, Line) when ?ALINE(Line) ->
+ -abs(Line);
+set_generated(false, Line) when ?ALINE(Line) ->
+ abs(Line);
+set_generated(true, {Line, Column}) when ?ALINE(Line),
+ ?ACOLUMN(Column) ->
+ {-abs(Line),Column};
+set_generated(false, {Line, Column}) when ?ALINE(Line),
+ ?ACOLUMN(Column) ->
+ {abs(Line),Column};
+set_generated(Generated, Anno) ->
+ _ = set(generated, Generated, Anno),
+ {location, Location} = lists:keyfind(location, 1, Anno),
+ NewLocation =
+ case Location of
+ {Line, Column} when Generated ->
+ {-abs(Line), Column};
+ {Line, Column} when not Generated ->
+ {abs(Line), Column};
+ Line when Generated ->
+ -abs(Line);
+ Line when not Generated ->
+ abs(Line)
+ end,
+ lists:keyreplace(location, 1, Anno, {location, NewLocation}).
+
+-spec set_line(Line, Anno) -> Anno when
+ Line :: line(),
+ Anno :: anno().
+
+set_line(Line, Anno) ->
+ case location(Anno) of
+ {_Line, Column} ->
+ set_location({Line, Column}, Anno);
+ _Line ->
+ set_location(Line, Anno)
+ end.
+
+-spec set_location(Location, Anno) -> Anno when
+ Location :: location(),
+ Anno :: anno().
+
+set_location(Line, L) when ?ALINE(L), ?LLINE(Line) ->
+ new_location(fix_line(Line, L));
+set_location(Line, {L, Column}) when ?ALINE(L), ?ACOLUMN(Column),
+ ?LLINE(Line) ->
+ new_location(fix_line(Line, L));
+set_location({L, C}=Loc, Line) when ?ALINE(Line), ?LLINE(L), ?LCOLUMN(C) ->
+ new_location(fix_location(Loc, Line));
+set_location({L, C}=Loc, {Line, Column}) when ?ALINE(Line), ?ACOLUMN(Column),
+ ?LLINE(L), ?LCOLUMN(C) ->
+ new_location(fix_location(Loc, Line));
+set_location(Location, Anno) ->
+ _ = set(location, Location, Anno),
+ {location, OldLocation} = lists:keyfind(location, 1, Anno),
+ NewLocation =
+ case {Location, OldLocation} of
+ {{_Line, _Column}=Loc, {L, _C}} ->
+ fix_location(Loc, L);
+ {Line, {L, _C}} ->
+ fix_line(Line, L);
+ {{_Line, _Column}=Loc, L} ->
+ fix_location(Loc, L);
+ {Line, L} ->
+ fix_line(Line, L)
+ end,
+ lists:keyreplace(location, 1, Anno, {location, NewLocation}).
+
+fix_location({Line, Column}, OldLine) ->
+ {fix_line(Line, OldLine), Column}.
+
+fix_line(Line, OldLine) when OldLine < 0, Line > 0 ->
+ -Line;
+fix_line(Line, _OldLine) ->
+ Line.
+
+-spec set_record(Record, Anno) -> Anno when
+ Record :: record(),
+ Anno :: anno().
+
+set_record(Record, Anno) ->
+ set(record, Record, Anno).
+
+-spec set_text(Text, Anno) -> Anno when
+ Text :: text(),
+ Anno :: anno().
+
+set_text(Text, Anno) ->
+ set(text, Text, Anno).
+
+set(Item, Value, Anno) ->
+ case {is_settable(Item, Value), Anno} of
+ {true, Line} when ?ALINE(Line) ->
+ set_anno(Item, Value, [{location, Line}]);
+ {true, {L, C}=Location} when ?ALINE(L), ?ACOLUMN(C) ->
+ set_anno(Item, Value, [{location, Location}]);
+ {true, A} when is_list(A), A =/= [] ->
+ set_anno(Item, Value, Anno);
+ _ ->
+ erlang:error(badarg, [Item, Value, Anno])
+ end.
+
+set_anno(Item, Value, Anno) ->
+ case default(Item, Value) of
+ true ->
+ reset(Anno, Item);
+ false ->
+ R = case anno_info(Anno, Item) of
+ undefined ->
+ [{Item, Value}|Anno];
+ _ ->
+ lists:keyreplace(Item, 1, Anno, {Item, Value})
+ end,
+ simplify(R)
+ end.
+
+reset(Anno, Item) ->
+ A = lists:keydelete(Item, 1, Anno),
+ reset_simplify(A).
+
+-ifdef(DEBUG).
+reset_simplify(A) ->
+ A.
+-else.
+reset_simplify(A) ->
+ simplify(A).
+-endif.
+
+simplify([{location, Location}]) ->
+ Location;
+simplify(Anno) ->
+ Anno.
+
+anno_info(Anno, Item, Default) ->
+ try lists:keyfind(Item, 1, Anno) of
+ false ->
+ Default;
+ {Item, Value} ->
+ Value
+ catch
+ _:_ ->
+ erlang:error(badarg, [Anno])
+ end.
+
+anno_info(Anno, Item) ->
+ try lists:keyfind(Item, 1, Anno) of
+ {Item, Value} ->
+ Value;
+ false ->
+ undefined
+ catch
+ _:_ ->
+ erlang:error(badarg, [Anno])
+ end.
+
+end_location("", Line, Column) ->
+ {Line, Column};
+end_location([$\n|String], Line, _Column) ->
+ end_location(String, Line+1, 1);
+end_location([_|String], Line, Column) ->
+ end_location(String, Line, Column+1).
+
+end_location("", Line) ->
+ Line;
+end_location([$\n|String], Line) ->
+ end_location(String, Line+1);
+end_location([_|String], Line) ->
+ end_location(String, Line).
+
+is_settable(file, File) ->
+ is_filename(File);
+is_settable(generated, Boolean) when Boolean; not Boolean ->
+ true;
+is_settable(location, Line) when ?LLINE(Line) ->
+ true;
+is_settable(location, {Line, Column}) when ?LLINE(Line), ?LCOLUMN(Column) ->
+ true;
+is_settable(record, Boolean) when Boolean; not Boolean ->
+ true;
+is_settable(text, Text) ->
+ is_string(Text);
+is_settable(_, _) ->
+ false.
+
+default(generated, false) -> true;
+default(record, false) -> true;
+default(_, _) -> false.
diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl
index 3502a50eaa..b7469a05da 100644
--- a/lib/stdlib/src/erl_parse.yrl
+++ b/lib/stdlib/src/erl_parse.yrl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -524,6 +524,8 @@ Erlang code.
-export([normalise/1,abstract/1,tokens/1,tokens/2]).
-export([abstract/2]).
-export([inop_prec/1,preop_prec/1,func_prec/0,max_prec/0]).
+-export([map_anno/2, fold_anno/3, mapfold_anno/3,
+ new_anno/1, anno_to_term/1, anno_from_term/1]).
-export([set_line/2,get_attribute/2,get_attributes/1]).
%% The following directive is needed for (significantly) faster compilation
@@ -533,6 +535,7 @@ Erlang code.
-export_type([abstract_clause/0, abstract_expr/0, abstract_form/0,
error_info/0]).
+%% XXX. To be refined.
-type abstract_clause() :: term().
-type abstract_expr() :: term().
-type abstract_form() :: term().
@@ -1101,4 +1104,159 @@ get_attribute(L, Name) ->
get_attributes(L) ->
erl_scan:attributes_info(L).
+-spec map_anno(Fun, Abstr) -> NewAbstr when
+ Fun :: fun((Anno) -> Anno),
+ Anno :: erl_anno:anno(),
+ Abstr :: abstract_form() | abstract_expr(),
+ NewAbstr :: abstract_form() | abstract_expr().
+
+map_anno(F0, Abstr) ->
+ F = fun(A, Acc) -> {F0(A), Acc} end,
+ {NewAbstr, []} = modify_anno1(Abstr, [], F),
+ NewAbstr.
+
+-spec fold_anno(Fun, Acc0, Abstr) -> NewAbstr when
+ Fun :: fun((Anno, AccIn) -> AccOut),
+ Anno :: erl_anno:anno(),
+ Acc0 :: term(),
+ AccIn :: term(),
+ AccOut :: term(),
+ Abstr :: abstract_form() | abstract_expr(),
+ NewAbstr :: abstract_form() | abstract_expr().
+
+fold_anno(F0, Acc0, Abstr) ->
+ F = fun(A, Acc) -> {A, F0(A, Acc)} end,
+ {_, NewAcc} = modify_anno1(Abstr, Acc0, F),
+ NewAcc.
+
+-spec mapfold_anno(Fun, Acc0, Abstr) -> {NewAbstr, Acc1} when
+ Fun :: fun((Anno, AccIn) -> {Anno, AccOut}),
+ Anno :: erl_anno:anno(),
+ Acc0 :: term(),
+ Acc1 :: term(),
+ AccIn :: term(),
+ AccOut :: term(),
+ Abstr :: abstract_form() | abstract_expr(),
+ NewAbstr :: abstract_form() | abstract_expr().
+
+mapfold_anno(F, Acc0, Abstr) ->
+ modify_anno1(Abstr, Acc0, F).
+
+-spec new_anno(Term) -> Abstr when
+ Term :: term(),
+ Abstr :: abstract_form() | abstract_expr().
+
+new_anno(Term) ->
+ F = fun(Loc) -> erl_anno:new(Loc) end,
+ map_anno(F, Term).
+
+-spec anno_to_term(Abstr) -> term() when
+ Abstr :: abstract_form() | abstract_expr().
+
+anno_to_term(Abstract) ->
+ F = fun(Anno) -> erl_anno:to_term(Anno) end,
+ map_anno(F, Abstract).
+
+-spec anno_from_term(Term) -> abstract_form() | abstract_expr() when
+ Term :: term().
+
+anno_from_term(Term) ->
+ F = fun(T) -> erl_anno:from_term(T) end,
+ map_anno(F, Term).
+
+%% Forms.
+%% Recognize what sys_pre_expand does:
+modify_anno1({'fun',A,F,{_,_,_}=Id}, Ac, Mf) ->
+ {A1,Ac1} = Mf(A, Ac),
+ {F1,Ac2} = modify_anno1(F, Ac1, Mf),
+ {{'fun',A1,F1,Id},Ac2};
+modify_anno1({named_fun,A,N,F,{_,_,_}=Id}, Ac, Mf) ->
+ {A1,Ac1} = Mf(A, Ac),
+ {F1,Ac2} = modify_anno1(F, Ac1, Mf),
+ {{named_fun,A1,N,F1,Id},Ac2};
+modify_anno1({attribute,A,N,[V]}, Ac, Mf) ->
+ {{attribute,A1,N1,V1},Ac1} = modify_anno1({attribute,A,N,V}, Ac, Mf),
+ {{attribute,A1,N1,[V1]},Ac1};
+%% End of sys_pre_expand special forms.
+modify_anno1({function,F,A}, Ac, _Mf) ->
+ {{function,F,A},Ac};
+modify_anno1({function,M,F,A}, Ac, Mf) ->
+ {M1,Ac1} = modify_anno1(M, Ac, Mf),
+ {F1,Ac2} = modify_anno1(F, Ac1, Mf),
+ {A1,Ac3} = modify_anno1(A, Ac2, Mf),
+ {{function,M1,F1,A1},Ac3};
+modify_anno1({attribute,A,record,{Name,Fields}}, Ac, Mf) ->
+ {A1,Ac1} = Mf(A, Ac),
+ {Fields1,Ac2} = modify_anno1(Fields, Ac1, Mf),
+ {{attribute,A1,record,{Name,Fields1}},Ac2};
+modify_anno1({attribute,A,spec,{Fun,Types}}, Ac, Mf) ->
+ {A1,Ac1} = Mf(A, Ac),
+ {Types1,Ac2} = modify_anno1(Types, Ac1, Mf),
+ {{attribute,A1,spec,{Fun,Types1}},Ac2};
+modify_anno1({attribute,A,callback,{Fun,Types}}, Ac, Mf) ->
+ {A1,Ac1} = Mf(A, Ac),
+ {Types1,Ac2} = modify_anno1(Types, Ac1, Mf),
+ {{attribute,A1,callback,{Fun,Types1}},Ac2};
+modify_anno1({attribute,A,type,{TypeName,TypeDef,Args}}, Ac, Mf) ->
+ {A1,Ac1} = Mf(A, Ac),
+ {TypeDef1,Ac2} = modify_anno1(TypeDef, Ac1, Mf),
+ {Args1,Ac3} = modify_anno1(Args, Ac2, Mf),
+ {{attribute,A1,type,{TypeName,TypeDef1,Args1}},Ac3};
+modify_anno1({attribute,A,opaque,{TypeName,TypeDef,Args}}, Ac, Mf) ->
+ {A1,Ac1} = Mf(A, Ac),
+ {TypeDef1,Ac2} = modify_anno1(TypeDef, Ac1, Mf),
+ {Args1,Ac3} = modify_anno1(Args, Ac2, Mf),
+ {{attribute,A1,opaque,{TypeName,TypeDef1,Args1}},Ac3};
+modify_anno1({attribute,A,Attr,Val}, Ac, Mf) ->
+ {A1,Ac1} = Mf(A, Ac),
+ {{attribute,A1,Attr,Val},Ac1};
+modify_anno1({warning,W}, Ac, _Mf) ->
+ {{warning,W},Ac};
+modify_anno1({error,W}, Ac, _Mf) ->
+ {{error,W},Ac};
+%% Expressions.
+modify_anno1({clauses,Cs}, Ac, Mf) ->
+ {Cs1,Ac1} = modify_anno1(Cs, Ac, Mf),
+ {{clauses,Cs1},Ac1};
+modify_anno1({typed_record_field,Field,Type}, Ac, Mf) ->
+ {Field1,Ac1} = modify_anno1(Field, Ac, Mf),
+ {Type1,Ac2} = modify_anno1(Type, Ac1, Mf),
+ {{typed_record_field,Field1,Type1},Ac2};
+modify_anno1({Tag,A}, Ac, Mf) ->
+ {A1,Ac1} = Mf(A, Ac),
+ {{Tag,A1},Ac1};
+modify_anno1({Tag,A,E1}, Ac, Mf) ->
+ {A1,Ac1} = Mf(A, Ac),
+ {E11,Ac2} = modify_anno1(E1, Ac1, Mf),
+ {{Tag,A1,E11},Ac2};
+modify_anno1({Tag,A,E1,E2}, Ac, Mf) ->
+ {A1,Ac1} = Mf(A, Ac),
+ {E11,Ac2} = modify_anno1(E1, Ac1, Mf),
+ {E21,Ac3} = modify_anno1(E2, Ac2, Mf),
+ {{Tag,A1,E11,E21},Ac3};
+modify_anno1({bin_element,A,E1,E2,TSL}, Ac, Mf) ->
+ {A1,Ac1} = Mf(A, Ac),
+ {E11,Ac2} = modify_anno1(E1, Ac1, Mf),
+ {E21,Ac3} = modify_anno1(E2, Ac2, Mf),
+ {{bin_element,A1,E11,E21, TSL},Ac3};
+modify_anno1({Tag,A,E1,E2,E3}, Ac, Mf) ->
+ {A1,Ac1} = Mf(A, Ac),
+ {E11,Ac2} = modify_anno1(E1, Ac1, Mf),
+ {E21,Ac3} = modify_anno1(E2, Ac2, Mf),
+ {E31,Ac4} = modify_anno1(E3, Ac3, Mf),
+ {{Tag,A1,E11,E21,E31},Ac4};
+modify_anno1({Tag,A,E1,E2,E3,E4}, Ac, Mf) ->
+ {A1,Ac1} = Mf(A, Ac),
+ {E11,Ac2} = modify_anno1(E1, Ac1, Mf),
+ {E21,Ac3} = modify_anno1(E2, Ac2, Mf),
+ {E31,Ac4} = modify_anno1(E3, Ac3, Mf),
+ {E41,Ac5} = modify_anno1(E4, Ac4, Mf),
+ {{Tag,A1,E11,E21,E31,E41},Ac5};
+modify_anno1([H|T], Ac, Mf) ->
+ {H1,Ac1} = modify_anno1(H, Ac, Mf),
+ {T1,Ac2} = modify_anno1(T, Ac1, Mf),
+ {[H1|T1],Ac2};
+modify_anno1([], Ac, _Mf) -> {[],Ac};
+modify_anno1(E, Ac, _Mf) when not is_tuple(E), not is_list(E) -> {E,Ac}.
+
%% vim: ft=erlang
diff --git a/lib/stdlib/src/stdlib.app.src b/lib/stdlib/src/stdlib.app.src
index a435d683a5..d4d2237b38 100644
--- a/lib/stdlib/src/stdlib.app.src
+++ b/lib/stdlib/src/stdlib.app.src
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -39,6 +39,7 @@
edlin_expand,
epp,
eval_bits,
+ erl_anno,
erl_bits,
erl_compile,
erl_eval,