aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/asn1/src/asn1ct_imm.erl5
-rw-r--r--lib/common_test/doc/src/install_chapter.xml63
-rw-r--r--lib/common_test/doc/src/run_test_chapter.xml25
-rw-r--r--lib/common_test/install.sh.in53
-rw-r--r--lib/common_test/priv/Makefile.in5
-rw-r--r--lib/common_test/priv/bin/.gitignore0
-rw-r--r--lib/common_test/priv/run_test.in63
-rw-r--r--lib/common_test/src/ct.erl45
-rw-r--r--lib/common_test/src/ct_framework.erl39
-rw-r--r--lib/common_test/src/ct_gen_conn.erl5
-rw-r--r--lib/common_test/src/ct_logs.erl9
-rw-r--r--lib/common_test/src/ct_run.erl32
-rw-r--r--lib/common_test/src/ct_telnet.erl4
-rw-r--r--lib/common_test/src/ct_telnet_client.erl4
-rw-r--r--lib/common_test/src/ct_testspec.erl34
-rw-r--r--lib/common_test/src/ct_util.hrl1
-rw-r--r--lib/common_test/test/ct_auto_compile_SUITE.erl48
-rw-r--r--lib/common_test/test/ct_test_server_if_1_SUITE.erl25
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE_data/tests1/t11_SUITE.erl28
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE_data/tests1/t12_SUITE.erl2
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE_data/tests2/t21_SUITE.erl27
-rw-r--r--lib/compiler/src/beam_bsm.erl4
-rw-r--r--lib/compiler/src/compile.erl10
-rw-r--r--lib/compiler/src/sys_pre_expand.erl5
-rw-r--r--lib/compiler/src/v3_core.erl67
-rw-r--r--lib/compiler/test/compile_SUITE.erl5
-rw-r--r--lib/compiler/test/guard_SUITE.erl17
-rw-r--r--lib/debugger/src/dbg_icmd.erl2
-rw-r--r--lib/debugger/src/dbg_ieval.erl2
-rw-r--r--lib/debugger/src/dbg_iload.erl353
-rw-r--r--lib/debugger/src/int.erl2
-rw-r--r--lib/dialyzer/src/dialyzer_utils.erl7
-rw-r--r--lib/diameter/src/compiler/diameter_codegen.erl4
-rw-r--r--lib/diameter/src/compiler/diameter_forms.hrl14
-rw-r--r--lib/diameter/test/diameter_capx_SUITE.erl12
-rw-r--r--lib/edoc/src/edoc.erl9
-rw-r--r--lib/edoc/src/edoc_layout.erl10
-rw-r--r--lib/edoc/src/edoc_lib.erl2
-rw-r--r--lib/edoc/src/edoc_macros.erl2
-rw-r--r--lib/edoc/src/edoc_parser.yrl4
-rw-r--r--lib/edoc/src/edoc_specs.erl45
-rw-r--r--lib/edoc/src/edoc_tags.erl2
-rw-r--r--lib/erl_docgen/src/docgen_otp_specs.erl12
-rw-r--r--lib/eunit/src/eunit_autoexport.erl11
-rw-r--r--lib/hipe/cerl/cerl_to_icode.erl4
-rw-r--r--lib/inets/src/inets_app/inets_lib.erl2
-rw-r--r--lib/kernel/src/user_drv.erl4
-rw-r--r--lib/kernel/test/code_SUITE.erl7
-rw-r--r--lib/kernel/test/heart_SUITE.erl8
-rw-r--r--lib/parsetools/include/yeccpre.hrl33
-rw-r--r--lib/parsetools/src/leex.erl4
-rw-r--r--lib/parsetools/src/yeccgramm.yrl26
-rw-r--r--lib/parsetools/src/yeccparser.erl114
-rw-r--r--lib/parsetools/test/yecc_SUITE.erl14
-rw-r--r--lib/ssh/doc/src/ssh_channel.xml22
-rw-r--r--lib/ssh/doc/src/ssh_sftp.xml112
-rw-r--r--lib/ssh/src/ssh_connection_handler.erl7
-rw-r--r--lib/ssh/src/ssh_sftp.erl13
-rw-r--r--lib/ssh/test/ssh_connection_SUITE.erl9
-rw-r--r--lib/ssh/test/ssh_test_lib.erl15
-rw-r--r--lib/ssh/test/ssh_to_openssh_SUITE.erl4
-rw-r--r--lib/ssh/vsn.mk2
-rw-r--r--lib/ssl/doc/src/Makefile2
-rw-r--r--lib/ssl/doc/src/ssl.xml39
-rw-r--r--lib/ssl/doc/src/ssl_app.xml16
-rw-r--r--lib/ssl/doc/src/ssl_crl_cache.xml6
-rw-r--r--lib/ssl/doc/src/ssl_crl_cache_api.xml2
-rw-r--r--lib/ssl/doc/src/ssl_distribution.xml38
-rw-r--r--lib/ssl/doc/src/ssl_protocol.xml10
-rw-r--r--lib/ssl/doc/src/ssl_session_cache_api.xml4
-rw-r--r--lib/ssl/doc/src/using_ssl.xml4
-rw-r--r--lib/stdlib/doc/src/Makefile3
-rw-r--r--lib/stdlib/doc/src/erl_anno.xml308
-rw-r--r--lib/stdlib/doc/src/erl_parse.xml98
-rw-r--r--lib/stdlib/doc/src/erl_scan.xml79
-rw-r--r--lib/stdlib/doc/src/ref_man.xml3
-rw-r--r--lib/stdlib/doc/src/specs.xml1
-rw-r--r--lib/stdlib/src/Makefile4
-rw-r--r--lib/stdlib/src/beam_lib.erl27
-rw-r--r--lib/stdlib/src/edlin.erl16
-rw-r--r--lib/stdlib/src/epp.erl171
-rw-r--r--lib/stdlib/src/erl_anno.erl460
-rw-r--r--lib/stdlib/src/erl_eval.erl35
-rw-r--r--lib/stdlib/src/erl_expand_records.erl40
-rw-r--r--lib/stdlib/src/erl_lint.erl141
-rw-r--r--lib/stdlib/src/erl_parse.yrl738
-rw-r--r--lib/stdlib/src/erl_pp.erl59
-rw-r--r--lib/stdlib/src/erl_scan.erl227
-rw-r--r--lib/stdlib/src/escript.erl28
-rw-r--r--lib/stdlib/src/io.erl4
-rw-r--r--lib/stdlib/src/ms_transform.erl5
-rw-r--r--lib/stdlib/src/otp_internal.erl66
-rw-r--r--lib/stdlib/src/qlc.erl96
-rw-r--r--lib/stdlib/src/qlc_pt.erl662
-rw-r--r--lib/stdlib/src/shell.erl35
-rw-r--r--lib/stdlib/src/stdlib.app.src3
-rw-r--r--lib/stdlib/test/Makefile1
-rw-r--r--lib/stdlib/test/epp_SUITE.erl52
-rw-r--r--lib/stdlib/test/erl_anno_SUITE.erl569
-rw-r--r--lib/stdlib/test/erl_lint_SUITE.erl40
-rw-r--r--lib/stdlib/test/erl_pp_SUITE.erl97
-rw-r--r--lib/stdlib/test/erl_scan_SUITE.erl285
-rw-r--r--lib/stdlib/test/qlc_SUITE.erl141
-rw-r--r--lib/stdlib/test/shell_SUITE.erl11
-rw-r--r--lib/syntax_tools/src/epp_dodger.erl2
-rw-r--r--lib/syntax_tools/src/erl_recomment.erl9
-rw-r--r--lib/test_server/doc/src/Makefile4
-rw-r--r--lib/test_server/src/erl2html2.erl15
-rw-r--r--lib/test_server/src/test_server_ctrl.erl18
-rw-r--r--lib/test_server/src/ts.erl594
-rw-r--r--lib/test_server/src/ts_lib.erl53
-rw-r--r--lib/tools/src/cover.erl40
-rw-r--r--lib/tools/src/xref.hrl4
-rw-r--r--lib/tools/src/xref_compiler.erl4
-rw-r--r--lib/tools/src/xref_reader.erl26
-rw-r--r--lib/tools/src/xref_scanner.erl6
-rw-r--r--lib/webtool/doc/src/Makefile4
-rw-r--r--lib/wx/api_gen/wx_gen_cpp.erl4
-rw-r--r--lib/wx/api_gen/wxapi.conf44
-rw-r--r--lib/wx/c_src/gen/wxe_events.cpp59
-rw-r--r--lib/wx/c_src/gen/wxe_funcs.cpp6
-rw-r--r--lib/wx/c_src/wxe_gl.cpp8
-rw-r--r--lib/wx/c_src/wxe_helpers.cpp167
-rw-r--r--lib/wx/c_src/wxe_helpers.h30
-rw-r--r--lib/wx/c_src/wxe_impl.cpp298
-rw-r--r--lib/wx/c_src/wxe_impl.h6
-rw-r--r--lib/wx/examples/demo/demo_html_tagger.erl8
-rw-r--r--lib/wx/include/wx.hrl44
-rw-r--r--lib/wx/test/wx_class_SUITE.erl14
-rw-r--r--lib/wx/test/wx_event_SUITE.erl42
130 files changed, 5204 insertions, 2449 deletions
diff --git a/lib/asn1/src/asn1ct_imm.erl b/lib/asn1/src/asn1ct_imm.erl
index 5bf69e9294..5297d5291c 100644
--- a/lib/asn1/src/asn1ct_imm.erl
+++ b/lib/asn1/src/asn1ct_imm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2012-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
@@ -2439,7 +2439,8 @@ bit_string_name2pos_fun(NNL, Src) ->
gen_name2pos(Fd, Name, Names) ->
Cs0 = gen_name2pos_cs(Names, Name),
Cs = Cs0 ++ [bit_clause(Name),nil_clause(),invalid_clause()],
- F = {function,1,Name,1,Cs},
+ F0 = {function,1,Name,1,Cs},
+ F = erl_parse:new_anno(F0),
file:write(Fd, [erl_pp:function(F)]).
gen_name2pos_cs([{K,V}|T], Name) ->
diff --git a/lib/common_test/doc/src/install_chapter.xml b/lib/common_test/doc/src/install_chapter.xml
index 7f8c606324..31125b945c 100644
--- a/lib/common_test/doc/src/install_chapter.xml
+++ b/lib/common_test/doc/src/install_chapter.xml
@@ -34,7 +34,7 @@
<title>General information</title>
<p>The two main interfaces for running tests with Common Test
- are an executable program named ct_run and an
+ are an executable program named <c>ct_run</c> and an
erlang module named <c>ct</c>. The ct_run program
is compiled for the underlying operating system (e.g. Unix/Linux
or Windows) during the build of the Erlang/OTP system, and is
@@ -43,67 +43,10 @@
The <c>ct</c> interface functions can be called from the Erlang shell,
or from any Erlang function, on any supported platform.</p>
- <p>A legacy Bourne shell script - named run_test - exists,
- which may be manually generated and installed. This script may be used
- instead of the ct_run program mentioned above, e.g. if the user
- wishes to modify or customize the Common Test start flags in a simpler
- way than making changes to the ct_run C program.</p>
-
<p>The Common Test application is installed with the Erlang/OTP
system and no additional installation step is required to start using
- Common Test by means of the ct_run executable program, and/or the interface
- functions in the <c>ct</c> module. If you wish to use the legacy Bourne
- shell script version run_test, however, this script needs to be
- generated first, according to the instructions below.</p>
-
- <note><p>Before reading on, please note that since Common Test version
- 1.5, the run_test shell script is no longer required for starting
- tests with Common Test from the OS command line. The ct_run
- program (descibed above) is the new recommended command line interface
- for Common Test. The shell script exists mainly for legacy reasons and
- may not be updated in future releases of Common Test. It may even be removed.
- </p></note>
-
- <p>Optional step to generate a shell script for starting Common Test:</p>
- <p>To generate the run_test shell script, navigate to the
- <c><![CDATA[common_test-<vsn>]]></c> directory, located among the other
- OTP applications (under the OTP lib directory). Here execute the
- <c>install.sh</c> script with argument <c>local</c>:</p>
-
- <p><c>
- $ ./install.sh local
- </c></p>
-
- <p>This generates the executable run_test script in the
- <c><![CDATA[common_test-<vsn>/priv/bin]]></c> directory. The script
- will include absolute paths to the Common Test and Test Server
- application directories, so it's possible to copy or move the script to
- a different location on the file system, if desired, without having to
- update it. It's of course possible to leave the script under the
- <c>priv/bin</c> directory and update the PATH variable accordingly (or
- create a link or alias to it).</p>
-
- <p>If you, for any reason, have copied Common Test and Test Server
- to a different location than the default OTP lib directory, you can
- generate a run_test script with a different top level directory,
- simply by specifying the directory, instead of <c>local</c>, when running
- <c>install.sh</c>. Example:</p>
-
- <p><c>
- $ install.sh /usr/local/test_tools
- </c></p>
-
- <p>Note that the <c><![CDATA[common_test-<vsn>]]></c> and
- <c><![CDATA[test_server-<vsn>]]></c> directories must be located under the
- same top directory. Note also that the install script does not copy files
- or update environment variables. It only generates the run_test
- script.</p>
-
- <p>Whenever you install a new version of Erlang/OTP, the run_test
- script needs to be regenerated, or updated manually with new directory names
- (new version numbers), for it to "see" the latest Common Test and Test Server
- versions.</p>
-
+ Common Test by means of the <c>ct_run</c> executable program, and/or
+ the interface functions in the <c>ct</c> module.</p>
</section>
</chapter>
diff --git a/lib/common_test/doc/src/run_test_chapter.xml b/lib/common_test/doc/src/run_test_chapter.xml
index 864f82cb63..df60e5f7f2 100644
--- a/lib/common_test/doc/src/run_test_chapter.xml
+++ b/lib/common_test/doc/src/run_test_chapter.xml
@@ -1005,6 +1005,31 @@
for starting the tests, the relaxed scanner
mode is enabled by means of the tuple: <c>{allow_user_terms,true}</c></p>
</section>
+ <section>
+ <title>Reading test specification terms</title>
+ <p>It's possible to look up terms in the current test specification
+ (i.e. the spec that's been used to configure and run the current test).
+ The function <c>get_testspec_terms()</c> returns a list of all test spec
+ terms (both config- and test terms) and <c>get_testspec_terms(Tags)</c>
+ returns the term (or a list of terms) matching the tag (or tags) in
+ <c>Tags</c>.</p>
+ <p>For example, in the test specification:</p>
+ <pre>
+ ...
+ {label, my_server_smoke_test}.
+ {config, "../../my_server_setup.cfg"}.
+ {config, "../../my_server_interface.cfg"}.
+ ...</pre>
+ <p>And in e.g. a test suite or a CT hook function:</p>
+ <pre>
+ ...
+ [{label,[{_Node,TestType}]}, {config,CfgFiles}] =
+ ct:get_testspec_terms([label,config]),
+
+ [verify_my_server_cfg(TestType, CfgFile) || {Node,CfgFile} &lt;- CfgFiles,
+ Node == node()];
+ ...</pre>
+ </section>
</section>
<section>
diff --git a/lib/common_test/install.sh.in b/lib/common_test/install.sh.in
deleted file mode 100644
index 5108c7a259..0000000000
--- a/lib/common_test/install.sh.in
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/bin/sh
-
-CT_ROOT=$1
-CT_VSN=@CT_VSN@
-TS_VSN=@TS_VSN@
-
-if [ -z "$CT_ROOT" ]
-then
- echo "install.sh: need CT_ROOT (absolute) directory or 'local' as argument"
- exit 1
-fi
-
-if [ $CT_ROOT = "local" ]
-then
- CT_DIR=`pwd`
- cd priv
- sed -e "s,@CTPATH@,$CT_DIR/ebin," \
- -e "s,@TSPATH@,$CT_DIR/../test_server/ebin," \
- run_test.in > bin/run_test
- chmod 775 bin/run_test
- echo "install successful, start script created in " $CT_ROOT/common_test-$CT_VSN/priv/bin
-else
-
- if [ ! -d "$CT_ROOT" ]
- then
- echo "install.sh: CT_ROOT argument must be a valid directory"
- exit 1
- fi
-
- if [ `echo $CT_ROOT | awk '{ print substr($1,1,1) }'` != "/" ]
- then
- echo "install.sh: need an absolute path to CT_ROOT"
- exit 1
- fi
-
- if [ ! -d $CT_ROOT/common_test-$CT_VSN ]
- then
- echo "install.sh: The directory $CT_ROOT/common_test-$CT_VSN does not exist"
- exit 1
- fi
-
- if [ -d $CT_ROOT/common_test-$CT_VSN/priv ]
- then
- cd $CT_ROOT/common_test-$CT_VSN/priv
- sed -e "s;@CTPATH@;$CT_ROOT/common_test-$CT_VSN/ebin;" \
- -e "s;@TSPATH@;$CT_ROOT/test_server-$TS_VSN/ebin;" \
- run_test.in > bin/run_test
- chmod 775 bin/run_test
- echo "install successful, start script created in " $CT_ROOT/common_test-$CT_VSN/priv/bin
- fi
-fi
-
-
diff --git a/lib/common_test/priv/Makefile.in b/lib/common_test/priv/Makefile.in
index 1bc6b82ebb..7765b06f95 100644
--- a/lib/common_test/priv/Makefile.in
+++ b/lib/common_test/priv/Makefile.in
@@ -66,12 +66,7 @@ JS = jquery-latest.js jquery.tablesorter.min.js
# Rules
#
-include ../../test_server/vsn.mk
debug opt:
- $(V_at)sed -e 's;@CT_VSN@;$(VSN);' \
- -e 's;@TS_VSN@;$(TEST_SERVER_VSN);' \
- ../install.sh.in > install.sh
- - $(V_at)chmod -f 775 install.sh
docs:
diff --git a/lib/common_test/priv/bin/.gitignore b/lib/common_test/priv/bin/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/common_test/priv/bin/.gitignore
+++ /dev/null
diff --git a/lib/common_test/priv/run_test.in b/lib/common_test/priv/run_test.in
deleted file mode 100644
index 1508751e4f..0000000000
--- a/lib/common_test/priv/run_test.in
+++ /dev/null
@@ -1,63 +0,0 @@
-#!/bin/sh
-
-args=""
-
-while [ $1 ]; do
- if [ $1 = "-config" ]; then
- args="$args -ct_config";
- elif [ $1 = "-decrypt_key" ]; then
- args="$args -ct_decrypt_key";
- elif [ $1 = "-decrypt_file" ]; then
- args="$args -ct_decrypt_file";
- elif [ $1 = "-vts" ]; then
- vts=1;
- args="$args $1";
- elif [ $1 = "-browser" ]; then
- browser=$2;
- args="$args $1";
- elif [ $1 = "-shell" ]; then
- shell=1;
- args="$args $1";
- elif [ $1 = "-ctname" ]; then
- ctname=$2;
- args="$args";
- elif [ $1 = "-ctmaster" ]; then
- master=1;
- args="$args";
- else
- args="$args $1"
- fi
- shift
-done
-
-if [ $vts ]; then
- erl -sname ct \
- -pa @CTPATH@ \
- -pa @TSPATH@ \
- -s webtool script_start vts $browser \
- -s ct_run script_start \
- $args;
-elif [ $shell ]; then
- erl -sname ct \
- -pa @CTPATH@ \
- -pa @TSPATH@ \
- -s ct_run script_start \
- $args;
-elif [ $ctname ]; then
- erl -sname $ctname \
- -pa @CTPATH@ \
- -pa @TSPATH@ \
- $args;
-elif [ $master ]; then
- erl -sname ct_master \
- -pa @CTPATH@ \
- -pa @TSPATH@ \
- $args;
-else
- erl -sname ct \
- -pa @CTPATH@ \
- -pa @TSPATH@ \
- -s ct_run script_start \
- -s erlang halt \
- $args
-fi
diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl
index 9d8fce2789..5ed1346f1e 100644
--- a/lib/common_test/src/ct.erl
+++ b/lib/common_test/src/ct.erl
@@ -79,6 +79,7 @@
%% Other interface functions
-export([get_status/0, abort_current_testcase/1,
get_event_mgr_ref/0,
+ get_testspec_terms/0, get_testspec_terms/1,
encrypt_config_file/2, encrypt_config_file/3,
decrypt_config_file/2, decrypt_config_file/3]).
@@ -463,6 +464,50 @@ reload_config(Required)->
ct_config:reload_config(Required).
%%%-----------------------------------------------------------------
+%%% @spec get_testspec_terms() -> TestSpecTerms | undefined
+%%% TestSpecTerms = [{Tag,Value}]
+%%% Value = [term()]
+%%%
+%%% @doc Get a list of all test specification terms used to
+%%% configure and run this test.
+%%%
+get_testspec_terms() ->
+ case ct_util:get_testdata(testspec) of
+ undefined ->
+ undefined;
+ CurrSpecRec ->
+ ct_testspec:testspec_rec2list(CurrSpecRec)
+ end.
+
+%%%-----------------------------------------------------------------
+%%% @spec get_testspec_terms(Tags) -> TestSpecTerms | undefined
+%%% Tags = [Tag] | Tag
+%%% Tag = atom()
+%%% TestSpecTerms = [{Tag,Value}] | {Tag,Value}
+%%% Value = [{Node,term()}] | [term()]
+%%% Node = atom()
+%%%
+%%% @doc Read one or more terms from the test specification used
+%%% to configure and run this test. Tag is any valid test specification
+%%% tag, such as e.g. <c>label</c>, <c>config</c>, <c>logdir</c>.
+%%% User specific terms are also available to read if the
+%%% <c>allow_user_terms</c> option has been set. Note that all value tuples
+%%% returned, except user terms, will have the node name as first element.
+%%% Note also that in order to read test terms, use <c>Tag = tests</c>
+%%% (rather than <c>suites</c>, <c>groups</c> or <c>cases</c>). Value is
+%%% then the list of *all* tests on the form:
+%%% <c>[{Node,Dir,[{TestSpec,GroupsAndCases1},...]},...], where
+%%% GroupsAndCases = [{Group,[Case]}] | [Case]</c>.
+get_testspec_terms(Tags) ->
+ case ct_util:get_testdata(testspec) of
+ undefined ->
+ undefined;
+ CurrSpecRec ->
+ ct_testspec:testspec_rec2list(Tags, CurrSpecRec)
+ end.
+
+
+%%%-----------------------------------------------------------------
%%% @spec log(Format) -> ok
%%% @equiv log(default,50,Format,[])
log(Format) ->
diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl
index ea3d7c8218..91368d3137 100644
--- a/lib/common_test/src/ct_framework.erl
+++ b/lib/common_test/src/ct_framework.erl
@@ -113,6 +113,7 @@ init_tc1(?MODULE,_,error_in_suite,[Config0]) when is_list(Config0) ->
ct_event:notify(#event{name=tc_start,
node=node(),
data={?MODULE,error_in_suite}}),
+ ct_suite_init(?MODULE, error_in_suite, [], Config0),
case ?val(error, Config0) of
undefined ->
{fail,"unknown_error_in_suite"};
@@ -635,7 +636,20 @@ try_set_default(Name,Key,Info,Where) ->
end_tc(Mod, Fun, Args) ->
%% Have to keep end_tc/3 for backwards compatibility issues
end_tc(Mod, Fun, Args, '$end_tc_dummy').
-end_tc(?MODULE,error_in_suite,_, _) -> % bad start!
+end_tc(?MODULE,error_in_suite,{Result,[Args]},Return) ->
+ %% this clause gets called if CT has encountered a suite that
+ %% can't be executed
+ FinalNotify =
+ case ct_hooks:end_tc(?MODULE, error_in_suite, Args, Result, Return) of
+ '$ct_no_change' ->
+ Result;
+ HookResult ->
+ HookResult
+ end,
+ Event = #event{name=tc_done,
+ node=node(),
+ data={?MODULE,error_in_suite,tag(FinalNotify)}},
+ ct_event:sync_notify(Event),
ok;
end_tc(Mod,Func,{TCPid,Result,[Args]}, Return) when is_pid(TCPid) ->
end_tc(Mod,Func,TCPid,Result,Args,Return);
@@ -1062,18 +1076,35 @@ get_all_cases1(_, []) ->
get_all(Mod, ConfTests) ->
case catch apply(Mod, all, []) of
- {'EXIT',_} ->
+ {'EXIT',{undef,[{Mod,all,[],_} | _]}} ->
Reason =
case code:which(Mod) of
non_existing ->
list_to_atom(atom_to_list(Mod)++
- " can not be compiled or loaded");
+ " can not be compiled or loaded");
_ ->
list_to_atom(atom_to_list(Mod)++":all/0 is missing")
end,
%% this makes test_server call error_in_suite as first
%% (and only) test case so we can report Reason properly
[{?MODULE,error_in_suite,[[{error,Reason}]]}];
+ {'EXIT',ExitReason} ->
+ case ct_util:get_testdata({error_in_suite,Mod}) of
+ undefined ->
+ ErrStr = io_lib:format("~n*** ERROR *** "
+ "~w:all/0 failed: ~p~n",
+ [Mod,ExitReason]),
+ io:format(user, ErrStr, []),
+ %% save the error info so it doesn't get printed twice
+ ct_util:set_testdata_async({{error_in_suite,Mod},
+ ExitReason});
+ _ExitReason ->
+ ct_util:delete_testdata({error_in_suite,Mod})
+ end,
+ Reason = list_to_atom(atom_to_list(Mod)++":all/0 failed"),
+ %% this makes test_server call error_in_suite as first
+ %% (and only) test case so we can report Reason properly
+ [{?MODULE,error_in_suite,[[{error,Reason}]]}];
AllTCs when is_list(AllTCs) ->
case catch save_seqs(Mod,AllTCs) of
{error,What} ->
@@ -1293,6 +1324,8 @@ report(What,Data) ->
end,
ct_logs:unregister_groupleader(ReportingPid),
case {Func,Result} of
+ {error_in_suite,_} when Suite == ?MODULE ->
+ ok;
{init_per_suite,_} ->
ok;
{end_per_suite,_} ->
diff --git a/lib/common_test/src/ct_gen_conn.erl b/lib/common_test/src/ct_gen_conn.erl
index 56082086f6..8da10ee0f3 100644
--- a/lib/common_test/src/ct_gen_conn.erl
+++ b/lib/common_test/src/ct_gen_conn.erl
@@ -24,10 +24,9 @@
-module(ct_gen_conn).
--compile(export_all).
-
--export([start/4, stop/1, get_conn_pid/1]).
+-export([start/4, stop/1, get_conn_pid/1, check_opts/1]).
-export([call/2, call/3, return/2, do_within_time/2]).
+-export([log/3, start_log/1, cont_log/2, end_log/0]).
%%----------------------------------------------------------------------
%% Exported types
diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl
index 4d5a75d354..7c8c720e13 100644
--- a/lib/common_test/src/ct_logs.erl
+++ b/lib/common_test/src/ct_logs.erl
@@ -2054,6 +2054,13 @@ runentry(Dir, Totals={Node,Label,Logs,
?testname_width-3)),
lists:flatten(io_lib:format("~ts...",[Trunc]))
end,
+ TotMissingStr =
+ if NotBuilt > 0 ->
+ ["<font color=\"red\">",
+ integer_to_list(NotBuilt),"</font>"];
+ true ->
+ integer_to_list(NotBuilt)
+ end,
Total = TotSucc+TotFail+AllSkip,
A = xhtml(["<td align=center><font size=\"-1\">",Node,
"</font></td>\n",
@@ -2073,7 +2080,7 @@ runentry(Dir, Totals={Node,Label,Logs,
"<td align=right>",TotFailStr,"</td>\n",
"<td align=right>",integer_to_list(AllSkip),
" (",UserSkipStr,"/",AutoSkipStr,")</td>\n",
- "<td align=right>",integer_to_list(NotBuilt),"</td>\n"],
+ "<td align=right>",TotMissingStr,"</td>\n"],
TotalsStr = A++B++C,
XHTML = [xhtml("<tr>\n", ["<tr class=\"",odd_or_even(),"\">\n"]),
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index 4d74fd6a80..33c4f352b0 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -77,7 +77,8 @@
multiply_timetraps = 1,
scale_timetraps = false,
create_priv_dir,
- testspecs = [],
+ testspec_files = [],
+ current_testspec,
tests,
starter}).
@@ -485,8 +486,11 @@ execute_one_spec(TS, Opts, Args) ->
case check_and_install_configfiles(AllConfig, TheLogDir, Opts) of
ok -> % read tests from spec
{Run,Skip} = ct_testspec:prepare_tests(TS, node()),
- do_run(Run, Skip, Opts#opts{config=AllConfig,
- logdir=TheLogDir}, Args);
+ Result = do_run(Run, Skip, Opts#opts{config=AllConfig,
+ logdir=TheLogDir,
+ current_testspec=TS}, Args),
+ ct_util:delete_testdata(testspec),
+ Result;
Error ->
Error
end.
@@ -577,7 +581,7 @@ combine_test_opts(TS, Specs, Opts) ->
Opts#opts{label = Label,
profile = Profile,
- testspecs = Specs,
+ testspec_files = Specs,
cover = Cover,
cover_stop = CoverStop,
logdir = which(logdir, LogDir),
@@ -702,7 +706,7 @@ script_start4(#opts{label = Label, profile = Profile,
logopts = LogOpts,
verbosity = Verbosity,
enable_builtin_hooks = EnableBuiltinHooks,
- logdir = LogDir, testspecs = Specs}, _Args) ->
+ logdir = LogDir, testspec_files = Specs}, _Args) ->
%% label - used by ct_logs
application:set_env(common_test, test_label, Label),
@@ -1103,7 +1107,7 @@ run_test2(StartOpts) ->
undefined ->
case lists:keysearch(prepared_tests, 1, StartOpts) of
{value,{_,{Run,Skip},Specs}} -> % use prepared tests
- run_prepared(Run, Skip, Opts#opts{testspecs = Specs},
+ run_prepared(Run, Skip, Opts#opts{testspec_files = Specs},
StartOpts);
false ->
run_dir(Opts, StartOpts)
@@ -1111,11 +1115,11 @@ run_test2(StartOpts) ->
Specs ->
Relaxed = get_start_opt(allow_user_terms, value, false, StartOpts),
%% using testspec(s) as input for test
- run_spec_file(Relaxed, Opts#opts{testspecs = Specs}, StartOpts)
+ run_spec_file(Relaxed, Opts#opts{testspec_files = Specs}, StartOpts)
end.
run_spec_file(Relaxed,
- Opts = #opts{testspecs = Specs},
+ Opts = #opts{testspec_files = Specs},
StartOpts) ->
Specs1 = case Specs of
[X|_] when is_integer(X) -> [Specs];
@@ -1154,7 +1158,10 @@ run_all_specs([{Specs,TS} | TSs], Opts, StartOpts, TotResult) ->
log_ts_names(Specs),
Combined = #opts{config = TSConfig} = combine_test_opts(TS, Specs, Opts),
AllConfig = merge_vals([Opts#opts.config, TSConfig]),
- try run_one_spec(TS, Combined#opts{config = AllConfig}, StartOpts) of
+ try run_one_spec(TS,
+ Combined#opts{config = AllConfig,
+ current_testspec=TS},
+ StartOpts) of
Result ->
run_all_specs(TSs, Opts, StartOpts, [Result | TotResult])
catch
@@ -1399,7 +1406,7 @@ run_testspec2(TestSpec) ->
case check_and_install_configfiles(
Opts#opts.config, LogDir1, Opts) of
ok ->
- Opts1 = Opts#opts{testspecs = [],
+ Opts1 = Opts#opts{testspec_files = [],
logdir = LogDir1,
include = AllInclude},
{Run,Skip} = ct_testspec:prepare_tests(TS, node()),
@@ -1706,6 +1713,9 @@ compile_and_run(Tests, Skip, Opts, Args) ->
ct_util:set_testdata({stylesheet,Opts#opts.stylesheet}),
%% save logopts
ct_util:set_testdata({logopts,Opts#opts.logopts}),
+ %% save info about current testspec (testspec record or undefined)
+ ct_util:set_testdata({testspec,Opts#opts.current_testspec}),
+
%% enable silent connections
case Opts#opts.silent_connections of
[] ->
@@ -1720,7 +1730,7 @@ compile_and_run(Tests, Skip, Opts, Args) ->
ct_logs:log("Silent connections", "~p", [Conns])
end
end,
- log_ts_names(Opts#opts.testspecs),
+ log_ts_names(Opts#opts.testspec_files),
TestSuites = suite_tuples(Tests),
{_TestSuites1,SuiteMakeErrors,AllMakeErrors} =
diff --git a/lib/common_test/src/ct_telnet.erl b/lib/common_test/src/ct_telnet.erl
index d906a267a1..96af55195f 100644
--- a/lib/common_test/src/ct_telnet.erl
+++ b/lib/common_test/src/ct_telnet.erl
@@ -29,7 +29,7 @@
%% Command timeout = 10 sec (time to wait for a command to return)
%% Max no of reconnection attempts = 3
%% Reconnection interval = 5 sek (time to wait in between reconnection attempts)
-%% Keep alive = true (will send NOP to the server every 10 sec if connection is idle)
+%% Keep alive = true (will send NOP to the server every 8 sec if connection is idle)
%% Polling limit = 0 (max number of times to poll to get a remaining string terminated)
%% Polling interval = 1 sec (sleep time between polls)</pre>
%% <p>These parameters can be altered by the user with the following
@@ -1007,7 +1007,7 @@ silent_teln_expect(Name,Pid,Data,Pattern,Prx,Opts) ->
put(silent,Old),
Result.
-%% teln_expect/5
+%% teln_expect/6
%%
%% This function implements the expect functionality over telnet. In
%% general there are three possible ways to go:
diff --git a/lib/common_test/src/ct_telnet_client.erl b/lib/common_test/src/ct_telnet_client.erl
index b0734d8d65..757ccc0aae 100644
--- a/lib/common_test/src/ct_telnet_client.erl
+++ b/lib/common_test/src/ct_telnet_client.erl
@@ -39,7 +39,7 @@
-define(TELNET_PORT, 23).
-define(OPEN_TIMEOUT,10000).
--define(IDLE_TIMEOUT,10000).
+-define(IDLE_TIMEOUT,8000).
%% telnet control characters
-define(SE, 240).
@@ -114,7 +114,7 @@ get_data(Pid) ->
%%%-----------------------------------------------------------------
%%% Internal functions
init(Parent, Server, Port, Timeout, KeepAlive, ConnName) ->
- case gen_tcp:connect(Server, Port, [list,{packet,0}], Timeout) of
+ case gen_tcp:connect(Server, Port, [list,{packet,0},{nodelay,true}], Timeout) of
{ok,Sock} ->
dbg("~p connected to: ~p (port: ~w, keep_alive: ~w)\n",
[ConnName,Server,Port,KeepAlive]),
diff --git a/lib/common_test/src/ct_testspec.erl b/lib/common_test/src/ct_testspec.erl
index 10a9bdac67..10c3f2a938 100644
--- a/lib/common_test/src/ct_testspec.erl
+++ b/lib/common_test/src/ct_testspec.erl
@@ -27,6 +27,8 @@
collect_tests_from_list/2, collect_tests_from_list/3,
collect_tests_from_file/2, collect_tests_from_file/3]).
+-export([testspec_rec2list/1, testspec_rec2list/2]).
+
-include("ct_util.hrl").
-define(testspec_fields, record_info(fields, testspec)).
@@ -973,7 +975,8 @@ add_tests([Term={Tag,all_nodes,Data}|Ts],Spec) ->
should_be_added(Tag,Node,Data,Spec)],
add_tests(Tests++Ts,Spec);
invalid -> % ignore term
- add_tests(Ts,Spec)
+ Unknown = Spec#testspec.unknown,
+ add_tests(Ts,Spec#testspec{unknown=Unknown++[Term]})
end;
%% create one test entry per node in Nodes and reinsert
add_tests([{Tag,[],Data}|Ts],Spec) ->
@@ -1001,7 +1004,8 @@ add_tests([Term={Tag,NodeOrOther,Data}|Ts],Spec) ->
handle_data(Tag,Node,Data,Spec),
add_tests(Ts,mod_field(Spec,Tag,NodeIxData));
invalid -> % ignore term
- add_tests(Ts,Spec)
+ Unknown = Spec#testspec.unknown,
+ add_tests(Ts,Spec#testspec{unknown=Unknown++[Term]})
end;
false ->
add_tests([{Tag,all_nodes,{NodeOrOther,Data}}|Ts],Spec)
@@ -1012,13 +1016,15 @@ add_tests([Term={Tag,Data}|Ts],Spec) ->
valid ->
add_tests([{Tag,all_nodes,Data}|Ts],Spec);
invalid ->
- add_tests(Ts,Spec)
+ Unknown = Spec#testspec.unknown,
+ add_tests(Ts,Spec#testspec{unknown=Unknown++[Term]})
end;
%% some other data than a tuple
add_tests([Other|Ts],Spec) ->
case get(relaxed) of
- true ->
- add_tests(Ts,Spec);
+ true ->
+ Unknown = Spec#testspec.unknown,
+ add_tests(Ts,Spec#testspec{unknown=Unknown++[Other]});
false ->
throw({error,{undefined_term_in_spec,Other}})
end;
@@ -1149,6 +1155,24 @@ per_node([N|Ns],Tag,Data,Refs) ->
per_node([],_,_,_) ->
[].
+%% Change the testspec record "back" to a list of tuples
+testspec_rec2list(Rec) ->
+ {Terms,_} = lists:mapfoldl(fun(unknown, Pos) ->
+ {element(Pos, Rec),Pos+1};
+ (F, Pos) ->
+ {{F,element(Pos, Rec)},Pos+1}
+ end,2,?testspec_fields),
+ lists:flatten(Terms).
+
+%% Extract one or more values from a testspec record and
+%% return the result as a list of tuples
+testspec_rec2list(Field, Rec) when is_atom(Field) ->
+ [Term] = testspec_rec2list([Field], Rec),
+ Term;
+testspec_rec2list(Fields, Rec) ->
+ Terms = testspec_rec2list(Rec),
+ [{Field,proplists:get_value(Field, Terms)} || Field <- Fields].
+
%% read the value for FieldName in record Rec#testspec
read_field(Rec, FieldName) ->
catch lists:foldl(fun(F, Pos) when F == FieldName ->
diff --git a/lib/common_test/src/ct_util.hrl b/lib/common_test/src/ct_util.hrl
index 845bb55486..f4cf407856 100644
--- a/lib/common_test/src/ct_util.hrl
+++ b/lib/common_test/src/ct_util.hrl
@@ -55,6 +55,7 @@
create_priv_dir=[],
alias=[],
tests=[],
+ unknown=[],
merge_tests=true}).
-record(cover, {app=none,
diff --git a/lib/common_test/test/ct_auto_compile_SUITE.erl b/lib/common_test/test/ct_auto_compile_SUITE.erl
index cc546ed30d..3e4da31ab4 100644
--- a/lib/common_test/test/ct_auto_compile_SUITE.erl
+++ b/lib/common_test/test/ct_auto_compile_SUITE.erl
@@ -108,6 +108,8 @@ ac_spec(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
file:copy(filename:join(DataDir, "bad_SUITE.erl"),
filename:join(PrivDir, "bad_SUITE.erl")),
+ Suite = filename:join(DataDir, "dummy_SUITE"),
+ compile:file(Suite, [{outdir,PrivDir}]),
TestSpec = [{label,ac_spec},
{auto_compile,false},
{suites,PrivDir,all}],
@@ -160,28 +162,34 @@ events_to_check(Test, N) ->
test_events(ac_flag) ->
[
- {ct_test_support_eh,start_logging,{'DEF','RUNDIR'}},
- {ct_test_support_eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
- {ct_test_support_eh,start_info,{1,1,3}},
- {ct_test_support_eh,tc_start,{dummy_SUITE,init_per_suite}},
- {ct_test_support_eh,tc_done,{dummy_SUITE,init_per_suite,ok}},
- {ct_test_support_eh,test_stats,{1,1,{1,0}}},
- {ct_test_support_eh,tc_start,{dummy_SUITE,end_per_suite}},
- {ct_test_support_eh,tc_done,{dummy_SUITE,end_per_suite,ok}},
- {ct_test_support_eh,test_done,{'DEF','STOP_TIME'}},
- {ct_test_support_eh,stop_logging,[]}
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{1,1,3}},
+ {?eh,tc_start,{ct_framework,error_in_suite}},
+ {?eh,tc_done,{ct_framework,error_in_suite,
+ {failed,{error,'bad_SUITE can not be compiled or loaded'}}}},
+ {?eh,tc_start,{dummy_SUITE,init_per_suite}},
+ {?eh,tc_done,{dummy_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,1,{1,0}}},
+ {?eh,tc_start,{dummy_SUITE,end_per_suite}},
+ {?eh,tc_done,{dummy_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}
];
test_events(ac_spec) ->
[
- {ct_test_support_eh,start_logging,{'DEF','RUNDIR'}},
- {ct_test_support_eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
- {ct_test_support_eh,start_info,{1,1,3}},
- {ct_test_support_eh,tc_start,{dummy_SUITE,init_per_suite}},
- {ct_test_support_eh,tc_done,{dummy_SUITE,init_per_suite,ok}},
- {ct_test_support_eh,test_stats,{1,1,{1,0}}},
- {ct_test_support_eh,tc_start,{dummy_SUITE,end_per_suite}},
- {ct_test_support_eh,tc_done,{dummy_SUITE,end_per_suite,ok}},
- {ct_test_support_eh,test_done,{'DEF','STOP_TIME'}},
- {ct_test_support_eh,stop_logging,[]}
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{1,1,3}},
+ {?eh,tc_start,{ct_framework,error_in_suite}},
+ {?eh,tc_done,{ct_framework,error_in_suite,
+ {failed,{error,'bad_SUITE can not be compiled or loaded'}}}},
+ {?eh,tc_start,{dummy_SUITE,init_per_suite}},
+ {?eh,tc_done,{dummy_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,1,{1,0}}},
+ {?eh,tc_start,{dummy_SUITE,end_per_suite}},
+ {?eh,tc_done,{dummy_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}
].
diff --git a/lib/common_test/test/ct_test_server_if_1_SUITE.erl b/lib/common_test/test/ct_test_server_if_1_SUITE.erl
index b6ef3062d4..214cb60c0d 100644
--- a/lib/common_test/test/ct_test_server_if_1_SUITE.erl
+++ b/lib/common_test/test/ct_test_server_if_1_SUITE.erl
@@ -236,14 +236,13 @@ test_events(ts_if_1) ->
{ts_if_2_SUITE,end_per_suite,
{failed,{error,{suite0_failed,{exited,suite0_goes_boom}}}}}},
-
{?eh,tc_start,{ct_framework,error_in_suite}},
- {?eh,test_stats,{2,6,{4,7}}},
-
+ {?eh,tc_done,{ct_framework,error_in_suite,
+ {failed,{error,'ts_if_3_SUITE:all/0 is missing'}}}},
{?eh,tc_start,{ct_framework,error_in_suite}},
- {?eh,test_stats,{2,7,{4,7}}},
-
+ {?eh,tc_done,{ct_framework,error_in_suite,
+ {failed,{error,'Bad return value from ts_if_4_SUITE:all/0'}}}},
{?eh,tc_start,{ts_if_5_SUITE,init_per_suite}},
{?eh,tc_done,{ts_if_5_SUITE,init_per_suite,
@@ -252,7 +251,7 @@ test_events(ts_if_1) ->
{?eh,tc_auto_skip,
{ts_if_5_SUITE,my_test_case,
{require_failed_in_suite0,{not_available,undef_variable}}}},
- {?eh,test_stats,{2,7,{4,8}}},
+ {?eh,test_stats,{2,5,{4,8}}},
{?eh,tc_auto_skip,
{ts_if_5_SUITE,end_per_suite,
{require_failed_in_suite0,{not_available,undef_variable}}}},
@@ -264,7 +263,7 @@ test_events(ts_if_1) ->
{?eh,tc_auto_skip,
{ts_if_6_SUITE,tc1,
{failed,{error,{suite0_failed,{exited,suite0_byebye}}}}}},
- {?eh,test_stats,{2,7,{4,9}}},
+ {?eh,test_stats,{2,5,{4,9}}},
{?eh,tc_auto_skip,
{ct_framework,end_per_suite,
{failed,{error,{suite0_failed,{exited,suite0_byebye}}}}}},
@@ -274,13 +273,13 @@ test_events(ts_if_1) ->
{?eh,tc_done,{ct_framework,init_per_suite,ok}},
{?eh,tc_done,
{ts_if_7_SUITE,tc1,{auto_skipped,{testcase0_failed,bad_return_value}}}},
- {?eh,test_stats,{2,7,{4,10}}},
+ {?eh,test_stats,{2,5,{4,10}}},
{?eh,tc_done,{ts_if_7_SUITE,
{init_per_group,g1,[]},
{auto_skipped,{group0_failed,bad_return_value}}}},
{?eh,tc_auto_skip,
{ts_if_7_SUITE,{tc2,g1},{group0_failed,bad_return_value}}},
- {?eh,test_stats,{2,7,{4,11}}},
+ {?eh,test_stats,{2,5,{4,11}}},
{?eh,tc_auto_skip,
{ts_if_7_SUITE,{end_per_group,g1},{group0_failed,bad_return_value}}},
@@ -288,7 +287,7 @@ test_events(ts_if_1) ->
{?eh,tc_done,{ts_if_7_SUITE,{init_per_group,g2,[]},ok}},
{?eh,tc_done,{ts_if_7_SUITE,tc2,
{auto_skipped,{testcase0_failed,bad_return_value}}}},
- {?eh,test_stats,{2,7,{4,12}}},
+ {?eh,test_stats,{2,5,{4,12}}},
{?eh,tc_start,{ts_if_7_SUITE,{end_per_group,g2,[]}}},
{?eh,tc_done,{ts_if_7_SUITE,{end_per_group,g2,[]},ok}}],
@@ -300,17 +299,17 @@ test_events(ts_if_1) ->
{?eh,tc_done,{ct_framework,init_per_suite,ok}},
{?eh,tc_start,{ts_if_8_SUITE,tc1}},
{?eh,tc_done,{ts_if_8_SUITE,tc1,{failed,{error,failed_on_purpose}}}},
- {?eh,test_stats,{2,8,{4,12}}},
+ {?eh,test_stats,{2,6,{4,12}}},
{?eh,tc_start,{ct_framework,end_per_suite}},
{?eh,tc_done,{ct_framework,end_per_suite,ok}},
{?eh,tc_user_skip,{skipped_by_spec_1_SUITE,all,"should be skipped"}},
- {?eh,test_stats,{2,8,{5,12}}},
+ {?eh,test_stats,{2,6,{5,12}}},
{?eh,tc_start,{skipped_by_spec_2_SUITE,init_per_suite}},
{?eh,tc_done,{skipped_by_spec_2_SUITE,init_per_suite,ok}},
{?eh,tc_user_skip,{skipped_by_spec_2_SUITE,tc1,"should be skipped"}},
- {?eh,test_stats,{2,8,{6,12}}},
+ {?eh,test_stats,{2,6,{6,12}}},
{?eh,tc_start,{skipped_by_spec_2_SUITE,end_per_suite}},
{?eh,tc_done,{skipped_by_spec_2_SUITE,end_per_suite,ok}},
diff --git a/lib/common_test/test/ct_testspec_3_SUITE_data/tests1/t11_SUITE.erl b/lib/common_test/test/ct_testspec_3_SUITE_data/tests1/t11_SUITE.erl
index b8216c3596..cfc6fa93d7 100644
--- a/lib/common_test/test/ct_testspec_3_SUITE_data/tests1/t11_SUITE.erl
+++ b/lib/common_test/test/ct_testspec_3_SUITE_data/tests1/t11_SUITE.erl
@@ -41,8 +41,12 @@ suite() ->
%% @end
%%--------------------------------------------------------------------
init_per_suite(Config) ->
+
+ TCName = ct:get_config(tcname),
+ CfgFiles = ct:get_config(file,undefined,[all]),
+
%% verify that expected config file can be read
- case {ct:get_config(tcname),ct:get_config(file,undefined,[all])} of
+ case {TCName,CfgFiles} of
{start_separate,[cfg11]} -> ok;
{start_join,[cfg11,cfg21]} -> ok;
{incl_separate1,[cfg11]} -> ok;
@@ -56,6 +60,28 @@ init_per_suite(Config) ->
_ -> ok
end,
+
+ %% test the get_testspec_terms functionality
+ if CfgFiles /= undefined ->
+ TSTerms = case ct:get_testspec_terms() of
+ undefined -> exit('testspec should not be undefined');
+ Result -> Result
+ end,
+ true = lists:keymember(config, 1, TSTerms),
+ {config,TSCfgFiles} = ct:get_testspec_terms(config),
+ [{config,TSCfgFiles},{tests,Tests}] =
+ ct:get_testspec_terms([config,tests]),
+ CfgNames = [list_to_atom(filename:basename(TSCfgFile)) ||
+ {Node,TSCfgFile} <- TSCfgFiles, Node == node()],
+ true = (length(CfgNames) == length(CfgFiles)),
+ [true = lists:member(CfgName,CfgFiles) || CfgName <- CfgNames],
+ true = lists:any(fun({{_Node,_Dir},Suites}) ->
+ lists:keymember(?MODULE, 1, Suites)
+ end, Tests);
+ true ->
+ ok
+ end,
+
Config.
%%--------------------------------------------------------------------
diff --git a/lib/common_test/test/ct_testspec_3_SUITE_data/tests1/t12_SUITE.erl b/lib/common_test/test/ct_testspec_3_SUITE_data/tests1/t12_SUITE.erl
index 7c51aca246..c3faebbd64 100644
--- a/lib/common_test/test/ct_testspec_3_SUITE_data/tests1/t12_SUITE.erl
+++ b/lib/common_test/test/ct_testspec_3_SUITE_data/tests1/t12_SUITE.erl
@@ -55,7 +55,7 @@ init_per_suite(Config) ->
{incl_both2,[cfg11,cfg12,cfg21]} -> ok;
{incl_both2,[cfg21]} -> ok;
_ -> ok
- end,
+ end,
Config.
%%--------------------------------------------------------------------
diff --git a/lib/common_test/test/ct_testspec_3_SUITE_data/tests2/t21_SUITE.erl b/lib/common_test/test/ct_testspec_3_SUITE_data/tests2/t21_SUITE.erl
index 36c1b4279b..e189b168c7 100644
--- a/lib/common_test/test/ct_testspec_3_SUITE_data/tests2/t21_SUITE.erl
+++ b/lib/common_test/test/ct_testspec_3_SUITE_data/tests2/t21_SUITE.erl
@@ -41,8 +41,11 @@ suite() ->
%% @end
%%--------------------------------------------------------------------
init_per_suite(Config) ->
+ TCName = ct:get_config(tcname),
+ CfgFiles = ct:get_config(file,undefined,[all]),
+
%% verify that expected config file can be read
- case {ct:get_config(tcname),ct:get_config(file,undefined,[all])} of
+ case {TCName,CfgFiles} of
{start_separate,[cfg11]} -> ok;
{start_join,[cfg11,cfg21]} -> ok;
{incl_separate1,[cfg11]} -> ok;
@@ -55,6 +58,28 @@ init_per_suite(Config) ->
{incl_both2,[cfg11]} -> ok;
_ -> ok
end,
+
+ %% test the get_testspec_terms functionality
+ if CfgFiles /= undefined ->
+ TSTerms = case ct:get_testspec_terms() of
+ undefined -> exit('testspec should not be undefined');
+ Result -> Result
+ end,
+ true = lists:keymember(config, 1, TSTerms),
+ {config,TSCfgFiles} = ct:get_testspec_terms(config),
+ [{config,TSCfgFiles},{tests,Tests}] =
+ ct:get_testspec_terms([config,tests]),
+ CfgNames = [list_to_atom(filename:basename(TSCfgFile)) ||
+ {Node,TSCfgFile} <- TSCfgFiles, Node == node()],
+ true = (length(CfgNames) == length(CfgFiles)),
+ [true = lists:member(CfgName,CfgFiles) || CfgName <- CfgNames],
+ true = lists:any(fun({{_Node,_Dir},Suites}) ->
+ lists:keymember(?MODULE, 1, Suites)
+ end, Tests);
+ true ->
+ ok
+ end,
+
Config.
%%--------------------------------------------------------------------
diff --git a/lib/compiler/src/beam_bsm.erl b/lib/compiler/src/beam_bsm.erl
index 427b7071ac..2a15c1ddf3 100644
--- a/lib/compiler/src/beam_bsm.erl
+++ b/lib/compiler/src/beam_bsm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2007-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
@@ -615,7 +615,7 @@ collect_warnings_instr([_|Is], D, Acc) ->
collect_warnings_instr([], _, Acc) -> Acc.
add_warning(Term, Anno, Ws) ->
- Line = abs(get_line(Anno)),
+ Line = get_line(Anno),
File = get_file(Anno),
[{File,[{Line,?MODULE,Term}]}|Ws].
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index 5bd33c4d18..b54d125774 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -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
@@ -41,7 +41,7 @@
-type option() :: atom() | {atom(), term()} | {'d', atom(), term()}.
--type err_info() :: {erl_scan:line() | 'none',
+-type err_info() :: {erl_anno:line() | 'none',
module(), term()}. %% ErrorDescriptor
-type errors() :: [{file:filename(), [err_info()]}].
-type warnings() :: [{file:filename(), [err_info()]}].
@@ -132,7 +132,8 @@ env_default_opts() ->
Str when is_list(Str) ->
case erl_scan:string(Str) of
{ok,Tokens,_} ->
- case erl_parse:parse_term(Tokens ++ [{dot, 1}]) of
+ Dot = {dot, erl_anno:new(1)},
+ case erl_parse:parse_term(Tokens ++ [Dot]) of
{ok,List} when is_list(List) -> List;
{ok,Term} -> [Term];
{error,_Reason} ->
@@ -1237,7 +1238,8 @@ save_abstract_code(#compile{ifile=File}=St) ->
{error,St#compile{errors=St#compile.errors ++ [{File,Es}]}}
end.
-abstract_code(#compile{code=Code,options=Opts,ofile=OFile}) ->
+abstract_code(#compile{code=Code0,options=Opts,ofile=OFile}) ->
+ Code = erl_parse:anno_to_term(Code0),
Abstr = erlang:term_to_binary({raw_abstract_v1,Code}, [compressed]),
case member(encrypt_debug_info, Opts) of
true ->
diff --git a/lib/compiler/src/sys_pre_expand.erl b/lib/compiler/src/sys_pre_expand.erl
index 6cc849a9d5..4c4628d580 100644
--- a/lib/compiler/src/sys_pre_expand.erl
+++ b/lib/compiler/src/sys_pre_expand.erl
@@ -1,7 +1,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
@@ -115,7 +115,8 @@ is_fa_list(_) -> false.
module_predef_funcs(St) ->
{Mpf1,St1}=module_predef_func_beh_info(St),
{Mpf2,St2}=module_predef_funcs_mod_info(St1),
- {Mpf1++Mpf2,St2}.
+ Mpf = [erl_parse:new_anno(F) || F <- Mpf1++Mpf2],
+ {Mpf,St2}.
module_predef_func_beh_info(#expand{callbacks=[]}=St) ->
{[], St};
diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl
index 2d12d832a3..ecaecb0ff6 100644
--- a/lib/compiler/src/v3_core.erl
+++ b/lib/compiler/src/v3_core.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1999-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
@@ -83,8 +83,6 @@
-include("core_parse.hrl").
--define(REC_OFFSET, 100000000). % Also in erl_expand_records.
-
%% Internal core expressions and help functions.
%% N.B. annotations fields in place as normal Core expressions.
@@ -170,8 +168,10 @@ form({attribute,_,file,{File,_Line}}, {Fs,As,Ws,_}, _Opts) ->
form({attribute,_,_,_}=F, {Fs,As,Ws,File}, _Opts) ->
{Fs,[attribute(F)|As],Ws,File}.
-attribute({attribute,Line,Name,Val}) ->
- {#c_literal{val=Name, anno=[Line]}, #c_literal{val=Val, anno=[Line]}}.
+attribute(Attribute) ->
+ Fun = fun(A) -> [erl_anno:location(A)] end,
+ {attribute,Line,Name,Val} = erl_parse:map_anno(Fun, Attribute),
+ {#c_literal{val=Name, anno=Line}, #c_literal{val=Val, anno=Line}}.
%% function_dump(module_info,_,_,_) -> ok;
%% function_dump(Name,Arity,Format,Terms) ->
@@ -729,7 +729,7 @@ make_bool_switch(L, E, V, T, F, #core{}) ->
make_bool_switch_body(L, E, V, T, F).
make_bool_switch_body(L, E, V, T, F) ->
- NegL = neg_line(abs_line(L)),
+ NegL = no_compiler_warning(L),
Error = {tuple,NegL,[{atom,NegL,badarg},V]},
{'case',NegL,E,
[{clause,NegL,[{atom,NegL,true}],[],[T]},
@@ -740,7 +740,7 @@ make_bool_switch_body(L, E, V, T, F) ->
make_bool_switch_guard(_, E, _, {atom,_,true}, {atom,_,false}) -> E;
make_bool_switch_guard(L, E, V, T, F) ->
- NegL = neg_line(abs_line(L)),
+ NegL = no_compiler_warning(L),
{'case',NegL,E,
[{clause,NegL,[{atom,NegL,true}],[],[T]},
{clause,NegL,[{atom,NegL,false}],[],[F]},
@@ -919,7 +919,7 @@ verify_suitable_fields([]) -> ok.
%% (We don't need an exact result for this purpose.)
count_bits(Int) ->
- count_bits_1(abs_line(Int), 64).
+ count_bits_1(abs(Int), 64).
count_bits_1(0, Bits) -> Bits;
count_bits_1(Int, Bits) -> count_bits_1(Int bsr 64, Bits+64).
@@ -2311,22 +2311,15 @@ bitstr_vars(Segs, Vs) ->
lit_vars(V, lit_vars(S, Vs0))
end, Vs, Segs).
-record_anno(L, St) when L >= ?REC_OFFSET ->
- case member(dialyzer, St#core.opts) of
- true ->
- [record | lineno_anno(L - ?REC_OFFSET, St)];
- false ->
- full_anno(L, St)
- end;
-record_anno(L, St) when L < -?REC_OFFSET ->
- case member(dialyzer, St#core.opts) of
+record_anno(L, St) ->
+ case
+ erl_anno:record(L) andalso member(dialyzer, St#core.opts)
+ of
true ->
- [record | lineno_anno(L + ?REC_OFFSET, St)];
+ [record | lineno_anno(L, St)];
false ->
full_anno(L, St)
- end;
-record_anno(L, St) ->
- full_anno(L, St).
+ end.
full_anno(L, #core{wanted=false}=St) ->
[result_not_wanted|lineno_anno(L, St)];
@@ -2334,13 +2327,10 @@ full_anno(L, #core{wanted=true}=St) ->
lineno_anno(L, St).
lineno_anno(L, St) ->
- {line, Line} = erl_parse:get_attribute(L, line),
- if
- Line < 0 ->
- [-Line] ++ St#core.file ++ [compiler_generated];
- true ->
- [Line] ++ St#core.file
- end.
+ Line = erl_anno:line(L),
+ Generated = erl_anno:generated(L),
+ CompilerGenerated = [compiler_generated || Generated],
+ [Line] ++ St#core.file ++ CompilerGenerated.
get_lineno_anno(Ce) ->
case get_anno(Ce) of
@@ -2348,15 +2338,8 @@ get_lineno_anno(Ce) ->
A when is_list(A) -> A
end.
-location(L) ->
- {location,Location} = erl_parse:get_attribute(L, location),
- Location.
-
-abs_line(L) ->
- erl_parse:set_line(L, fun(Line) -> abs(Line) end).
-
-neg_line(L) ->
- erl_parse:set_line(L, fun(Line) -> -abs(Line) end).
+no_compiler_warning(Anno) ->
+ erl_anno:set_generated(true, Anno).
%%
%% The following three functions are used both with cerl:cerl() and with i()'s
@@ -2400,6 +2383,10 @@ format_error(bad_binary) ->
format_error(badmap) ->
"map construction will fail because of a type mismatch".
-add_warning(Line, Term, #core{ws=Ws,file=[{file,File}]}=St) when Line >= 0 ->
- St#core{ws=[{File,[{location(Line),?MODULE,Term}]}|Ws]};
-add_warning(_, _, St) -> St.
+add_warning(Anno, Term, #core{ws=Ws,file=[{file,File}]}=St) ->
+ case erl_anno:generated(Anno) of
+ false ->
+ St#core{ws=[{File,[{erl_anno:location(Anno),?MODULE,Term}]}|Ws]};
+ true ->
+ St
+ end.
diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl
index 6d4fde662b..6b0369bf98 100644
--- a/lib/compiler/test/compile_SUITE.erl
+++ b/lib/compiler/test/compile_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2014. 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
@@ -126,7 +126,8 @@ file_1(Config) when is_list(Config) ->
forms_2(Config) when is_list(Config) ->
Src = "/foo/bar",
AbsSrc = filename:absname(Src),
- {ok,simple,Binary} = compile:forms([{attribute,1,module,simple}],
+ Anno = erl_anno:new(1),
+ {ok,simple,Binary} = compile:forms([{attribute,Anno,module,simple}],
[binary,{source,Src}]),
code:load_binary(simple, Src, Binary),
Info = simple:module_info(compile),
diff --git a/lib/compiler/test/guard_SUITE.erl b/lib/compiler/test/guard_SUITE.erl
index d91ee7ea08..512207898e 100644
--- a/lib/compiler/test/guard_SUITE.erl
+++ b/lib/compiler/test/guard_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2001-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
@@ -1373,10 +1373,11 @@ literal_type_tests_1(Config) ->
[{is_function,L1,L2} ||
L1 <- literals(), L2 <- literals()]),
?line Mod = literal_test,
- ?line Func = {function, 0, test, 0, [{clause,0,[],[],Tests}]},
- ?line Form = [{attribute,0,module,Mod},
- {attribute,0,compile,export_all},
- Func, {eof,0}],
+ Anno = erl_anno:new(0),
+ Func = {function, Anno, test, 0, [{clause,Anno,[],[],Tests}]},
+ Form = [{attribute,Anno,module,Mod},
+ {attribute,Anno,compile,export_all},
+ Func, {eof,Anno}],
%% Print generated code for inspection.
?line lists:foreach(fun (F) -> io:put_chars([erl_pp:form(F),"\n"]) end, Form),
@@ -1411,7 +1412,8 @@ test(T, L) ->
{ok,Toks,_Line} = erl_scan:string(S),
{ok,E} = erl_parse:parse_exprs(Toks),
{value,Val,_Bs} = erl_eval:exprs(E, []),
- {match,0,{atom,0,Val},hd(E)}.
+ Anno = erl_anno:new(0),
+ {match,Anno,{atom,Anno,Val},hd(E)}.
test(T, L1, L2) ->
S0 = io_lib:format("begin io:format(\"~~p~n\", [{~p,~p,~p}]), if ~w(~w, ~w) -> true; true -> false end end. ", [T,L1,L2,T,L1,L2]),
@@ -1419,7 +1421,8 @@ test(T, L1, L2) ->
{ok,Toks,_Line} = erl_scan:string(S),
{ok,E} = erl_parse:parse_exprs(Toks),
{value,Val,_Bs} = erl_eval:exprs(E, []),
- {match,0,{atom,0,Val},hd(E)}.
+ Anno = erl_anno:new(0),
+ {match,Anno,{atom,Anno,Val},hd(E)}.
smoke_disasm(Config, Mod, Bin) ->
Priv = ?config(priv_dir, Config),
diff --git a/lib/debugger/src/dbg_icmd.erl b/lib/debugger/src/dbg_icmd.erl
index ce12c1beb3..b9d7506cde 100644
--- a/lib/debugger/src/dbg_icmd.erl
+++ b/lib/debugger/src/dbg_icmd.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1998-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
diff --git a/lib/debugger/src/dbg_ieval.erl b/lib/debugger/src/dbg_ieval.erl
index cfc2a19ccd..0e176b243f 100644
--- a/lib/debugger/src/dbg_ieval.erl
+++ b/lib/debugger/src/dbg_ieval.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1998-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
diff --git a/lib/debugger/src/dbg_iload.erl b/lib/debugger/src/dbg_iload.erl
index ad05a7c529..f1a85e8e71 100644
--- a/lib/debugger/src/dbg_iload.erl
+++ b/lib/debugger/src/dbg_iload.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1998-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
@@ -163,11 +163,11 @@ clauses([C0|Cs]) ->
[C1|clauses(Cs)];
clauses([]) -> [].
-clause({clause,Line,H0,G0,B0}, Lc) ->
+clause({clause,Anno,H0,G0,B0}, Lc) ->
H1 = head(H0),
G1 = guard(G0),
B1 = exprs(B0, Lc),
- {clause,Line,H1,G1,B1}.
+ {clause,ln(Anno),H1,G1,B1}.
head(Ps) -> patterns(Ps).
@@ -181,46 +181,46 @@ patterns([]) -> [].
%% N.B. Only valid patterns are included here.
-pattern({var,Line,V}) -> {var,Line,V};
-pattern({char,Line,I}) -> {value,Line,I};
-pattern({integer,Line,I}) -> {value,Line,I};
-pattern({match,Line,Pat1,Pat2}) ->
- {match,Line,pattern(Pat1),pattern(Pat2)};
-pattern({float,Line,F}) -> {value,Line,F};
-pattern({atom,Line,A}) -> {value,Line,A};
-pattern({string,Line,S}) -> {value,Line,S};
-pattern({nil,Line}) -> {value,Line,[]};
-pattern({cons,Line,H0,T0}) ->
+pattern({var,Anno,V}) -> {var,ln(Anno),V};
+pattern({char,Anno,I}) -> {value,ln(Anno),I};
+pattern({integer,Anno,I}) -> {value,ln(Anno),I};
+pattern({match,Anno,Pat1,Pat2}) ->
+ {match,ln(Anno),pattern(Pat1),pattern(Pat2)};
+pattern({float,Anno,F}) -> {value,ln(Anno),F};
+pattern({atom,Anno,A}) -> {value,ln(Anno),A};
+pattern({string,Anno,S}) -> {value,ln(Anno),S};
+pattern({nil,Anno}) -> {value,ln(Anno),[]};
+pattern({cons,Anno,H0,T0}) ->
H1 = pattern(H0),
T1 = pattern(T0),
- {cons,Line,H1,T1};
-pattern({tuple,Line,Ps0}) ->
+ {cons,ln(Anno),H1,T1};
+pattern({tuple,Anno,Ps0}) ->
Ps1 = pattern_list(Ps0),
- {tuple,Line,Ps1};
-pattern({map,Line,Fs0}) ->
+ {tuple,ln(Anno),Ps1};
+pattern({map,Anno,Fs0}) ->
Fs1 = lists:map(fun ({map_field_exact,L,K,V}) ->
{map_field_exact,L,expr(K, false),pattern(V)}
end, Fs0),
- {map,Line,Fs1};
-pattern({op,_,'-',{integer,Line,I}}) ->
- {value,Line,-I};
-pattern({op,_,'+',{integer,Line,I}}) ->
- {value,Line,I};
-pattern({op,_,'-',{char,Line,I}}) ->
- {value,Line,-I};
-pattern({op,_,'+',{char,Line,I}}) ->
- {value,Line,I};
-pattern({op,_,'-',{float,Line,I}}) ->
- {value,Line,-I};
-pattern({op,_,'+',{float,Line,I}}) ->
- {value,Line,I};
-pattern({bin,Line,Grp}) ->
+ {map,ln(Anno),Fs1};
+pattern({op,_,'-',{integer,Anno,I}}) ->
+ {value,ln(Anno),-I};
+pattern({op,_,'+',{integer,Anno,I}}) ->
+ {value,ln(Anno),I};
+pattern({op,_,'-',{char,Anno,I}}) ->
+ {value,ln(Anno),-I};
+pattern({op,_,'+',{char,Anno,I}}) ->
+ {value,ln(Anno),I};
+pattern({op,_,'-',{float,Anno,I}}) ->
+ {value,ln(Anno),-I};
+pattern({op,_,'+',{float,Anno,I}}) ->
+ {value,ln(Anno),I};
+pattern({bin,Anno,Grp}) ->
Grp1 = pattern_list(Grp),
- {bin,Line,Grp1};
-pattern({bin_element,Line,Expr,Size,Type}) ->
+ {bin,ln(Anno),Grp1};
+pattern({bin_element,Anno,Expr,Size,Type}) ->
Expr1 = pattern(Expr),
Size1 = expr(Size, false),
- {bin_element,Line,Expr1,Size1,Type}.
+ {bin_element,ln(Anno),Expr1,Size1,Type}.
%% These patterns are processed "in parallel" for purposes of variable
%% definition etc.
@@ -240,90 +240,90 @@ and_guard([G0|Gs]) ->
[G1|and_guard(Gs)];
and_guard([]) -> [].
-guard_test({call,Line,{remote,_,{atom,_,erlang},{atom,_,F}},As0}) ->
+guard_test({call,Anno,{remote,_,{atom,_,erlang},{atom,_,F}},As0}) ->
As = gexpr_list(As0),
- {safe_bif,Line,erlang,F,As};
-guard_test({op,Line,Op,L0}) ->
+ {safe_bif,ln(Anno),erlang,F,As};
+guard_test({op,Anno,Op,L0}) ->
true = erl_internal:arith_op(Op, 1) orelse %Assertion.
erl_internal:bool_op(Op, 1),
L1 = gexpr(L0),
- {safe_bif,Line,erlang,Op,[L1]};
-guard_test({op,Line,Op,L0,R0}) when Op =:= 'andalso'; Op =:= 'orelse' ->
+ {safe_bif,ln(Anno),erlang,Op,[L1]};
+guard_test({op,Anno,Op,L0,R0}) when Op =:= 'andalso'; Op =:= 'orelse' ->
L1 = gexpr(L0),
R1 = gexpr(R0), %They see the same variables
- {Op,Line,L1,R1};
-guard_test({op,Line,Op,L0,R0}) ->
+ {Op,ln(Anno),L1,R1};
+guard_test({op,Anno,Op,L0,R0}) ->
true = erl_internal:comp_op(Op, 2) orelse %Assertion.
erl_internal:bool_op(Op, 2) orelse
erl_internal:arith_op(Op, 2),
L1 = gexpr(L0),
R1 = gexpr(R0), %They see the same variables
- {safe_bif,Line,erlang,Op,[L1,R1]};
+ {safe_bif,ln(Anno),erlang,Op,[L1,R1]};
guard_test({var,_,_}=V) ->V; % Boolean var
-guard_test({atom,Line,true}) -> {value,Line,true};
+guard_test({atom,Anno,true}) -> {value,ln(Anno),true};
%% All other constants at this level means false.
-guard_test({atom,Line,_}) -> {value,Line,false};
-guard_test({integer,Line,_}) -> {value,Line,false};
-guard_test({char,Line,_}) -> {value,Line,false};
-guard_test({float,Line,_}) -> {value,Line,false};
-guard_test({string,Line,_}) -> {value,Line,false};
-guard_test({nil,Line}) -> {value,Line,false};
-guard_test({cons,Line,_,_}) -> {value,Line,false};
-guard_test({tuple,Line,_}) -> {value,Line,false};
-guard_test({map,Line,_}) -> {value,Line,false};
-guard_test({map,Line,_,_}) -> {value,Line,false};
-guard_test({bin,Line,_}) -> {value,Line,false}.
-
-gexpr({var,Line,V}) -> {var,Line,V};
-gexpr({integer,Line,I}) -> {value,Line,I};
-gexpr({char,Line,I}) -> {value,Line,I};
-gexpr({float,Line,F}) -> {value,Line,F};
-gexpr({atom,Line,A}) -> {value,Line,A};
-gexpr({string,Line,S}) -> {value,Line,S};
-gexpr({nil,Line}) -> {value,Line,[]};
-gexpr({cons,Line,H0,T0}) ->
+guard_test({atom,Anno,_}) -> {value,ln(Anno),false};
+guard_test({integer,Anno,_}) -> {value,ln(Anno),false};
+guard_test({char,Anno,_}) -> {value,ln(Anno),false};
+guard_test({float,Anno,_}) -> {value,ln(Anno),false};
+guard_test({string,Anno,_}) -> {value,ln(Anno),false};
+guard_test({nil,Anno}) -> {value,ln(Anno),false};
+guard_test({cons,Anno,_,_}) -> {value,ln(Anno),false};
+guard_test({tuple,Anno,_}) -> {value,ln(Anno),false};
+guard_test({map,Anno,_}) -> {value,ln(Anno),false};
+guard_test({map,Anno,_,_}) -> {value,ln(Anno),false};
+guard_test({bin,Anno,_}) -> {value,ln(Anno),false}.
+
+gexpr({var,Anno,V}) -> {var,ln(Anno),V};
+gexpr({integer,Anno,I}) -> {value,ln(Anno),I};
+gexpr({char,Anno,I}) -> {value,ln(Anno),I};
+gexpr({float,Anno,F}) -> {value,ln(Anno),F};
+gexpr({atom,Anno,A}) -> {value,ln(Anno),A};
+gexpr({string,Anno,S}) -> {value,ln(Anno),S};
+gexpr({nil,Anno}) -> {value,ln(Anno),[]};
+gexpr({cons,Anno,H0,T0}) ->
case {gexpr(H0),gexpr(T0)} of
{{value,Line,H1},{value,Line,T1}} -> {value,Line,[H1|T1]};
- {H1,T1} -> {cons,Line,H1,T1}
+ {H1,T1} -> {cons,ln(Anno),H1,T1}
end;
-gexpr({tuple,Line,Es0}) ->
+gexpr({tuple,Anno,Es0}) ->
Es1 = gexpr_list(Es0),
- {tuple,Line,Es1};
-gexpr({map,Line,Fs0}) ->
+ {tuple,ln(Anno),Es1};
+gexpr({map,Anno,Fs0}) ->
Fs1 = map_fields(Fs0, fun gexpr/1),
- {map,Line,Fs1};
-gexpr({map,Line,E0,Fs0}) ->
+ {map,ln(Anno),Fs1};
+gexpr({map,Anno,E0,Fs0}) ->
E1 = gexpr(E0),
Fs1 = map_fields(Fs0, fun gexpr/1),
- {map,Line,E1,Fs1};
-gexpr({bin,Line,Flds0}) ->
+ {map,ln(Anno),E1,Fs1};
+gexpr({bin,Anno,Flds0}) ->
Flds = gexpr_list(Flds0),
- {bin,Line,Flds};
-gexpr({bin_element,Line,Expr0,Size0,Type}) ->
+ {bin,ln(Anno),Flds};
+gexpr({bin_element,Anno,Expr0,Size0,Type}) ->
Expr = gexpr(Expr0),
Size = gexpr(Size0),
- {bin_element,Line,Expr,Size,Type};
+ {bin_element,ln(Anno),Expr,Size,Type};
%%% The previous passes have added the module name 'erlang' to
%%% all BIF calls, even in guards.
-gexpr({call,Line,{remote,_,{atom,_,erlang},{atom,_,self}},[]}) ->
- {dbg, Line, self, []};
-gexpr({call,Line,{remote,_,{atom,_,erlang},{atom,_,F}},As0}) ->
+gexpr({call,Anno,{remote,_,{atom,_,erlang},{atom,_,self}},[]}) ->
+ {dbg,ln(Anno),self,[]};
+gexpr({call,Anno,{remote,_,{atom,_,erlang},{atom,_,F}},As0}) ->
As = gexpr_list(As0),
- {safe_bif,Line,erlang,F,As};
-gexpr({op,Line,Op,A0}) ->
+ {safe_bif,ln(Anno),erlang,F,As};
+gexpr({op,Anno,Op,A0}) ->
erl_internal:arith_op(Op, 1),
A1 = gexpr(A0),
- {safe_bif,Line,erlang,Op,[A1]};
-gexpr({op,Line,Op,L0,R0}) when Op =:= 'andalso'; Op =:= 'orelse' ->
+ {safe_bif,ln(Anno),erlang,Op,[A1]};
+gexpr({op,Anno,Op,L0,R0}) when Op =:= 'andalso'; Op =:= 'orelse' ->
L1 = gexpr(L0),
R1 = gexpr(R0), %They see the same variables
- {Op,Line,L1,R1};
-gexpr({op,Line,Op,L0,R0}) ->
+ {Op,ln(Anno),L1,R1};
+gexpr({op,Anno,Op,L0,R0}) ->
true = erl_internal:arith_op(Op, 2) orelse erl_internal:comp_op(Op, 2)
orelse erl_internal:bool_op(Op, 2),
L1 = gexpr(L0),
R1 = gexpr(R0), %They see the same variables
- {safe_bif,Line,erlang,Op,[L1,R1]}.
+ {safe_bif,ln(Anno),erlang,Op,[L1,R1]}.
%% These expressions are processed "in parallel" for purposes of variable
%% definition etc.
@@ -343,118 +343,119 @@ exprs([E0|Es], Lc) ->
[E1|exprs(Es, Lc)];
exprs([], _Lc) -> [].
-expr({var,Line,V}, _Lc) -> {var,Line,V};
-expr({integer,Line,I}, _Lc) -> {value,Line,I};
-expr({char,Line,I}, _Lc) -> {value,Line,I};
-expr({float,Line,F}, _Lc) -> {value,Line,F};
-expr({atom,Line,A}, _Lc) -> {value,Line,A};
-expr({string,Line,S}, _Lc) -> {value,Line,S};
-expr({nil,Line}, _Lc) -> {value,Line,[]};
-expr({cons,Line,H0,T0}, _Lc) ->
+expr({var,Anno,V}, _Lc) -> {var,ln(Anno),V};
+expr({integer,Anno,I}, _Lc) -> {value,ln(Anno),I};
+expr({char,Anno,I}, _Lc) -> {value,ln(Anno),I};
+expr({float,Anno,F}, _Lc) -> {value,ln(Anno),F};
+expr({atom,Anno,A}, _Lc) -> {value,ln(Anno),A};
+expr({string,Anno,S}, _Lc) -> {value,ln(Anno),S};
+expr({nil,Anno}, _Lc) -> {value,ln(Anno),[]};
+expr({cons,Anno,H0,T0}, _Lc) ->
case {expr(H0, false),expr(T0, false)} of
{{value,Line,H1},{value,Line,T1}} -> {value,Line,[H1|T1]};
- {H1,T1} -> {cons,Line,H1,T1}
+ {H1,T1} -> {cons,ln(Anno),H1,T1}
end;
-expr({tuple,Line,Es0}, _Lc) ->
+expr({tuple,Anno,Es0}, _Lc) ->
Es1 = expr_list(Es0),
- {tuple,Line,Es1};
-expr({map,Line,Fs0}, _Lc) ->
+ {tuple,ln(Anno),Es1};
+expr({map,Anno,Fs0}, _Lc) ->
Fs1 = map_fields(Fs0),
- {map,Line,Fs1};
-expr({map,Line,E0,Fs0}, _Lc) ->
+ {map,ln(Anno),Fs1};
+expr({map,Anno,E0,Fs0}, _Lc) ->
E1 = expr(E0, false),
Fs1 = map_fields(Fs0),
- {map,Line,E1,Fs1};
-expr({block,Line,Es0}, Lc) ->
+ {map,ln(Anno),E1,Fs1};
+expr({block,Anno,Es0}, Lc) ->
%% Unfold block into a sequence.
Es1 = exprs(Es0, Lc),
- {block,Line,Es1};
-expr({'if',Line,Cs0}, Lc) ->
+ {block,ln(Anno),Es1};
+expr({'if',Anno,Cs0}, Lc) ->
Cs1 = icr_clauses(Cs0, Lc),
- {'if',Line,Cs1};
-expr({'case',Line,E0,Cs0}, Lc) ->
+ {'if',ln(Anno),Cs1};
+expr({'case',Anno,E0,Cs0}, Lc) ->
E1 = expr(E0, false),
Cs1 = icr_clauses(Cs0, Lc),
- {'case',Line,E1,Cs1};
-expr({'receive',Line,Cs0}, Lc) ->
+ {'case',ln(Anno),E1,Cs1};
+expr({'receive',Anno,Cs0}, Lc) ->
Cs1 = icr_clauses(Cs0, Lc),
- {'receive',Line,Cs1};
-expr({'receive',Line,Cs0,To0,ToEs0}, Lc) ->
+ {'receive',ln(Anno),Cs1};
+expr({'receive',Anno,Cs0,To0,ToEs0}, Lc) ->
To1 = expr(To0, false),
ToEs1 = exprs(ToEs0, Lc),
Cs1 = icr_clauses(Cs0, Lc),
- {'receive',Line,Cs1,To1,ToEs1};
-expr({'fun',Line,{clauses,Cs0},{_,_,Name}}, _Lc) when is_atom(Name) ->
+ {'receive',ln(Anno),Cs1,To1,ToEs1};
+expr({'fun',Anno,{clauses,Cs0},{_,_,Name}}, _Lc) when is_atom(Name) ->
%% New R10B-2 format (abstract_v2).
Cs = fun_clauses(Cs0),
- {make_fun,Line,Name,Cs};
-expr({'fun',Line,{function,F,A},{_Index,_OldUniq,Name}}, _Lc) ->
+ {make_fun,ln(Anno),Name,Cs};
+expr({'fun',Anno,{function,F,A},{_Index,_OldUniq,Name}}, _Lc) ->
%% New R8 format (abstract_v2).
+ Line = ln(Anno),
As = new_vars(A, Line),
Cs = [{clause,Line,As,[],[{local_call,Line,F,As,true}]}],
{make_fun,Line,Name,Cs};
-expr({named_fun,Line,FName,Cs0,{_,_,Name}}, _Lc) when is_atom(Name) ->
+expr({named_fun,Anno,FName,Cs0,{_,_,Name}}, _Lc) when is_atom(Name) ->
Cs = fun_clauses(Cs0),
- {make_named_fun,Line,Name,FName,Cs};
-expr({'fun',Line,{function,{atom,_,M},{atom,_,F},{integer,_,A}}}, _Lc)
+ {make_named_fun,ln(Anno),Name,FName,Cs};
+expr({'fun',Anno,{function,{atom,_,M},{atom,_,F},{integer,_,A}}}, _Lc)
when 0 =< A, A =< 255 ->
%% New format in R15 for fun M:F/A (literal values).
- {value,Line,erlang:make_fun(M, F, A)};
-expr({'fun',Line,{function,M,F,A}}, _Lc) ->
+ {value,ln(Anno),erlang:make_fun(M, F, A)};
+expr({'fun',Anno,{function,M,F,A}}, _Lc) ->
%% New format in R15 for fun M:F/A (one or more variables).
MFA = expr_list([M,F,A]),
- {make_ext_fun,Line,MFA};
-expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,self}},[]}, _Lc) ->
- {dbg,Line,self,[]};
-expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,get_stacktrace}},[]}, _Lc) ->
- {dbg,Line,get_stacktrace,[]};
-expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,throw}},[_]=As}, _Lc) ->
- {dbg,Line,throw,expr_list(As)};
-expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,error}},[_]=As}, _Lc) ->
- {dbg,Line,error,expr_list(As)};
-expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,exit}},[_]=As}, _Lc) ->
- {dbg,Line,exit,expr_list(As)};
-expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,raise}},[_,_,_]=As}, _Lc) ->
- {dbg,Line,raise,expr_list(As)};
-expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,apply}},[_,_,_]=As0}, Lc) ->
+ {make_ext_fun,ln(Anno),MFA};
+expr({call,Anno,{remote,_,{atom,_,erlang},{atom,_,self}},[]}, _Lc) ->
+ {dbg,ln(Anno),self,[]};
+expr({call,Anno,{remote,_,{atom,_,erlang},{atom,_,get_stacktrace}},[]}, _Lc) ->
+ {dbg,ln(Anno),get_stacktrace,[]};
+expr({call,Anno,{remote,_,{atom,_,erlang},{atom,_,throw}},[_]=As}, _Lc) ->
+ {dbg,ln(Anno),throw,expr_list(As)};
+expr({call,Anno,{remote,_,{atom,_,erlang},{atom,_,error}},[_]=As}, _Lc) ->
+ {dbg,ln(Anno),error,expr_list(As)};
+expr({call,Anno,{remote,_,{atom,_,erlang},{atom,_,exit}},[_]=As}, _Lc) ->
+ {dbg,ln(Anno),exit,expr_list(As)};
+expr({call,Anno,{remote,_,{atom,_,erlang},{atom,_,raise}},[_,_,_]=As}, _Lc) ->
+ {dbg,ln(Anno),raise,expr_list(As)};
+expr({call,Anno,{remote,_,{atom,_,erlang},{atom,_,apply}},[_,_,_]=As0}, Lc) ->
As = expr_list(As0),
- {apply,Line,As,Lc};
-expr({call,Line,{remote,_,{atom,_,Mod},{atom,_,Func}},As0}, Lc) ->
+ {apply,ln(Anno),As,Lc};
+expr({call,Anno,{remote,_,{atom,_,Mod},{atom,_,Func}},As0}, Lc) ->
As = expr_list(As0),
case erlang:is_builtin(Mod, Func, length(As)) of
false ->
- {call_remote,Line,Mod,Func,As,Lc};
+ {call_remote,ln(Anno),Mod,Func,As,Lc};
true ->
case bif_type(Mod, Func, length(As0)) of
- safe -> {safe_bif,Line,Mod,Func,As};
- unsafe ->{bif,Line,Mod,Func,As}
+ safe -> {safe_bif,ln(Anno),Mod,Func,As};
+ unsafe ->{bif,ln(Anno),Mod,Func,As}
end
end;
-expr({call,Line,{remote,_,Mod0,Func0},As0}, Lc) ->
+expr({call,Anno,{remote,_,Mod0,Func0},As0}, Lc) ->
%% New R8 format (abstract_v2).
Mod = expr(Mod0, false),
Func = expr(Func0, false),
As = consify(expr_list(As0)),
- {apply,Line,[Mod,Func,As],Lc};
-expr({call,Line,{atom,_,Func},As0}, Lc) ->
+ {apply,ln(Anno),[Mod,Func,As],Lc};
+expr({call,Anno,{atom,_,Func},As0}, Lc) ->
As = expr_list(As0),
- {local_call,Line,Func,As,Lc};
-expr({call,Line,Fun0,As0}, Lc) ->
+ {local_call,ln(Anno),Func,As,Lc};
+expr({call,Anno,Fun0,As0}, Lc) ->
Fun = expr(Fun0, false),
As = expr_list(As0),
- {apply_fun,Line,Fun,As,Lc};
-expr({'catch',Line,E0}, _Lc) ->
+ {apply_fun,ln(Anno),Fun,As,Lc};
+expr({'catch',Anno,E0}, _Lc) ->
%% No new variables added.
E1 = expr(E0, false),
- {'catch',Line,E1};
-expr({'try',Line,Es0,CaseCs0,CatchCs0,As0}, Lc) ->
+ {'catch',ln(Anno),E1};
+expr({'try',Anno,Es0,CaseCs0,CatchCs0,As0}, Lc) ->
%% No new variables added.
Es = expr_list(Es0),
CaseCs = icr_clauses(CaseCs0, Lc),
CatchCs = icr_clauses(CatchCs0, Lc),
As = expr_list(As0),
- {'try',Line,Es,CaseCs,CatchCs,As};
-expr({lc,Line,E0,Gs0}, _Lc) -> %R8.
+ {'try',ln(Anno),Es,CaseCs,CatchCs,As};
+expr({lc,Anno,E0,Gs0}, _Lc) -> %R8.
Gs = lists:map(fun ({generate,L,P0,Qs}) ->
{generate,L,expr(P0, false),expr(Qs, false)};
({b_generate,L,P0,Qs}) -> %R12.
@@ -465,8 +466,8 @@ expr({lc,Line,E0,Gs0}, _Lc) -> %R8.
false -> expr(Expr, false)
end
end, Gs0),
- {lc,Line,expr(E0, false),Gs};
-expr({bc,Line,E0,Gs0}, _Lc) -> %R12.
+ {lc,ln(Anno),expr(E0, false),Gs};
+expr({bc,Anno,E0,Gs0}, _Lc) -> %R12.
Gs = lists:map(fun ({generate,L,P0,Qs}) ->
{generate,L,expr(P0, false),expr(Qs, false)};
({b_generate,L,P0,Qs}) -> %R12.
@@ -477,41 +478,41 @@ expr({bc,Line,E0,Gs0}, _Lc) -> %R12.
false -> expr(Expr, false)
end
end, Gs0),
- {bc,Line,expr(E0, false),Gs};
-expr({match,Line,P0,E0}, _Lc) ->
+ {bc,ln(Anno),expr(E0, false),Gs};
+expr({match,Anno,P0,E0}, _Lc) ->
E1 = expr(E0, false),
P1 = pattern(P0),
- {match,Line,P1,E1};
-expr({op,Line,Op,A0}, _Lc) ->
+ {match,ln(Anno),P1,E1};
+expr({op,Anno,Op,A0}, _Lc) ->
A1 = expr(A0, false),
- {op,Line,Op,[A1]};
-expr({op,Line,'++',L0,R0}, _Lc) ->
+ {op,ln(Anno),Op,[A1]};
+expr({op,Anno,'++',L0,R0}, _Lc) ->
L1 = expr(L0, false),
R1 = expr(R0, false), %They see the same variables
- {op,Line,append,[L1,R1]};
-expr({op,Line,'--',L0,R0}, _Lc) ->
+ {op,ln(Anno),append,[L1,R1]};
+expr({op,Anno,'--',L0,R0}, _Lc) ->
L1 = expr(L0, false),
R1 = expr(R0, false), %They see the same variables
- {op,Line,subtract,[L1,R1]};
-expr({op,Line,'!',L0,R0}, _Lc) ->
+ {op,ln(Anno),subtract,[L1,R1]};
+expr({op,Anno,'!',L0,R0}, _Lc) ->
L1 = expr(L0, false),
R1 = expr(R0, false), %They see the same variables
- {send,Line,L1,R1};
-expr({op,Line,Op,L0,R0}, _Lc) when Op =:= 'andalso'; Op =:= 'orelse' ->
+ {send,ln(Anno),L1,R1};
+expr({op,Anno,Op,L0,R0}, _Lc) when Op =:= 'andalso'; Op =:= 'orelse' ->
L1 = expr(L0, false),
R1 = expr(R0, false), %They see the same variables
- {Op,Line,L1,R1};
-expr({op,Line,Op,L0,R0}, _Lc) ->
+ {Op,ln(Anno),L1,R1};
+expr({op,Anno,Op,L0,R0}, _Lc) ->
L1 = expr(L0, false),
R1 = expr(R0, false), %They see the same variables
- {op,Line,Op,[L1,R1]};
-expr({bin,Line,Grp}, _Lc) ->
+ {op,ln(Anno),Op,[L1,R1]};
+expr({bin,Anno,Grp}, _Lc) ->
Grp1 = expr_list(Grp),
- {bin,Line,Grp1};
-expr({bin_element,Line,Expr,Size,Type}, _Lc) ->
+ {bin,ln(Anno),Grp1};
+expr({bin_element,Anno,Expr,Size,Type}, _Lc) ->
Expr1 = expr(Expr, false),
Size1 = expr(Size, false),
- {bin_element,Line,Expr1,Size1,Type};
+ {bin_element,ln(Anno),Expr1,Size1,Type};
expr(Other, _Lc) ->
exit({?MODULE,{unknown_expr,Other}}).
@@ -519,7 +520,6 @@ consify([A|As]) ->
{cons,0,A,consify(As)};
consify([]) -> {value,0,[]}.
-
%% -type expr_list([Expression]) -> [Expression].
%% These expressions are processed "in parallel" for purposes of variable
%% definition etc.
@@ -534,17 +534,17 @@ icr_clauses([C0|Cs], Lc) ->
[C1|icr_clauses(Cs, Lc)];
icr_clauses([], _) -> [].
-fun_clauses([{clause,L,H,G,B}|Cs]) ->
- [{clause,L,head(H),guard(G),exprs(B, true)}|fun_clauses(Cs)];
+fun_clauses([{clause,A,H,G,B}|Cs]) ->
+ [{clause,ln(A),head(H),guard(G),exprs(B, true)}|fun_clauses(Cs)];
fun_clauses([]) -> [].
map_fields(Fs) ->
map_fields(Fs, fun (E) -> expr(E, false) end).
-map_fields([{map_field_assoc,L,N,V}|Fs], F) ->
- [{map_field_assoc,L,F(N),F(V)}|map_fields(Fs)];
-map_fields([{map_field_exact,L,N,V}|Fs], F) ->
- [{map_field_exact,L,F(N),F(V)}|map_fields(Fs)];
+map_fields([{map_field_assoc,A,N,V}|Fs], F) ->
+ [{map_field_assoc,ln(A),F(N),F(V)}|map_fields(Fs)];
+map_fields([{map_field_exact,A,N,V}|Fs], F) ->
+ [{map_field_exact,ln(A),F(N),F(V)}|map_fields(Fs)];
map_fields([], _) -> [].
%% new_var_name() -> VarName.
@@ -564,6 +564,9 @@ new_vars(N, L, Vs) when N > 0 ->
new_vars(N-1, L, [V|Vs]);
new_vars(0, _, Vs) -> Vs.
+ln(Anno) ->
+ erl_anno:line(Anno).
+
bif_type(erlang, Name, Arity) ->
case erl_internal:guard_bif(Name, Arity) of
true ->
diff --git a/lib/debugger/src/int.erl b/lib/debugger/src/int.erl
index 908390ce50..33954ca82c 100644
--- a/lib/debugger/src/int.erl
+++ b/lib/debugger/src/int.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1998-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
diff --git a/lib/dialyzer/src/dialyzer_utils.erl b/lib/dialyzer/src/dialyzer_utils.erl
index 1cc9528fed..e29fc3ba8b 100644
--- a/lib/dialyzer/src/dialyzer_utils.erl
+++ b/lib/dialyzer/src/dialyzer_utils.erl
@@ -385,10 +385,11 @@ get_optional_callbacks(Abs) ->
%% - Constraint is of the form {subtype, T1, T2} where T1 and T2
%% are erl_types:erl_type()
-get_spec_info([{attribute, Ln, Contract, {Id, TypeSpec}}|Left],
+get_spec_info([{attribute, Attr, Contract, {Id, TypeSpec}}|Left],
SpecDict, CallbackDict, RecordsDict, ModName, OptCb, File)
when ((Contract =:= 'spec') or (Contract =:= 'callback')),
is_list(TypeSpec) ->
+ Ln = erl_anno:line(Attr),
MFA = case Id of
{_, _, _} = T -> T;
{F, A} -> {ModName, F, A}
@@ -519,7 +520,7 @@ get_options1([], Warnings) ->
Warnings.
-type collected_attribute() ::
- {Args :: term(), erl_scan:line(), file:filename()}.
+ {Args :: term(), erl_anno:line(), file:filename()}.
collect_attribute(Abs, Tag) ->
collect_attribute(Abs, Tag, "nofile").
@@ -643,7 +644,7 @@ get_options_with_tag(Tag, Abs) ->
%% Check F/A, and collect (unchecked) warning tags with line and file.
-spec check_fa_list([collected_attribute()], atom(), [fa()]) ->
- [{{atom(), erl_scan:line(), file:filename()},fa()}].
+ [{{atom(), erl_anno:line(), file:filename()},fa()}].
check_fa_list(AttrFile, Tag, Functions) ->
FuncTab = gb_sets:from_list(Functions),
diff --git a/lib/diameter/src/compiler/diameter_codegen.erl b/lib/diameter/src/compiler/diameter_codegen.erl
index d91a776321..d5a9c81b09 100644
--- a/lib/diameter/src/compiler/diameter_codegen.erl
+++ b/lib/diameter/src/compiler/diameter_codegen.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2010-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
@@ -183,7 +183,7 @@ erl_forms(Mod, ParseD) ->
f_enumerated_avp(ParseD),
f_empty_value(ParseD),
f_dict(ParseD),
- {eof, ?LINE}]],
+ {eof, erl_anno:new(?LINE)}]],
lists:append(Forms).
diff --git a/lib/diameter/src/compiler/diameter_forms.hrl b/lib/diameter/src/compiler/diameter_forms.hrl
index dd03401b9e..04d5834c88 100644
--- a/lib/diameter/src/compiler/diameter_forms.hrl
+++ b/lib/diameter/src/compiler/diameter_forms.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2010-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
@@ -28,8 +28,10 @@
[],
[?APPLY(erlang, error, [?ATOM(badarg)])]}).
+-define(ANNO(L), erl_anno:new(L)).
+
%% Form tag with line number.
--define(F(T), T, ?LINE).
+-define(F(T), T, ?ANNO(?LINE)).
%% Yes, that's right. The replacement is to the first unmatched ')'.
-define(attribute, ?F(attribute)).
@@ -47,10 +49,10 @@
-define(record_index, ?F(record_index)).
-define(tuple, ?F(tuple)).
--define(ATOM(T), {atom, ?LINE, T}).
--define(INTEGER(N), {integer, ?LINE, N}).
--define(VAR(V), {var, ?LINE, V}).
--define(NIL, {nil, ?LINE}).
+-define(ATOM(T), {atom, ?ANNO(?LINE), T}).
+-define(INTEGER(N), {integer, ?ANNO(?LINE), N}).
+-define(VAR(V), {var, ?ANNO(?LINE), V}).
+-define(NIL, {nil, ?ANNO(?LINE)}).
-define(CALL(F,A), {?call, ?ATOM(F), A}).
-define(APPLY(M,F,A), {?call, {?remote, ?ATOM(M), ?ATOM(F)}, A}).
diff --git a/lib/diameter/test/diameter_capx_SUITE.erl b/lib/diameter/test/diameter_capx_SUITE.erl
index 02501ce779..1c0f25864c 100644
--- a/lib/diameter/test/diameter_capx_SUITE.erl
+++ b/lib/diameter/test/diameter_capx_SUITE.erl
@@ -378,10 +378,14 @@ dict(N) ->
%% id's, failing with app_not_configured if it can't.
load_dict(N) ->
Mod = dict(N),
- Forms = [{attribute, 1, module, Mod},
- {attribute, 2, compile, [export_all]},
- {function, 3, id, 0,
- [{clause, 4, [], [], [{integer, 4, N}]}]}],
+ A1 = erl_anno:new(1),
+ A2 = erl_anno:new(2),
+ A3 = erl_anno:new(3),
+ A4 = erl_anno:new(4),
+ Forms = [{attribute, A1, module, Mod},
+ {attribute, A2, compile, [export_all]},
+ {function, A3, id, 0,
+ [{clause, A4, [], [], [{integer, A4, N}]}]}],
{ok, Mod, Bin, []} = compile:forms(Forms, [return]),
{module, Mod} = code:load_binary(Mod, Mod, Bin),
N = Mod:id().
diff --git a/lib/edoc/src/edoc.erl b/lib/edoc/src/edoc.erl
index 88e7ab5346..90f1fc3071 100644
--- a/lib/edoc/src/edoc.erl
+++ b/lib/edoc/src/edoc.erl
@@ -689,13 +689,12 @@ scan_and_parse(Epp) ->
fix_last_line(Toks0) ->
Toks1 = lists:reverse(Toks0),
- {line, LastLine} = erl_scan:token_info(hd(Toks1), line),
+ LastLine = erl_scan:line(hd(Toks1)),
fll(Toks1, LastLine, []).
-fll([{Category, Attributes0, Symbol} | L], LastLine, Ts) ->
- F = fun(_OldLine) -> LastLine end,
- Attributes = erl_scan:set_attribute(line, Attributes0, F),
- lists:reverse(L, [{Category, Attributes, Symbol} | Ts]);
+fll([{Category, Anno0, Symbol} | L], LastLine, Ts) ->
+ Anno = erl_anno:set_line(LastLine, Anno0),
+ lists:reverse(L, [{Category, Anno, Symbol} | Ts]);
fll([T | L], LastLine, Ts) ->
fll(L, LastLine, [T | Ts]);
fll(L, _LastLine, Ts) ->
diff --git a/lib/edoc/src/edoc_layout.erl b/lib/edoc/src/edoc_layout.erl
index 6309e88475..62d5eb9a18 100644
--- a/lib/edoc/src/edoc_layout.erl
+++ b/lib/edoc/src/edoc_layout.erl
@@ -535,7 +535,8 @@ t_clause(Name, Type) ->
pp_clause(Pre, Type) ->
Types = ot_utype([Type]),
Atom = lists:duplicate(iolist_size(Pre), $a),
- L1 = erl_pp:attribute({attribute,0,spec,{{list_to_atom(Atom),0},[Types]}}),
+ Attr = {attribute,0,spec,{{list_to_atom(Atom),0},[Types]}},
+ L1 = erl_pp:attribute(erl_parse:new_anno(Attr)),
"-spec " ++ L2 = lists:flatten(L1),
L3 = Pre ++ lists:nthtail(length(Atom), L2),
re:replace(L3, "\n ", "\n", [{return,list},global]).
@@ -555,7 +556,8 @@ format_type(Prefix, _Name, Type, Last, _Opts) ->
pp_type(Prefix, Type) ->
Atom = list_to_atom(lists:duplicate(iolist_size(Prefix), $a)),
- L1 = erl_pp:attribute({attribute,0,type,{Atom,ot_utype(Type),[]}}),
+ Attr = {attribute,0,type,{Atom,ot_utype(Type),[]}},
+ L1 = erl_pp:attribute(erl_parse:new_anno(Attr)),
{L2,N} = case lists:dropwhile(fun(C) -> C =/= $: end, lists:flatten(L1)) of
":: " ++ L3 -> {L3,9}; % compensation for extra "()" and ":"
"::\n" ++ L3 -> {"\n"++L3,6}
@@ -1085,8 +1087,8 @@ ot_var(E) ->
{var,0,list_to_atom(get_attrval(name, E))}.
ot_atom(E) ->
- {ok, [Atom], _} = erl_scan:string(get_attrval(value, E), 0),
- Atom.
+ {ok, [{atom,A,Name}], _} = erl_scan:string(get_attrval(value, E), 0),
+ {atom,erl_anno:line(A),Name}.
ot_integer(E) ->
{integer,0,list_to_integer(get_attrval(value, E))}.
diff --git a/lib/edoc/src/edoc_lib.erl b/lib/edoc/src/edoc_lib.erl
index c248964dc4..dcc239f6b4 100644
--- a/lib/edoc/src/edoc_lib.erl
+++ b/lib/edoc/src/edoc_lib.erl
@@ -1012,7 +1012,7 @@ get_plugin(Key, Default, Opts) ->
%% ---------------------------------------------------------------------
%% Error handling
--type line() :: erl_scan:line().
+-type line() :: erl_anno:line().
-type err() :: 'eof'
| {'missing', char()}
| {line(), atom(), string()}
diff --git a/lib/edoc/src/edoc_macros.erl b/lib/edoc/src/edoc_macros.erl
index bdcb3fe81f..e1a54d5090 100644
--- a/lib/edoc/src/edoc_macros.erl
+++ b/lib/edoc/src/edoc_macros.erl
@@ -311,7 +311,7 @@ macro_content([C | Cs], As, L, N) ->
macro_content([], _As, _L, _N) ->
throw('end').
--type line() :: erl_scan:line().
+-type line() :: erl_anno:line().
-type err() :: 'unterminated_macro'
| 'macro_name'
| {'macro_name', string()}
diff --git a/lib/edoc/src/edoc_parser.yrl b/lib/edoc/src/edoc_parser.yrl
index 48c01c8dce..835e7ccaa6 100644
--- a/lib/edoc/src/edoc_parser.yrl
+++ b/lib/edoc/src/edoc_parser.yrl
@@ -338,7 +338,7 @@ build_def(S, P, As, T) ->
args = lists:reverse(As)},
type = T};
false ->
- return_error(element(2, P), "variable expected after '('")
+ return_error(tok_line(P), "variable expected after '('")
end.
all_vars([#t_var{} | As]) ->
@@ -452,7 +452,7 @@ parse_throws(S, L) ->
%% ---------------------------------------------------------------------
--spec throw_error(term(), erl_scan:line()) -> no_return().
+-spec throw_error(term(), erl_anno:line()) -> no_return().
throw_error({parse_spec, E}, L) ->
throw_error({"specification", E}, L);
diff --git a/lib/edoc/src/edoc_specs.erl b/lib/edoc/src/edoc_specs.erl
index 3bf81c6503..59f6cb8ddf 100644
--- a/lib/edoc/src/edoc_specs.erl
+++ b/lib/edoc/src/edoc_specs.erl
@@ -1,7 +1,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
@@ -58,7 +58,7 @@ type(Form, TypeDocs) ->
end,
{#t_name{name = N}, T, As, Doc0}
end,
- #tag{name = type, line = element(2, Type),
+ #tag{name = type, line = get_line(element(2, Type)),
origin = code,
data = {#t_typedef{name = TypeName,
args = d2e(Args),
@@ -71,7 +71,7 @@ type(Form, TypeDocs) ->
spec(Form, Clause) ->
{Name, _Arity, TypeSpecs} = get_spec(Form),
TypeSpec = lists:nth(Clause, TypeSpecs),
- #tag{name = spec, line = element(2, TypeSpec),
+ #tag{name = spec, line = get_line(element(2, TypeSpec)),
origin = code,
data = aspec(d2e(TypeSpec), Name)}.
@@ -83,7 +83,7 @@ dummy_spec(Form) ->
{#t_name{name = Name}, Arity, TypeSpecs} = get_spec(Form),
As = string:join(lists:duplicate(Arity, "_X"), ","),
S = lists:flatten(io_lib:format("~p(~s) -> true\n", [Name, As])),
- #tag{name = spec, line = element(2, hd(TypeSpecs)),
+ #tag{name = spec, line = get_line(element(2, hd(TypeSpecs))),
origin = code, data = S}.
-spec docs(Forms::[syntaxTree()],
@@ -140,7 +140,7 @@ find_type_docs([F | Fs], Cs, Fun) ->
%% Postcomments before the dot after the typespec are ignored.
C2 = [C1 | [C ||
C <- erl_syntax:get_postcomments(F),
- get_line(erl_syntax:get_pos(C)) >= LastTypeLine]],
+ erl_syntax:get_pos(C) >= LastTypeLine]],
C3 = collect_comments(Fs, LastTypeLine),
#tag{data = Doc0} = Fun(lists:reverse(C2 ++ C3), LastTypeLine),
case strip(Doc0) of % Strip away "f(). \n"
@@ -157,7 +157,7 @@ find_type_docs([F | Fs], Cs, Fun) ->
collect_comments([], _Line) ->
[];
collect_comments([F | Fs], Line) ->
- L1 = get_line(erl_syntax:get_pos(F)),
+ L1 = erl_syntax:get_pos(F),
if
L1 =:= Line + 1;
L1 =:= Line -> % a separate postcomment
@@ -190,29 +190,26 @@ get_name_and_last_line(F) ->
{Name, Data} = erl_syntax_lib:analyze_wild_attribute(F),
type = edoc_specs:tag(Name),
Attr = {attribute, erl_syntax:get_pos(F), Name, Data},
- Ref = make_ref(),
- Fun = fun(L) -> {Ref, get_line(L)} end,
+ Fun = fun(A) ->
+ Line = get_line(A),
+ case get('$max_line') of
+ Max when Max < Line ->
+ _ = put('$max_line', Line);
+ _ ->
+ ok
+ end
+ end,
+ undefined = put('$max_line', 0),
+ _ = erl_parse:map_anno(Fun, Attr),
+ Line = erase('$max_line'),
TypeName = case Data of
{N, _T, As} when is_atom(N) -> % skip records
{N, length(As)}
end,
- Line = gll(erl_lint:modify_line(Attr, Fun), Ref),
{TypeName, Line}.
-gll({Ref, Line}, Ref) ->
- Line;
-gll([], _Ref) ->
- 0;
-gll(List, Ref) when is_list(List) ->
- lists:max([gll(E, Ref) || E <- List]);
-gll(Tuple, Ref) when is_tuple(Tuple) ->
- gll(tuple_to_list(Tuple), Ref);
-gll(_, _) ->
- 0.
-
-get_line(Pos) ->
- {line, Line} = erl_scan:attributes_info(Pos, line),
- Line.
+get_line(Anno) ->
+ erl_anno:line(Anno).
%% Collect all Erlang types. Types in comments (@type) shadow Erlang
%% types (-spec/-opaque).
@@ -348,7 +345,7 @@ d2e({type,_,constraint,[Sub,Ts0]}) ->
Ts = [ST,T] = d2e([ST0,T0]),
#t_def{name = ST, type = typevar_anno(T, Ts)};
_ ->
- throw_error(element(2, Sub), "cannot handle guard", [])
+ throw_error(get_line(element(2, Sub)), "cannot handle guard", [])
end;
d2e({type,_,union,Ts0}) ->
Ts = d2e(Ts0),
diff --git a/lib/edoc/src/edoc_tags.erl b/lib/edoc/src/edoc_tags.erl
index c1c453511a..9e2e41e902 100644
--- a/lib/edoc/src/edoc_tags.erl
+++ b/lib/edoc/src/edoc_tags.erl
@@ -342,7 +342,7 @@ parse_typedef(Data, Line, _Env, Where) ->
Def
end.
--type line() :: erl_scan:line().
+-type line() :: erl_anno:line().
-spec parse_file(_, line(), _, _) -> no_return().
diff --git a/lib/erl_docgen/src/docgen_otp_specs.erl b/lib/erl_docgen/src/docgen_otp_specs.erl
index e2eee2b3c0..b62e69529b 100644
--- a/lib/erl_docgen/src/docgen_otp_specs.erl
+++ b/lib/erl_docgen/src/docgen_otp_specs.erl
@@ -1,7 +1,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
@@ -202,7 +202,8 @@ t_clause(Name, Type) ->
pp_clause(Pre, Type) ->
Types = ot_utype([Type]),
Atom = lists:duplicate(iolist_size(Pre), $a),
- L1 = erl_pp:attribute({attribute,0,spec,{{list_to_atom(Atom),0},[Types]}}),
+ Attr = {attribute,0,spec,{{list_to_atom(Atom),0},[Types]}},
+ L1 = erl_pp:attribute(erl_parse:new_anno(Attr)),
"-spec " ++ L2 = lists:flatten(L1),
L3 = Pre ++ lists:nthtail(length(Atom), L2),
re:replace(L3, "\n ", "\n", [{return,list},global]).
@@ -222,7 +223,8 @@ format_type(_Name, Type, _Opts) ->
pp_type(Prefix, Type) ->
Atom = list_to_atom(lists:duplicate(iolist_size(Prefix), $a)),
- L1 = erl_pp:attribute({attribute,0,type,{Atom,ot_utype(Type),[]}}),
+ Attr = {attribute,0,type,{Atom,ot_utype(Type),[]}},
+ L1 = erl_pp:attribute(erl_parse:new_anno(Attr)),
{L2,N} = case lists:dropwhile(fun(C) -> C =/= $: end, lists:flatten(L1)) of
":: " ++ L3 -> {L3,9}; % compensation for extra "()" and ":"
"::\n" ++ L3 -> {"\n"++L3,6}
@@ -569,8 +571,8 @@ ot_var(E) ->
{var,0,list_to_atom(get_attrval(name, E))}.
ot_atom(E) ->
- {ok, [Atom], _} = erl_scan:string(get_attrval(value, E), 0),
- Atom.
+ {ok, [{atom,A,Name}], _} = erl_scan:string(get_attrval(value, E), 0),
+ {atom,erl_anno:line(A),Name}.
ot_integer(E) ->
{integer,0,list_to_integer(get_attrval(value, E))}.
diff --git a/lib/eunit/src/eunit_autoexport.erl b/lib/eunit/src/eunit_autoexport.erl
index 36ae3b71d7..7bb78f5ea8 100644
--- a/lib/eunit/src/eunit_autoexport.erl
+++ b/lib/eunit/src/eunit_autoexport.erl
@@ -79,11 +79,12 @@ rewrite([{function,_,test,0,_}=F | Fs], As, Module, _Test) ->
rewrite([F | Fs], As, Module, Test) ->
rewrite(Fs, [F | As], Module, Test);
rewrite([], As, Module, Test) ->
+ L = erl_anno:new(0),
{if Test ->
- [{function,0,test,0,
- [{clause,0,[],[],
- [{call,0,{remote,0,{atom,0,eunit},{atom,0,test}},
- [{atom,0,Module}]}]}]}
+ [{function,L,test,0,
+ [{clause,L,[],[],
+ [{call,L,{remote,L,{atom,L,eunit},{atom,L,test}},
+ [{atom,L,Module}]}]}]}
| As];
true ->
As
@@ -96,4 +97,4 @@ module_decl(Name, M, Fs, Exports) ->
Es = if Test -> [{test,0} | Exports];
true -> Exports
end,
- [M, {attribute,0,export,Es} | lists:reverse(Fs1)].
+ [M, {attribute,erl_anno:new(0),export,Es} | lists:reverse(Fs1)].
diff --git a/lib/hipe/cerl/cerl_to_icode.erl b/lib/hipe/cerl/cerl_to_icode.erl
index 2645056be1..f98aaa12f3 100644
--- a/lib/hipe/cerl/cerl_to_icode.erl
+++ b/lib/hipe/cerl/cerl_to_icode.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2003-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
@@ -110,7 +110,7 @@
effect = false :: boolean(),
fail = [], % [] or fail-to label
class = expr :: 'expr' | 'guard',
- line = 0 :: erl_scan:line(), % current line number
+ line = 0 :: erl_anno:line(), % current line number
'receive' :: 'undefined' | #'receive'{}
}).
diff --git a/lib/inets/src/inets_app/inets_lib.erl b/lib/inets/src/inets_app/inets_lib.erl
index e79959f678..fa6adaebd0 100644
--- a/lib/inets/src/inets_app/inets_lib.erl
+++ b/lib/inets/src/inets_app/inets_lib.erl
@@ -26,7 +26,7 @@
%% Help function, elapsed milliseconds since T0
millisec_passed({_,_,_} = T0 ) ->
%% OTP 17 and earlier
- timer:now_diff(inets_time_compat:monotonic_time(), T0) div 1000;
+ timer:now_diff(inets_time_compat:timestamp(), T0) div 1000;
millisec_passed(T0) ->
%% OTP 18
diff --git a/lib/kernel/src/user_drv.erl b/lib/kernel/src/user_drv.erl
index e6ce85c379..380c685869 100644
--- a/lib/kernel/src/user_drv.erl
+++ b/lib/kernel/src/user_drv.erl
@@ -133,6 +133,7 @@ server1(Iport, Oport, Shell) ->
flatten(io_lib:format("~ts\n",
[erlang:system_info(system_version)]))},
Iport, Oport),
+
%% Enter the server loop.
server_loop(Iport, Oport, Curr, User, Gr, queue:new()).
@@ -315,6 +316,9 @@ handle_escape(Iport, Oport, User, Gr, IOQueue) ->
_ -> % {ok,jcl} | undefined
io_request({put_chars,unicode,"\nUser switch command\n"}, Iport, Oport),
+ %% init edlin used by switch command and have it copy the
+ %% text buffer from current group process
+ edlin:init(gr_cur_pid(Gr)),
server_loop(Iport, Oport, User, switch_loop(Iport, Oport, Gr), IOQueue)
end.
diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl
index afedc17e57..549c65d034 100644
--- a/lib/kernel/test/code_SUITE.erl
+++ b/lib/kernel/test/code_SUITE.erl
@@ -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
@@ -1396,8 +1396,9 @@ on_load_binary(_) ->
{tuple,6,[{atom,6,Mod},{call,6,{atom,6,self},[]}]}},
{'receive',7,[{clause,8,[{atom,8,go}],[],[{atom,8,ok}]}]}]}]},
{function,11,ok,0,[{clause,11,[],[],[{atom,11,true}]}]}],
- {ok,Mod,Bin} = compile:forms(Forms, [report]),
- [io:put_chars(erl_pp:form(F)) || F <- Forms],
+ Forms1 = erl_parse:new_anno(Forms),
+ {ok,Mod,Bin} = compile:forms(Forms1, [report]),
+ [io:put_chars(erl_pp:form(F)) || F <- Forms1],
{Pid1,Ref1} = spawn_monitor(fun() ->
code:load_binary(Mod, File, Bin),
diff --git a/lib/kernel/test/heart_SUITE.erl b/lib/kernel/test/heart_SUITE.erl
index 35d3b75b34..43224cf554 100644
--- a/lib/kernel/test/heart_SUITE.erl
+++ b/lib/kernel/test/heart_SUITE.erl
@@ -562,13 +562,15 @@ suicide_by_heart() ->
generate(Module, Attributes, FunStrings) ->
FunForms = function_forms(FunStrings),
Forms = [
- {attribute,1,module,Module},
- {attribute,2,export,[FA || {FA,_} <- FunForms]}
- ] ++ [{attribute, 3, A, V}|| {A, V} <- Attributes] ++
+ {attribute,a(1),module,Module},
+ {attribute,a(2),export,[FA || {FA,_} <- FunForms]}
+ ] ++ [{attribute, a(3), A, V}|| {A, V} <- Attributes] ++
[ Function || {_, Function} <- FunForms],
{ok, Module, Bin} = compile:forms(Forms),
Bin.
+a(L) ->
+ erl_anno:new(L).
function_forms([]) -> [];
function_forms([S|Ss]) ->
diff --git a/lib/parsetools/include/yeccpre.hrl b/lib/parsetools/include/yeccpre.hrl
index 855bff5fdc..b9bba9a7c2 100644
--- a/lib/parsetools/include/yeccpre.hrl
+++ b/lib/parsetools/include/yeccpre.hrl
@@ -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
@@ -124,21 +124,10 @@ yecc_end(Line) ->
{'$end', Line}.
yecctoken_end_location(Token) ->
- try
- {text, Str} = erl_scan:token_info(Token, text),
- {line, Line} = erl_scan:token_info(Token, line),
- Parts = re:split(Str, "\n"),
- Dline = length(Parts) - 1,
- Yline = Line + Dline,
- case erl_scan:token_info(Token, column) of
- {column, Column} ->
- Col = byte_size(lists:last(Parts)),
- {Yline, Col + if Dline =:= 0 -> Column; true -> 1 end};
- undefined ->
- Yline
- end
- catch _:_ ->
- yecctoken_location(Token)
+ try erl_anno:end_location(element(2, Token)) of
+ undefined -> yecctoken_location(Token);
+ Loc -> Loc
+ catch _:_ -> yecctoken_location(Token)
end.
-compile({nowarn_unused_function, yeccerror/1}).
@@ -149,15 +138,15 @@ yeccerror(Token) ->
-compile({nowarn_unused_function, yecctoken_to_string/1}).
yecctoken_to_string(Token) ->
- case catch erl_scan:token_info(Token, text) of
- {text, Txt} -> Txt;
- _ -> yecctoken2string(Token)
+ try erl_scan:text(Token) of
+ undefined -> yecctoken2string(Token);
+ Txt -> Txt
+ catch _:_ -> yecctoken2string(Token)
end.
yecctoken_location(Token) ->
- case catch erl_scan:token_info(Token, location) of
- {location, Loc} -> Loc;
- _ -> element(2, Token)
+ try erl_scan:location(Token)
+ catch _:_ -> element(2, Token)
end.
-compile({nowarn_unused_function, yecctoken2string/1}).
diff --git a/lib/parsetools/src/leex.erl b/lib/parsetools/src/leex.erl
index 03f864ff03..15d42a4d9c 100644
--- a/lib/parsetools/src/leex.erl
+++ b/lib/parsetools/src/leex.erl
@@ -1545,7 +1545,7 @@ out_action_code(File, XrlFile, {_A,Code,_Vars,Name,Args,ArgsChars}) ->
%% Should set the file to the .erl file, but instead assumes that
%% ?LEEXINC is syntactically correct.
io:fwrite(File, "\n-compile({inline,~w/~w}).\n", [Name, length(Args)]),
- {line, L} = erl_scan:token_info(hd(Code), line),
+ L = erl_scan:line(hd(Code)),
output_file_directive(File, XrlFile, L-2),
io:fwrite(File, "~s(~s) ->~n", [Name, ArgsChars]),
io:fwrite(File, " ~s\n", [pp_tokens(Code, L)]).
@@ -1557,7 +1557,7 @@ pp_tokens(Tokens, Line0) -> pp_tokens(Tokens, Line0, none).
pp_tokens([], _Line0, _) -> [];
pp_tokens([T | Ts], Line0, Prev) ->
- {line, Line} = erl_scan:token_info(T, line),
+ Line = erl_scan:line(T),
[pp_sep(Line, Line0, Prev, T), pp_symbol(T) | pp_tokens(Ts, Line, T)].
pp_symbol({var,_,Var}) -> atom_to_list(Var);
diff --git a/lib/parsetools/src/yeccgramm.yrl b/lib/parsetools/src/yeccgramm.yrl
index 562a9a7458..d76ebfc569 100644
--- a/lib/parsetools/src/yeccgramm.yrl
+++ b/lib/parsetools/src/yeccgramm.yrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. 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
@@ -38,8 +38,8 @@ rule -> head '->' symbols attached_code dot: {rule, ['$1' | '$3'], '$4'}.
head -> symbol : '$1'.
symbols -> symbol : ['$1'].
symbols -> symbol symbols : ['$1' | '$2'].
-strings -> string : ['$1'].
-strings -> string strings : ['$1' | '$2'].
+strings -> string : [string('$1')].
+strings -> string strings : [string('$1') | '$2'].
attached_code -> ':' tokens : {erlang_code, '$2'}.
attached_code -> '$empty' : {erlang_code, [{atom, 0, '$undefined'}]}.
tokens -> token : ['$1'].
@@ -48,12 +48,12 @@ symbol -> var : symbol('$1').
symbol -> atom : symbol('$1').
symbol -> integer : symbol('$1').
symbol -> reserved_word : symbol('$1').
-token -> var : '$1'.
-token -> atom : '$1'.
-token -> float : '$1'.
-token -> integer : '$1'.
-token -> string : '$1'.
-token -> char : '$1'.
+token -> var : token('$1').
+token -> atom : token('$1').
+token -> float : token('$1').
+token -> integer : token('$1').
+token -> string : token('$1').
+token -> char : token('$1').
token -> reserved_symbol : {value_of('$1'), line_of('$1')}.
token -> reserved_word : {value_of('$1'), line_of('$1')}.
token -> '->' : {'->', line_of('$1')}. % Have to be treated in this
@@ -67,8 +67,14 @@ Erlang code.
symbol(Symbol) ->
#symbol{line = line_of(Symbol), name = value_of(Symbol)}.
+token(Token) ->
+ setelement(2, Token, line_of(Token)).
+
+string(Token) ->
+ setelement(2, Token, line_of(Token)).
+
value_of(Token) ->
element(3, Token).
line_of(Token) ->
- element(2, Token).
+ erl_anno:line(element(2, Token)).
diff --git a/lib/parsetools/src/yeccparser.erl b/lib/parsetools/src/yeccparser.erl
index 54f9ba5a58..fa0a1c4e2a 100644
--- a/lib/parsetools/src/yeccparser.erl
+++ b/lib/parsetools/src/yeccparser.erl
@@ -7,17 +7,23 @@
symbol(Symbol) ->
#symbol{line = line_of(Symbol), name = value_of(Symbol)}.
+token(Token) ->
+ setelement(2, Token, line_of(Token)).
+
+string(Token) ->
+ setelement(2, Token, line_of(Token)).
+
value_of(Token) ->
element(3, Token).
line_of(Token) ->
- element(2, Token).
+ erl_anno:line(element(2, Token)).
--file("/clearcase/otp/erts/lib/parsetools/include/yeccpre.hrl", 0).
+-file("lib/parsetools/include/yeccpre.hrl", 0).
%%
%% %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
@@ -44,10 +50,11 @@ parse(Tokens) ->
-spec parse_and_scan({function() | {atom(), atom()}, [_]}
| {atom(), atom(), [_]}) -> yecc_ret().
-parse_and_scan({F, A}) -> % Fun or {M, F}
+parse_and_scan({F, A}) ->
yeccpars0([], {{F, A}, no_line}, 0, [], []);
parse_and_scan({M, F, A}) ->
- yeccpars0([], {{{M, F}, A}, no_line}, 0, [], []).
+ Arity = length(A),
+ yeccpars0([], {{fun M:F/Arity, A}, no_line}, 0, [], []).
-spec format_error(any()) -> [char() | list()].
format_error(Message) ->
@@ -140,13 +147,13 @@ yecc_end(Line) ->
yecctoken_end_location(Token) ->
try
- {text, Str} = erl_scan:token_info(Token, text),
- {line, Line} = erl_scan:token_info(Token, line),
+ Str = erl_scan:text(Token),
+ Line = erl_scan:line(Token),
Parts = re:split(Str, "\n"),
Dline = length(Parts) - 1,
Yline = Line + Dline,
- case erl_scan:token_info(Token, column) of
- {column, Column} ->
+ case erl_scan:column(Token) of
+ Column when is_integer(Column) ->
Col = byte_size(lists:last(Parts)),
{Yline, Col + if Dline =:= 0 -> Column; true -> 1 end};
undefined ->
@@ -156,23 +163,26 @@ yecctoken_end_location(Token) ->
yecctoken_location(Token)
end.
+-compile({nowarn_unused_function, yeccerror/1}).
yeccerror(Token) ->
Text = yecctoken_to_string(Token),
Location = yecctoken_location(Token),
{error, {Location, ?MODULE, ["syntax error before: ", Text]}}.
+-compile({nowarn_unused_function, yecctoken_to_string/1}).
yecctoken_to_string(Token) ->
- case catch erl_scan:token_info(Token, text) of
- {text, Txt} -> Txt;
+ case catch erl_scan:text(Token) of
+ Txt when is_list(Txt) -> Txt;
_ -> yecctoken2string(Token)
end.
yecctoken_location(Token) ->
- case catch erl_scan:token_info(Token, location) of
- {location, Loc} -> Loc;
+ case catch erl_scan:location(Token) of
+ Loc when Loc =/= undefined -> Loc;
_ -> element(2, Token)
end.
+-compile({nowarn_unused_function, yecctoken2string/1}).
yecctoken2string({atom, _, A}) -> io_lib:write(A);
yecctoken2string({integer,_,N}) -> io_lib:write(N);
yecctoken2string({float,_,F}) -> io_lib:write(F);
@@ -180,7 +190,7 @@ yecctoken2string({char,_,C}) -> io_lib:write_char(C);
yecctoken2string({var,_,V}) -> io_lib:format("~s", [V]);
yecctoken2string({string,_,S}) -> io_lib:write_string(S);
yecctoken2string({reserved_symbol, _, A}) -> io_lib:write(A);
-yecctoken2string({_Cat, _, Val}) -> io_lib:write(Val);
+yecctoken2string({_Cat, _, Val}) -> io_lib:format("~p",[Val]);
yecctoken2string({dot, _}) -> "'.'";
yecctoken2string({'$end', _}) ->
[];
@@ -193,7 +203,7 @@ yecctoken2string(Other) ->
--file("yeccparser.erl", 196).
+-file("yeccgramm.erl", 207).
yeccpars2(0=S, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccpars2_0(S, Cat, Ss, Stack, T, Ts, Tzr);
@@ -268,7 +278,7 @@ yeccpars2(34=S, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccpars2(35=S, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccpars2_35(S, Cat, Ss, Stack, T, Ts, Tzr);
yeccpars2(Other, _, _, _, _, _, _) ->
- erlang:error({yecc_bug,"1.3",{missing_state_in_action_table, Other}}).
+ erlang:error({yecc_bug,"1.4",{missing_state_in_action_table, Other}}).
yeccpars2_0(S, atom, Ss, Stack, T, Ts, Tzr) ->
yeccpars1(S, 6, Ss, Stack, T, Ts, Tzr);
@@ -417,16 +427,20 @@ yeccpars2_19(_S, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccgoto_token(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr).
yeccpars2_20(_S, Cat, Ss, Stack, T, Ts, Tzr) ->
- yeccgoto_token(hd(Ss), Cat, Ss, Stack, T, Ts, Tzr).
+ NewStack = yeccpars2_20_(Stack),
+ yeccgoto_token(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr).
yeccpars2_21(_S, Cat, Ss, Stack, T, Ts, Tzr) ->
- yeccgoto_token(hd(Ss), Cat, Ss, Stack, T, Ts, Tzr).
+ NewStack = yeccpars2_21_(Stack),
+ yeccgoto_token(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr).
yeccpars2_22(_S, Cat, Ss, Stack, T, Ts, Tzr) ->
- yeccgoto_token(hd(Ss), Cat, Ss, Stack, T, Ts, Tzr).
+ NewStack = yeccpars2_22_(Stack),
+ yeccgoto_token(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr).
yeccpars2_23(_S, Cat, Ss, Stack, T, Ts, Tzr) ->
- yeccgoto_token(hd(Ss), Cat, Ss, Stack, T, Ts, Tzr).
+ NewStack = yeccpars2_23_(Stack),
+ yeccgoto_token(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr).
yeccpars2_24(_S, Cat, Ss, Stack, T, Ts, Tzr) ->
NewStack = yeccpars2_24_(Stack),
@@ -437,10 +451,12 @@ yeccpars2_25(_S, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccgoto_token(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr).
yeccpars2_26(_S, Cat, Ss, Stack, T, Ts, Tzr) ->
- yeccgoto_token(hd(Ss), Cat, Ss, Stack, T, Ts, Tzr).
+ NewStack = yeccpars2_26_(Stack),
+ yeccgoto_token(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr).
yeccpars2_27(_S, Cat, Ss, Stack, T, Ts, Tzr) ->
- yeccgoto_token(hd(Ss), Cat, Ss, Stack, T, Ts, Tzr).
+ NewStack = yeccpars2_27_(Stack),
+ yeccgoto_token(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr).
yeccpars2_28(_S, Cat, Ss, Stack, T, Ts, Tzr) ->
[_|Nss] = Ss,
@@ -616,6 +632,38 @@ yeccpars2_19_(__Stack0) ->
{ ':' , line_of ( __1 ) }
end | __Stack].
+-compile({inline,yeccpars2_20_/1}).
+-file("yeccgramm.yrl", 48).
+yeccpars2_20_(__Stack0) ->
+ [__1 | __Stack] = __Stack0,
+ [begin
+ token ( __1 )
+ end | __Stack].
+
+-compile({inline,yeccpars2_21_/1}).
+-file("yeccgramm.yrl", 52).
+yeccpars2_21_(__Stack0) ->
+ [__1 | __Stack] = __Stack0,
+ [begin
+ token ( __1 )
+ end | __Stack].
+
+-compile({inline,yeccpars2_22_/1}).
+-file("yeccgramm.yrl", 49).
+yeccpars2_22_(__Stack0) ->
+ [__1 | __Stack] = __Stack0,
+ [begin
+ token ( __1 )
+ end | __Stack].
+
+-compile({inline,yeccpars2_23_/1}).
+-file("yeccgramm.yrl", 50).
+yeccpars2_23_(__Stack0) ->
+ [__1 | __Stack] = __Stack0,
+ [begin
+ token ( __1 )
+ end | __Stack].
+
-compile({inline,yeccpars2_24_/1}).
-file("yeccgramm.yrl", 53).
yeccpars2_24_(__Stack0) ->
@@ -632,6 +680,22 @@ yeccpars2_25_(__Stack0) ->
{ value_of ( __1 ) , line_of ( __1 ) }
end | __Stack].
+-compile({inline,yeccpars2_26_/1}).
+-file("yeccgramm.yrl", 51).
+yeccpars2_26_(__Stack0) ->
+ [__1 | __Stack] = __Stack0,
+ [begin
+ token ( __1 )
+ end | __Stack].
+
+-compile({inline,yeccpars2_27_/1}).
+-file("yeccgramm.yrl", 47).
+yeccpars2_27_(__Stack0) ->
+ [__1 | __Stack] = __Stack0,
+ [begin
+ token ( __1 )
+ end | __Stack].
+
-compile({inline,yeccpars2_28_/1}).
-file("yeccgramm.yrl", 42).
yeccpars2_28_(__Stack0) ->
@@ -653,7 +717,7 @@ yeccpars2_29_(__Stack0) ->
yeccpars2_32_(__Stack0) ->
[__1 | __Stack] = __Stack0,
[begin
- [ __1 ]
+ [ string ( __1 ) ]
end | __Stack].
-compile({inline,yeccpars2_33_/1}).
@@ -661,7 +725,7 @@ yeccpars2_32_(__Stack0) ->
yeccpars2_33_(__Stack0) ->
[__2,__1 | __Stack] = __Stack0,
[begin
- [ __1 | __2 ]
+ [ string ( __1 ) | __2 ]
end | __Stack].
-compile({inline,yeccpars2_34_/1}).
@@ -681,4 +745,4 @@ yeccpars2_35_(__Stack0) ->
end | __Stack].
--file("yeccgramm.yrl", 75).
+-file("yeccgramm.yrl", 82).
diff --git a/lib/parsetools/test/yecc_SUITE.erl b/lib/parsetools/test/yecc_SUITE.erl
index c18dc15e37..b8d658e5c2 100644
--- a/lib/parsetools/test/yecc_SUITE.erl
+++ b/lib/parsetools/test/yecc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2005-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
@@ -1521,7 +1521,9 @@ otp_7945(doc) ->
"OTP-7945. A bug introduced in R13A.";
otp_7945(suite) -> [];
otp_7945(Config) when is_list(Config) ->
- ?line {error,_} = erl_parse:parse([{atom,3,foo},{'.',2,9,9}]),
+ A2 = erl_anno:new(2),
+ A3 = erl_anno:new(3),
+ {error,_} = erl_parse:parse([{atom,3,foo},{'.',A2,9,9}]),
ok.
otp_8483(doc) ->
@@ -1786,7 +1788,8 @@ otp_7969(Config) when is_list(Config) ->
?line {ok, Ts11, _}=R1 = erl_scan:string("f() -> a."),
?line F1 = fun() -> {ok,Ts11 ++ [{'$end',2}],2} end,
- ?line{ok,{function,1,f,0,[{clause,1,[],[],[{atom,1,a}]}]}} =
+ A1 = erl_anno:new(1),
+ {ok,{function,A1,f,0,[{clause,A1,[],[],[{atom,A1,a}]}]}} =
erl_parse:parse_and_scan({F1, []}),
?line F2 = fun() -> erl_scan:string("f() -> ,") end,
?line {error,{1,erl_parse,_}} = erl_parse:parse_and_scan({F2, []}),
@@ -1797,7 +1800,7 @@ otp_7969(Config) when is_list(Config) ->
put(foo,bar), R1
end
end,
- ?line {ok,{function,1,f,0,[{clause,1,[],[],[{atom,1,a}]}]}} =
+ {ok,{function,A1,f,0,[{clause,A1,[],[],[{atom,A1,a}]}]}} =
erl_parse:parse_and_scan({F3,[]}),
F4 = fun() -> {error, {1, ?MODULE, bad}, 2} end,
?line {error, {1,?MODULE,bad}} = erl_parse:parse_and_scan({F4, []}),
@@ -1813,7 +1816,8 @@ otp_8919(doc) ->
"OTP-8919. Improve formating of Yecc error messages.";
otp_8919(suite) -> [];
otp_8919(Config) when is_list(Config) ->
- {error,{1,Mod,Mess}} = erl_parse:parse([{cat,1,"hello"}]),
+ A1 = erl_anno:new(1),
+ {error,{1,Mod,Mess}} = erl_parse:parse([{cat,A1,"hello"}]),
"syntax error before: \"hello\"" = lists:flatten(Mod:format_error(Mess)),
ok.
diff --git a/lib/ssh/doc/src/ssh_channel.xml b/lib/ssh/doc/src/ssh_channel.xml
index 429ef3c849..b8a03c350a 100644
--- a/lib/ssh/doc/src/ssh_channel.xml
+++ b/lib/ssh/doc/src/ssh_channel.xml
@@ -88,7 +88,7 @@
<fsummary>Makes a synchronous call to a channel.</fsummary>
<type>
<v>ChannelRef = pid() </v>
- <d>As returned by <c>start_link/4</c></d>
+ <d>As returned by <seealso marker = "#start_link-4">ssh_channel:start_link/4</seealso></d>
<v>Msg = term()</v>
<v>Timeout = timeout()</v>
<v>Reply = term()</v>
@@ -112,7 +112,7 @@
ChannelRef and returns ok.</fsummary>
<type>
<v>ChannelRef = pid()</v>
- <d>As returned by <c>start_link/4</c></d>
+ <d>As returned by <seealso marker = "#start_link-4">ssh_channel:start_link/4</seealso></d>
<v>Msg = term()</v>
</type>
<desc>
@@ -129,8 +129,8 @@
<name>enter_loop(State) -> _ </name>
<fsummary>Makes an existing process an ssh_channel process.</fsummary>
<type>
- <v>State = term() - as returned by
- <seealso marker = "#init-1">ssh_channel:init/1</seealso></v>
+ <v>State = term()</v>
+ <d>as returned by <seealso marker = "#init-1">ssh_channel:init/1</seealso></d>
</type>
<desc>
<p>Makes an existing process an <c>ssh_channel</c>
@@ -188,7 +188,7 @@
<name>reply(Client, Reply) -> _</name>
<fsummary>Sends a reply to a client.</fsummary>
<type>
- <v>Client - opaque to the user, see explanation below</v>
+ <v>Client = opaque()</v>
<v>Reply = term()</v>
</type>
<desc>
@@ -259,7 +259,7 @@
<v>State = term()</v>
<d>Internal state of the channel.</d>
<v>Extra = term()</v>
- <d>Passed “as-is” from the <c>{advanced,Extra}</c>
+ <d>Passed "as-is" from the <c>{advanced,Extra}</c>
part of the update instruction.</d>
</type>
<desc>
@@ -313,13 +313,15 @@
<c>ssh_channel:call/[2,3]</c>.</fsummary>
<type>
<v>Msg = term()</v>
- <v>From = Opaque to the user, is to be used as argument to
- ssh_channel:reply/2</v>
+ <v>From = opaque()</v>
+ <d>Is to be used as argument to
+ <seealso marker="#reply-2">ssh_channel:reply/2</seealso></d>
<v>State = term()</v>
<v>Result = {reply, Reply, NewState} | {reply, Reply, NewState, timeout()}
| {noreply, NewState} | {noreply , NewState, timeout()}
| {stop, Reason, Reply, NewState} | {stop, Reason, NewState} </v>
- <v>Reply = term() - will be the return value of ssh_channel:call/[2,3]</v>
+ <v>Reply = term()</v>
+ <d>Will be the return value of <seealso marker="#call-2">ssh_channel:call/[2,3]</seealso></d>
<v>NewState = term()</v>
<v>Reason = term()</v>
</type>
@@ -418,7 +420,7 @@
<func>
<name>Module:terminate(Reason, State) -> _</name>
<fsummary>Does cleaning up before channel process termination.
-</fsummary>
+ </fsummary>
<type>
<v>Reason = term()</v>
<v>State = term()</v>
diff --git a/lib/ssh/doc/src/ssh_sftp.xml b/lib/ssh/doc/src/ssh_sftp.xml
index 02970bfa42..643130fe6b 100644
--- a/lib/ssh/doc/src/ssh_sftp.xml
+++ b/lib/ssh/doc/src/ssh_sftp.xml
@@ -70,10 +70,28 @@
<desc><p>The <c><![CDATA[apread]]></c> function reads from a specified position,
combining the <c><![CDATA[position]]></c> and <c><![CDATA[aread]]></c> functions.</p>
- <p><seealso marker="#apread/3">ssh_sftp:apread/4</seealso></p> </desc>
+ <p><seealso marker="#apread-4">ssh_sftp:apread/4</seealso></p> </desc>
</func>
<func>
+ <name>apwrite(ChannelPid, Handle, Position, Data) -> ok | {error, Reason}</name>
+ <fsummary>Writes asynchronously to an open file.</fsummary>
+ <type>
+ <v>ChannelPid = pid()</v>
+ <v>Handle = term()</v>
+ <v>Position = integer()</v>
+ <v>Len = integer()</v>
+ <v>Data = binary()</v>
+ <v>Timeout = timeout()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p><c><![CDATA[apwrite]]></c> writes on a specified position, combining
+ the <c><![CDATA[position]]></c> and <c><![CDATA[awrite]]></c> operations.</p>
+ <p><seealso marker="#awrite-3">ssh_sftp:awrite/3</seealso> </p></desc>
+ </func>
+
+ <func>
<name>aread(ChannelPid, Handle, Len) -> {async, N} | {error, Error}</name>
<fsummary>Reads asynchronously from an open file.</fsummary>
<type>
@@ -95,23 +113,7 @@
</desc>
</func>
- <func>
- <name>apwrite(ChannelPid, Handle, Position, Data) -> ok | {error, Reason}</name>
- <fsummary>Writes asynchronously to an open file.</fsummary>
- <type>
- <v>ChannelPid = pid()</v>
- <v>Handle = term()</v>
- <v>Position = integer()</v>
- <v>Len = integer()</v>
- <v>Data = binary()</v>
- <v>Timeout = timeout()</v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p><c><![CDATA[apwrite]]></c> writes on a specified position, combining
- the <c><![CDATA[position]]></c> and <c><![CDATA[awrite]]></c> operations.</p>
- <p><seealso marker="#awrite/3">ssh_sftp:awrite/3</seealso> </p></desc>
- </func>
+
<func>
<name>awrite(ChannelPid, Handle, Data) -> ok | {error, Reason}</name>
@@ -163,7 +165,7 @@
</type>
<desc>
<p>Deletes the file specified by <c><![CDATA[Name]]></c>, like
- <seealso marker="kernel:file#delete/1">file:delete/1</seealso></p>
+ <seealso marker="kernel:file#delete-1">file:delete/1</seealso></p>
</desc>
</func>
@@ -232,7 +234,7 @@
<desc>
<p>Creates a symbolic link pointing to <c><![CDATA[Target]]></c> with the
name <c><![CDATA[Name]]></c>, like
- <seealso marker="kernel:file#make_symlink/2">file:make_symlink/2</seealso></p>
+ <seealso marker="kernel:file#make_symlink-2">file:make_symlink/2</seealso></p>
</desc>
</func>
@@ -297,7 +299,7 @@
<desc>
<p>Opens a handle to a tar file on the server, associated with <c>ChannelPid</c>.
The handle can be used for remote tar creation and extraction, as defined by the
- <seealso marker="stdlib:erl_tar#init/3">erl_tar:init/3</seealso> function.
+ <seealso marker="stdlib:erl_tar#init-3">erl_tar:init/3</seealso> function.
</p>
<p> For code exampel see Section
@@ -387,7 +389,7 @@
<desc>
<p>The <c><![CDATA[pread]]></c> function reads from a specified position,
combining the <c><![CDATA[position]]></c> and <c><![CDATA[read]]></c> functions.</p>
- <p><seealso marker="#read/4">ssh_sftp:read/4</seealso></p>
+ <p><seealso marker="#read-4">ssh_sftp:read/4</seealso></p>
</desc>
</func>
@@ -406,7 +408,7 @@
<desc>
<p>The <c><![CDATA[pread]]></c> function writes to a specified position,
combining the <c><![CDATA[position]]></c> and <c><![CDATA[write]]></c> functions.</p>
- <p><seealso marker="#write/3">ssh_sftp:write/3</seealso></p>
+ <p><seealso marker="#write-3">ssh_sftp:write/3</seealso></p>
</desc>
</func>
@@ -449,7 +451,7 @@
<desc>
<p>Reads a file from the server, and returns the data in a binary,
like
- <seealso marker="kernel:file#read_file/1">file:read_file/1</seealso></p>
+ <seealso marker="kernel:file#read_file-1">file:read_file/1</seealso></p>
</desc>
</func>
@@ -468,7 +470,7 @@
<desc>
<p>Returns a <c><![CDATA[file_info]]></c> record from the file specified by
<c><![CDATA[Name]]></c> or <c><![CDATA[Handle]]></c>,
- like <seealso marker="kernel:file#read_file_info/2">file:read_file_info/2</seealso></p>
+ like <seealso marker="kernel:file#read_file_info-2">file:read_file_info/2</seealso></p>
</desc>
</func>
@@ -485,7 +487,7 @@
<desc>
<p>Reads the link target from the symbolic link specified
by <c><![CDATA[name]]></c>, like
- <seealso marker="kernel:file#read_link/1">file:read_link/1</seealso></p>
+ <seealso marker="kernel:file#read_link-1">file:read_link/1</seealso></p>
</desc>
</func>
@@ -504,7 +506,7 @@
<desc>
<p>Returns a <c><![CDATA[file_info]]></c> record from the symbolic
link specified by <c><![CDATA[Name]]></c> or <c><![CDATA[Handle]]></c>, like
- <seealso marker="kernel:file#read_link_info/2">file:read_link_info/2</seealso></p>
+ <seealso marker="kernel:file#read_link_info-2">file:read_link_info/2</seealso></p>
</desc>
</func>
@@ -522,7 +524,7 @@
<desc>
<p>Renames a file named <c><![CDATA[OldName]]></c> and gives it the name
<c><![CDATA[NewName]]></c>, like
- <seealso marker="kernel:file#rename/2">file:rename/2</seealso></p>
+ <seealso marker="kernel:file#rename-2">file:rename/2</seealso></p>
</desc>
</func>
@@ -580,26 +582,7 @@
</type>
<desc>
<p>Stops an SFTP channel. Does not close the SSH connection.
- Use <seealso marker="ssh#close/1">ssh:close/1</seealso> to close it.</p>
- </desc>
- </func>
-
- <func>
- <name>write_file(ChannelPid, File, Iolist) -></name>
- <name>write_file(ChannelPid, File, Iolist, Timeout) -> ok | {error, Reason}</name>
- <fsummary>Writes a file.</fsummary>
- <type>
- <v>ChannelPid = pid()</v>
- <v>File = string()</v>
- <v>Iolist = iolist()</v>
- <v>Timeout = timeout()</v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Writes a file to the server, like <seealso
- marker="kernel:file#write_file/2">file:write_file/2</seealso> The
- file is created if it does not exist. The file is overwritten
- if it exists.</p>
+ Use <seealso marker="ssh#close-1">ssh:close/1</seealso> to close it.</p>
</desc>
</func>
@@ -617,9 +600,9 @@
</type>
<desc>
<p>Writes <c><![CDATA[data]]></c> to the file referenced by <c><![CDATA[Handle]]></c>.
- The file is to be opened with <c><![CDATA[write]]></c> or <c><![CDATA[append]]></c>
- flag. Returns <c><![CDATA[ok]]></c> if successful or <c><![CDATA[{error, Reason}]]></c>
- otherwise.</p>
+ The file is to be opened with <c><![CDATA[write]]></c> or <c><![CDATA[append]]></c>
+ flag. Returns <c><![CDATA[ok]]></c> if successful or <c><![CDATA[{error, Reason}]]></c>
+ otherwise.</p>
<p>Typical error reasons:</p>
<taglist>
<tag><c><![CDATA[ebadf]]></c></tag>
@@ -633,7 +616,26 @@
</taglist>
</desc>
</func>
-
+
+ <func>
+ <name>write_file(ChannelPid, File, Iolist) -></name>
+ <name>write_file(ChannelPid, File, Iolist, Timeout) -> ok | {error, Reason}</name>
+ <fsummary>Writes a file.</fsummary>
+ <type>
+ <v>ChannelPid = pid()</v>
+ <v>File = string()</v>
+ <v>Iolist = iolist()</v>
+ <v>Timeout = timeout()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Writes a file to the server, like <seealso
+ marker="kernel:file#write_file-2">file:write_file/2</seealso> The
+ file is created if it does not exist. The file is overwritten
+ if it exists.</p>
+ </desc>
+ </func>
+
<func>
<name>write_file_info(ChannelPid, Name, Info) -></name>
<name>write_file_info(ChannelPid, Name, Info, Timeout) -> ok | {error, Reason}</name>
@@ -647,11 +649,11 @@
</type>
<desc>
<p>Writes file information from a <c><![CDATA[file_info]]></c> record to the
- file specified by <c><![CDATA[Name]]></c>, like
- <seealso marker="kernel:file#write_file_info/2">file:write_file_info/[2,3]</seealso></p>
+ file specified by <c><![CDATA[Name]]></c>, like
+ <seealso marker="kernel:file#write_file_info-2">file:write_file_info/[2,3]</seealso></p>
</desc>
</func>
</funcs>
-
+
</erlref>
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index e1f2e059e8..4dea284071 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -70,6 +70,7 @@
undecoded_packet_length, % integer()
key_exchange_init_msg, % #ssh_msg_kexinit{}
renegotiate = false, % boolean()
+ last_size_rekey = 0,
connection_queue,
address,
port,
@@ -635,7 +636,8 @@ handle_event(renegotiate, StateName, State) ->
%% Rekey due to sent data limit reached?
handle_event(data_size, connected, #state{ssh_params = Ssh0} = State) ->
- {ok, [{send_oct,Sent}]} = inet:getstat(State#state.socket, [send_oct]),
+ {ok, [{send_oct,Sent0}]} = inet:getstat(State#state.socket, [send_oct]),
+ Sent = Sent0 - State#state.last_size_rekey,
MaxSent = proplists:get_value(rekey_limit, State#state.opts, 1024000000),
timer:apply_after(?REKEY_DATA_TIMOUT, gen_fsm, send_all_state_event, [self(), data_size]),
case Sent >= MaxSent of
@@ -645,7 +647,8 @@ handle_event(data_size, connected, #state{ssh_params = Ssh0} = State) ->
{next_state, kexinit,
next_packet(State#state{ssh_params = Ssh,
key_exchange_init_msg = KeyInitMsg,
- renegotiate = true})};
+ renegotiate = true,
+ last_size_rekey = Sent0})};
_ ->
{next_state, connected, next_packet(State)}
end;
diff --git a/lib/ssh/src/ssh_sftp.erl b/lib/ssh/src/ssh_sftp.erl
index c264eabc78..bab688f226 100644
--- a/lib/ssh/src/ssh_sftp.erl
+++ b/lib/ssh/src/ssh_sftp.erl
@@ -508,12 +508,12 @@ init([Cm, ChannelId, Options]) ->
%%--------------------------------------------------------------------
handle_call({{timeout, infinity}, wait_for_version_negotiation}, From,
#state{xf = #ssh_xfer{vsn = undefined} = Xf} = State) ->
- {noreply, State#state{xf = Xf#ssh_xfer{vsn = From}}};
+ {noreply, State#state{xf = Xf#ssh_xfer{vsn = {wait, From, undefined}}}};
handle_call({{timeout, Timeout}, wait_for_version_negotiation}, From,
#state{xf = #ssh_xfer{vsn = undefined} = Xf} = State) ->
- timer:send_after(Timeout, {timeout, undefined, From}),
- {noreply, State#state{xf = Xf#ssh_xfer{vsn = From}}};
+ TRef = erlang:send_after(Timeout, self(), {timeout, undefined, From}),
+ {noreply, State#state{xf = Xf#ssh_xfer{vsn = {wait, From, TRef}}}};
handle_call({_, wait_for_version_negotiation}, _, State) ->
{reply, ok, State};
@@ -865,7 +865,12 @@ do_handle_reply(#state{xf = Xf} = State,
case Xf#ssh_xfer.vsn of
undefined ->
ok;
- From ->
+ {wait, From, TRef} ->
+ if is_reference(TRef) ->
+ erlang:cancel_timer(TRef);
+ true ->
+ ok
+ end,
ssh_channel:reply(From, ok)
end,
State#state{xf = Xf#ssh_xfer{vsn = Version, ext = Ext}, rep_buf = Rest};
diff --git a/lib/ssh/test/ssh_connection_SUITE.erl b/lib/ssh/test/ssh_connection_SUITE.erl
index c9441a46b0..6fc09876ad 100644
--- a/lib/ssh/test/ssh_connection_SUITE.erl
+++ b/lib/ssh/test/ssh_connection_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2008-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
@@ -76,12 +76,13 @@ end_per_suite(_Config) ->
crypto:stop().
%%--------------------------------------------------------------------
-init_per_group(openssh, _Config) ->
+init_per_group(openssh, Config) ->
case gen_tcp:connect("localhost", 22, []) of
{error,econnrefused} ->
{skip,"No openssh deamon"};
{ok, Socket} ->
- gen_tcp:close(Socket)
+ gen_tcp:close(Socket),
+ ssh_test_lib:openssh_sanity_check(Config)
end;
init_per_group(_, Config) ->
Config.
@@ -93,7 +94,7 @@ end_per_group(_, Config) ->
init_per_testcase(_TestCase, Config) ->
%% To make sure we start clean as it is not certain that
%% end_per_testcase will be run!
- ssh:stop(),
+ end_per_testcase(Config),
ssh:start(),
Config.
diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl
index b8abf5e80e..8ca05746db 100644
--- a/lib/ssh/test/ssh_test_lib.erl
+++ b/lib/ssh/test/ssh_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2004-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
@@ -358,3 +358,16 @@ do_inet_port(Node) ->
{ok, Socket} = rpc:call(Node, gen_tcp, listen, [0, [{reuseaddr, true}]]),
{ok, Port} = rpc:call(Node, inet, port, [Socket]),
{Port, Socket}.
+
+openssh_sanity_check(Config) ->
+ ssh:start(),
+ case ssh:connect("localhost", 22, []) of
+ {ok, Pid} ->
+ ssh:close(Pid),
+ ssh:stop(),
+ Config;
+ Err ->
+ Str = lists:append(io_lib:format("~p", [Err])),
+ ssh:stop(),
+ {skip, Str}
+ end.
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index af70eeb46c..d99123f871 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2008-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
@@ -66,7 +66,7 @@ init_per_suite(Config) ->
{error,econnrefused} ->
{skip,"No openssh deamon"};
_ ->
- Config
+ ssh_test_lib:openssh_sanity_check(Config)
end;
_Else ->
{skip,"Could not start crypto!"}
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index b2b85a717f..40bda0c19f 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,4 +1,4 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 3.2.2
+SSH_VSN = 3.2.3
APP_VSN = "ssh-$(SSH_VSN)"
diff --git a/lib/ssl/doc/src/Makefile b/lib/ssl/doc/src/Makefile
index cfbf98f6e3..143756bd39 100644
--- a/lib/ssl/doc/src/Makefile
+++ b/lib/ssl/doc/src/Makefile
@@ -37,7 +37,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
# Target Specs
# ----------------------------------------------------
XML_APPLICATION_FILES = refman.xml
-XML_REF3_FILES = ssl.xml ssl_crl_cache.xml ssl_crl_cache.xml ssl_session_cache_api.xml
+XML_REF3_FILES = ssl.xml ssl_crl_cache.xml ssl_crl_cache_api.xml ssl_session_cache_api.xml
XML_REF6_FILES = ssl_app.xml
XML_PART_FILES = release_notes.xml usersguide.xml
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index d070cb4019..cdf6870c25 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -37,8 +37,7 @@
<title>SSL</title>
<list type="bulleted">
- <item><c>ssl</c> requires the <c>crypto</c> and <c>public_key</c>
- applications.</item>
+ <item>For application dependencies see <seealso marker="ssl_app"> ssl(6)</seealso> </item>
<item>Supported SSL/TLS-versions are SSL-3.0, TLS-1.0,
TLS-1.1, and TLS-1.2.</item>
<item>For security reasons SSL-2.0 is not supported.</item>
@@ -46,7 +45,7 @@
but can be configured.</item>
<item>Ephemeral Diffie-Hellman cipher suites are supported,
but not Diffie Hellman Certificates cipher suites.</item>
- <item>Elliptic Curve cipher suites are supported if the <c>crypto</c>
+ <item>Elliptic Curve cipher suites are supported if the Crypto
application supports it and named curves are used.
</item>
<item>Export cipher suites are not supported as the
@@ -64,7 +63,7 @@
<section>
<title>DATA TYPES</title>
- <p>The following data types are used in the functions for <c>ssl</c>:</p>
+ <p>The following data types are used in the functions for SSL:</p>
<taglist>
@@ -82,9 +81,9 @@
<p>For valid options, see the
<seealso marker="kernel:inet">inet(3)</seealso> and
<seealso marker="kernel:gen_tcp">gen_tcp(3)</seealso> manual pages
- in <c>kernel</c>.</p></item>
+ in Kernel.</p></item>
- <tag><c>ssloption()</c></tag>
+ <tag><marker id="type-ssloption"></marker><c>ssloption()</c></tag>
<item><p><c>= {verify, verify_type()}</c></p>
<p><c>| {verify_fun, {fun(), term()}}</c></p>
<p><c>| {fail_if_no_peer_cert, boolean()} {depth, integer()}</c></p>
@@ -262,7 +261,7 @@ atom()}} |
</code>
<p>The verification fun is called during the X509-path
- validation when an error or an extension unknown to the <c>ssl</c>
+ validation when an error or an extension unknown to the SSL
application is encountered. It is also called
when a certificate is considered valid by the path validation
to allow access to each certificate in the path to the user
@@ -339,7 +338,7 @@ marker="public_key:public_key#pkix_path_validation-3">public_key:pkix_path_valid
<tag><c>{crl_check, boolean() | peer | best_effort }</c></tag>
<item>
Perform CRL (Certificate Revocation List) verification
- <seealso marker="public_key:public_key#pkix_crl_validate-3">
+ <seealso marker="public_key:public_key#pkix_crls_validate-3">
(public_key:pkix_crls_validate/3)</seealso> on all the certificates during the path validation
<seealso
marker="public_key:public_key#pkix_path_validation-3">(public_key:pkix_path_validation/3)
@@ -376,14 +375,15 @@ marker="public_key:public_key#pkix_path_validation-3">public_key:pkix_path_valid
<tag><c>{partial_chain, fun(Chain::[DerCert]) -> {trusted_ca, DerCert} |
unknown_ca }</c></tag>
<item><p>Claim an intermediate CA in the chain as trusted. TLS then
- performs <c>public_key:pkix_path_validation/3</c>
+ performs <seealso
+ marker="public_key:public_key#pkix_path_validation-3">public_key:pkix_path_validation/3</seealso>
with the selected CA as trusted anchor and the rest of the chain.</p></item>
<tag><c>{versions, [protocol()]}</c></tag>
<item><p>TLS protocol versions supported by started clients and servers.
This option overrides the application environment option
<c>protocol_version</c>. If the environment option is not set, it defaults
- to all versions, except SSL-3.0, supported by the <c>ssl</c> application.
+ to all versions, except SSL-3.0, supported by the SSL application.
See also <seealso marker="ssl:ssl_app">ssl(6).</seealso></p></item>
<tag><c>{hibernate_after, integer()|undefined}</c></tag>
@@ -1000,21 +1000,21 @@ fun(srp, Username :: string(), UserState :: term()) ->
<func>
<name>start() -> </name>
<name>start(Type) -> ok | {error, Reason}</name>
- <fsummary>Starts the <c>ssl</c>application.</fsummary>
+ <fsummary>Starts the SSL application.</fsummary>
<type>
<v>Type = permanent | transient | temporary</v>
</type>
<desc>
- <p>Starts the <c>ssl</c> application. Default type
+ <p>Starts the SSL application. Default type
is <c>temporary</c>.</p>
</desc>
</func>
<func>
<name>stop() -> ok </name>
- <fsummary>Stops the <c>ssl</c> application.</fsummary>
+ <fsummary>Stops the SSL application.</fsummary>
<desc>
- <p>Stops the <c>ssl</c> application.</p>
+ <p>Stops the SSL application.</p>
</desc>
</func>
@@ -1056,16 +1056,16 @@ fun(srp, Username :: string(), UserState :: term()) ->
<func>
<name>versions() -> [versions_info()]</name>
<fsummary>Returns version information relevant for the
- <c>ssl</c> application.</fsummary>
+ SSL application.</fsummary>
<type>
<v>versions_info() = {app_vsn, string()} | {supported | available, [protocol()] </v>
</type>
<desc>
- <p>Returns version information relevant for the <c>ssl</c>
+ <p>Returns version information relevant for the SSL
application.</p>
<taglist>
<tag><c>app_vsn</c></tag>
- <item>The application version of the <c>ssl</c> application.</item>
+ <item>The application version of the SSL application.</item>
<tag><c>supported</c></tag>
<item>TLS/SSL versions supported by default.
@@ -1078,8 +1078,8 @@ fun(srp, Username :: string(), UserState :: term()) ->
</seealso>.</item>
<tag><c>available</c></tag>
- <item>All TLS/SSL versions supported by the <c>ssl</c> application.
- TLS 1.2 requires sufficient support from the <c>crypto</c>
+ <item>All TLS/SSL versions supported by the SSL application.
+ TLS 1.2 requires sufficient support from the Crypto
application.</item>
</taglist>
</desc>
@@ -1095,4 +1095,3 @@ fun(srp, Username :: string(), UserState :: term()) ->
</section>
</erlref>
-
diff --git a/lib/ssl/doc/src/ssl_app.xml b/lib/ssl/doc/src/ssl_app.xml
index 43c69ba377..f17f5cb9fe 100644
--- a/lib/ssl/doc/src/ssl_app.xml
+++ b/lib/ssl/doc/src/ssl_app.xml
@@ -35,21 +35,21 @@
<description></description>
<section>
<title>DEPENDENCIES</title>
- <p>The <c>ssl</c> application uses the <c>public_key</c> and
- <c>crypto</c> application to handle public keys and encryption, hence
- these applications must be loaded for the <c>ssl</c> application to work.
+ <p>The SSL application uses the <c>public_key</c> and
+ Crypto application to handle public keys and encryption, hence
+ these applications must be loaded for the SSL application to work.
In an embedded environment this means they must be started with
- <c>application:start/[1,2]</c> before the <c>ssl</c> application is
+ <c>application:start/[1,2]</c> before the SSL application is
started.</p>
</section>
<section>
<title>CONFIGURATION</title>
<p>The application environment configuration parameters in this section
- are defined for the <c>ssl</c> application. For more information
+ are defined for the SSL application. For more information
about configuration parameters, see the
<seealso marker="kernel:application">application(3)</seealso>
- manual page in <c>kernel</c>.</p>
+ manual page in Kernel.</p>
<p>The environment parameters can be set on the command line,
for example:</p>
@@ -60,7 +60,7 @@
<tag><c><![CDATA[protocol_version = <seealso marker="kernel:error_logger">ssl:protocol()</seealso> <optional>]]></c>.</tag>
<item><p>Protocol supported by started clients and
servers. If this option is not set, it defaults to all
- protocols currently supported by the <c>ssl</c> application.
+ protocols currently supported by the SSL application.
This option can be overridden by the version option
to <c>ssl:connect/[2,3]</c> and <c>ssl:listen/2</c>.</p></item>
@@ -91,7 +91,7 @@
<section>
<title>ERROR LOGGER AND EVENT HANDLERS</title>
- <p>The <c>ssl</c> applications uses the default <seealso marker="kernel:error_logger">OTP error logger</seealso> to log unexpected errors and TLS alerts. The logging of TLS alerts may be turned off with the <c>log_alert</c> option. </p>
+ <p>The SSL application uses the default <seealso marker="kernel:error_logger">OTP error logger</seealso> to log unexpected errors and TLS alerts. The logging of TLS alerts may be turned off with the <c>log_alert</c> option. </p>
</section>
<section>
diff --git a/lib/ssl/doc/src/ssl_crl_cache.xml b/lib/ssl/doc/src/ssl_crl_cache.xml
index 62bf2ea7b7..83b03375b1 100644
--- a/lib/ssl/doc/src/ssl_crl_cache.xml
+++ b/lib/ssl/doc/src/ssl_crl_cache.xml
@@ -29,7 +29,7 @@
<p>
Implements an internal CRL (Certificate Revocation List) cache.
In addition to implementing the <seealso
- marker="ssl_cache_crl_api"> ssl_cache_crl_api</seealso> behaviour
+ marker="ssl_crl_cache_api"> ssl_crl_cache_api</seealso> behaviour
the following functions are available.
</p>
</description>
@@ -44,7 +44,7 @@
<v> Reason = term()</v>
</type>
<desc>
- Delete CRLs from the ssl applications local cache.
+ <p>Delete CRLs from the ssl applications local cache. </p>
</desc>
</func>
<func>
@@ -58,7 +58,7 @@
<v> Reason = term()</v>
</type>
<desc>
- Insert CRLs into the ssl applications local cache.
+ <p>Insert CRLs into the ssl applications local cache. </p>
</desc>
</func>
</funcs>
diff --git a/lib/ssl/doc/src/ssl_crl_cache_api.xml b/lib/ssl/doc/src/ssl_crl_cache_api.xml
index 557b7814b8..1d9353a2cc 100644
--- a/lib/ssl/doc/src/ssl_crl_cache_api.xml
+++ b/lib/ssl/doc/src/ssl_crl_cache_api.xml
@@ -70,7 +70,7 @@
</type>
<desc>
<p> <c>fun fresh_crl/2 </c> will be used as input option <c>update_crl</c> to
- <seealso marker="public_key#pkix_path_validation-3">public_key:pkix_crls_validate/3 </seealso> </p>
+ <seealso marker="public_key:public_key#pkix_crls_validate-3">public_key:pkix_crls_validate/3 </seealso> </p>
</desc>
</func>
diff --git a/lib/ssl/doc/src/ssl_distribution.xml b/lib/ssl/doc/src/ssl_distribution.xml
index c9f7b1b27f..effb304938 100644
--- a/lib/ssl/doc/src/ssl_distribution.xml
+++ b/lib/ssl/doc/src/ssl_distribution.xml
@@ -38,11 +38,11 @@
connection-based protocol as bearer. However, a module that
implements the protocol-specific parts of the connection setup is
needed. The default distribution module is <c>inet_tcp_dist</c>
- in the <c>kernel</c> application. When starting an
+ in the Kernel application. When starting an
Erlang node distributed, <c>net_kernel</c> uses this module to
set up listen ports and connections.</p>
- <p>In the <c>ssl</c> application, an exra distribution
+ <p>In the SSL application, an exra distribution
module, <c>inet_tls_dist</c>, can be used as an
alternative. All distribution connections will use SSL and
all participating Erlang nodes in a distributed system must use
@@ -57,7 +57,7 @@
<list type="bulleted">
<item><em>Step 1:</em> Build boot scripts including the
- <c>ssl</c> application.</item>
+ SSL application.</item>
<item><em>Step 2:</em> Specify the distribution module for
<c>net_kernel</c>.</item>
<item><em>Step 3:</em> Specify the security options and other
@@ -74,8 +74,8 @@
see the <c>sasl</c> documentation. This is only an example of
what can be done.</p>
- <p>The simplest boot script possible includes only the <c>kernel</c>
- and <c>stdlib</c> applications. Such a script is located in the
+ <p>The simplest boot script possible includes only the Kernel
+ and STDLIB applications. Such a script is located in the
<c>bin</c> directory of the Erlang distribution. The source for the
script is found under the Erlang installation top directory under
<c><![CDATA[releases/<OTP version>/start_clean.rel]]></c>.</p>
@@ -84,12 +84,12 @@
<list type="bulleted">
<item><p>Copy that script to another location (and preferably another
name).</p></item>
- <item><p>Add the applications <c>crypto</c>, <c>public_key</c>, and
- <c>ssl</c> with their current version numbers after the
- <c>stdlib</c>application.</p></item>
+ <item><p>Add the applications Crypto, Public Key, and
+ SSL with their current version numbers after the
+ STDLIB application.</p></item>
</list>
- <p>The following shows an example <c>.rel</c> file with <c>ssl</c>
+ <p>The following shows an example <c>.rel</c> file with SSL
added:</p>
<code type="none">
{release, {"OTP APN 181 01","R15A"}, {erts, "5.9"},
@@ -132,27 +132,27 @@ Eshell V5.0 (abort with ^G)
1> whereis(ssl_manager).
<0.41.0> ]]></code>
- <p>The <c>whereis</c> function-call verifies that the <c>ssl</c>
+ <p>The <c>whereis</c> function-call verifies that the SSL
application is started.</p>
<p>As an alternative to building a bootscript, you can explicitly
- add the path to the <c>ssl</c> <c>ebin</c> directory on the command
+ add the path to the SSL <c>ebin</c> directory on the command
line. This is done with command-line option <c>-pa</c>. This
- works as the <c>ssl</c> application does not need to be started for the
- distribution to come up, as a clone of the <c>ssl</c> application is
- hooked into the <c>kernel</c> application. So, as long as the
- <c>ssl</c> application code can be reached, the distribution starts.
+ works as the SSL application does not need to be started for the
+ distribution to come up, as a clone of the SSL application is
+ hooked into the Kernel application. So, as long as the
+ SSL application code can be reached, the distribution starts.
The <c>-pa</c> method is only recommended for testing purposes.</p>
- <note><p>The clone of the <c>ssl</c> application must
+ <note><p>The clone of the SSL application must
enable the use of the SSL code in such an early bootstage as
needed to set up the distribution. However, this makes it
- impossible to soft upgrade the <c>ssl</c> application.</p></note>
+ impossible to soft upgrade the SSL application.</p></note>
</section>
<section>
<title>Specifying Distribution Module for net_kernel</title>
- <p>The distribution module for <c>ssl</c> is named <c>inet_tls_dist</c>
+ <p>The distribution module for SSL is named <c>inet_tls_dist</c>
and is specified on the command line with option <c>-proto_dist</c>.
The argument to <c>-proto_dist</c> is to be the module
name without suffix <c>_dist</c>. So, this distribution
@@ -172,7 +172,7 @@ Eshell V5.0 (abort with ^G)
(ssl_test@myhost)1> </code>
<p>However, a node started in this way refuses to talk
- to other nodes, as no <c>ssl</c> parameters are supplied
+ to other nodes, as no SSL parameters are supplied
(see the next section).</p>
</section>
diff --git a/lib/ssl/doc/src/ssl_protocol.xml b/lib/ssl/doc/src/ssl_protocol.xml
index 20f53c98e1..cc49515066 100644
--- a/lib/ssl/doc/src/ssl_protocol.xml
+++ b/lib/ssl/doc/src/ssl_protocol.xml
@@ -32,19 +32,19 @@
<file>ssl_protocol.xml</file>
</header>
- <p>The Erlang <c>ssl</c> application implements the SSL/TLS protocol
+ <p>The Erlang SSL application implements the SSL/TLS protocol
for the currently supported versions, see the
<seealso marker="ssl">ssl(3)</seealso> manual page.
</p>
- <p>By default <c>ssl</c> is run over the TCP/IP protocol even
+ <p>By default SSL/TLS is run over the TCP/IP protocol even
though you can plug in any other reliable transport protocol
with the same Application Programming Interface (API) as the
- <c>gen_tcp</c> module in <c>kernel</c>.</p>
+ <c>gen_tcp</c> module in Kernel.</p>
<p>If a client and a server wants to use an upgrade mechanism, such as
defined by RFC 2817, to upgrade a regular TCP/IP connection to an SSL
- connection, this is supported by the Erlang <c>ssl</c> API. This can be
+ connection, this is supported by the Erlang SSL application API. This can be
useful for, for example, supporting HTTP and HTTPS on the same port and
implementing virtual hosting.
</p>
@@ -143,7 +143,7 @@
connections. Sessions are used to avoid the expensive negotiation
of new security parameters for each connection."</p>
- <p>Session data is by default kept by the <c>ssl</c> application in a
+ <p>Session data is by default kept by the SSL application in a
memory storage, hence session data is lost at application
restart or takeover. Users can define their own callback module
to handle session data storage if persistent data storage is
diff --git a/lib/ssl/doc/src/ssl_session_cache_api.xml b/lib/ssl/doc/src/ssl_session_cache_api.xml
index 9cd16c5f58..c89d3874a1 100644
--- a/lib/ssl/doc/src/ssl_session_cache_api.xml
+++ b/lib/ssl/doc/src/ssl_session_cache_api.xml
@@ -108,8 +108,8 @@
API functions. Is called by the cache handling processes
<c>init</c> function, hence putting the same requirements on it
as a normal process <c>init</c> function. This function is
- called twice when starting the <c>ssl</c> application, once with
- the role client and once with the role server, as the <c>ssl</c>
+ called twice when starting the SSL application, once with
+ the role client and once with the role server, as the SSL
application must be prepared to take on both roles.
</p>
</desc>
diff --git a/lib/ssl/doc/src/using_ssl.xml b/lib/ssl/doc/src/using_ssl.xml
index 01b7970fb6..dbbc1aa9d3 100644
--- a/lib/ssl/doc/src/using_ssl.xml
+++ b/lib/ssl/doc/src/using_ssl.xml
@@ -32,10 +32,10 @@
<file>using_ssl.xml</file>
</header>
<p>To see relevant version information for ssl, call
- <seealso marker="ssl:versions-0"><c>ssl:versions/0</c></seealso>
+ <seealso marker="ssl:ssl#versions-0"><c>ssl:versions/0</c></seealso>
.</p>
- <p>To see all supported cipher suites, call <seealso marker="ssl:cipher_suites-1"><c>ssl:cipher_suites(all)</c> </seealso>.
+ <p>To see all supported cipher suites, call <seealso marker="ssl:ssl#cipher_suites-1"><c>ssl:cipher_suites(all)</c> </seealso>.
The available cipher suites for a connection depend on your certificate.
Specific cipher suites that you want your connection to use can also be
specified. Default is to use the strongest available.</p>
diff --git a/lib/stdlib/doc/src/Makefile b/lib/stdlib/doc/src/Makefile
index f5d8b2072a..ce1e19a2a4 100644
--- a/lib/stdlib/doc/src/Makefile
+++ b/lib/stdlib/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2012. All Rights Reserved.
+# Copyright Ericsson AB 1997-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
@@ -48,6 +48,7 @@ XML_REF3_FILES = \
digraph.xml \
digraph_utils.xml \
epp.xml \
+ erl_anno.xml \
erl_eval.xml \
erl_expand_records.xml \
erl_id_trans.xml \
diff --git a/lib/stdlib/doc/src/erl_anno.xml b/lib/stdlib/doc/src/erl_anno.xml
new file mode 100644
index 0000000000..281feacdc4
--- /dev/null
+++ b/lib/stdlib/doc/src/erl_anno.xml
@@ -0,0 +1,308 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2015</year>
+ <year>2015</year>
+ <holder>Ericsson AB, All Rights Reserved</holder>
+ </copyright>
+ <legalnotice>
+ 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 on line 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.
+
+ The Initial Developer of the Original Code is Ericsson AB.
+ </legalnotice>
+
+ <title>erl_anno</title>
+ <prepared>Hans Bolinder</prepared>
+ <responsible>Kenneth Lundin</responsible>
+ <docno>1</docno>
+ <approved></approved>
+ <checked></checked>
+ <date>2015-02-26</date>
+ <rev>A</rev>
+ <file>erl_anno.xml</file>
+ </header>
+ <module>erl_anno</module>
+
+ <modulesummary>
+ Abstract Datatype for the Annotations of the Erlang Compiler
+ </modulesummary>
+
+ <description>
+ <p>This module implements an abstract type that is used by the
+ Erlang Compiler and its helper modules for holding data such as
+ column, line number, and text. The data type is a collection of
+ <marker id="annotations"><em>annotations</em></marker> as
+ described in the following.</p>
+ <p>The Erlang Token Scanner returns tokens with a subset of
+ the following annotations, depending on the options:</p>
+ <taglist>
+ <tag><c>column</c></tag>
+ <item><p>The column where the token begins.</p></item>
+ <tag><c>location</c></tag>
+ <item><p>The line and column where the token begins, or
+ just the line if the column unknown.</p>
+ </item>
+ <tag><c>text</c></tag>
+ <item><p>The token's text.</p></item>
+ </taglist>
+ <p>From the above the following annotation is derived:</p>
+ <taglist>
+ <tag><c>line</c></tag>
+ <item><p>The line where the token begins.</p></item>
+ </taglist>
+ <p>Furthermore, the following annotations are supported by
+ this module, and used by various modules:</p>
+ <taglist>
+ <tag><c>file</c></tag>
+ <item><p>A filename.</p></item>
+ <tag><c>generated</c></tag>
+ <item><p>A Boolean indicating if the abstract code is
+ compiler generated. The Erlang Compiler does not emit warnings
+ for such code.</p>
+ </item>
+ <tag><c>record</c></tag>
+ <item><p>A Boolean indicating if the origin of the abstract
+ code is a record. Used by Dialyzer to assign types to tuple
+ elements.</p>
+ </item>
+ </taglist>
+ <p>The functions
+ <seealso marker="erl_scan#column/1">column()</seealso>,
+ <seealso marker="erl_scan#end_location/1">end_location()</seealso>,
+ <seealso marker="erl_scan#line/1">line()</seealso>,
+ <seealso marker="erl_scan#location/1">location()</seealso>, and
+ <seealso marker="erl_scan#text/1">text()</seealso>
+ in the <c>erl_scan</c> module can be used for inspecting
+ annotations in tokens.</p>
+ <p>The functions
+ <seealso marker="erl_parse#map_anno/2">map_anno()</seealso>,
+ <seealso marker="erl_parse#fold_anno/3">fold_anno()</seealso>,
+ <seealso marker="erl_parse#mapfold_anno/3">mapfold_anno()</seealso>,
+ <seealso marker="erl_parse#new_anno/1">new_anno()</seealso>,
+ <seealso marker="erl_parse#anno_from_term/1">
+ anno_from_term()</seealso>, and
+ <seealso marker="erl_parse#anno_to_term/1">
+ anno_to_term()</seealso> in the <c>erl_parse</c> module can be
+ used for manipulating annotations in abstract code.
+ </p>
+ </description>
+
+ <datatypes>
+ <datatype>
+ <name><marker id="type-anno">anno()</marker></name>
+ <desc><p>A collection of annotations.</p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="anno_term"></name>
+ <desc>
+ <p>The term representing a collection of annotations. It is
+ either a <c>location()</c> or a list of key-value pairs.</p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="column"></name>
+ </datatype>
+ <datatype>
+ <name name="line"></name>
+ <desc>
+ <p>To be changed to a non-negative integer in Erlang/OTP 19.0.</p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="location"></name>
+ </datatype>
+ <datatype>
+ <name name="text"></name>
+ </datatype>
+ </datatypes>
+
+ <funcs>
+ <func>
+ <name name="column" arity="1"/>
+ <type name="column"></type>
+ <fsummary>Return the column</fsummary>
+ <desc>
+ <p>Returns the column of the annotations <anno>Anno</anno>.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name name="end_location" arity="1"/>
+ <type name="location"></type>
+ <fsummary>Return the end location of the text</fsummary>
+ <desc>
+ <p>Returns the end location of the text of the
+ annotations <anno>Anno</anno>. If there is no text,
+ <c>undefined</c> is returned.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name name="file" arity="1"/>
+ <type name="filename"></type>
+ <fsummary>Return the filename</fsummary>
+ <desc>
+ <p>Returns the filename of the annotations <anno>Anno</anno>.
+ If there is no filename, <c>undefined</c> is returned.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name name="from_term" arity="1"/>
+ <fsummary>Return annotations given a term</fsummary>
+ <desc>
+ <p>Returns annotations with the representation <anno>Term</anno>.
+ </p>
+ <!--
+ <p>Although it is possible to create new annotations by calling
+ <c>from_term/1</c>, the intention is that one should not do
+ so - the proper way to create annotations is to call
+ <c>new/1</c> and then modify the annotations
+ by calling the <c>set_*</c> functions.</p>
+ -->
+ <p>See also <seealso marker="#to_term/1">to_term()</seealso>.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name name="generated" arity="1"/>
+ <type name="generated"></type>
+ <fsummary>Return the generated Boolean</fsummary>
+ <desc>
+ <p>Returns <c>true</c> if the annotations <anno>Anno</anno>
+ has been marked as generated. The default is to return
+ <c>false</c>.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name name="is_anno" arity="1"/>
+ <fsummary>Test for a collection of annotations</fsummary>
+ <desc>
+ <p>Returns <c>true</c> if <anno>Term</anno> is a collection of
+ annotations, <c>false</c> otherwise.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="line" arity="1"/>
+ <type name="line"></type>
+ <fsummary>Return the line</fsummary>
+ <desc>
+ <p>Returns the line of the annotations <anno>Anno</anno>.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name name="location" arity="1"/>
+ <type name="location"></type>
+ <fsummary>Return the location</fsummary>
+ <desc>
+ <p>Returns the location of the annotations <anno>Anno</anno>.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name name="new" arity="1"/>
+ <type name="location"></type>
+ <fsummary>Create a new collection of annotations</fsummary>
+ <desc>
+ <p>Creates a new collection of annotations given a location.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="set_file" arity="2"/>
+ <type name="filename"></type>
+ <fsummary>Modify the filename</fsummary>
+ <desc>
+ <p>Modifies the filename of the annotations <anno>Anno</anno>.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name name="set_generated" arity="2"/>
+ <type name="generated"></type>
+ <fsummary>Modify the generated marker</fsummary>
+ <desc>
+ <p>Modifies the generated marker of the annotations
+ <anno>Anno</anno>.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name name="set_line" arity="2"/>
+ <type name="line"></type>
+ <fsummary>Modify the line</fsummary>
+ <desc>
+ <p>Modifies the line of the annotations <anno>Anno</anno>.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name name="set_location" arity="2"/>
+ <type name="location"></type>
+ <fsummary>Modify the location</fsummary>
+ <desc>
+ <p>Modifies the location of the annotations <anno>Anno</anno>.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name name="set_record" arity="2"/>
+ <type name="record"></type>
+ <fsummary>Modify the record marker</fsummary>
+ <desc>
+ <p>Modifies the record marker of the annotations <anno>Anno</anno>.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name name="set_text" arity="2"/>
+ <type name="text"></type>
+ <fsummary>Modify the text</fsummary>
+ <desc>
+ <p>Modifies the text of the annotations <anno>Anno</anno>.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name name="text" arity="1"/>
+ <type name="text"></type>
+ <fsummary>Return the text</fsummary>
+ <desc>
+ <p>Returns the text of the annotations <anno>Anno</anno>.
+ If there is no text, <c>undefined</c> is returned.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name name="to_term" arity="1"/>
+ <fsummary>Return the term representing a collection of
+ annotations</fsummary>
+ <desc>
+ <p>Returns the term representing the annotations <anno>Anno</anno>.
+ </p>
+ <p>See also <seealso marker="#from_term/1">from_term()</seealso>.
+ </p>
+ </desc>
+ </func>
+ </funcs>
+ <section>
+ <title>See Also</title>
+ <p><seealso marker="erl_scan">erl_scan(3)</seealso>,
+ <seealso marker="erl_parse">erl_parse(3)</seealso>
+ </p>
+ </section>
+</erlref>
diff --git a/lib/stdlib/doc/src/erl_parse.xml b/lib/stdlib/doc/src/erl_parse.xml
index cf0bff48cd..b97d06e919 100644
--- a/lib/stdlib/doc/src/erl_parse.xml
+++ b/lib/stdlib/doc/src/erl_parse.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2014</year>
+ <year>1996</year><year>2015</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -192,6 +192,97 @@
considered a string.</p>
</desc>
</func>
+ <func>
+ <name name="map_anno" arity="2"/>
+ <fsummary>
+ Map a function over the annotations of an abstract form
+ </fsummary>
+ <desc>
+ <p>Modifies the abstract form <anno>Abstr</anno> by applying
+ <anno>Fun</anno> on every collection of annotations of the
+ abstract form. The abstract form is traversed in a
+ depth-first, left-to-right, fashion.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name name="fold_anno" arity="3"/>
+ <fsummary>
+ Fold a function over the annotations of an abstract form
+ </fsummary>
+ <desc>
+ <p>Updates an accumulator by applying <anno>Fun</anno> on
+ every collection of annotations of the abstract form
+ <anno>Abstr</anno>. The first call to <anno>Fun</anno> has
+ <anno>AccIn</anno> as argument, and the returned accumulator
+ <anno>AccOut</anno> is passed to the next call, and so on.
+ The final value of the accumulator is returned. The abstract
+ form is traversed in a depth-first, left-to-right, fashion.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name name="mapfold_anno" arity="3"/>
+ <fsummary>
+ Map and fold a function over the annotations of an abstract form
+ </fsummary>
+ <desc>
+ <p>Modifies the abstract form <anno>Abstr</anno> by applying
+ <anno>Fun</anno> on every collection of annotations of the
+ abstract form, while at the same time updating an
+ accumulator. The first call to <anno>Fun</anno> has
+ <anno>AccIn</anno> as second argument, and the returned
+ accumulator <anno>AccOut</anno> is passed to the next call,
+ and so on. The modified abstract form as well as the the
+ final value of the accumulator is returned. The abstract
+ form is traversed in a depth-first, left-to-right, fashion.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name name="new_anno" arity="1"/>
+ <fsummary>
+ Create new annotations
+ </fsummary>
+ <desc>
+ <p>Creates an abstract form from a term which has the same
+ structure as an abstract form, but <seealso
+ marker="erl_anno#type-location">locations</seealso> where the
+ abstract form has annotations. For each location, <seealso
+ marker="erl_anno#new/1"><c>erl_anno:new/1</c></seealso> is
+ called, and the annotations replace the location.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name name="anno_from_term" arity="1"/>
+ <fsummary>
+ Return annotations as terms
+ </fsummary>
+ <desc>
+ <p>Assumes that <anno>Term</anno> is a term with the same
+ structure as an abstract form, but with terms, T say, on
+ those places where an abstract form has annotations. Returns
+ an abstract form where every term T has been replaced by the
+ value returned by calling <c>erl_anno:from_term(T)</c>. The
+ term <anno>Term</anno> is traversed in a depth-first,
+ left-to-right, fashion.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name name="anno_to_term" arity="1"/>
+ <fsummary>
+ Return the representation of annotations
+ </fsummary>
+ <desc>
+ <p>Returns a term where every collection of annotations Anno of
+ <anno>Abstr</anno> has been replaced by the term returned by
+ calling <c>erl_anno:to_term(Anno)</c>. The abstract form is
+ traversed in a depth-first, left-to-right, fashion.
+ </p>
+ </desc>
+ </func>
</funcs>
<section>
@@ -211,8 +302,9 @@
<section>
<title>See Also</title>
<p><seealso marker="io">io(3)</seealso>,
- <seealso marker="erl_scan">erl_scan(3)</seealso>,
- ERTS User's Guide</p>
+ <seealso marker="erl_anno">erl_anno(3)</seealso>,
+ <seealso marker="erl_scan">erl_scan(3)</seealso>,
+ <seealso marker="erts:absform">ERTS User's Guide</seealso></p>
</section>
</erlref>
diff --git a/lib/stdlib/doc/src/erl_scan.xml b/lib/stdlib/doc/src/erl_scan.xml
index 855c8fc195..8f9c1db25b 100644
--- a/lib/stdlib/doc/src/erl_scan.xml
+++ b/lib/stdlib/doc/src/erl_scan.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2013</year>
+ <year>1996</year><year>2015</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -120,7 +120,7 @@
<c>string(<anno>String</anno>,
<anno>StartLocation</anno>, [])</c>.</p>
<p><c><anno>StartLocation</anno></c> indicates the initial location
- when scanning starts. If <c><anno>StartLocation</anno></c> is a line
+ when scanning starts. If <c><anno>StartLocation</anno></c> is a line,
<c>attributes()</c> as well as <c><anno>EndLocation</anno></c> and
<c><anno>ErrorLocation</anno></c> will be lines. If
<c><anno>StartLocation</anno></c> is a pair of a line and a column
@@ -132,8 +132,12 @@
line where the token begins, as well as the text of the
token (if the <c>text</c> option is given), all of which can
be accessed by calling <seealso
- marker="#token_info/1">token_info/1,2</seealso> or <seealso
- marker="#attributes_info/1">attributes_info/1,2</seealso>.</p>
+ marker="#token_info/1">token_info/1,2</seealso>, <seealso
+ marker="#attributes_info/1">attributes_info/1,2</seealso>,
+ <seealso marker="#column/1">column/1</seealso>,
+ <seealso marker="#line/1">line/1</seealso>,
+ <seealso marker="#location/1">location/1</seealso>, and
+ <seealso marker="#text/1">text/1</seealso>.</p>
<p>A <em>token</em> is a tuple containing information about
syntactic category, the token attributes, and the actual
terminal symbol. For punctuation characters (e.g. <c>;</c>,
@@ -237,6 +241,70 @@
</desc>
</func>
<func>
+ <name name="category" arity="1"/>
+ <fsummary>Return the category</fsummary>
+ <desc>
+ <p>Returns the category of <c><anno>Token</anno></c>.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name name="symbol" arity="1"/>
+ <fsummary>Return the symbol</fsummary>
+ <desc>
+ <p>Returns the symbol of <c><anno>Token</anno></c>.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name name="column" arity="1"/>
+ <fsummary>Return the column</fsummary>
+ <desc>
+ <p>Returns the column of <c><anno>Token</anno></c>'s
+ collection of annotations.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name name="end_location" arity="1"/>
+ <fsummary>Return the end location of the text</fsummary>
+ <desc>
+ <p>Returns the end location of the text of
+ <c><anno>Token</anno></c>'s collection of annotations. If
+ there is no text,
+ <c>undefined</c> is returned.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name name="line" arity="1"/>
+ <fsummary>Return the line</fsummary>
+ <desc>
+ <p>Returns the line of <c><anno>Token</anno></c>'s collection
+ of annotations.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name name="location" arity="1"/>
+ <fsummary>Return the location</fsummary>
+ <desc>
+ <p>Returns the location of <c><anno>Token</anno></c>'s
+ collection of annotations.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name name="text" arity="1"/>
+ <fsummary>Return the text</fsummary>
+ <desc>
+ <p>Returns the text of <c><anno>Token</anno></c>'s collection
+ of annotations. If there is no text, <c>undefined</c> is
+ returned.
+ </p>
+ </desc>
+ </func>
+ <func>
<name name="token_info" arity="1"/>
<fsummary>Return information about a token</fsummary>
<desc>
@@ -417,6 +485,7 @@ Module:format_error(ErrorDescriptor)</code>
<section>
<title>See Also</title>
<p><seealso marker="io">io(3)</seealso>,
- <seealso marker="erl_parse">erl_parse(3)</seealso></p>
+ <seealso marker="erl_anno">erl_anno(3)</seealso>,
+ <seealso marker="erl_parse">erl_parse(3)</seealso></p>
</section>
</erlref>
diff --git a/lib/stdlib/doc/src/ref_man.xml b/lib/stdlib/doc/src/ref_man.xml
index ea4009dc3e..94c1fb55c2 100644
--- a/lib/stdlib/doc/src/ref_man.xml
+++ b/lib/stdlib/doc/src/ref_man.xml
@@ -4,7 +4,7 @@
<application xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>1996</year><year>2013</year>
+ <year>1996</year><year>2015</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -45,6 +45,7 @@
<xi:include href="digraph.xml"/>
<xi:include href="digraph_utils.xml"/>
<xi:include href="epp.xml"/>
+ <xi:include href="erl_anno.xml"/>
<xi:include href="erl_eval.xml"/>
<xi:include href="erl_expand_records.xml"/>
<xi:include href="erl_id_trans.xml"/>
diff --git a/lib/stdlib/doc/src/specs.xml b/lib/stdlib/doc/src/specs.xml
index fd77b52da6..6ae0154800 100644
--- a/lib/stdlib/doc/src/specs.xml
+++ b/lib/stdlib/doc/src/specs.xml
@@ -11,6 +11,7 @@
<xi:include href="../specs/specs_digraph.xml"/>
<xi:include href="../specs/specs_digraph_utils.xml"/>
<xi:include href="../specs/specs_epp.xml"/>
+ <xi:include href="../specs/specs_erl_anno.xml"/>
<xi:include href="../specs/specs_erl_eval.xml"/>
<xi:include href="../specs/specs_erl_expand_records.xml"/>
<xi:include href="../specs/specs_erl_id_trans.xml"/>
diff --git a/lib/stdlib/src/Makefile b/lib/stdlib/src/Makefile
index 1b3744b6fb..85b858febd 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 \
@@ -168,6 +169,7 @@ docs:
# specifications.
primary_bootstrap_compiler: \
$(BOOTSTRAP_COMPILER)/ebin/epp.beam \
+ $(BOOTSTRAP_COMPILER)/ebin/erl_anno.beam \
$(BOOTSTRAP_COMPILER)/ebin/erl_scan.beam \
$(BOOTSTRAP_COMPILER)/ebin/erl_parse.beam \
$(BOOTSTRAP_COMPILER)/ebin/erl_lint.beam \
diff --git a/lib/stdlib/src/beam_lib.erl b/lib/stdlib/src/beam_lib.erl
index 1a7b7d5a5e..4a6b489204 100644
--- a/lib/stdlib/src/beam_lib.erl
+++ b/lib/stdlib/src/beam_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2000-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
@@ -652,7 +652,13 @@ chunk_to_data(abstract_code=Id, Chunk, File, _Cs, AtomTable, Mod) ->
{'EXIT', _} ->
error({invalid_chunk, File, chunk_name_to_id(Id, File)});
Term ->
- {AtomTable, {Id, Term}}
+ try
+ {AtomTable, {Id, anno_from_term(Term)}}
+ catch
+ _:_ ->
+ error({invalid_chunk, File,
+ chunk_name_to_id(Id, File)})
+ end
end
end;
chunk_to_data(atoms=Id, _Chunk, _File, Cs, AtomTable0, _Mod) ->
@@ -878,7 +884,22 @@ decrypt_abst(Type, Module, File, Id, AtomTable, Bin) ->
decrypt_abst_1({Type,Key,IVec,_BlockSize}, Bin) ->
ok = start_crypto(),
NewBin = crypto:block_decrypt(Type, Key, IVec, Bin),
- binary_to_term(NewBin).
+ Term = binary_to_term(NewBin),
+ anno_from_term(Term).
+
+anno_from_term({raw_abstract_v1, Forms}) ->
+ {raw_abstract_v1, anno_from_forms(Forms)};
+anno_from_term({Tag, Forms}) when Tag =:= abstract_v1; Tag =:= abstract_v2 ->
+ try {Tag, anno_from_forms(Forms)}
+ catch
+ _:_ ->
+ {Tag, Forms}
+ end;
+anno_from_term(T) ->
+ T.
+
+anno_from_forms(Forms) ->
+ [erl_parse:anno_from_term(Form) || Form <- Forms].
start_crypto() ->
case crypto:start() of
diff --git a/lib/stdlib/src/edlin.erl b/lib/stdlib/src/edlin.erl
index b3bc5f6d92..362669545e 100644
--- a/lib/stdlib/src/edlin.erl
+++ b/lib/stdlib/src/edlin.erl
@@ -21,7 +21,7 @@
%% A simple Emacs-like line editor.
%% About Latin-1 characters: see the beginning of erl_scan.erl.
--export([init/0,start/1,start/2,edit_line/2,prefix_arg/1]).
+-export([init/0,init/1,start/1,start/2,edit_line/2,prefix_arg/1]).
-export([erase_line/1,erase_inp/1,redraw_line/1]).
-export([length_before/1,length_after/1,prompt/1]).
-export([current_line/1, current_chars/1]).
@@ -44,6 +44,20 @@
init() ->
put(kill_buffer, []).
+init(Pid) ->
+ %% copy the kill_buffer from the process Pid
+ CopiedKillBuf =
+ case erlang:process_info(Pid, dictionary) of
+ {dictionary,Dict} ->
+ case proplists:get_value(kill_buffer, Dict) of
+ undefined -> [];
+ Buf -> Buf
+ end;
+ undefined ->
+ []
+ end,
+ put(kill_buffer, CopiedKillBuf).
+
%% start(Prompt)
%% edit(Characters, Continuation)
%% Return
diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl
index 5f8637c118..7866b5f792 100644
--- a/lib/stdlib/src/epp.erl
+++ b/lib/stdlib/src/epp.erl
@@ -1,7 +1,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
@@ -158,7 +158,7 @@ scan_erl_form(Epp) ->
{'ok', AbsForm} | {'eof', Line} | {error, ErrorInfo} when
Epp :: epp_handle(),
AbsForm :: erl_parse:abstract_form(),
- Line :: erl_scan:line(),
+ Line :: erl_anno:line(),
ErrorInfo :: erl_scan:error_info() | erl_parse:error_info().
parse_erl_form(Epp) ->
@@ -220,7 +220,7 @@ format_error(E) -> file:format_error(E).
IncludePath :: [DirectoryName :: file:name()],
Form :: erl_parse:abstract_form() | {'error', ErrorInfo} | {'eof',Line},
PredefMacros :: macros(),
- Line :: erl_scan:line(),
+ Line :: erl_anno:line(),
ErrorInfo :: erl_scan:error_info() | erl_parse:error_info(),
OpenError :: file:posix() | badarg | system_limit.
@@ -235,7 +235,7 @@ parse_file(Ifile, Path, Predefs) ->
{'default_encoding', DefEncoding :: source_encoding()} |
'extra'],
Form :: erl_parse:abstract_form() | {'error', ErrorInfo} | {'eof',Line},
- Line :: erl_scan:line(),
+ Line :: erl_anno:line(),
ErrorInfo :: erl_scan:error_info() | erl_parse:error_info(),
Extra :: [{'encoding', source_encoding() | 'none'}],
OpenError :: file:posix() | badarg | system_limit.
@@ -257,7 +257,7 @@ parse_file(Ifile, Options) ->
-spec parse_file(Epp) -> [Form] when
Epp :: epp_handle(),
Form :: erl_parse:abstract_form() | {'error', ErrorInfo} | {'eof',Line},
- Line :: erl_scan:line(),
+ Line :: erl_anno:line(),
ErrorInfo :: erl_scan:error_info() | erl_parse:error_info().
parse_file(Epp) ->
@@ -280,7 +280,7 @@ parse_file(Epp) ->
{error,E} ->
[{error,E}|parse_file(Epp)];
{eof,Location} ->
- [{eof,Location}]
+ [{eof,erl_anno:new(Location)}]
end.
-spec default_encoding() -> source_encoding().
@@ -547,7 +547,8 @@ init_server(Pid, Name, Options, St0) ->
path=Path, macs=Ms1,
default_encoding=DefEncoding},
From = wait_request(St),
- enter_file_reply(From, Name, AtLocation, AtLocation),
+ Anno = erl_anno:new(AtLocation),
+ enter_file_reply(From, Name, Anno, AtLocation, code),
wait_req_scan(St);
{error,E} ->
epp_reply(Pid, {error,E})
@@ -559,15 +560,16 @@ init_server(Pid, Name, Options, St0) ->
predef_macros(File) ->
Machine = list_to_atom(erlang:system_info(machine)),
+ Anno = line1(),
dict:from_list([
- {{atom,'FILE'}, {none,[{string,1,File}]}},
- {{atom,'LINE'}, {none,[{integer,1,1}]}},
+ {{atom,'FILE'}, {none,[{string,Anno,File}]}},
+ {{atom,'LINE'}, {none,[{integer,Anno,1}]}},
{{atom,'MODULE'}, undefined},
{{atom,'MODULE_STRING'}, undefined},
{{atom,'BASE_MODULE'}, undefined},
{{atom,'BASE_MODULE_STRING'}, undefined},
- {{atom,'MACHINE'}, {none,[{atom,1,Machine}]}},
- {{atom,Machine}, {none,[{atom,1,true}]}}
+ {{atom,'MACHINE'}, {none,[{atom,Anno,Machine}]}},
+ {{atom,Machine}, {none,[{atom,Anno,true}]}}
]).
%% user_predef(PreDefMacros, Macros) ->
@@ -595,8 +597,9 @@ user_predef([M|Pdm], Ms) when is_atom(M) ->
{ok,_Def} -> %% Predefined macros
{error,{redefine_predef,M}};
error ->
+ A = line1(),
user_predef(Pdm,
- dict:store({atom,M}, [{none, {none,[{atom,1,true}]}}], Ms))
+ dict:store({atom,M}, [{none, {none,[{atom,A,true}]}}], Ms))
end;
user_predef([Md|_Pdm], _Ms) -> {error,{bad,Md}};
user_predef([], Ms) -> {ok,Ms}.
@@ -645,7 +648,7 @@ wait_req_skip(St, Sis) ->
enter_file(_NewName, Inc, From, St)
when length(St#epp.sstk) >= 8 ->
- epp_reply(From, {error,{abs_loc(Inc),epp,{depth,"include"}}}),
+ epp_reply(From, {error,{loc(Inc),epp,{depth,"include"}}}),
wait_req_scan(St);
enter_file(NewName, Inc, From, St) ->
case file:path_open(St#epp.path, NewName, [read]) of
@@ -653,7 +656,7 @@ enter_file(NewName, Inc, From, St) ->
Loc = start_loc(St#epp.location),
wait_req_scan(enter_file2(NewF, Pname, From, St, Loc));
{error,_E} ->
- epp_reply(From, {error,{abs_loc(Inc),epp,{include,file,NewName}}}),
+ epp_reply(From, {error,{loc(Inc),epp,{include,file,NewName}}}),
wait_req_scan(St)
end.
@@ -661,9 +664,9 @@ enter_file(NewName, Inc, From, St) ->
%% Set epp to use this file and "enter" it.
enter_file2(NewF, Pname, From, St0, AtLocation) ->
- Loc = start_loc(AtLocation),
- enter_file_reply(From, Pname, Loc, AtLocation),
- Ms = dict:store({atom,'FILE'}, {none,[{string,Loc,Pname}]}, St0#epp.macs),
+ Anno = erl_anno:new(AtLocation),
+ enter_file_reply(From, Pname, Anno, AtLocation, code),
+ Ms = dict:store({atom,'FILE'}, {none,[{string,Anno,Pname}]}, St0#epp.macs),
%% update the head of the include path to be the directory of the new
%% source file, so that an included file can always include other files
%% relative to its current location (this is also how C does it); note
@@ -673,16 +676,20 @@ enter_file2(NewF, Pname, From, St0, AtLocation) ->
Path = [filename:dirname(Pname) | tl(St0#epp.path)],
DefEncoding = St0#epp.default_encoding,
_ = set_encoding(NewF, DefEncoding),
- #epp{file=NewF,location=Loc,name=Pname,name2=Pname,delta=0,
+ #epp{file=NewF,location=AtLocation,name=Pname,name2=Pname,delta=0,
sstk=[St0|St0#epp.sstk],path=Path,macs=Ms,
default_encoding=DefEncoding}.
-enter_file_reply(From, Name, Location, AtLocation) ->
- Attr = loc_attr(AtLocation),
- Rep = {ok, [{'-',Attr},{atom,Attr,file},{'(',Attr},
- {string,Attr,file_name(Name)},{',',Attr},
- {integer,Attr,get_line(Location)},{')',Location},
- {dot,Attr}]},
+enter_file_reply(From, Name, LocationAnno, AtLocation, Where) ->
+ Anno0 = loc_anno(AtLocation),
+ Anno = case Where of
+ code -> Anno0;
+ generated -> erl_anno:set_generated(true, Anno0)
+ end,
+ Rep = {ok, [{'-',Anno},{atom,Anno,file},{'(',Anno},
+ {string,Anno,file_name(Name)},{',',Anno},
+ {integer,Anno,get_line(LocationAnno)},{')',LocationAnno},
+ {dot,Anno}]},
epp_reply(From, Rep).
%% Flatten filename to a string. Must be a valid filename.
@@ -710,18 +717,20 @@ leave_file(From, St) ->
#epp{location=OldLoc, delta=Delta, name=OldName,
name2=OldName2} = OldSt,
CurrLoc = add_line(OldLoc, Delta),
+ Anno = erl_anno:new(CurrLoc),
Ms = dict:store({atom,'FILE'},
- {none,[{string,CurrLoc,OldName2}]},
+ {none,[{string,Anno,OldName2}]},
St#epp.macs),
NextSt = OldSt#epp{sstk=Sts,macs=Ms,uses=St#epp.uses},
- enter_file_reply(From, OldName, CurrLoc, CurrLoc),
+ enter_file_reply(From, OldName, Anno, CurrLoc, code),
case OldName2 =:= OldName of
true ->
ok;
false ->
NFrom = wait_request(NextSt),
- enter_file_reply(NFrom, OldName2, OldLoc,
- neg_line(CurrLoc))
+ OldAnno = erl_anno:new(OldLoc),
+ enter_file_reply(NFrom, OldName2, OldAnno,
+ CurrLoc, generated)
end,
wait_req_scan(NextSt);
[] ->
@@ -818,9 +827,9 @@ scan_extends(_Ts, _As, Ms) -> Ms.
%% scan_define(Tokens, DefineToken, From, EppState)
-scan_define([{'(',_Lp},{Type,_Lm,M}=Mac,{',',Lc}|Toks], _Def, From, St)
+scan_define([{'(',_Lp},{Type,_Lm,M}=Mac,{',',_}=Comma|Toks], _Def, From, St)
when Type =:= atom; Type =:= var ->
- case catch macro_expansion(Toks, Lc) of
+ case catch macro_expansion(Toks, Comma) of
Expansion when is_list(Expansion) ->
case dict:find({atom,M}, St#epp.macs) of
{ok, Defs} when is_list(Defs) ->
@@ -910,10 +919,12 @@ macro_ref([]) ->
[];
macro_ref([{'?', _}, {'?', _} | Rest]) ->
macro_ref(Rest);
-macro_ref([{'?', _}, {atom, Lm, A} | Rest]) ->
+macro_ref([{'?', _}, {atom, _, A}=Atom | Rest]) ->
+ Lm = loc(Atom),
Arity = count_args(Rest, Lm, A),
[{{atom, A}, Arity} | macro_ref(Rest)];
-macro_ref([{'?', _}, {var, Lm, A} | Rest]) ->
+macro_ref([{'?', _}, {var, _, A}=Var | Rest]) ->
+ Lm = loc(Var),
Arity = count_args(Rest, Lm, A),
[{{atom, A}, Arity} | macro_ref(Rest)];
macro_ref([_Token | Rest]) ->
@@ -940,7 +951,7 @@ scan_include([{'(',_Llp},{string,_Lf,NewName0},{')',_Lrp},{dot,_Ld}], Inc,
NewName = expand_var(NewName0),
enter_file(NewName, Inc, From, St);
scan_include(_Toks, Inc, From, St) ->
- epp_reply(From, {error,{abs_loc(Inc),epp,{bad,include}}}),
+ epp_reply(From, {error,{loc(Inc),epp,{bad,include}}}),
wait_req_scan(St).
%% scan_include_lib(Tokens, IncludeToken, From, EppState)
@@ -955,7 +966,7 @@ find_lib_dir(NewName) ->
scan_include_lib([{'(',_Llp},{string,_Lf,_NewName0},{')',_Lrp},{dot,_Ld}],
Inc, From, St)
when length(St#epp.sstk) >= 8 ->
- epp_reply(From, {error,{abs_loc(Inc),epp,{depth,"include_lib"}}}),
+ epp_reply(From, {error,{loc(Inc),epp,{depth,"include_lib"}}}),
wait_req_scan(St);
scan_include_lib([{'(',_Llp},{string,_Lf,NewName0},{')',_Lrp},{dot,_Ld}],
Inc, From, St) ->
@@ -974,18 +985,18 @@ scan_include_lib([{'(',_Llp},{string,_Lf,NewName0},{')',_Lrp},{dot,_Ld}],
St, Loc));
{error,_E2} ->
epp_reply(From,
- {error,{abs_loc(Inc),epp,
+ {error,{loc(Inc),epp,
{include,lib,NewName}}}),
wait_req_scan(St)
end;
_Error ->
- epp_reply(From, {error,{abs_loc(Inc),epp,
+ epp_reply(From, {error,{loc(Inc),epp,
{include,lib,NewName}}}),
wait_req_scan(St)
end
end;
scan_include_lib(_Toks, Inc, From, St) ->
- epp_reply(From, {error,{abs_loc(Inc),epp,{bad,include_lib}}}),
+ epp_reply(From, {error,{loc(Inc),epp,{bad,include_lib}}}),
wait_req_scan(St).
%% scan_ifdef(Tokens, IfdefToken, From, EppState)
@@ -1088,11 +1099,12 @@ scan_endif(_Toks, Endif, From, St) ->
scan_file([{'(',_Llp},{string,_Ls,Name},{',',_Lc},{integer,_Li,Ln},{')',_Lrp},
{dot,_Ld}], Tf, From, St) ->
- enter_file_reply(From, Name, Ln, neg_line(abs_loc(Tf))),
- Ms = dict:store({atom,'FILE'}, {none,[{string,1,Name}]}, St#epp.macs),
+ Anno = erl_anno:new(Ln),
+ enter_file_reply(From, Name, Anno, loc(Tf), generated),
+ Ms = dict:store({atom,'FILE'}, {none,[{string,line1(),Name}]}, St#epp.macs),
Locf = loc(Tf),
NewLoc = new_location(Ln, St#epp.location, Locf),
- Delta = abs(get_line(element(2, Tf)))-Ln + St#epp.delta,
+ Delta = get_line(element(2, Tf))-Ln + St#epp.delta,
wait_req_scan(St#epp{name2=Name,location=NewLoc,delta=Delta,macs=Ms});
scan_file(_Toks, Tf, From, St) ->
epp_reply(From, {error,{loc(Tf),epp,{bad,file}}}),
@@ -1153,7 +1165,7 @@ skip_else(_Else, From, St, Sis) ->
skip_toks(From, St, Sis).
%% macro_pars(Tokens, ArgStack)
-%% macro_expansion(Tokens, Line)
+%% macro_expansion(Tokens, Anno)
%% Extract the macro parameters and the expansion from a macro definition.
macro_pars([{')',_Lp}, {',',Ld}|Ex], Args) ->
@@ -1165,11 +1177,12 @@ macro_pars([{var,_L,Name}, {',',_}|Ts], Args) ->
false = lists:member(Name, Args),
macro_pars(Ts, [Name|Args]).
-macro_expansion([{')',_Lp},{dot,_Ld}], _L0) -> [];
-macro_expansion([{dot,Ld}], _L0) -> throw({error,Ld,missing_parenthesis});
-macro_expansion([T|Ts], _L0) ->
- [T|macro_expansion(Ts, element(2, T))];
-macro_expansion([], L0) -> throw({error,L0,premature_end}).
+macro_expansion([{')',_Lp},{dot,_Ld}], _Anno0) -> [];
+macro_expansion([{dot,_}=Dot], _Anno0) ->
+ throw({error,loc(Dot),missing_parenthesis});
+macro_expansion([T|Ts], _Anno0) ->
+ [T|macro_expansion(Ts, T)];
+macro_expansion([], Anno0) -> throw({error,loc(Anno0),premature_end}).
%% expand_macros(Tokens, Macros)
%% expand_macro(Tokens, MacroToken, RestTokens)
@@ -1239,17 +1252,17 @@ expand_macros([{'?',_Lq},{atom,_Lm,M}=MacT|Toks], Ms) ->
expand_macros(atom, MacT, M, Toks, Ms);
%% Special macros
expand_macros([{'?',_Lq},{var,Lm,'LINE'}=Tok|Toks], Ms) ->
- {line,Line} = erl_scan:token_info(Tok, line),
+ Line = erl_scan:line(Tok),
[{integer,Lm,Line}|expand_macros(Toks, Ms)];
expand_macros([{'?',_Lq},{var,_Lm,M}=MacT|Toks], Ms) ->
expand_macros(atom, MacT, M, Toks, Ms);
%% Illegal macros
expand_macros([{'?',_Lq},Token|_Toks], _Ms) ->
- T = case erl_scan:token_info(Token, text) of
- {text,Text} ->
+ T = case erl_scan:text(Token) of
+ Text when is_list(Text) ->
Text;
undefined ->
- {symbol,Symbol} = erl_scan:token_info(Token, symbol),
+ Symbol = erl_scan:symbol(Token),
io_lib:write(Symbol)
end,
throw({error,loc(Token),{call,[$?|T]}});
@@ -1383,7 +1396,7 @@ expand_arg([], Ts, L, Rest, Bs) ->
%%% stringify(Ts, L) returns a list of one token: a string which when
%%% tokenized would yield the token list Ts.
-%% erl_scan:token_info(T, text) is not backward compatible with this.
+%% erl_scan:text(T) is not backward compatible with this.
%% Note that escaped characters will be replaced by themselves.
token_src({dot, _}) ->
".";
@@ -1456,36 +1469,29 @@ fname_join(Components) ->
filename:join(Components).
%% The line only. (Other tokens may have the column and text as well...)
-loc_attr(Line) when is_integer(Line) ->
- Line;
-loc_attr({Line,_Column}) ->
- Line.
+loc_anno(Line) when is_integer(Line) ->
+ erl_anno:new(Line);
+loc_anno({Line,_Column}) ->
+ erl_anno:new(Line).
loc(Token) ->
- {location,Location} = erl_scan:token_info(Token, location),
- Location.
+ erl_scan:location(Token).
-abs_loc(Token) ->
- loc(setelement(2, Token, abs_line(element(2, Token)))).
-
-neg_line(L) ->
- erl_scan:set_attribute(line, L, fun(Line) -> -abs(Line) end).
-
-abs_line(L) ->
- erl_scan:set_attribute(line, L, fun(Line) -> abs(Line) end).
-
-add_line(L, Offset) ->
- erl_scan:set_attribute(line, L, fun(Line) -> Line+Offset end).
+add_line(Line, Offset) when is_integer(Line) ->
+ Line+Offset;
+add_line({Line, Column}, Offset) ->
+ {Line+Offset, Column}.
start_loc(Line) when is_integer(Line) ->
1;
start_loc({_Line, _Column}) ->
- {1,1}.
+ {1, 1}.
-get_line(Line) when is_integer(Line) ->
- Line;
-get_line({Line,_Column}) ->
- Line.
+line1() ->
+ erl_anno:new(1).
+
+get_line(Anno) ->
+ erl_anno:line(Anno).
%% epp has always output -file attributes when entering and leaving
%% included files (-include, -include_lib). Starting with R11B the
@@ -1525,14 +1531,15 @@ get_line({Line,_Column}) ->
interpret_file_attribute(Forms) ->
interpret_file_attr(Forms, 0, []).
-interpret_file_attr([{attribute,Loc,file,{File,Line}}=Form | Forms],
+interpret_file_attr([{attribute,Anno,file,{File,Line}}=Form | Forms],
Delta, Fs) ->
- {line, L} = erl_scan:attributes_info(Loc, line),
+ L = get_line(Anno),
+ Generated = erl_anno:generated(Anno),
if
- L < 0 ->
+ Generated ->
%% -file attribute
- interpret_file_attr(Forms, (abs(L) + Delta) - Line, Fs);
- true ->
+ interpret_file_attr(Forms, (L + Delta) - Line, Fs);
+ not Generated ->
%% -include or -include_lib
% true = L =:= Line,
case Fs of
@@ -1543,11 +1550,11 @@ interpret_file_attr([{attribute,Loc,file,{File,Line}}=Form | Forms],
end
end;
interpret_file_attr([Form0 | Forms], Delta, Fs) ->
- F = fun(Attrs) ->
- F2 = fun(L) -> abs(L) + Delta end,
- erl_scan:set_attribute(line, Attrs, F2)
+ F = fun(Anno) ->
+ Line = erl_anno:line(Anno),
+ erl_anno:set_line(Line + Delta, Anno)
end,
- Form = erl_lint:modify_line(Form0, F),
+ Form = erl_parse:map_anno(F, Form0),
[Form | interpret_file_attr(Forms, Delta, Fs)];
interpret_file_attr([], _Delta, _Fs) ->
[].
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_eval.erl b/lib/stdlib/src/erl_eval.erl
index e86e10b170..39f833009f 100644
--- a/lib/stdlib/src/erl_eval.erl
+++ b/lib/stdlib/src/erl_eval.erl
@@ -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
@@ -479,12 +479,13 @@ expr({value,_,Val}, Bs, _Lf, _Ef, RBs) -> % Special case straight values.
find_maxline(LC) ->
put('$erl_eval_max_line', 0),
- F = fun(L) ->
+ F = fun(A) ->
+ L = erl_anno:line(A),
case is_integer(L) and (L > get('$erl_eval_max_line')) of
true -> put('$erl_eval_max_line', L);
false -> ok
end end,
- _ = erl_lint:modify_line(LC, F),
+ _ = erl_parse:map_anno(F, LC),
erase('$erl_eval_max_line').
hide_calls(LC, MaxLine) ->
@@ -494,14 +495,16 @@ hide_calls(LC, MaxLine) ->
%% v/1 and local calls are hidden.
hide({value,L,V}, Id, D) ->
- {{atom,Id,ok}, Id+1, dict:store(Id, {value,L,V}, D)};
+ A = erl_anno:new(Id),
+ {{atom,A,ok}, Id+1, dict:store(Id, {value,L,V}, D)};
hide({call,L,{atom,_,N}=Atom,Args}, Id0, D0) ->
{NArgs, Id, D} = hide(Args, Id0, D0),
C = case erl_internal:bif(N, length(Args)) of
true ->
{call,L,Atom,NArgs};
false ->
- {call,Id,{remote,L,{atom,L,m},{atom,L,f}},NArgs}
+ A = erl_anno:new(Id),
+ {call,A,{remote,L,{atom,L,m},{atom,L,f}},NArgs}
end,
{C, Id+1, dict:store(Id, {call,Atom}, D)};
hide(T0, Id0, D0) when is_tuple(T0) ->
@@ -514,11 +517,23 @@ hide([E0 | Es0], Id0, D0) ->
hide(E, Id, D) ->
{E, Id, D}.
-unhide_calls({atom,Id,ok}, MaxLine, D) when Id > MaxLine ->
- dict:fetch(Id, D);
-unhide_calls({call,Id,{remote,L,_M,_F},Args}, MaxLine, D) when Id > MaxLine ->
- {call,Atom} = dict:fetch(Id, D),
- {call,L,Atom,unhide_calls(Args, MaxLine, D)};
+unhide_calls({atom,A,ok}=E, MaxLine, D) ->
+ L = erl_anno:line(A),
+ if
+ L > MaxLine ->
+ dict:fetch(L, D);
+ true ->
+ E
+ end;
+unhide_calls({call,A,{remote,L,{atom,L,m},{atom,L,f}}=F,Args}, MaxLine, D) ->
+ Line = erl_anno:line(A),
+ if
+ Line > MaxLine ->
+ {call,Atom} = dict:fetch(Line, D),
+ {call,L,Atom,unhide_calls(Args, MaxLine, D)};
+ true ->
+ {call,A,F,unhide_calls(Args, MaxLine, D)}
+ end;
unhide_calls(T, MaxLine, D) when is_tuple(T) ->
list_to_tuple(unhide_calls(tuple_to_list(T), MaxLine, D));
unhide_calls([E | Es], MaxLine, D) ->
diff --git a/lib/stdlib/src/erl_expand_records.erl b/lib/stdlib/src/erl_expand_records.erl
index dc74d611a3..0d3debae22 100644
--- a/lib/stdlib/src/erl_expand_records.erl
+++ b/lib/stdlib/src/erl_expand_records.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2005-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
@@ -38,8 +38,6 @@
checked_ra=[] % successfully accessed records
}).
--define(REC_OFFSET, 100000000). % A hundred millions. Also in v3_core.
-
-spec(module(AbsForms, CompileOptions) -> AbsForms when
AbsForms :: [erl_parse:abstract_form()],
CompileOptions :: [compile:option()]).
@@ -149,7 +147,7 @@ pattern({record_index,Line,Name,Field}, St) ->
pattern({record,Line0,Name,Pfs}, St0) ->
Fs = record_fields(Name, St0),
{TMs,St1} = pattern_list(pattern_fields(Fs, Pfs), St0),
- Line = record_offset(Line0, St1),
+ Line = mark_record(Line0, St1),
{{tuple,Line,[{atom,Line0,Name} | TMs]},St1};
pattern({bin,Line,Es0}, St0) ->
{Es1,St1} = pattern_bin(Es0, St0),
@@ -243,7 +241,7 @@ record_test_in_guard(Line, Term, Name, St) ->
expr({atom,Line,false}, St);
false ->
Fs = record_fields(Name, St),
- NLine = neg_line(Line),
+ NLine = no_compiler_warning(Line),
expr({call,NLine,{remote,NLine,{atom,NLine,erlang},{atom,NLine,is_record}},
[Term,{atom,Line,Name},{integer,Line,length(Fs)+1}]},
St)
@@ -269,7 +267,7 @@ record_test_in_body(Line, Expr, Name, St0) ->
%% evaluate to a tuple properly.
Fs = record_fields(Name, St0),
{Var,St} = new_var(Line, St0),
- NLine = neg_line(Line),
+ NLine = no_compiler_warning(Line),
expr({block,Line,
[{match,Line,Var,Expr},
{call,NLine,{remote,NLine,{atom,NLine,erlang},
@@ -333,7 +331,7 @@ expr({record_index,Line,Name,F}, St) ->
I = index_expr(Line, F, Name, record_fields(Name, St)),
expr(I, St);
expr({record,Line0,Name,Is}, St) ->
- Line = record_offset(Line0, St),
+ Line = mark_record(Line0, St),
expr({tuple,Line,[{atom,Line0,Name} |
record_inits(record_fields(Name, St), Is)]},
St);
@@ -459,7 +457,7 @@ strict_record_access(E0, St0) ->
conj([], _E) ->
empty;
conj([{{Name,_Rp},L,R,Sz} | AL], E) ->
- NL = neg_line(L),
+ NL = no_compiler_warning(L),
T1 = {op,NL,'orelse',
{call,NL,
{remote,NL,{atom,NL,erlang},{atom,NL,is_record}},
@@ -575,8 +573,8 @@ strict_get_record_field(Line, R, {atom,_,F}=Index, Name, St0) ->
Fs = record_fields(Name, St),
I = index_expr(F, Fs, 2),
P = record_pattern(2, I, Var, length(Fs)+1, Line, [{atom,Line,Name}]),
- NLine = neg_line(Line),
- RLine = record_offset(NLine, St),
+ NLine = no_compiler_warning(Line),
+ RLine = mark_record(NLine, St),
E = {'case',NLine,R,
[{clause,NLine,[{tuple,RLine,P}],[],[Var]},
{clause,NLine,[{var,NLine,'_'}],[],
@@ -590,7 +588,8 @@ strict_get_record_field(Line, R, {atom,_,F}=Index, Name, St0) ->
I = index_expr(Line, Index, Name, Fs),
{ExpR,St1} = expr(R, St0),
%% Just to make comparison simple:
- ExpRp = erl_lint:modify_line(ExpR, fun(_L) -> 0 end),
+ A0 = erl_anno:new(0),
+ ExpRp = erl_parse:map_anno(fun(_A) -> A0 end, ExpR),
RA = {{Name,ExpRp},Line,ExpR,length(Fs)+1},
St2 = St1#exprec{strict_ra = [RA | St1#exprec.strict_ra]},
{{call,Line,
@@ -691,8 +690,8 @@ record_update(R, Name, Fs, Us0, St0) ->
record_match(R, Name, Lr, Fs, Us, St0) ->
{Ps,News,St1} = record_upd_fs(Fs, Us, St0),
- NLr = neg_line(Lr),
- RLine = record_offset(Lr, St1),
+ NLr = no_compiler_warning(Lr),
+ RLine = mark_record(Lr, St1),
{{'case',Lr,R,
[{clause,Lr,[{tuple,RLine,[{atom,Lr,Name} | Ps]}],[],
[{tuple,RLine,[{atom,Lr,Name} | News]}]},
@@ -723,8 +722,8 @@ record_setel(R, Name, Fs, Us0) ->
Us = [T || {_,T} <- Us2],
Lr = element(2, hd(Us)),
Wildcards = duplicate(length(Fs), {var,Lr,'_'}),
- NLr = neg_line(Lr),
- %% Note: calling record_offset() here is not necessary since it is
+ NLr = no_compiler_warning(Lr),
+ %% Note: calling mark_record() here is not necessary since it is
%% targeted at Dialyzer which always calls the compiler with
%% 'strict_record_updates' meaning that record_setel() will never
%% be called.
@@ -956,12 +955,11 @@ opt_remove_2({call,Line,{atom,_,is_record},
end;
opt_remove_2(A, _) -> A.
-neg_line(L) ->
- erl_parse:set_line(L, fun(Line) -> -abs(Line) end).
+no_compiler_warning(Anno) ->
+ erl_anno:set_generated(true, Anno).
-record_offset(L, St) ->
+mark_record(Anno, St) ->
case lists:member(dialyzer, St#exprec.compile) of
- true when L >= 0 -> L+?REC_OFFSET;
- true when L < 0 -> L-?REC_OFFSET;
- false -> L
+ true -> erl_anno:set_record(true, Anno);
+ false -> Anno
end.
diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl
index cbe6eeec3c..821d81a6b4 100644
--- a/lib/stdlib/src/erl_lint.erl
+++ b/lib/stdlib/src/erl_lint.erl
@@ -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
@@ -34,6 +34,8 @@
-import(lists, [member/2,map/2,foldl/3,foldr/3,mapfoldl/3,all/2,reverse/1]).
+-deprecated([{modify_line, 2, next_major_release}]).
+
%% bool_option(OnOpt, OffOpt, Default, Options) -> boolean().
%% value_option(Flag, Default, Options) -> Value.
%% value_option(Flag, Default, OnOpt, OnVal, OffOpt, OffVal, Options) ->
@@ -76,7 +78,7 @@ value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) ->
%%-define(DEBUGF(X,Y), io:format(X, Y)).
-define(DEBUGF(X,Y), void).
--type line() :: erl_scan:line(). % a convenient alias
+-type line() :: erl_anno:line(). % a convenient alias
-type fa() :: {atom(), arity()}. % function+arity
-type ta() :: {atom(), arity()}. % type+arity
@@ -111,7 +113,8 @@ value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) ->
defined=gb_sets:empty() %Defined fuctions
:: gb_sets:set(fa()),
on_load=[] :: [fa()], %On-load function
- on_load_line=0 :: line(), %Line for on_load
+ on_load_line=erl_anno:new(0) %Line for on_load
+ :: erl_anno:anno(),
clashes=[], %Exported functions named as BIFs
not_deprecated=[], %Not considered deprecated
func=[], %Current function
@@ -140,7 +143,7 @@ value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) ->
-type lint_state() :: #lint{}.
-type error_description() :: term().
--type error_info() :: {erl_scan:line(), module(), error_description()}.
+-type error_info() :: {erl_anno:line(), module(), error_description()}.
%% format_error(Error)
%% Return a string describing the error.
@@ -227,6 +230,8 @@ format_error({deprecated, MFA, ReplacementMFA, Rel}) ->
[format_mfa(MFA), Rel, format_mfa(ReplacementMFA)]);
format_error({deprecated, {M1, F1, A1}, String}) when is_list(String) ->
io_lib:format("~p:~p/~p: ~s", [M1, F1, A1, String]);
+format_error({deprecated_type, {M1, F1, A1}, String}) when is_list(String) ->
+ io_lib:format("~p:~p~s: ~s", [M1, F1, gen_type_paren(A1), String]);
format_error({removed, MFA, ReplacementMFA, Rel}) ->
io_lib:format("call to ~s will fail, since it was removed in ~s; "
"use ~s", [format_mfa(MFA), Rel, format_mfa(ReplacementMFA)]);
@@ -425,13 +430,13 @@ exprs(Exprs, BindingsList) ->
exprs_opt(Exprs, BindingsList, Opts) ->
{St0,Vs} = foldl(fun({{record,_SequenceNumber,_Name},Attr0}, {St1,Vs1}) ->
- Attr = zip_file_and_line(Attr0, "none"),
+ Attr = set_file(Attr0, "none"),
{attribute_state(Attr, St1),Vs1};
({V,_}, {St1,Vs1}) ->
{St1,[{V,{bound,unused,[]}} | Vs1]}
end, {start("nofile",Opts),[]}, BindingsList),
Vt = orddict:from_list(Vs),
- {_Evt,St} = exprs(zip_file_and_line(Exprs, "nofile"), Vt, St0),
+ {_Evt,St} = exprs(set_file(Exprs, "nofile"), Vt, St0),
return_status(St).
used_vars(Exprs, BindingsList) ->
@@ -439,7 +444,7 @@ used_vars(Exprs, BindingsList) ->
({V,_Val}, Vs0) -> [{V,{bound,unused,[]}} | Vs0]
end, [], BindingsList),
Vt = orddict:from_list(Vs),
- {Evt,_St} = exprs(zip_file_and_line(Exprs, "nofile"), Vt, start()),
+ {Evt,_St} = exprs(set_file(Exprs, "nofile"), Vt, start()),
{ok, foldl(fun({V,{_,used,_}}, L) -> [V | L];
(_, L) -> L
end, [], Evt)}.
@@ -605,8 +610,8 @@ pack_warnings(Ws) ->
add_error(E, St) -> St#lint{errors=[{St#lint.file,E}|St#lint.errors]}.
-add_error(FileLine, E, St) ->
- {File,Location} = loc(FileLine),
+add_error(Anno, E, St) ->
+ {File,Location} = loc(Anno),
add_error({Location,erl_lint,E}, St#lint{file = File}).
add_warning(W, St) -> St#lint{warnings=[{St#lint.file,W}|St#lint.warnings]}.
@@ -615,22 +620,19 @@ add_warning(FileLine, W, St) ->
{File,Location} = loc(FileLine),
add_warning({Location,erl_lint,W}, St#lint{file = File}).
-loc(L) ->
- case erl_parse:get_attribute(L, location) of
- {location,{{File,Line},Column}} ->
- {File,{Line,Column}};
- {location,{File,Line}} ->
- {File,Line}
- end.
+loc(Anno) ->
+ File = erl_anno:file(Anno),
+ Location = erl_anno:location(Anno),
+ {File,Location}.
%% forms([Form], State) -> State'
forms(Forms0, St0) ->
Forms = eval_file_attribute(Forms0, St0),
+ %% Annotations from now on include the 'file' item.
Locals = local_functions(Forms),
AutoImportSuppressed = auto_import_suppressed(St0#lint.compile),
StDeprecated = disallowed_compile_flags(Forms,St0),
- %% Line numbers are from now on pairs {File,Line}.
St1 = includes_qlc_hrl(Forms, StDeprecated#lint{locals = Locals,
no_auto = AutoImportSuppressed}),
St2 = bif_clashes(Forms, St1),
@@ -666,15 +668,14 @@ eval_file_attribute(Forms, St) ->
eval_file_attr([{attribute,_L,file,{File,_Line}}=Form | Forms], _File) ->
[Form | eval_file_attr(Forms, File)];
eval_file_attr([Form0 | Forms], File) ->
- Form = zip_file_and_line(Form0, File),
+ Form = set_file(Form0, File),
[Form | eval_file_attr(Forms, File)];
eval_file_attr([], _File) ->
[].
-zip_file_and_line(T, File) ->
- F0 = fun(Line) -> {File,Line} end,
- F = fun(L) -> erl_parse:set_line(L, F0) end,
- modify_line(T, F).
+set_file(T, File) ->
+ F = fun(Anno) -> erl_anno:set_file(File, Anno) end,
+ erl_parse:map_anno(F, T).
%% form(Form, State) -> State'
%% Check a form returning the updated State. Handle generic cases here.
@@ -796,9 +797,11 @@ not_deprecated(Forms, St0) ->
disallowed_compile_flags(Forms, St0) ->
%% There are (still) no line numbers in St0#lint.compile.
Errors0 = [ {St0#lint.file,{L,erl_lint,disallowed_nowarn_bif_clash}} ||
- {attribute,[{line,{_,L}}],compile,nowarn_bif_clash} <- Forms ],
+ {attribute,A,compile,nowarn_bif_clash} <- Forms,
+ {_,L} <- [loc(A)] ],
Errors1 = [ {St0#lint.file,{L,erl_lint,disallowed_nowarn_bif_clash}} ||
- {attribute,[{line,{_,L}}],compile,{nowarn_bif_clash, {_,_}}} <- Forms ],
+ {attribute,A,compile,{nowarn_bif_clash, {_,_}}} <- Forms,
+ {_,L} <- [loc(A)] ],
Disabled = (not is_warn_enabled(bif_clash, St0)),
Errors = if
Disabled andalso Errors0 =:= [] ->
@@ -1299,7 +1302,7 @@ imported(F, A, St) ->
error -> no
end.
--spec on_load(line(), fa(), lint_state()) -> lint_state().
+-spec on_load(erl_anno:anno(), fa(), lint_state()) -> lint_state().
%% Check an on_load directive and remember it.
on_load(Line, {Name,Arity}=Fa, #lint{on_load=OnLoad0}=St0)
@@ -1954,10 +1957,10 @@ is_guard_test(E) ->
is_guard_test(Expression, Forms) ->
RecordAttributes = [A || A = {attribute, _, record, _D} <- Forms],
St0 = foldl(fun(Attr0, St1) ->
- Attr = zip_file_and_line(Attr0, "none"),
+ Attr = set_file(Attr0, "none"),
attribute_state(Attr, St1)
end, start(), RecordAttributes),
- is_guard_test2(zip_file_and_line(Expression, "nofile"), St0#lint.records).
+ is_guard_test2(set_file(Expression, "nofile"), St0#lint.records).
%% is_guard_test2(Expression, RecordDefs :: dict:dict()) -> boolean().
is_guard_test2({call,Line,{atom,Lr,record},[E,A]}, RDs) ->
@@ -2619,7 +2622,7 @@ type_def(_Attr, _Line, {record, _RecName}, Fields, [], St0) ->
%% The record field names and such are checked in the record format.
%% We only need to check the types.
Types = [T || {typed_record_field, _, T} <- Fields],
- check_type({type, -1, product, Types}, St0);
+ check_type({type, nowarn(), product, Types}, St0);
type_def(Attr, Line, TypeName, ProtoType, Args, St0) ->
TypeDefs = St0#lint.types,
Arity = length(Args),
@@ -2628,7 +2631,7 @@ type_def(Attr, Line, TypeName, ProtoType, Args, St0) ->
StoreType =
fun(St) ->
NewDefs = dict:store(TypePair, Info, TypeDefs),
- CheckType = {type, -1, product, [ProtoType|Args]},
+ CheckType = {type, nowarn(), product, [ProtoType|Args]},
check_type(CheckType, St#lint{types=NewDefs})
end,
case is_default_type(TypePair) of
@@ -2684,7 +2687,9 @@ check_type({ann_type, _L, [_Var, Type]}, SeenVars, St) ->
check_type({paren_type, _L, [Type]}, SeenVars, St) ->
check_type(Type, SeenVars, St);
check_type({remote_type, L, [{atom, _, Mod}, {atom, _, Name}, Args]},
- SeenVars, #lint{module=CurrentMod} = St) ->
+ SeenVars, St0) ->
+ St = deprecated_type(L, Mod, Name, Args, St0),
+ CurrentMod = St#lint.module,
case Mod =:= CurrentMod of
true -> check_type({user_type, L, Name, Args}, SeenVars, St);
false ->
@@ -2712,7 +2717,7 @@ check_type({type, L, 'fun', [Dom, Range]}, SeenVars, St) ->
{type, _, any} -> St;
_ -> add_error(L, {type_syntax, 'fun'}, St)
end,
- check_type({type, -1, product, [Dom, Range]}, SeenVars, St1);
+ check_type({type, nowarn(), product, [Dom, Range]}, SeenVars, St1);
check_type({type, L, range, [From, To]}, SeenVars, St) ->
St1 =
case {erl_eval:partial_eval(From), erl_eval:partial_eval(To)} of
@@ -2729,7 +2734,7 @@ check_type({type, _L, map, Pairs}, SeenVars, St) ->
check_type(Pair, AccSeenVars, AccSt)
end, {SeenVars, St}, Pairs);
check_type({type, _L, map_field_assoc, [Dom, Range]}, SeenVars, St) ->
- check_type({type, -1, product, [Dom, Range]}, SeenVars, St);
+ check_type({type, nowarn(), product, [Dom, Range]}, SeenVars, St);
check_type({type, _L, tuple, any}, SeenVars, St) -> {SeenVars, St};
check_type({type, _L, any}, SeenVars, St) -> {SeenVars, St};
check_type({type, L, binary, [Base, Unit]}, SeenVars, St) ->
@@ -2772,7 +2777,7 @@ check_type({type, La, TypeName, Args}, SeenVars, St) ->
end;
_ -> St
end,
- check_type({type, -1, product, Args}, SeenVars, St1);
+ check_type({type, nowarn(), product, Args}, SeenVars, St1);
check_type({user_type, L, TypeName, Args}, SeenVars, St) ->
Arity = length(Args),
TypePair = {TypeName, Arity},
@@ -2919,11 +2924,16 @@ check_specs([FunType|Left], Arity, St0) ->
true -> St0;
false -> add_error(L, spec_wrong_arity, St0)
end,
- St2 = check_type({type, -1, product, [FunType1|CTypes]}, St1),
+ St2 = check_type({type, nowarn(), product, [FunType1|CTypes]}, St1),
check_specs(Left, Arity, St2);
check_specs([], _Arity, St) ->
St.
+nowarn() ->
+ A0 = erl_anno:new(0),
+ A1 = erl_anno:set_generated(true, A0),
+ erl_anno:set_file("", A1).
+
check_specs_without_function(#lint{module=Mod,defined=Funcs,specs=Specs}=St) ->
Fun = fun({M, F, A}, Line, AccSt) when M =:= Mod ->
FA = {F, A},
@@ -3452,58 +3462,15 @@ vt_no_unused(Vt) -> [V || {_,{_,U,_L}}=V <- Vt, U =/= unused].
%% copy_expr(Expr, Line) -> Expr.
%% Make a copy of Expr converting all line numbers to Line.
-copy_expr(Expr, Line) ->
- modify_line(Expr, fun(_L) -> Line end).
+copy_expr(Expr, Anno) ->
+ erl_parse:map_anno(fun(_A) -> Anno end, Expr).
%% modify_line(Form, Fun) -> Form
%% modify_line(Expression, Fun) -> Expression
%% Applies Fun to each line number occurrence.
modify_line(T, F0) ->
- modify_line1(T, F0).
-
-%% Forms.
-modify_line1({function,F,A}, _Mf) -> {function,F,A};
-modify_line1({function,M,F,A}, Mf) ->
- {function,modify_line1(M, Mf),modify_line1(F, Mf),modify_line1(A, Mf)};
-modify_line1({attribute,L,record,{Name,Fields}}, Mf) ->
- {attribute,Mf(L),record,{Name,modify_line1(Fields, Mf)}};
-modify_line1({attribute,L,spec,{Fun,Types}}, Mf) ->
- {attribute,Mf(L),spec,{Fun,modify_line1(Types, Mf)}};
-modify_line1({attribute,L,callback,{Fun,Types}}, Mf) ->
- {attribute,Mf(L),callback,{Fun,modify_line1(Types, Mf)}};
-modify_line1({attribute,L,type,{TypeName,TypeDef,Args}}, Mf) ->
- {attribute,Mf(L),type,{TypeName,modify_line1(TypeDef, Mf),
- modify_line1(Args, Mf)}};
-modify_line1({attribute,L,opaque,{TypeName,TypeDef,Args}}, Mf) ->
- {attribute,Mf(L),opaque,{TypeName,modify_line1(TypeDef, Mf),
- modify_line1(Args, Mf)}};
-modify_line1({attribute,L,Attr,Val}, Mf) -> {attribute,Mf(L),Attr,Val};
-modify_line1({warning,W}, _Mf) -> {warning,W};
-modify_line1({error,W}, _Mf) -> {error,W};
-%% Expressions.
-modify_line1({clauses,Cs}, Mf) -> {clauses,modify_line1(Cs, Mf)};
-modify_line1({typed_record_field,Field,Type}, Mf) ->
- {typed_record_field,modify_line1(Field, Mf),modify_line1(Type, Mf)};
-modify_line1({Tag,L}, Mf) -> {Tag,Mf(L)};
-modify_line1({Tag,L,E1}, Mf) ->
- {Tag,Mf(L),modify_line1(E1, Mf)};
-modify_line1({Tag,L,E1,E2}, Mf) ->
- {Tag,Mf(L),modify_line1(E1, Mf),modify_line1(E2, Mf)};
-modify_line1({bin_element,L,E1,E2,TSL}, Mf) ->
- {bin_element,Mf(L),modify_line1(E1, Mf),modify_line1(E2, Mf), TSL};
-modify_line1({Tag,L,E1,E2,E3}, Mf) ->
- {Tag,Mf(L),modify_line1(E1, Mf),modify_line1(E2, Mf),modify_line1(E3, Mf)};
-modify_line1({Tag,L,E1,E2,E3,E4}, Mf) ->
- {Tag,Mf(L),
- modify_line1(E1, Mf),
- modify_line1(E2, Mf),
- modify_line1(E3, Mf),
- modify_line1(E4, Mf)};
-modify_line1([H|T], Mf) ->
- [modify_line1(H, Mf)|modify_line1(T, Mf)];
-modify_line1([], _Mf) -> [];
-modify_line1(E, _Mf) when not is_tuple(E), not is_list(E) -> E.
+ erl_parse:map_anno(F0, T).
%% Check a record_info call. We have already checked that it is not
%% shadowed by an import.
@@ -3573,6 +3540,20 @@ deprecated_function(Line, M, F, As, St) ->
St
end.
+deprecated_type(L, M, N, As, St) ->
+ NAs = length(As),
+ case otp_internal:obsolete_type(M, N, NAs) of
+ {deprecated, String} when is_list(String) ->
+ case is_warn_enabled(deprecated_type, St) of
+ true ->
+ add_warning(L, {deprecated_type, {M,N,NAs}, String}, St);
+ false ->
+ St
+ end;
+ no ->
+ St
+ end.
+
obsolete_guard({call,Line,{atom,Lr,F},As}, St0) ->
Arity = length(As),
case erl_internal:old_type_test(F, Arity) of
diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl
index 3502a50eaa..e328e065e3 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
@@ -92,7 +92,7 @@ spec_fun -> atom ':' atom '/' integer '::' : {'$1', '$3', '$5'}.
typed_attr_val -> expr ',' typed_record_fields : {typed_record, '$1', '$3'}.
typed_attr_val -> expr '::' top_type : {type_def, '$1', '$3'}.
-typed_record_fields -> '{' typed_exprs '}' : {tuple, ?line('$1'), '$2'}.
+typed_record_fields -> '{' typed_exprs '}' : {tuple, ?anno('$1'), '$2'}.
typed_exprs -> typed_expr : ['$1'].
typed_exprs -> typed_expr ',' typed_exprs : ['$1'|'$3'].
@@ -105,26 +105,26 @@ type_sigs -> type_sig : ['$1'].
type_sigs -> type_sig ';' type_sigs : ['$1'|'$3'].
type_sig -> fun_type : '$1'.
-type_sig -> fun_type 'when' type_guards : {type, ?line('$1'), bounded_fun,
+type_sig -> fun_type 'when' type_guards : {type, ?anno('$1'), bounded_fun,
['$1','$3']}.
type_guards -> type_guard : ['$1'].
type_guards -> type_guard ',' type_guards : ['$1'|'$3'].
-type_guard -> atom '(' top_types ')' : {type, ?line('$1'), constraint,
+type_guard -> atom '(' top_types ')' : {type, ?anno('$1'), constraint,
['$1', '$3']}.
type_guard -> var '::' top_type : build_def('$1', '$3').
top_types -> top_type : ['$1'].
top_types -> top_type ',' top_types : ['$1'|'$3'].
-top_type -> var '::' top_type_100 : {ann_type, ?line('$1'), ['$1','$3']}.
+top_type -> var '::' top_type_100 : {ann_type, ?anno('$1'), ['$1','$3']}.
top_type -> top_type_100 : '$1'.
top_type_100 -> type_200 : '$1'.
top_type_100 -> type_200 '|' top_type_100 : lift_unions('$1','$3').
-type_200 -> type_300 '..' type_300 : {type, ?line('$1'), range,
+type_200 -> type_300 '..' type_300 : {type, ?anno('$1'), range,
[skip_paren('$1'),
skip_paren('$3')]}.
type_200 -> type_300 : '$1'.
@@ -140,61 +140,61 @@ type_400 -> type_500 : '$1'.
type_500 -> prefix_op type : ?mkop1('$1', skip_paren('$2')).
type_500 -> type : '$1'.
-type -> '(' top_type ')' : {paren_type, ?line('$2'), ['$2']}.
+type -> '(' top_type ')' : {paren_type, ?anno('$2'), ['$2']}.
type -> var : '$1'.
type -> atom : '$1'.
type -> atom '(' ')' : build_gen_type('$1').
type -> atom '(' top_types ')' : build_type('$1', '$3').
-type -> atom ':' atom '(' ')' : {remote_type, ?line('$1'),
+type -> atom ':' atom '(' ')' : {remote_type, ?anno('$1'),
['$1', '$3', []]}.
-type -> atom ':' atom '(' top_types ')' : {remote_type, ?line('$1'),
+type -> atom ':' atom '(' top_types ')' : {remote_type, ?anno('$1'),
['$1', '$3', '$5']}.
-type -> '[' ']' : {type, ?line('$1'), nil, []}.
-type -> '[' top_type ']' : {type, ?line('$1'), list, ['$2']}.
-type -> '[' top_type ',' '...' ']' : {type, ?line('$1'),
+type -> '[' ']' : {type, ?anno('$1'), nil, []}.
+type -> '[' top_type ']' : {type, ?anno('$1'), list, ['$2']}.
+type -> '[' top_type ',' '...' ']' : {type, ?anno('$1'),
nonempty_list, ['$2']}.
-type -> '#' '{' '}' : {type, ?line('$1'), map, []}.
-type -> '#' '{' map_pair_types '}' : {type, ?line('$1'), map, '$3'}.
-type -> '{' '}' : {type, ?line('$1'), tuple, []}.
-type -> '{' top_types '}' : {type, ?line('$1'), tuple, '$2'}.
-type -> '#' atom '{' '}' : {type, ?line('$1'), record, ['$2']}.
-type -> '#' atom '{' field_types '}' : {type, ?line('$1'),
+type -> '#' '{' '}' : {type, ?anno('$1'), map, []}.
+type -> '#' '{' map_pair_types '}' : {type, ?anno('$1'), map, '$3'}.
+type -> '{' '}' : {type, ?anno('$1'), tuple, []}.
+type -> '{' top_types '}' : {type, ?anno('$1'), tuple, '$2'}.
+type -> '#' atom '{' '}' : {type, ?anno('$1'), record, ['$2']}.
+type -> '#' atom '{' field_types '}' : {type, ?anno('$1'),
record, ['$2'|'$4']}.
type -> binary_type : '$1'.
type -> integer : '$1'.
-type -> 'fun' '(' ')' : {type, ?line('$1'), 'fun', []}.
+type -> 'fun' '(' ')' : {type, ?anno('$1'), 'fun', []}.
type -> 'fun' '(' fun_type_100 ')' : '$3'.
fun_type_100 -> '(' '...' ')' '->' top_type
- : {type, ?line('$1'), 'fun',
- [{type, ?line('$1'), any}, '$5']}.
+ : {type, ?anno('$1'), 'fun',
+ [{type, ?anno('$1'), any}, '$5']}.
fun_type_100 -> fun_type : '$1'.
-fun_type -> '(' ')' '->' top_type : {type, ?line('$1'), 'fun',
- [{type, ?line('$1'), product, []}, '$4']}.
+fun_type -> '(' ')' '->' top_type : {type, ?anno('$1'), 'fun',
+ [{type, ?anno('$1'), product, []}, '$4']}.
fun_type -> '(' top_types ')' '->' top_type
- : {type, ?line('$1'), 'fun',
- [{type, ?line('$1'), product, '$2'},'$5']}.
+ : {type, ?anno('$1'), 'fun',
+ [{type, ?anno('$1'), product, '$2'},'$5']}.
map_pair_types -> map_pair_type : ['$1'].
map_pair_types -> map_pair_type ',' map_pair_types : ['$1'|'$3'].
-map_pair_type -> top_type '=>' top_type : {type, ?line('$2'), map_field_assoc,['$1','$3']}.
+map_pair_type -> top_type '=>' top_type : {type, ?anno('$2'), map_field_assoc,['$1','$3']}.
field_types -> field_type : ['$1'].
field_types -> field_type ',' field_types : ['$1'|'$3'].
-field_type -> atom '::' top_type : {type, ?line('$1'), field_type,
+field_type -> atom '::' top_type : {type, ?anno('$1'), field_type,
['$1', '$3']}.
-binary_type -> '<<' '>>' : {type, ?line('$1'),binary,
- [abstract(0, ?line('$1')),
- abstract(0, ?line('$1'))]}.
-binary_type -> '<<' bin_base_type '>>' : {type, ?line('$1'),binary,
- ['$2', abstract(0, ?line('$1'))]}.
-binary_type -> '<<' bin_unit_type '>>' : {type, ?line('$1'),binary,
- [abstract(0, ?line('$1')), '$2']}.
+binary_type -> '<<' '>>' : {type, ?anno('$1'),binary,
+ [abstract2(0, ?anno('$1')),
+ abstract2(0, ?anno('$1'))]}.
+binary_type -> '<<' bin_base_type '>>' : {type, ?anno('$1'),binary,
+ ['$2', abstract2(0, ?anno('$1'))]}.
+binary_type -> '<<' bin_unit_type '>>' : {type, ?anno('$1'),binary,
+ [abstract2(0, ?anno('$1')), '$2']}.
binary_type -> '<<' bin_base_type ',' bin_unit_type '>>'
- : {type, ?line('$1'), binary, ['$2', '$4']}.
+ : {type, ?anno('$1'), binary, ['$2', '$4']}.
bin_base_type -> var ':' type : build_bin_type(['$1'], '$3').
@@ -210,7 +210,7 @@ function_clauses -> function_clause : ['$1'].
function_clauses -> function_clause ';' function_clauses : ['$1'|'$3'].
function_clause -> atom clause_args clause_guard clause_body :
- {clause,?line('$1'),element(3, '$1'),'$2','$3','$4'}.
+ {clause,?anno('$1'),element(3, '$1'),'$2','$3','$4'}.
clause_args -> argument_list : element(1, '$1').
@@ -221,10 +221,10 @@ clause_guard -> '$empty' : [].
clause_body -> '->' exprs: '$2'.
-expr -> 'catch' expr : {'catch',?line('$1'),'$2'}.
+expr -> 'catch' expr : {'catch',?anno('$1'),'$2'}.
expr -> expr_100 : '$1'.
-expr_100 -> expr_150 '=' expr_100 : {match,?line('$2'),'$1','$3'}.
+expr_100 -> expr_150 '=' expr_100 : {match,?anno('$2'),'$1','$3'}.
expr_100 -> expr_150 '!' expr_100 : ?mkop2('$1', '$2', '$3').
expr_100 -> expr_150 : '$1'.
@@ -260,7 +260,7 @@ expr_700 -> record_expr : '$1'.
expr_700 -> expr_800 : '$1'.
expr_800 -> expr_max ':' expr_max :
- {remote,?line('$2'),'$1','$3'}.
+ {remote,?anno('$2'),'$1','$3'}.
expr_800 -> expr_max : '$1'.
expr_max -> var : '$1'.
@@ -272,7 +272,7 @@ expr_max -> binary_comprehension : '$1'.
expr_max -> tuple : '$1'.
%%expr_max -> struct : '$1'.
expr_max -> '(' expr ')' : '$2'.
-expr_max -> 'begin' exprs 'end' : {block,?line('$1'),'$2'}.
+expr_max -> 'begin' exprs 'end' : {block,?anno('$1'),'$2'}.
expr_max -> if_expr : '$1'.
expr_max -> case_expr : '$1'.
expr_max -> receive_expr : '$1'.
@@ -280,22 +280,22 @@ expr_max -> fun_expr : '$1'.
expr_max -> try_expr : '$1'.
-list -> '[' ']' : {nil,?line('$1')}.
-list -> '[' expr tail : {cons,?line('$1'),'$2','$3'}.
+list -> '[' ']' : {nil,?anno('$1')}.
+list -> '[' expr tail : {cons,?anno('$1'),'$2','$3'}.
-tail -> ']' : {nil,?line('$1')}.
+tail -> ']' : {nil,?anno('$1')}.
tail -> '|' expr ']' : '$2'.
-tail -> ',' expr tail : {cons,?line('$2'),'$2','$3'}.
+tail -> ',' expr tail : {cons,?anno('$2'),'$2','$3'}.
-binary -> '<<' '>>' : {bin,?line('$1'),[]}.
-binary -> '<<' bin_elements '>>' : {bin,?line('$1'),'$2'}.
+binary -> '<<' '>>' : {bin,?anno('$1'),[]}.
+binary -> '<<' bin_elements '>>' : {bin,?anno('$1'),'$2'}.
bin_elements -> bin_element : ['$1'].
bin_elements -> bin_element ',' bin_elements : ['$1'|'$3'].
bin_element -> bit_expr opt_bit_size_expr opt_bit_type_list :
- {bin_element,?line('$1'),'$1','$2','$3'}.
+ {bin_element,?anno('$1'),'$1','$2','$3'}.
bit_expr -> prefix_op expr_max : ?mkop1('$1', '$2').
bit_expr -> expr_max : '$1'.
@@ -316,29 +316,29 @@ bit_size_expr -> expr_max : '$1'.
list_comprehension -> '[' expr '||' lc_exprs ']' :
- {lc,?line('$1'),'$2','$4'}.
+ {lc,?anno('$1'),'$2','$4'}.
binary_comprehension -> '<<' binary '||' lc_exprs '>>' :
- {bc,?line('$1'),'$2','$4'}.
+ {bc,?anno('$1'),'$2','$4'}.
lc_exprs -> lc_expr : ['$1'].
lc_exprs -> lc_expr ',' lc_exprs : ['$1'|'$3'].
lc_expr -> expr : '$1'.
-lc_expr -> expr '<-' expr : {generate,?line('$2'),'$1','$3'}.
-lc_expr -> binary '<=' expr : {b_generate,?line('$2'),'$1','$3'}.
+lc_expr -> expr '<-' expr : {generate,?anno('$2'),'$1','$3'}.
+lc_expr -> binary '<=' expr : {b_generate,?anno('$2'),'$1','$3'}.
-tuple -> '{' '}' : {tuple,?line('$1'),[]}.
-tuple -> '{' exprs '}' : {tuple,?line('$1'),'$2'}.
+tuple -> '{' '}' : {tuple,?anno('$1'),[]}.
+tuple -> '{' exprs '}' : {tuple,?anno('$1'),'$2'}.
%%struct -> atom tuple :
-%% {struct,?line('$1'),element(3, '$1'),element(3, '$2')}.
+%% {struct,?anno('$1'),element(3, '$1'),element(3, '$2')}.
map_expr -> '#' map_tuple :
- {map, ?line('$1'),'$2'}.
+ {map, ?anno('$1'),'$2'}.
map_expr -> expr_max '#' map_tuple :
- {map, ?line('$2'),'$1','$3'}.
+ {map, ?anno('$2'),'$1','$3'}.
map_expr -> map_expr '#' map_tuple :
- {map, ?line('$2'),'$1','$3'}.
+ {map, ?anno('$2'),'$1','$3'}.
map_tuple -> '{' '}' : [].
map_tuple -> '{' map_fields '}' : '$2'.
@@ -350,10 +350,10 @@ map_field -> map_field_assoc : '$1'.
map_field -> map_field_exact : '$1'.
map_field_assoc -> map_key '=>' expr :
- {map_field_assoc,?line('$1'),'$1','$3'}.
+ {map_field_assoc,?anno('$1'),'$1','$3'}.
map_field_exact -> map_key ':=' expr :
- {map_field_exact,?line('$1'),'$1','$3'}.
+ {map_field_exact,?anno('$1'),'$1','$3'}.
map_key -> expr : '$1'.
@@ -363,17 +363,17 @@ map_key -> expr : '$1'.
%% always atoms for the moment, this might change in the future.
record_expr -> '#' atom '.' atom :
- {record_index,?line('$1'),element(3, '$2'),'$4'}.
+ {record_index,?anno('$1'),element(3, '$2'),'$4'}.
record_expr -> '#' atom record_tuple :
- {record,?line('$1'),element(3, '$2'),'$3'}.
+ {record,?anno('$1'),element(3, '$2'),'$3'}.
record_expr -> expr_max '#' atom '.' atom :
- {record_field,?line('$2'),'$1',element(3, '$3'),'$5'}.
+ {record_field,?anno('$2'),'$1',element(3, '$3'),'$5'}.
record_expr -> expr_max '#' atom record_tuple :
- {record,?line('$2'),'$1',element(3, '$3'),'$4'}.
+ {record,?anno('$2'),'$1',element(3, '$3'),'$4'}.
record_expr -> record_expr '#' atom '.' atom :
- {record_field,?line('$2'),'$1',element(3, '$3'),'$5'}.
+ {record_field,?anno('$2'),'$1',element(3, '$3'),'$5'}.
record_expr -> record_expr '#' atom record_tuple :
- {record,?line('$2'),'$1',element(3, '$3'),'$4'}.
+ {record,?anno('$2'),'$1',element(3, '$3'),'$4'}.
record_tuple -> '{' '}' : [].
record_tuple -> '{' record_fields '}' : '$2'.
@@ -381,47 +381,47 @@ record_tuple -> '{' record_fields '}' : '$2'.
record_fields -> record_field : ['$1'].
record_fields -> record_field ',' record_fields : ['$1' | '$3'].
-record_field -> var '=' expr : {record_field,?line('$1'),'$1','$3'}.
-record_field -> atom '=' expr : {record_field,?line('$1'),'$1','$3'}.
+record_field -> var '=' expr : {record_field,?anno('$1'),'$1','$3'}.
+record_field -> atom '=' expr : {record_field,?anno('$1'),'$1','$3'}.
%% N.B. This is called from expr_700.
function_call -> expr_800 argument_list :
- {call,?line('$1'),'$1',element(1, '$2')}.
+ {call,?anno('$1'),'$1',element(1, '$2')}.
-if_expr -> 'if' if_clauses 'end' : {'if',?line('$1'),'$2'}.
+if_expr -> 'if' if_clauses 'end' : {'if',?anno('$1'),'$2'}.
if_clauses -> if_clause : ['$1'].
if_clauses -> if_clause ';' if_clauses : ['$1' | '$3'].
if_clause -> guard clause_body :
- {clause,?line(hd(hd('$1'))),[],'$1','$2'}.
+ {clause,?anno(hd(hd('$1'))),[],'$1','$2'}.
case_expr -> 'case' expr 'of' cr_clauses 'end' :
- {'case',?line('$1'),'$2','$4'}.
+ {'case',?anno('$1'),'$2','$4'}.
cr_clauses -> cr_clause : ['$1'].
cr_clauses -> cr_clause ';' cr_clauses : ['$1' | '$3'].
cr_clause -> expr clause_guard clause_body :
- {clause,?line('$1'),['$1'],'$2','$3'}.
+ {clause,?anno('$1'),['$1'],'$2','$3'}.
receive_expr -> 'receive' cr_clauses 'end' :
- {'receive',?line('$1'),'$2'}.
+ {'receive',?anno('$1'),'$2'}.
receive_expr -> 'receive' 'after' expr clause_body 'end' :
- {'receive',?line('$1'),[],'$3','$4'}.
+ {'receive',?anno('$1'),[],'$3','$4'}.
receive_expr -> 'receive' cr_clauses 'after' expr clause_body 'end' :
- {'receive',?line('$1'),'$2','$4','$5'}.
+ {'receive',?anno('$1'),'$2','$4','$5'}.
fun_expr -> 'fun' atom '/' integer :
- {'fun',?line('$1'),{function,element(3, '$2'),element(3, '$4')}}.
+ {'fun',?anno('$1'),{function,element(3, '$2'),element(3, '$4')}}.
fun_expr -> 'fun' atom_or_var ':' atom_or_var '/' integer_or_var :
- {'fun',?line('$1'),{function,'$2','$4','$6'}}.
+ {'fun',?anno('$1'),{function,'$2','$4','$6'}}.
fun_expr -> 'fun' fun_clauses 'end' :
- build_fun(?line('$1'), '$2').
+ build_fun(?anno('$1'), '$2').
atom_or_var -> atom : '$1'.
atom_or_var -> var : '$1'.
@@ -433,16 +433,16 @@ fun_clauses -> fun_clause : ['$1'].
fun_clauses -> fun_clause ';' fun_clauses : ['$1' | '$3'].
fun_clause -> argument_list clause_guard clause_body :
- {Args,Pos} = '$1',
- {clause,Pos,'fun',Args,'$2','$3'}.
+ {Args,Anno} = '$1',
+ {clause,Anno,'fun',Args,'$2','$3'}.
fun_clause -> var argument_list clause_guard clause_body :
{clause,element(2, '$1'),element(3, '$1'),element(1, '$2'),'$3','$4'}.
try_expr -> 'try' exprs 'of' cr_clauses try_catch :
- build_try(?line('$1'),'$2','$4','$5').
+ build_try(?anno('$1'),'$2','$4','$5').
try_expr -> 'try' exprs try_catch :
- build_try(?line('$1'),'$2',[],'$3').
+ build_try(?anno('$1'),'$2',[],'$3').
try_catch -> 'catch' try_clauses 'end' :
{'$2',[]}.
@@ -455,18 +455,18 @@ try_clauses -> try_clause : ['$1'].
try_clauses -> try_clause ';' try_clauses : ['$1' | '$3'].
try_clause -> expr clause_guard clause_body :
- L = ?line('$1'),
- {clause,L,[{tuple,L,[{atom,L,throw},'$1',{var,L,'_'}]}],'$2','$3'}.
+ A = ?anno('$1'),
+ {clause,A,[{tuple,A,[{atom,A,throw},'$1',{var,A,'_'}]}],'$2','$3'}.
try_clause -> atom ':' expr clause_guard clause_body :
- L = ?line('$1'),
- {clause,L,[{tuple,L,['$1','$3',{var,L,'_'}]}],'$4','$5'}.
+ A = ?anno('$1'),
+ {clause,A,[{tuple,A,['$1','$3',{var,A,'_'}]}],'$4','$5'}.
try_clause -> var ':' expr clause_guard clause_body :
- L = ?line('$1'),
- {clause,L,[{tuple,L,['$1','$3',{var,L,'_'}]}],'$4','$5'}.
+ A = ?anno('$1'),
+ {clause,A,[{tuple,A,['$1','$3',{var,A,'_'}]}],'$4','$5'}.
-argument_list -> '(' ')' : {[],?line('$1')}.
-argument_list -> '(' exprs ')' : {'$2',?line('$1')}.
+argument_list -> '(' ')' : {[],?anno('$1')}.
+argument_list -> '(' exprs ')' : {'$2',?anno('$1')}.
exprs -> expr : ['$1'].
@@ -483,7 +483,7 @@ atomic -> strings : '$1'.
strings -> string : '$1'.
strings -> string strings :
- {string,?line('$1'),element(3, '$1') ++ element(3, '$2')}.
+ {string,?anno('$1'),element(3, '$1') ++ element(3, '$2')}.
prefix_op -> '+' : '$1'.
prefix_op -> '-' : '$1'.
@@ -524,8 +524,14 @@ 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]).
+-deprecated([{set_line, 2, next_major_release},
+ {get_attribute, 2, next_major_release},
+ {get_attributes, 1, next_major_release}]).
+
%% The following directive is needed for (significantly) faster compilation
%% of the generated .erl file by the HiPE compiler. Please do not remove.
-compile([{hipe,[{regalloc,linear_scan}]}]).
@@ -533,30 +539,31 @@ 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().
-type error_description() :: term().
--type error_info() :: {erl_scan:line(), module(), error_description()}.
+-type error_info() :: {erl_anno:line(), module(), error_description()}.
-type token() :: erl_scan:token().
-%% mkop(Op, Arg) -> {op,Line,Op,Arg}.
-%% mkop(Left, Op, Right) -> {op,Line,Op,Left,Right}.
+%% mkop(Op, Arg) -> {op,Anno,Op,Arg}.
+%% mkop(Left, Op, Right) -> {op,Anno,Op,Left,Right}.
--define(mkop2(L, OpPos, R),
+-define(mkop2(L, OpAnno, R),
begin
- {Op,Pos} = OpPos,
- {op,Pos,Op,L,R}
+ {Op,Anno} = OpAnno,
+ {op,Anno,Op,L,R}
end).
--define(mkop1(OpPos, A),
+-define(mkop1(OpAnno, A),
begin
- {Op,Pos} = OpPos,
- {op,Pos,Op,A}
+ {Op,Anno} = OpAnno,
+ {op,Anno,Op,A}
end).
-%% keep track of line info in tokens
--define(line(Tup), element(2, Tup)).
+%% keep track of annotation info in tokens
+-define(anno(Tup), element(2, Tup)).
%% Entry points compatible to old erl_parse.
%% These really suck and are only here until Calle gets multiple
@@ -566,10 +573,10 @@ Erlang code.
Tokens :: [token()],
AbsForm :: abstract_form(),
ErrorInfo :: error_info().
-parse_form([{'-',L1},{atom,L2,spec}|Tokens]) ->
- parse([{'-',L1},{'spec',L2}|Tokens]);
-parse_form([{'-',L1},{atom,L2,callback}|Tokens]) ->
- parse([{'-',L1},{'callback',L2}|Tokens]);
+parse_form([{'-',A1},{atom,A2,spec}|Tokens]) ->
+ parse([{'-',A1},{'spec',A2}|Tokens]);
+parse_form([{'-',A1},{atom,A2,callback}|Tokens]) ->
+ parse([{'-',A1},{'callback',A2}|Tokens]);
parse_form(Tokens) ->
parse(Tokens).
@@ -578,7 +585,8 @@ parse_form(Tokens) ->
ExprList :: [abstract_expr()],
ErrorInfo :: error_info().
parse_exprs(Tokens) ->
- case parse([{atom,0,f},{'(',0},{')',0},{'->',0}|Tokens]) of
+ A = erl_anno:new(0),
+ case parse([{atom,A,f},{'(',A},{')',A},{'->',A}|Tokens]) of
{ok,{function,_Lf,f,0,[{clause,_Lc,[],[],Exprs}]}} ->
{ok,Exprs};
{error,_} = Err -> Err
@@ -589,42 +597,43 @@ parse_exprs(Tokens) ->
Term :: term(),
ErrorInfo :: error_info().
parse_term(Tokens) ->
- case parse([{atom,0,f},{'(',0},{')',0},{'->',0}|Tokens]) of
- {ok,{function,_Lf,f,0,[{clause,_Lc,[],[],[Expr]}]}} ->
+ A = erl_anno:new(0),
+ case parse([{atom,A,f},{'(',A},{')',A},{'->',A}|Tokens]) of
+ {ok,{function,_Af,f,0,[{clause,_Ac,[],[],[Expr]}]}} ->
try normalise(Expr) of
Term -> {ok,Term}
catch
- _:_R -> {error,{?line(Expr),?MODULE,"bad term"}}
+ _:_R -> {error,{location(?anno(Expr)),?MODULE,"bad term"}}
end;
- {ok,{function,_Lf,f,0,[{clause,_Lc,[],[],[_E1,E2|_Es]}]}} ->
- {error,{?line(E2),?MODULE,"bad term"}};
+ {ok,{function,_Af,f,A,[{clause,_Ac,[],[],[_E1,E2|_Es]}]}} ->
+ {error,{location(?anno(E2)),?MODULE,"bad term"}};
{error,_} = Err -> Err
end.
-type attributes() :: 'export' | 'file' | 'import' | 'module'
| 'opaque' | 'record' | 'type'.
-build_typed_attribute({atom,La,record},
- {typed_record, {atom,_Ln,RecordName}, RecTuple}) ->
- {attribute,La,record,{RecordName,record_tuple(RecTuple)}};
-build_typed_attribute({atom,La,Attr},
+build_typed_attribute({atom,Aa,record},
+ {typed_record, {atom,_An,RecordName}, RecTuple}) ->
+ {attribute,Aa,record,{RecordName,record_tuple(RecTuple)}};
+build_typed_attribute({atom,Aa,Attr},
{type_def, {call,_,{atom,_,TypeName},Args}, Type})
when Attr =:= 'type' ; Attr =:= 'opaque' ->
case lists:all(fun({var, _, _}) -> true;
(_) -> false
end, Args) of
- true -> {attribute,La,Attr,{TypeName,Type,Args}};
- false -> error_bad_decl(La, Attr)
+ true -> {attribute,Aa,Attr,{TypeName,Type,Args}};
+ false -> error_bad_decl(Aa, Attr)
end;
-build_typed_attribute({atom,La,Attr},_) ->
+build_typed_attribute({atom,Aa,Attr},_) ->
case Attr of
- record -> error_bad_decl(La, record);
- type -> error_bad_decl(La, type);
- opaque -> error_bad_decl(La, opaque);
- _ -> ret_err(La, "bad attribute")
+ record -> error_bad_decl(Aa, record);
+ type -> error_bad_decl(Aa, type);
+ opaque -> error_bad_decl(Aa, opaque);
+ _ -> ret_err(Aa, "bad attribute")
end.
-build_type_spec({Kind,La}, {SpecFun, TypeSpecs})
+build_type_spec({Kind,Aa}, {SpecFun, TypeSpecs})
when (Kind =:= spec) or (Kind =:= callback) ->
NewSpecFun =
case SpecFun of
@@ -639,7 +648,7 @@ build_type_spec({Kind,La}, {SpecFun, TypeSpecs})
%% Old style spec. Allow this for now.
{Mod,Fun,Arity}
end,
- {attribute,La,Kind,{NewSpecFun, TypeSpecs}}.
+ {attribute,Aa,Kind,{NewSpecFun, TypeSpecs}}.
find_arity_from_specs([Spec|_]) ->
%% Use the first spec to find the arity. If all are not the same,
@@ -651,40 +660,40 @@ find_arity_from_specs([Spec|_]) ->
{type, _, 'fun', [{type, _, product, Args},_]} = Fun,
length(Args).
-build_def({var, L, '_'}, _Types) ->
- ret_err(L, "bad type variable");
+build_def({var, A, '_'}, _Types) ->
+ ret_err(A, "bad type variable");
build_def(LHS, Types) ->
- IsSubType = {atom, ?line(LHS), is_subtype},
- {type, ?line(LHS), constraint, [IsSubType, [LHS, Types]]}.
+ IsSubType = {atom, ?anno(LHS), is_subtype},
+ {type, ?anno(LHS), constraint, [IsSubType, [LHS, Types]]}.
-lift_unions(T1, {type, _La, union, List}) ->
- {type, ?line(T1), union, [T1|List]};
+lift_unions(T1, {type, _Aa, union, List}) ->
+ {type, ?anno(T1), union, [T1|List]};
lift_unions(T1, T2) ->
- {type, ?line(T1), union, [T1, T2]}.
+ {type, ?anno(T1), union, [T1, T2]}.
-skip_paren({paren_type,_L,[Type]}) ->
+skip_paren({paren_type,_A,[Type]}) ->
skip_paren(Type);
skip_paren(Type) ->
Type.
-build_gen_type({atom, La, tuple}) ->
- {type, La, tuple, any};
-build_gen_type({atom, La, map}) ->
- {type, La, map, any};
-build_gen_type({atom, La, Name}) ->
+build_gen_type({atom, Aa, tuple}) ->
+ {type, Aa, tuple, any};
+build_gen_type({atom, Aa, map}) ->
+ {type, Aa, map, any};
+build_gen_type({atom, Aa, Name}) ->
Tag = type_tag(Name, 0),
- {Tag, La, Name, []}.
+ {Tag, Aa, Name, []}.
build_bin_type([{var, _, '_'}|Left], Int) ->
build_bin_type(Left, Int);
build_bin_type([], Int) ->
skip_paren(Int);
-build_bin_type([{var, La, _}|_], _) ->
- ret_err(La, "Bad binary type").
+build_bin_type([{var, Aa, _}|_], _) ->
+ ret_err(Aa, "Bad binary type").
-build_type({atom, L, Name}, Types) ->
+build_type({atom, A, Name}, Types) ->
Tag = type_tag(Name, length(Types)),
- {Tag, L, Name, Types}.
+ {Tag, A, Name, Types}.
type_tag(TypeName, NumberOfTypeVariables) ->
case erl_internal:is_type(TypeName, NumberOfTypeVariables) of
@@ -692,71 +701,75 @@ type_tag(TypeName, NumberOfTypeVariables) ->
false -> user_type
end.
+abstract2(Term, Anno) ->
+ Line = erl_anno:line(Anno),
+ abstract(Term, Line).
+
%% build_attribute(AttrName, AttrValue) ->
-%% {attribute,Line,module,Module}
-%% {attribute,Line,export,Exports}
-%% {attribute,Line,import,Imports}
-%% {attribute,Line,record,{Name,Inits}}
-%% {attribute,Line,file,{Name,Line}}
-%% {attribute,Line,Name,Val}
-
-build_attribute({atom,La,module}, Val) ->
+%% {attribute,Anno,module,Module}
+%% {attribute,Anno,export,Exports}
+%% {attribute,Anno,import,Imports}
+%% {attribute,Anno,record,{Name,Inits}}
+%% {attribute,Anno,file,{Name,Line}}
+%% {attribute,Anno,Name,Val}
+
+build_attribute({atom,Aa,module}, Val) ->
case Val of
- [{atom,_Lm,Module}] ->
- {attribute,La,module,Module};
- [{atom,_Lm,Module},ExpList] ->
- {attribute,La,module,{Module,var_list(ExpList)}};
+ [{atom,_Am,Module}] ->
+ {attribute,Aa,module,Module};
+ [{atom,_Am,Module},ExpList] ->
+ {attribute,Aa,module,{Module,var_list(ExpList)}};
_Other ->
- error_bad_decl(La, module)
+ error_bad_decl(Aa, module)
end;
-build_attribute({atom,La,export}, Val) ->
+build_attribute({atom,Aa,export}, Val) ->
case Val of
[ExpList] ->
- {attribute,La,export,farity_list(ExpList)};
- _Other -> error_bad_decl(La, export)
+ {attribute,Aa,export,farity_list(ExpList)};
+ _Other -> error_bad_decl(Aa, export)
end;
-build_attribute({atom,La,import}, Val) ->
+build_attribute({atom,Aa,import}, Val) ->
case Val of
- [{atom,_Lm,Mod},ImpList] ->
- {attribute,La,import,{Mod,farity_list(ImpList)}};
- _Other -> error_bad_decl(La, import)
+ [{atom,_Am,Mod},ImpList] ->
+ {attribute,Aa,import,{Mod,farity_list(ImpList)}};
+ _Other -> error_bad_decl(Aa, import)
end;
-build_attribute({atom,La,record}, Val) ->
+build_attribute({atom,Aa,record}, Val) ->
case Val of
- [{atom,_Ln,Record},RecTuple] ->
- {attribute,La,record,{Record,record_tuple(RecTuple)}};
- _Other -> error_bad_decl(La, record)
+ [{atom,_An,Record},RecTuple] ->
+ {attribute,Aa,record,{Record,record_tuple(RecTuple)}};
+ _Other -> error_bad_decl(Aa, record)
end;
-build_attribute({atom,La,file}, Val) ->
+build_attribute({atom,Aa,file}, Val) ->
case Val of
- [{string,_Ln,Name},{integer,_Ll,Line}] ->
- {attribute,La,file,{Name,Line}};
- _Other -> error_bad_decl(La, file)
+ [{string,_An,Name},{integer,_Al,Line}] ->
+ {attribute,Aa,file,{Name,Line}};
+ _Other -> error_bad_decl(Aa, file)
end;
-build_attribute({atom,La,Attr}, Val) ->
+build_attribute({atom,Aa,Attr}, Val) ->
case Val of
[Expr0] ->
Expr = attribute_farity(Expr0),
- {attribute,La,Attr,term(Expr)};
- _Other -> ret_err(La, "bad attribute")
+ {attribute,Aa,Attr,term(Expr)};
+ _Other -> ret_err(Aa, "bad attribute")
end.
-var_list({cons,_Lc,{var,_,V},Tail}) ->
+var_list({cons,_Ac,{var,_,V},Tail}) ->
[V|var_list(Tail)];
-var_list({nil,_Ln}) -> [];
+var_list({nil,_An}) -> [];
var_list(Other) ->
- ret_err(?line(Other), "bad variable list").
+ ret_err(?anno(Other), "bad variable list").
-attribute_farity({cons,L,H,T}) ->
- {cons,L,attribute_farity(H),attribute_farity(T)};
-attribute_farity({tuple,L,Args0}) ->
+attribute_farity({cons,A,H,T}) ->
+ {cons,A,attribute_farity(H),attribute_farity(T)};
+attribute_farity({tuple,A,Args0}) ->
Args = attribute_farity_list(Args0),
- {tuple,L,Args};
-attribute_farity({map,L,Args0}) ->
+ {tuple,A,Args};
+attribute_farity({map,A,Args0}) ->
Args = attribute_farity_map(Args0),
- {map,L,Args};
-attribute_farity({op,L,'/',{atom,_,_}=Name,{integer,_,_}=Arity}) ->
- {tuple,L,[Name,Arity]};
+ {map,A,Args};
+attribute_farity({op,A,'/',{atom,_,_}=Name,{integer,_,_}=Arity}) ->
+ {tuple,A,[Name,Arity]};
attribute_farity(Other) -> Other.
attribute_farity_list(Args) ->
@@ -764,45 +777,45 @@ attribute_farity_list(Args) ->
%% It is not meaningful to have farity keys.
attribute_farity_map(Args) ->
- [{Op,L,K,attribute_farity(V)} || {Op,L,K,V} <- Args].
+ [{Op,A,K,attribute_farity(V)} || {Op,A,K,V} <- Args].
--spec error_bad_decl(integer(), attributes()) -> no_return().
+-spec error_bad_decl(erl_anno:anno(), attributes()) -> no_return().
-error_bad_decl(L, S) ->
- ret_err(L, io_lib:format("bad ~w declaration", [S])).
+error_bad_decl(Anno, S) ->
+ ret_err(Anno, io_lib:format("bad ~w declaration", [S])).
-farity_list({cons,_Lc,{op,_Lo,'/',{atom,_La,A},{integer,_Li,I}},Tail}) ->
+farity_list({cons,_Ac,{op,_Ao,'/',{atom,_Aa,A},{integer,_Ai,I}},Tail}) ->
[{A,I}|farity_list(Tail)];
-farity_list({nil,_Ln}) -> [];
+farity_list({nil,_An}) -> [];
farity_list(Other) ->
- ret_err(?line(Other), "bad function arity").
+ ret_err(?anno(Other), "bad function arity").
-record_tuple({tuple,_Lt,Fields}) ->
+record_tuple({tuple,_At,Fields}) ->
record_fields(Fields);
record_tuple(Other) ->
- ret_err(?line(Other), "bad record declaration").
+ ret_err(?anno(Other), "bad record declaration").
-record_fields([{atom,La,A}|Fields]) ->
- [{record_field,La,{atom,La,A}}|record_fields(Fields)];
-record_fields([{match,_Lm,{atom,La,A},Expr}|Fields]) ->
- [{record_field,La,{atom,La,A},Expr}|record_fields(Fields)];
+record_fields([{atom,Aa,A}|Fields]) ->
+ [{record_field,Aa,{atom,Aa,A}}|record_fields(Fields)];
+record_fields([{match,_Am,{atom,Aa,A},Expr}|Fields]) ->
+ [{record_field,Aa,{atom,Aa,A},Expr}|record_fields(Fields)];
record_fields([{typed,Expr,TypeInfo}|Fields]) ->
[Field] = record_fields([Expr]),
TypeInfo1 =
case Expr of
{match, _, _, _} -> TypeInfo; %% If we have an initializer.
- {atom, La, _} ->
+ {atom, Aa, _} ->
case has_undefined(TypeInfo) of
false ->
TypeInfo2 = maybe_add_paren(TypeInfo),
- lift_unions(abstract(undefined, La), TypeInfo2);
+ lift_unions(abstract2(undefined, Aa), TypeInfo2);
true ->
TypeInfo
end
end,
[{typed_record_field,Field,TypeInfo1}|record_fields(Fields)];
record_fields([Other|_Fields]) ->
- ret_err(?line(Other), "bad record field");
+ ret_err(?anno(Other), "bad record field");
record_fields([]) -> [].
has_undefined({atom,_,undefined}) ->
@@ -816,52 +829,53 @@ has_undefined({type,_,union,Ts}) ->
has_undefined(_) ->
false.
-maybe_add_paren({ann_type,L,T}) ->
- {paren_type,L,[{ann_type,L,T}]};
+maybe_add_paren({ann_type,A,T}) ->
+ {paren_type,A,[{ann_type,A,T}]};
maybe_add_paren(T) ->
T.
term(Expr) ->
try normalise(Expr)
- catch _:_R -> ret_err(?line(Expr), "bad attribute")
+ catch _:_R -> ret_err(?anno(Expr), "bad attribute")
end.
-%% build_function([Clause]) -> {function,Line,Name,Arity,[Clause]}
+%% build_function([Clause]) -> {function,Anno,Name,Arity,[Clause]}
build_function(Cs) ->
Name = element(3, hd(Cs)),
Arity = length(element(4, hd(Cs))),
- {function,?line(hd(Cs)),Name,Arity,check_clauses(Cs, Name, Arity)}.
+ {function,?anno(hd(Cs)),Name,Arity,check_clauses(Cs, Name, Arity)}.
-%% build_fun(Line, [Clause]) -> {'fun',Line,{clauses,[Clause]}}.
+%% build_fun(Anno, [Clause]) -> {'fun',Anno,{clauses,[Clause]}}.
-build_fun(Line, Cs) ->
+build_fun(Anno, Cs) ->
Name = element(3, hd(Cs)),
Arity = length(element(4, hd(Cs))),
CheckedCs = check_clauses(Cs, Name, Arity),
case Name of
'fun' ->
- {'fun',Line,{clauses,CheckedCs}};
+ {'fun',Anno,{clauses,CheckedCs}};
Name ->
- {named_fun,Line,Name,CheckedCs}
+ {named_fun,Anno,Name,CheckedCs}
end.
check_clauses(Cs, Name, Arity) ->
[case C of
- {clause,L,N,As,G,B} when N =:= Name, length(As) =:= Arity ->
- {clause,L,As,G,B};
- {clause,L,_N,_As,_G,_B} ->
- ret_err(L, "head mismatch")
+ {clause,A,N,As,G,B} when N =:= Name, length(As) =:= Arity ->
+ {clause,A,As,G,B};
+ {clause,A,_N,_As,_G,_B} ->
+ ret_err(A, "head mismatch")
end || C <- Cs].
-build_try(L,Es,Scs,{Ccs,As}) ->
- {'try',L,Es,Scs,Ccs,As}.
+build_try(A,Es,Scs,{Ccs,As}) ->
+ {'try',A,Es,Scs,Ccs,As}.
-spec ret_err(_, _) -> no_return().
-ret_err(L, S) ->
- {location,Location} = get_attribute(L, location),
- return_error(Location, S).
+ret_err(Anno, S) ->
+ return_error(location(Anno), S).
+location(Anno) ->
+ erl_anno:location(Anno).
%% Convert between the abstract form of a term and a term.
@@ -909,7 +923,8 @@ normalise_list([]) ->
Data :: term(),
AbsTerm :: abstract_expr().
abstract(T) ->
- abstract(T, 0, enc_func(epp:default_encoding())).
+ Anno = erl_anno:new(0),
+ abstract(T, Anno, enc_func(epp:default_encoding())).
-type encoding_func() :: fun((non_neg_integer()) -> boolean()).
@@ -919,16 +934,18 @@ abstract(T) ->
Options :: Line | [Option],
Option :: {line, Line} | {encoding, Encoding},
Encoding :: 'latin1' | 'unicode' | 'utf8' | 'none' | encoding_func(),
- Line :: erl_scan:line(),
+ Line :: erl_anno:line(),
AbsTerm :: abstract_expr().
abstract(T, Line) when is_integer(Line) ->
- abstract(T, Line, enc_func(epp:default_encoding()));
+ Anno = erl_anno:new(Line),
+ abstract(T, Anno, enc_func(epp:default_encoding()));
abstract(T, Options) when is_list(Options) ->
Line = proplists:get_value(line, Options, 0),
Encoding = proplists:get_value(encoding, Options,epp:default_encoding()),
EncFunc = enc_func(Encoding),
- abstract(T, Line, EncFunc).
+ Anno = erl_anno:new(Line),
+ abstract(T, Anno, EncFunc).
-define(UNICODE(C),
(C < 16#D800 orelse
@@ -942,53 +959,53 @@ enc_func(none) -> none;
enc_func(Fun) when is_function(Fun, 1) -> Fun;
enc_func(Term) -> erlang:error({badarg, Term}).
-abstract(T, L, _E) when is_integer(T) -> {integer,L,T};
-abstract(T, L, _E) when is_float(T) -> {float,L,T};
-abstract(T, L, _E) when is_atom(T) -> {atom,L,T};
-abstract([], L, _E) -> {nil,L};
-abstract(B, L, _E) when is_bitstring(B) ->
- {bin, L, [abstract_byte(Byte, L) || Byte <- bitstring_to_list(B)]};
-abstract([H|T], L, none=E) ->
- {cons,L,abstract(H, L, E),abstract(T, L, E)};
-abstract(List, L, E) when is_list(List) ->
- abstract_list(List, [], L, E);
-abstract(Tuple, L, E) when is_tuple(Tuple) ->
- {tuple,L,abstract_tuple_list(tuple_to_list(Tuple), L, E)};
-abstract(Map, L, E) when is_map(Map) ->
- {map,L,abstract_map_fields(maps:to_list(Map),L,E)}.
-
-abstract_list([H|T], String, L, E) ->
+abstract(T, A, _E) when is_integer(T) -> {integer,A,T};
+abstract(T, A, _E) when is_float(T) -> {float,A,T};
+abstract(T, A, _E) when is_atom(T) -> {atom,A,T};
+abstract([], A, _E) -> {nil,A};
+abstract(B, A, _E) when is_bitstring(B) ->
+ {bin, A, [abstract_byte(Byte, A) || Byte <- bitstring_to_list(B)]};
+abstract([H|T], A, none=E) ->
+ {cons,A,abstract(H, A, E),abstract(T, A, E)};
+abstract(List, A, E) when is_list(List) ->
+ abstract_list(List, [], A, E);
+abstract(Tuple, A, E) when is_tuple(Tuple) ->
+ {tuple,A,abstract_tuple_list(tuple_to_list(Tuple), A, E)};
+abstract(Map, A, E) when is_map(Map) ->
+ {map,A,abstract_map_fields(maps:to_list(Map),A,E)}.
+
+abstract_list([H|T], String, A, E) ->
case is_integer(H) andalso H >= 0 andalso E(H) of
true ->
- abstract_list(T, [H|String], L, E);
+ abstract_list(T, [H|String], A, E);
false ->
- AbstrList = {cons,L,abstract(H, L, E),abstract(T, L, E)},
- not_string(String, AbstrList, L, E)
+ AbstrList = {cons,A,abstract(H, A, E),abstract(T, A, E)},
+ not_string(String, AbstrList, A, E)
end;
-abstract_list([], String, L, _E) ->
- {string, L, lists:reverse(String)};
-abstract_list(T, String, L, E) ->
- not_string(String, abstract(T, L, E), L, E).
-
-not_string([C|T], Result, L, E) ->
- not_string(T, {cons, L, {integer, L, C}, Result}, L, E);
-not_string([], Result, _L, _E) ->
+abstract_list([], String, A, _E) ->
+ {string, A, lists:reverse(String)};
+abstract_list(T, String, A, E) ->
+ not_string(String, abstract(T, A, E), A, E).
+
+not_string([C|T], Result, A, E) ->
+ not_string(T, {cons, A, {integer, A, C}, Result}, A, E);
+not_string([], Result, _A, _E) ->
Result.
-abstract_tuple_list([H|T], L, E) ->
- [abstract(H, L, E)|abstract_tuple_list(T, L, E)];
-abstract_tuple_list([], _L, _E) ->
+abstract_tuple_list([H|T], A, E) ->
+ [abstract(H, A, E)|abstract_tuple_list(T, A, E)];
+abstract_tuple_list([], _A, _E) ->
[].
-abstract_map_fields(Fs,L,E) ->
- [{map_field_assoc,L,abstract(K,L,E),abstract(V,L,E)}||{K,V}<-Fs].
+abstract_map_fields(Fs,A,E) ->
+ [{map_field_assoc,A,abstract(K,A,E),abstract(V,A,E)}||{K,V}<-Fs].
-abstract_byte(Byte, L) when is_integer(Byte) ->
- {bin_element, L, {integer, L, Byte}, default, default};
-abstract_byte(Bits, L) ->
+abstract_byte(Byte, A) when is_integer(Byte) ->
+ {bin_element, A, {integer, A, Byte}, default, default};
+abstract_byte(Bits, A) ->
Sz = bit_size(Bits),
<<Val:Sz>> = Bits,
- {bin_element, L, {integer, L, Val}, {integer, L, Sz}, default}.
+ {bin_element, A, {integer, A, Val}, {integer, A, Sz}, default}.
%% Generate a list of tokens representing the abstract term.
@@ -1002,32 +1019,32 @@ tokens(Abs) ->
AbsTerm :: abstract_expr(),
MoreTokens :: [token()],
Tokens :: [token()].
-tokens({char,L,C}, More) -> [{char,L,C}|More];
-tokens({integer,L,N}, More) -> [{integer,L,N}|More];
-tokens({float,L,F}, More) -> [{float,L,F}|More];
-tokens({atom,L,A}, More) -> [{atom,L,A}|More];
-tokens({var,L,V}, More) -> [{var,L,V}|More];
-tokens({string,L,S}, More) -> [{string,L,S}|More];
-tokens({nil,L}, More) -> [{'[',L},{']',L}|More];
-tokens({cons,L,Head,Tail}, More) ->
- [{'[',L}|tokens(Head, tokens_tail(Tail, More))];
-tokens({tuple,L,[]}, More) ->
- [{'{',L},{'}',L}|More];
-tokens({tuple,L,[E|Es]}, More) ->
- [{'{',L}|tokens(E, tokens_tuple(Es, ?line(E), More))].
-
-tokens_tail({cons,L,Head,Tail}, More) ->
- [{',',L}|tokens(Head, tokens_tail(Tail, More))];
-tokens_tail({nil,L}, More) ->
- [{']',L}|More];
+tokens({char,A,C}, More) -> [{char,A,C}|More];
+tokens({integer,A,N}, More) -> [{integer,A,N}|More];
+tokens({float,A,F}, More) -> [{float,A,F}|More];
+tokens({atom,Aa,A}, More) -> [{atom,Aa,A}|More];
+tokens({var,A,V}, More) -> [{var,A,V}|More];
+tokens({string,A,S}, More) -> [{string,A,S}|More];
+tokens({nil,A}, More) -> [{'[',A},{']',A}|More];
+tokens({cons,A,Head,Tail}, More) ->
+ [{'[',A}|tokens(Head, tokens_tail(Tail, More))];
+tokens({tuple,A,[]}, More) ->
+ [{'{',A},{'}',A}|More];
+tokens({tuple,A,[E|Es]}, More) ->
+ [{'{',A}|tokens(E, tokens_tuple(Es, ?anno(E), More))].
+
+tokens_tail({cons,A,Head,Tail}, More) ->
+ [{',',A}|tokens(Head, tokens_tail(Tail, More))];
+tokens_tail({nil,A}, More) ->
+ [{']',A}|More];
tokens_tail(Other, More) ->
- L = ?line(Other),
- [{'|',L}|tokens(Other, [{']',L}|More])].
+ A = ?anno(Other),
+ [{'|',A}|tokens(Other, [{']',A}|More])].
-tokens_tuple([E|Es], Line, More) ->
- [{',',Line}|tokens(E, tokens_tuple(Es, ?line(E), More))];
-tokens_tuple([], Line, More) ->
- [{'}',Line}|More].
+tokens_tuple([E|Es], Anno, More) ->
+ [{',',Anno}|tokens(E, tokens_tuple(Es, ?anno(E), More))];
+tokens_tuple([], Anno, More) ->
+ [{'}',Anno}|More].
%% Give the relative precedences of operators.
@@ -1092,13 +1109,168 @@ max_prec() -> 900.
%%% longer apply. To get all present attributes as a property list
%%% get_attributes() should be used.
+-compile({nowarn_deprecated_function,{erl_scan,set_attribute,3}}).
set_line(L, F) ->
erl_scan:set_attribute(line, L, F).
+-compile({nowarn_deprecated_function,{erl_scan,attributes_info,2}}).
get_attribute(L, Name) ->
erl_scan:attributes_info(L, Name).
+-compile({nowarn_deprecated_function,{erl_scan,attributes_info,1}}).
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) ->
+ map_anno(fun erl_anno:new/1, Term).
+
+-spec anno_to_term(Abstr) -> term() when
+ Abstr :: abstract_form() | abstract_expr().
+
+anno_to_term(Abstract) ->
+ map_anno(fun erl_anno:to_term/1, Abstract).
+
+-spec anno_from_term(Term) -> abstract_form() | abstract_expr() when
+ Term :: term().
+
+anno_from_term(Term) ->
+ map_anno(fun erl_anno:from_term/1, 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/erl_pp.erl b/lib/stdlib/src/erl_pp.erl
index 469ce544c7..623a29f923 100644
--- a/lib/stdlib/src/erl_pp.erl
+++ b/lib/stdlib/src/erl_pp.erl
@@ -1,7 +1,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
@@ -46,6 +46,23 @@
-record(options, {hook, encoding, opts}).
+%-define(DEBUG, true).
+
+-ifdef(DEBUG).
+-define(TEST(T),
+ %% Assumes that erl_anno has been compiled with DEBUG=true.
+ %% erl_pp does not use the annoations, but test it anyway.
+ %% Note: hooks are not handled.
+ _ = try
+ erl_parse:map_anno(fun(A) when is_list(A) -> A end, T)
+ catch
+ _:_ ->
+ erlang:error(badarg, [T])
+ end).
+-else.
+-define(TEST(T), ok).
+-endif.
+
%%%
%%% Exported functions
%%%
@@ -61,6 +78,7 @@ form(Thing) ->
Options :: options()).
form(Thing, Options) ->
+ ?TEST(Thing),
State = state(Options),
frmt(lform(Thing, options(Options), State), State).
@@ -75,6 +93,7 @@ attribute(Thing) ->
Options :: options()).
attribute(Thing, Options) ->
+ ?TEST(Thing),
State = state(Options),
frmt(lattribute(Thing, options(Options), State), State).
@@ -89,6 +108,7 @@ function(F) ->
Options :: options()).
function(F, Options) ->
+ ?TEST(F),
frmt(lfunction(F, options(Options)), state(Options)).
-spec(guard(Guard) -> io_lib:chars() when
@@ -102,6 +122,7 @@ guard(Gs) ->
Options :: options()).
guard(Gs, Options) ->
+ ?TEST(Gs),
frmt(lguard(Gs, options(Options)), state(Options)).
-spec(exprs(Expressions) -> io_lib:chars() when
@@ -123,12 +144,14 @@ exprs(Es, Options) ->
Options :: options()).
exprs(Es, I, Options) ->
+ ?TEST(Es),
frmt({seq,[],[],[$,],lexprs(Es, options(Options))}, I, state(Options)).
-spec(expr(Expression) -> io_lib:chars() when
Expression :: erl_parse:abstract_expr()).
expr(E) ->
+ ?TEST(E),
frmt(lexpr(E, 0, options(none)), state(none)).
-spec(expr(Expression, Options) -> io_lib:chars() when
@@ -136,6 +159,7 @@ expr(E) ->
Options :: options()).
expr(E, Options) ->
+ ?TEST(E),
frmt(lexpr(E, 0, options(Options)), state(Options)).
-spec(expr(Expression, Indent, Options) -> io_lib:chars() when
@@ -144,6 +168,7 @@ expr(E, Options) ->
Options :: options()).
expr(E, I, Options) ->
+ ?TEST(E),
frmt(lexpr(E, 0, options(Options)), I, state(Options)).
-spec(expr(Expression, Indent, Precedence, Options) -> io_lib:chars() when
@@ -153,6 +178,7 @@ expr(E, I, Options) ->
Options :: options()).
expr(E, I, P, Options) ->
+ ?TEST(E),
frmt(lexpr(E, P, options(Options)), I, state(Options)).
%%%
@@ -213,24 +239,25 @@ lattribute({attribute,_Line,Name,Arg}, Opts, State) ->
[lattribute(Name, Arg, Opts, State),leaf(".\n")].
lattribute(module, {M,Vs}, _Opts, _State) ->
- attr("module",[{var,0,pname(M)},
- foldr(fun(V, C) -> {cons,0,{var,0,V},C}
- end, {nil,0}, Vs)]);
+ A = a0(),
+ attr("module",[{var,A,pname(M)},
+ foldr(fun(V, C) -> {cons,A,{var,A,V},C}
+ end, {nil,A}, Vs)]);
lattribute(module, M, _Opts, _State) ->
- attr("module", [{var,0,pname(M)}]);
+ attr("module", [{var,a0(),pname(M)}]);
lattribute(export, Falist, _Opts, _State) ->
- call({var,0,"-export"}, [falist(Falist)], 0, options(none));
+ call({var,a0(),"-export"}, [falist(Falist)], 0, options(none));
lattribute(import, Name, _Opts, _State) when is_list(Name) ->
- attr("import", [{var,0,pname(Name)}]);
+ attr("import", [{var,a0(),pname(Name)}]);
lattribute(import, {From,Falist}, _Opts, _State) ->
- attr("import",[{var,0,pname(From)},falist(Falist)]);
+ attr("import",[{var,a0(),pname(From)},falist(Falist)]);
lattribute(optional_callbacks, Falist, Opts, _State) ->
ArgL = try falist(Falist)
catch _:_ -> abstract(Falist, Opts)
end,
- call({var,0,"-optional_callbacks"}, [ArgL], 0, options(none));
+ call({var,a0(),"-optional_callbacks"}, [ArgL], 0, options(none));
lattribute(file, {Name,Line}, _Opts, State) ->
- attr("file", [{var,0,(State#pp.string_fun)(Name)},{integer,0,Line}]);
+ attr("file", [{var,a0(),(State#pp.string_fun)(Name)},{integer,a0(),Line}]);
lattribute(record, {Name,Is}, Opts, _State) ->
Nl = leaf(format("-record(~w,", [Name])),
[{first,Nl,record_fields(Is, Opts)},$)];
@@ -242,7 +269,7 @@ abstract(Arg, #options{encoding = Encoding}) ->
typeattr(Tag, {TypeName,Type,Args}, _Opts) ->
{first,leaf("-"++atom_to_list(Tag)++" "),
- typed(call({atom,0,TypeName}, Args, 0, options(none)), Type)}.
+ typed(call({atom,a0(),TypeName}, Args, 0, options(none)), Type)}.
ltype({ann_type,_Line,[V,T]}) ->
typed(lexpr(V, options(none)), T);
@@ -384,7 +411,7 @@ ltypes(Ts, F) ->
[F(T) || T <- Ts].
attr(Name, Args) ->
- call({var,0,format("-~s", [Name])}, Args, 0, options(none)).
+ call({var,a0(),format("-~s", [Name])}, Args, 0, options(none)).
pname(['' | As]) ->
[$. | pname(As)];
@@ -396,9 +423,10 @@ pname(A) when is_atom(A) ->
write(A).
falist([]) ->
- {nil,0};
+ {nil,a0()};
falist([{Name,Arity}|Falist]) ->
- {cons,0,{var,0,format("~w/~w", [Name,Arity])},falist(Falist)}.
+ A = a0(),
+ {cons,A,{var,A,format("~w/~w", [Name,Arity])},falist(Falist)}.
lfunction({function,_Line,Name,_Arity,Cs}, Opts) ->
Cll = nl_clauses(fun (C, H) -> func_clause(Name, C, H) end, $;, Opts, Cs),
@@ -1111,6 +1139,9 @@ write_char(C, PP) ->
%% Utilities
%%
+a0() ->
+ erl_anno:new(0).
+
chars_size([C | Es]) when is_integer(C) ->
1 + chars_size(Es);
chars_size([E | Es]) ->
diff --git a/lib/stdlib/src/erl_scan.erl b/lib/stdlib/src/erl_scan.erl
index 4960a86760..5e7cc5f6d6 100644
--- a/lib/stdlib/src/erl_scan.erl
+++ b/lib/stdlib/src/erl_scan.erl
@@ -1,7 +1,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
@@ -55,6 +55,15 @@
token_info/1,token_info/2,
attributes_info/1,attributes_info/2,set_attribute/3]).
+-export([column/1,end_location/1,line/1,location/1,text/1,
+ category/1,symbol/1]).
+
+-deprecated([{attributes_info, 1, next_major_release},
+ {attributes_info, 2, next_major_release},
+ {set_attribute, 3, next_major_release},
+ {token_info, 1, next_major_release},
+ {token_info, 2, next_major_release}]).
+
%%% Private
-export([continuation_location/1]).
@@ -78,9 +87,9 @@
-define(SETATTRFUN(F), is_function(F, 1)).
-type category() :: atom().
--type column() :: pos_integer().
--type line() :: integer().
--type location() :: line() | {line(),column()}.
+-type column() :: pos_integer(). % Deprecated
+-type line() :: integer(). % Deprecated
+-type location() :: line() | {line(),column()}. % Deprecated
-type resword_fun() :: fun((atom()) -> boolean()).
-type option() :: 'return' | 'return_white_spaces' | 'return_comments'
| 'text' | {'reserved_word_fun', resword_fun()}.
@@ -197,6 +206,56 @@ continuation_location({erl_scan_continuation,_,no_col,_,Line,_,_,_}) ->
continuation_location({erl_scan_continuation,_,Col,_,Line,_,_,_}) ->
{Line,Col}.
+-spec column(Token) -> erl_anno:column() | 'undefined' when
+ Token :: token().
+
+column(Token) ->
+ erl_anno:column(element(2, Token)).
+
+-spec end_location(Token) -> erl_anno:location() | 'undefined' when
+ Token :: token().
+
+end_location(Token) ->
+ erl_anno:end_location(element(2, Token)).
+
+-spec line(Token) -> erl_anno:line() when
+ Token :: token().
+
+line(Token) ->
+ erl_anno:line(element(2, Token)).
+
+-spec location(Token) -> erl_anno:location() when
+ Token :: token().
+
+location(Token) ->
+ erl_anno:location(element(2, Token)).
+
+-spec text(Token) -> erl_anno:text() | 'undefined' when
+ Token :: token().
+
+text(Token) ->
+ erl_anno:text(element(2, Token)).
+
+-spec category(Token) -> category() when
+ Token :: token().
+
+category({Category,_Anno}) ->
+ Category;
+category({Category,_Anno,_Symbol}) ->
+ Category;
+category(T) ->
+ erlang:error(badarg, [T]).
+
+-spec symbol(Token) -> symbol() when
+ Token :: token().
+
+symbol({Category,_Anno}) ->
+ Category;
+symbol({_Category,_Anno,Symbol}) ->
+ Symbol;
+symbol(T) ->
+ erlang:error(badarg, [T]).
+
-type attribute_item() :: 'column' | 'length' | 'line'
| 'location' | 'text'.
-type info_location() :: location() | term().
@@ -276,7 +335,17 @@ attributes_info({Line,Column}, column=Item) when ?ALINE(Line),
attributes_info(Line, column) when ?ALINE(Line) ->
undefined;
attributes_info(Attrs, column=Item) ->
- attr_info(Attrs, Item);
+ case attr_info(Attrs, Item) of
+ undefined ->
+ case erl_anno:column(Attrs) of
+ undefined ->
+ undefined;
+ Column ->
+ {Item,Column}
+ end;
+ T ->
+ T
+ end;
attributes_info(Attrs, length=Item) ->
case attributes_info(Attrs, text) of
undefined ->
@@ -290,14 +359,26 @@ attributes_info({Line,Column}, line=Item) when ?ALINE(Line),
?COLUMN(Column) ->
{Item,Line};
attributes_info(Attrs, line=Item) ->
- attr_info(Attrs, Item);
+ case attr_info(Attrs, Item) of
+ undefined ->
+ case attr_info(Attrs, location) of
+ {location,{Line,_Column}} ->
+ {Item,Line};
+ {location,Line} ->
+ {Item,Line};
+ undefined ->
+ undefined
+ end;
+ T ->
+ T
+ end;
attributes_info({Line,Column}=Location, location=Item) when ?ALINE(Line),
?COLUMN(Column) ->
{Item,Location};
attributes_info(Line, location=Item) when ?ALINE(Line) ->
{Item,Line};
attributes_info(Attrs, location=Item) ->
- {line,Line} = attributes_info(Attrs, line), % assume line is present
+ {line,Line} = attributes_info(Attrs, line),
case attributes_info(Attrs, column) of
undefined ->
%% If set_attribute() has assigned a term such as {17,42}
@@ -419,12 +500,28 @@ set_attr(line, {Line,Column}, Fun) when ?ALINE(Line), ?COLUMN(Column) ->
[{line,Ln},{column,Column}]
end;
set_attr(line=Tag, Attrs, Fun) when is_list(Attrs) ->
- {line,Line} = lists:keyfind(Tag, 1, Attrs),
- case lists:keyreplace(Tag, 1, Attrs, {line,Fun(Line)}) of
- [{line,Ln}] when ?ALINE(Ln) ->
- Ln;
- As ->
- As
+ case lists:keyfind(Tag, 1, Attrs) of
+ {line,Line} ->
+ case lists:keyreplace(Tag, 1, Attrs, {line,Fun(Line)}) of
+ [{line,Ln}] when ?ALINE(Ln) ->
+ Ln;
+ As ->
+ As
+ end;
+ false ->
+ {location, Location} = lists:keyfind(location, 1, Attrs),
+ Ln = case Location of
+ {Line,Column} when ?ALINE(Line), ?COLUMN(Column) ->
+ {Fun(Line),Column};
+ _ ->
+ Fun(Location)
+ end,
+ case lists:keyreplace(location, 1, Attrs, {location,Ln}) of
+ [{location,Ln}] when ?ALINE(Ln) ->
+ Ln;
+ As ->
+ As
+ end
end;
set_attr(T1, T2, T3) ->
erlang:error(badarg, [T1,T2,T3]).
@@ -708,17 +805,17 @@ scan_name(Cs, Ncs) ->
-define(STR(St, S), if St#erl_scan.text -> S; true -> [] end).
scan_dot([$%|_]=Cs, St, Line, Col, Toks, Ncs) ->
- Attrs = attributes(Line, Col, St, Ncs),
- {ok,[{dot,Attrs}|Toks],Cs,Line,incr_column(Col, 1)};
+ Anno = anno(Line, Col, St, Ncs),
+ {ok,[{dot,Anno}|Toks],Cs,Line,incr_column(Col, 1)};
scan_dot([$\n=C|Cs], St, Line, Col, Toks, Ncs) ->
- Attrs = attributes(Line, Col, St, ?STR(St, Ncs++[C])),
- {ok,[{dot,Attrs}|Toks],Cs,Line+1,new_column(Col, 1)};
+ Anno = anno(Line, Col, St, ?STR(St, Ncs++[C])),
+ {ok,[{dot,Anno}|Toks],Cs,Line+1,new_column(Col, 1)};
scan_dot([C|Cs], St, Line, Col, Toks, Ncs) when ?WHITE_SPACE(C) ->
- Attrs = attributes(Line, Col, St, ?STR(St, Ncs++[C])),
- {ok,[{dot,Attrs}|Toks],Cs,Line,incr_column(Col, 2)};
+ Anno = anno(Line, Col, St, ?STR(St, Ncs++[C])),
+ {ok,[{dot,Anno}|Toks],Cs,Line,incr_column(Col, 2)};
scan_dot(eof=Cs, St, Line, Col, Toks, Ncs) ->
- Attrs = attributes(Line, Col, St, Ncs),
- {ok,[{dot,Attrs}|Toks],Cs,Line,incr_column(Col, 1)};
+ Anno = anno(Line, Col, St, Ncs),
+ {ok,[{dot,Anno}|Toks],Cs,Line,incr_column(Col, 1)};
scan_dot(Cs, St, Line, Col, Toks, Ncs) ->
tok2(Cs, St, Line, Col, Toks, Ncs, '.', 1).
@@ -773,12 +870,12 @@ scan_nl_tabs(Cs, St, Line, Col, Toks, N) ->
%% stop anyway, nothing is gained by not collecting all white spaces.
scan_nl_white_space([$\n|Cs], #erl_scan{text = false}=St, Line, no_col=Col,
Toks0, Ncs) ->
- Toks = [{white_space,Line,lists:reverse(Ncs)}|Toks0],
+ Toks = [{white_space,anno(Line),lists:reverse(Ncs)}|Toks0],
scan_newline(Cs, St, Line+1, Col, Toks);
scan_nl_white_space([$\n|Cs], St, Line, Col, Toks, Ncs0) ->
Ncs = lists:reverse(Ncs0),
- Attrs = attributes(Line, Col, St, Ncs),
- Token = {white_space,Attrs,Ncs},
+ Anno = anno(Line, Col, St, Ncs),
+ Token = {white_space,Anno,Ncs},
scan_newline(Cs, St, Line+1, new_column(Col, length(Ncs)), [Token|Toks]);
scan_nl_white_space([C|Cs], St, Line, Col, Toks, Ncs) when ?WHITE_SPACE(C) ->
scan_nl_white_space(Cs, St, Line, Col, Toks, [C|Ncs]);
@@ -786,19 +883,20 @@ scan_nl_white_space([]=Cs, _St, Line, Col, Toks, Ncs) ->
{more,{Cs,Col,Toks,Line,Ncs,fun scan_nl_white_space/6}};
scan_nl_white_space(Cs, #erl_scan{text = false}=St, Line, no_col=Col,
Toks, Ncs) ->
- scan1(Cs, St, Line+1, Col, [{white_space,Line,lists:reverse(Ncs)}|Toks]);
+ Anno = anno(Line),
+ scan1(Cs, St, Line+1, Col, [{white_space,Anno,lists:reverse(Ncs)}|Toks]);
scan_nl_white_space(Cs, St, Line, Col, Toks, Ncs0) ->
Ncs = lists:reverse(Ncs0),
- Attrs = attributes(Line, Col, St, Ncs),
- Token = {white_space,Attrs,Ncs},
+ Anno = anno(Line, Col, St, Ncs),
+ Token = {white_space,Anno,Ncs},
scan1(Cs, St, Line+1, new_column(Col, length(Ncs)), [Token|Toks]).
newline_end(Cs, #erl_scan{text = false}=St, Line, no_col=Col,
Toks, _N, Ncs) ->
- scan1(Cs, St, Line+1, Col, [{white_space,Line,Ncs}|Toks]);
+ scan1(Cs, St, Line+1, Col, [{white_space,anno(Line),Ncs}|Toks]);
newline_end(Cs, St, Line, Col, Toks, N, Ncs) ->
- Attrs = attributes(Line, Col, St, Ncs),
- scan1(Cs, St, Line+1, new_column(Col, N), [{white_space,Attrs,Ncs}|Toks]).
+ Anno = anno(Line, Col, St, Ncs),
+ scan1(Cs, St, Line+1, new_column(Col, N), [{white_space,Anno,Ncs}|Toks]).
scan_spcs([$\s|Cs], St, Line, Col, Toks, N) when N < 16 ->
scan_spcs(Cs, St, Line, Col, Toks, N+1);
@@ -847,20 +945,20 @@ scan_char([$\\|Cs]=Cs0, St, Line, Col, Toks) ->
{eof,Ncol} ->
scan_error(char, Line, Col, Line, Ncol, eof);
{nl,Val,Str,Ncs,Ncol} ->
- Attrs = attributes(Line, Col, St, ?STR(St, "$\\"++Str)), %"
- Ntoks = [{char,Attrs,Val}|Toks],
+ Anno = anno(Line, Col, St, ?STR(St, "$\\"++Str)), %"
+ Ntoks = [{char,Anno,Val}|Toks],
scan1(Ncs, St, Line+1, Ncol, Ntoks);
{Val,Str,Ncs,Ncol} ->
- Attrs = attributes(Line, Col, St, ?STR(St, "$\\"++Str)), %"
- Ntoks = [{char,Attrs,Val}|Toks],
+ Anno = anno(Line, Col, St, ?STR(St, "$\\"++Str)), %"
+ Ntoks = [{char,Anno,Val}|Toks],
scan1(Ncs, St, Line, Ncol, Ntoks)
end;
scan_char([$\n=C|Cs], St, Line, Col, Toks) ->
- Attrs = attributes(Line, Col, St, ?STR(St, [$$,C])),
- scan1(Cs, St, Line+1, new_column(Col, 1), [{char,Attrs,C}|Toks]);
+ Anno = anno(Line, Col, St, ?STR(St, [$$,C])),
+ scan1(Cs, St, Line+1, new_column(Col, 1), [{char,Anno,C}|Toks]);
scan_char([C|Cs], St, Line, Col, Toks) when ?UNICODE(C) ->
- Attrs = attributes(Line, Col, St, ?STR(St, [$$,C])),
- scan1(Cs, St, Line, incr_column(Col, 2), [{char,Attrs,C}|Toks]);
+ Anno = anno(Line, Col, St, ?STR(St, [$$,C])),
+ scan1(Cs, St, Line, incr_column(Col, 2), [{char,Anno,C}|Toks]);
scan_char([C|_Cs], _St, Line, Col, _Toks) when ?CHAR(C) ->
scan_error({illegal,character}, Line, Col, Line, incr_column(Col, 1), eof);
scan_char([], _St, Line, Col, Toks) ->
@@ -879,8 +977,8 @@ scan_string(Cs, St, Line, Col, Toks, {Wcs,Str,Line0,Col0}) ->
Estr = string:substr(Nwcs, 1, 16), % Expanded escape chars.
scan_error({string,$\",Estr}, Line0, Col0, Nline, Ncol, Ncs); %"
{Ncs,Nline,Ncol,Nstr,Nwcs} ->
- Attrs = attributes(Line0, Col0, St, Nstr),
- scan1(Ncs, St, Nline, Ncol, [{string,Attrs,Nwcs}|Toks])
+ Anno = anno(Line0, Col0, St, Nstr),
+ scan1(Ncs, St, Nline, Ncol, [{string,Anno,Nwcs}|Toks])
end.
scan_qatom(Cs, St, Line, Col, Toks, {Wcs,Str,Line0,Col0}) ->
@@ -896,8 +994,8 @@ scan_qatom(Cs, St, Line, Col, Toks, {Wcs,Str,Line0,Col0}) ->
{Ncs,Nline,Ncol,Nstr,Nwcs} ->
case catch list_to_atom(Nwcs) of
A when is_atom(A) ->
- Attrs = attributes(Line0, Col0, St, Nstr),
- scan1(Ncs, St, Nline, Ncol, [{atom,Attrs,A}|Toks]);
+ Anno = anno(Line0, Col0, St, Nstr),
+ scan1(Ncs, St, Nline, Ncol, [{atom,Anno,A}|Toks]);
_ ->
scan_error({illegal,atom}, Line0, Col0, Nline, Ncol, Ncs)
end
@@ -1173,28 +1271,28 @@ scan_comment(Cs, St, Line, Col, Toks, Ncs0) ->
tok3(Cs, St, Line, Col, Toks, comment, Ncs, Ncs).
tok2(Cs, #erl_scan{text = false}=St, Line, no_col=Col, Toks, _Wcs, P) ->
- scan1(Cs, St, Line, Col, [{P,Line}|Toks]);
+ scan1(Cs, St, Line, Col, [{P,anno(Line)}|Toks]);
tok2(Cs, St, Line, Col, Toks, Wcs, P) ->
- Attrs = attributes(Line, Col, St, Wcs),
- scan1(Cs, St, Line, incr_column(Col, length(Wcs)), [{P,Attrs}|Toks]).
+ Anno = anno(Line, Col, St, Wcs),
+ scan1(Cs, St, Line, incr_column(Col, length(Wcs)), [{P,Anno}|Toks]).
tok2(Cs, #erl_scan{text = false}=St, Line, no_col=Col, Toks, _Wcs, P, _N) ->
- scan1(Cs, St, Line, Col, [{P,Line}|Toks]);
+ scan1(Cs, St, Line, Col, [{P,anno(Line)}|Toks]);
tok2(Cs, St, Line, Col, Toks, Wcs, P, N) ->
- Attrs = attributes(Line, Col, St, Wcs),
- scan1(Cs, St, Line, incr_column(Col, N), [{P,Attrs}|Toks]).
+ Anno = anno(Line, Col, St, Wcs),
+ scan1(Cs, St, Line, incr_column(Col, N), [{P,Anno}|Toks]).
tok3(Cs, #erl_scan{text = false}=St, Line, no_col=Col, Toks, Item, _S, Sym) ->
- scan1(Cs, St, Line, Col, [{Item,Line,Sym}|Toks]);
+ scan1(Cs, St, Line, Col, [{Item,anno(Line),Sym}|Toks]);
tok3(Cs, St, Line, Col, Toks, Item, String, Sym) ->
- Token = {Item,attributes(Line, Col, St, String),Sym},
+ Token = {Item,anno(Line, Col, St, String),Sym},
scan1(Cs, St, Line, incr_column(Col, length(String)), [Token|Toks]).
tok3(Cs, #erl_scan{text = false}=St, Line, no_col=Col, Toks, Item,
_String, Sym, _Length) ->
- scan1(Cs, St, Line, Col, [{Item,Line,Sym}|Toks]);
+ scan1(Cs, St, Line, Col, [{Item,anno(Line),Sym}|Toks]);
tok3(Cs, St, Line, Col, Toks, Item, String, Sym, Length) ->
- Token = {Item,attributes(Line, Col, St, String),Sym},
+ Token = {Item,anno(Line, Col, St, String),Sym},
scan1(Cs, St, Line, incr_column(Col, Length), [Token|Toks]).
scan_error(Error, Line, Col, EndLine, EndCol, Rest) ->
@@ -1205,23 +1303,28 @@ scan_error(Error, Line, Col, EndLine, EndCol, Rest) ->
scan_error(Error, ErrorLoc, EndLoc, Rest) ->
{{error,{ErrorLoc,?MODULE,Error},EndLoc},Rest}.
--compile({inline,[attributes/4]}).
+-compile({inline,[anno/4]}).
-attributes(Line, no_col, #erl_scan{text = false}, _String) ->
- Line;
-attributes(Line, no_col, #erl_scan{text = true}, String) ->
- [{line,Line},{text,String}];
-attributes(Line, Col, #erl_scan{text = false}, _String) ->
- {Line,Col};
-attributes(Line, Col, #erl_scan{text = true}, String) ->
- [{line,Line},{column,Col},{text,String}].
+anno(Line, no_col, #erl_scan{text = false}, _String) ->
+ anno(Line);
+anno(Line, no_col, #erl_scan{text = true}, String) ->
+ Anno = anno(Line),
+ erl_anno:set_text(String, Anno);
+anno(Line, Col, #erl_scan{text = false}, _String) ->
+ anno({Line, Col});
+anno(Line, Col, #erl_scan{text = true}, String) ->
+ Anno = anno({Line, Col}),
+ erl_anno:set_text(String, Anno).
location(Line, no_col) ->
Line;
location(Line, Col) when is_integer(Col) ->
{Line,Col}.
--compile({inline,[incr_column/2,new_column/2]}).
+-compile({inline,[anno/1,incr_column/2,new_column/2]}).
+
+anno(Location) ->
+ erl_anno:new(Location).
incr_column(no_col=Col, _N) ->
Col;
diff --git a/lib/stdlib/src/escript.erl b/lib/stdlib/src/escript.erl
index 90e1f3a8d6..f0827009a5 100644
--- a/lib/stdlib/src/escript.erl
+++ b/lib/stdlib/src/escript.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2007-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
@@ -620,12 +620,13 @@ parse_source(S, File, Fd, StartLine, HeaderSz, CheckOnly) ->
{ok, {attribute,_, module, M} = Form} ->
epp_parse_file(Epp, S2#state{module = M}, [Form, FileForm]);
{ok, _} ->
- ModForm = {attribute,1,module, Module},
+ ModForm = {attribute,a1(),module, Module},
epp_parse_file2(Epp, S2, [ModForm, FileForm], OptModRes);
{error, _} ->
epp_parse_file2(Epp, S2, [FileForm], OptModRes);
- {eof, _LastLine} = Eof ->
- S#state{forms_or_bin = [FileForm, Eof]}
+ {eof, LastLine} ->
+ Anno = anno(LastLine),
+ S#state{forms_or_bin = [FileForm, {eof, Anno}]}
end,
ok = epp:close(Epp),
ok = file:close(Fd),
@@ -644,7 +645,7 @@ check_source(S, CheckOnly) ->
%% Optionally add export of main/1
Forms2 =
case ExpMain of
- false -> [{attribute,0,export, [{main,1}]} | Forms];
+ false -> [{attribute, a0(), export, [{main,1}]} | Forms];
true -> Forms
end,
Forms3 = [FileForm2, ModForm2 | Forms2],
@@ -722,8 +723,9 @@ epp_parse_file2(Epp, S, Forms, Parsed) ->
io:format("~ts:~w: ~ts\n",
[S#state.file,Ln,Mod:format_error(Args)]),
epp_parse_file(Epp, S#state{n_errors = S#state.n_errors + 1}, [Form | Forms]);
- {eof, _LastLine} = Eof ->
- S#state{forms_or_bin = lists:reverse([Eof | Forms])}
+ {eof, LastLine} ->
+ Anno = anno(LastLine),
+ S#state{forms_or_bin = lists:reverse([{eof, Anno} | Forms])}
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -778,7 +780,8 @@ interpret(Forms, HasRecs, File, Args) ->
end,
Dict = parse_to_dict(Forms2),
ArgsA = erl_parse:abstract(Args, 0),
- Call = {call,0,{atom,0,main},[ArgsA]},
+ Anno = a0(),
+ Call = {call,Anno,{atom,Anno,main},[ArgsA]},
try
_ = erl_eval:expr(Call,
erl_eval:new_bindings(),
@@ -890,6 +893,15 @@ enc() ->
Enc -> [Enc]
end.
+a0() ->
+ anno(0).
+
+a1() ->
+ anno(1).
+
+anno(L) ->
+ erl_anno:new(L).
+
fatal(Str) ->
throw(Str).
diff --git a/lib/stdlib/src/io.erl b/lib/stdlib/src/io.erl
index b9ace2f442..0b59546dc4 100644
--- a/lib/stdlib/src/io.erl
+++ b/lib/stdlib/src/io.erl
@@ -1,7 +1,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
@@ -45,7 +45,7 @@
%% ErrorDescription is whatever the I/O-server sends.
-type server_no_data() :: {'error', ErrorDescription :: term()} | 'eof'.
--type location() :: erl_scan:location().
+-type location() :: erl_anno:location().
%%-------------------------------------------------------------------------
diff --git a/lib/stdlib/src/ms_transform.erl b/lib/stdlib/src/ms_transform.erl
index 7b6f4e5b50..6e3723bb98 100644
--- a/lib/stdlib/src/ms_transform.erl
+++ b/lib/stdlib/src/ms_transform.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2002-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
@@ -822,9 +822,10 @@ th(T,B,OB) when is_tuple(T) ->
th(Nonstruct,B,_OB) ->
{Nonstruct,B}.
-warn_var_clash(Line,Name,OuterBound) ->
+warn_var_clash(Anno,Name,OuterBound) ->
case gb_sets:is_member(Name,OuterBound) of
true ->
+ Line = erl_anno:line(Anno),
add_warning(Line,{?WARN_SHADOW_VAR,Name});
_ ->
ok
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index 0fb6974426..24721da187 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1999-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
@@ -18,7 +18,7 @@
%%
-module(otp_internal).
--export([obsolete/3]).
+-export([obsolete/3, obsolete_type/3]).
%%----------------------------------------------------------------------
@@ -26,7 +26,7 @@
-type mfas() :: mfa() | {atom(), atom(), [byte()]}.
-type release() :: string().
--spec obsolete(atom(), atom(), byte()) ->
+-spec obsolete(module(), atom(), arity()) ->
'no' | {tag(), string()} | {tag(), mfas(), release()}.
obsolete(Module, Name, Arity) ->
@@ -595,6 +595,39 @@ obsolete_1(core_lib, is_literal_list, 1) ->
" instead"};
obsolete_1(core_lib, literal_value, 1) ->
{deprecated,{core_lib,concrete,1}};
+obsolete_1(erl_scan, set_attribute, 3) ->
+ {deprecated,
+ "deprecated (will be removed in OTP 19); use erl_anno:set_line/2 instead"};
+obsolete_1(erl_scan, attributes_info, 1) ->
+ {deprecated,
+ "deprecated (will be removed in OTP 19); use "
+ "erl_anno:{column,line,location,text}/1 instead"};
+obsolete_1(erl_scan, attributes_info, 2) ->
+ {deprecated,
+ "deprecated (will be removed in OTP 19); use "
+ "erl_anno:{column,line,location,text}/1 instead"};
+obsolete_1(erl_scan, token_info, 1) ->
+ {deprecated,
+ "deprecated (will be removed in OTP 19); use "
+ "erl_scan:{category,column,line,location,symbol,text}/1 instead"};
+obsolete_1(erl_scan, token_info, 2) ->
+ {deprecated,
+ "deprecated (will be removed in OTP 19); use "
+ "erl_scan:{category,column,line,location,symbol,text}/1 instead"};
+obsolete_1(erl_parse, set_line, 2) ->
+ {deprecated,
+ "deprecated (will be removed in OTP 19); use erl_anno:set_line/2 instead"};
+obsolete_1(erl_parse, get_attributes, 1) ->
+ {deprecated,
+ "deprecated (will be removed in OTP 19); use "
+ "erl_anno:{column,line,location,text}/1 instead"};
+obsolete_1(erl_parse, get_attribute, 2) ->
+ {deprecated,
+ "deprecated (will be removed in OTP 19); use "
+ "erl_anno:{column,line,location,text}/1 instead"};
+obsolete_1(erl_lint, modify_line, 2) ->
+ {deprecated,
+ "deprecated (will be removed in OTP 19); use erl_parse:map_anno/2 instead"};
obsolete_1(ssl, negotiated_next_protocol, 1) ->
{deprecated,{ssl,negotiated_protocol,1}};
@@ -644,3 +677,30 @@ is_snmp_agent_function(add_agent_caps, 2) -> true;
is_snmp_agent_function(del_agent_caps, 1) -> true;
is_snmp_agent_function(get_agent_caps, 0) -> true;
is_snmp_agent_function(_, _) -> false.
+
+-spec obsolete_type(module(), atom(), arity()) ->
+ 'no' | {tag(), string()} | {tag(), mfas(), release()}.
+
+obsolete_type(Module, Name, NumberOfVariables) ->
+ case obsolete_type_1(Module, Name, NumberOfVariables) of
+%% {deprecated=Tag,{_,_,_}=Replacement} ->
+%% {Tag,Replacement,"in a future release"};
+ {_,String}=Ret when is_list(String) ->
+ Ret;
+%% {_,_,_}=Ret ->
+%% Ret;
+ no ->
+ no
+ end.
+
+obsolete_type_1(erl_scan,column,0) ->
+ {deprecated,
+ "deprecated (will be removed in OTP 19); use erl_anno:column() instead"};
+obsolete_type_1(erl_scan,line,0) ->
+ {deprecated,
+ "deprecated (will be removed in OTP 19); use erl_anno:line() instead"};
+obsolete_type_1(erl_scan,location,0) ->
+ {deprecated,
+ "deprecated (will be removed in OTP 19); use erl_anno:location() instead"};
+obsolete_type_1(_,_,_) ->
+ no.
diff --git a/lib/stdlib/src/qlc.erl b/lib/stdlib/src/qlc.erl
index 5b19ee6190..ad8aafbb1a 100644
--- a/lib/stdlib/src/qlc.erl
+++ b/lib/stdlib/src/qlc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2004-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
@@ -1006,7 +1006,7 @@ listify(T) ->
-record(simple_qlc,
{p, % atom(), pattern variable
le,
- line,
+ line :: erl_anno:anno(),
init_value,
optz % #optz
}).
@@ -1148,15 +1148,18 @@ abstract(Info, true=_Flat, NElements, Depth) ->
[{match,_,Expr,Q}] ->
Q;
[{match,_,Expr,Q} | Body] ->
- {block, 0, lists:reverse(Body, [Q])};
+ {block, anno0(), lists:reverse(Body, [Q])};
_ ->
- {block, 0, lists:reverse(Body0, [Expr])}
+ {block, anno0(), lists:reverse(Body0, [Expr])}
end.
-abstract({qlc, E0, Qs0, Opt}, NElements, Depth) ->
+abstract(Info, NElements, Depth) ->
+ abstract1(Info, NElements, Depth, anno1()).
+
+abstract1({qlc, E0, Qs0, Opt}, NElements, Depth, A) ->
Qs = lists:map(fun({generate, P, LE}) ->
- {generate, 1, binary_to_term(P),
- abstract(LE, NElements, Depth)};
+ {generate, A, binary_to_term(P),
+ abstract1(LE, NElements, Depth, A)};
(F) ->
binary_to_term(F)
end, Qs0),
@@ -1165,12 +1168,12 @@ abstract({qlc, E0, Qs0, Opt}, NElements, Depth) ->
[] -> [];
_ -> [abstract_term(Opt, 1)]
end,
- ?QLC_Q(1, 1, 1, 1, {lc,1,E,Qs}, Os);
-abstract({table, {M, F, As0}}, _NElements, _Depth)
+ ?QLC_Q(A, A, A, A, {lc,A,E,Qs}, Os);
+abstract1({table, {M, F, As0}}, _NElements, _Depth, Anno)
when is_atom(M), is_atom(F), is_list(As0) ->
As = [abstract_term(A, 1) || A <- As0],
- {call, 1, {remote, 1, {atom, 1, M}, {atom, 1, F}}, As};
-abstract({table, TableDesc}, _NElements, _Depth) ->
+ {call, Anno, {remote, Anno, {atom, Anno, M}, {atom, Anno, F}}, As};
+abstract1({table, TableDesc}, _NElements, _Depth, _A) ->
case io_lib:deep_char_list(TableDesc) of
true ->
{ok, Tokens, _} = erl_scan:string(lists:flatten(TableDesc++".")),
@@ -1179,27 +1182,28 @@ abstract({table, TableDesc}, _NElements, _Depth) ->
false -> % abstract expression
TableDesc
end;
-abstract({append, Infos}, NElements, Depth) ->
+abstract1({append, Infos}, NElements, Depth, A) ->
As = lists:foldr(fun(Info, As0) ->
- {cons,1,abstract(Info, NElements, Depth),As0}
- end, {nil, 1}, Infos),
- {call, 1, {remote, 1, {atom, 1, ?MODULE}, {atom, 1, append}}, [As]};
-abstract({sort, Info, SortOptions}, NElements, Depth) ->
- {call, 1, {remote, 1, {atom, 1, ?MODULE}, {atom, 1, sort}},
- [abstract(Info, NElements, Depth), abstract_term(SortOptions, 1)]};
-abstract({keysort, Info, Kp, SortOptions}, NElements, Depth) ->
- {call, 1, {remote, 1, {atom, 1, ?MODULE}, {atom, 1, keysort}},
- [abstract_term(Kp, 1), abstract(Info, NElements, Depth),
+ {cons,A,abstract1(Info, NElements, Depth, A),
+ As0}
+ end, {nil, A}, Infos),
+ {call, A, {remote, A, {atom, A, ?MODULE}, {atom, A, append}}, [As]};
+abstract1({sort, Info, SortOptions}, NElements, Depth, A) ->
+ {call, A, {remote, A, {atom, A, ?MODULE}, {atom, A, sort}},
+ [abstract1(Info, NElements, Depth, A), abstract_term(SortOptions, 1)]};
+abstract1({keysort, Info, Kp, SortOptions}, NElements, Depth, A) ->
+ {call, A, {remote, A, {atom, A, ?MODULE}, {atom, A, keysort}},
+ [abstract_term(Kp, 1), abstract1(Info, NElements, Depth, A),
abstract_term(SortOptions, 1)]};
-abstract({list,L,MS}, NElements, Depth) ->
- {call, 1, {remote, 1, {atom, 1, ets}, {atom, 1, match_spec_run}},
- [abstract(L, NElements, Depth),
- {call, 1, {remote, 1, {atom, 1, ets}, {atom, 1, match_spec_compile}},
+abstract1({list,L,MS}, NElements, Depth, A) ->
+ {call, A, {remote, A, {atom, A, ets}, {atom, A, match_spec_run}},
+ [abstract1(L, NElements, Depth, A),
+ {call, A, {remote, A, {atom, A, ets}, {atom, A, match_spec_compile}},
[abstract_term(depth(MS, Depth), 1)]}]};
-abstract({list, L}, NElements, Depth) when NElements =:= infinity;
- NElements >= length(L) ->
+abstract1({list, L}, NElements, Depth, _A) when NElements =:= infinity;
+ NElements >= length(L) ->
abstract_term(depth(L, Depth), 1);
-abstract({list, L}, NElements, Depth) ->
+abstract1({list, L}, NElements, Depth, _A) ->
abstract_term(depth(lists:sublist(L, NElements), Depth) ++ '...', 1).
depth(List, infinity) ->
@@ -1251,14 +1255,14 @@ abstract_term(Term) ->
abstract_term(Term, 0).
abstract_term(Term, Line) ->
- abstr_term(Term, Line).
+ abstr_term(Term, anno(Line)).
abstr_term(Tuple, Line) when is_tuple(Tuple) ->
{tuple,Line,[abstr_term(E, Line) || E <- tuple_to_list(Tuple)]};
abstr_term([_ | _]=L, Line) ->
case io_lib:char_list(L) of
true ->
- erl_parse:abstract(L, Line);
+ erl_parse:abstract(L, erl_anno:line(Line));
false ->
abstr_list(L, Line)
end;
@@ -1285,7 +1289,7 @@ abstr_term(Fun, Line) when is_function(Fun) ->
abstr_term(PPR, Line) when is_pid(PPR); is_port(PPR); is_reference(PPR) ->
{special, Line, lists:flatten(io_lib:write(PPR))};
abstr_term(Simple, Line) ->
- erl_parse:abstract(Simple, Line).
+ erl_parse:abstract(Simple, erl_anno:line(Line)).
abstr_list([H | T], Line) ->
{cons, Line, abstr_term(H, Line), abstr_list(T, Line)};
@@ -1519,7 +1523,7 @@ join_info(Join, QInfo, Qdata, Code) ->
%% Only compared constants (==).
[Cs1_0, Cs2_0]
end,
- L = 0,
+ L = anno0(),
G1_0 = {var,L,'G1'}, G2_0 = {var,L,'G2'},
JP = element(JQNum + 1, Code),
%% Create code for wh1 and wh2 in #join{}:
@@ -1571,7 +1575,7 @@ join_merge_info(QNum, QInfo, Code, G, ExtraConstants) ->
{P, P};
_ ->
{PV, _} = aux_name1('P', 0, abstract_vars(P)),
- L = 0,
+ L = erl_anno:new(0),
V = {var, L, PV},
{V, {match, L, V, P}}
end,
@@ -1579,19 +1583,20 @@ join_merge_info(QNum, QInfo, Code, G, ExtraConstants) ->
LEI = {generate, term_to_binary(M), LEInfo},
TP = term_to_binary(G),
CFs = [begin
- Call = {call,0,{atom,0,element},[{integer,0,Col},EPV]},
- F = list2op([{op,0,Op,abstract_term(Con),Call}
- || {Con,Op} <- ConstOps], 'or'),
+ A = anno0(),
+ Call = {call,A,{atom,A,element},[{integer,A,Col},EPV]},
+ F = list2op([{op,A,Op,abstract_term(Con),Call}
+ || {Con,Op} <- ConstOps], 'or', A),
term_to_binary(F)
end ||
{Col,ConstOps} <- ExtraConstants],
{{I,G}, [{generate, TP, {qlc, DQP, [LEI | CFs], []}}]}
end.
-list2op([E], _Op) ->
+list2op([E], _Op, _Anno) ->
E;
-list2op([E | Es], Op) ->
- {op,0,Op,E,list2op(Es, Op)}.
+list2op([E | Es], Op, Anno) ->
+ {op,Anno,Op,E,list2op(Es, Op, Anno)}.
join_lookup_info(QNum, QInfo, G) ->
{generate, _, LEInfo}=I = lists:nth(QNum, QInfo),
@@ -1704,7 +1709,7 @@ eval_le(LE_fun, GOpt) ->
prep_qlc_lc({simple_v1, PVar, LE_fun, L}, Opt, GOpt, _H) ->
check_lookup_option(Opt, false),
- prep_simple_qlc(PVar, L, eval_le(LE_fun, GOpt), Opt);
+ prep_simple_qlc(PVar, anno(L), eval_le(LE_fun, GOpt), Opt);
prep_qlc_lc({qlc_v1, QFun, CodeF, Qdata0, QOpt}, Opt, GOpt, _H) ->
F = fun(?qual_data(_QNum, _GoI, _SI, fil)=QualData, ModGens) ->
{QualData, ModGens};
@@ -1821,7 +1826,7 @@ may_create_simple(#qlc_opt{unique = Unique, cache = Cache} = Opt,
if
Unique and not IsUnique;
(Cache =/= false) and not IsCached ->
- prep_simple_qlc(?SIMPLE_QVAR, 1, Prep, Opt);
+ prep_simple_qlc(?SIMPLE_QVAR, anno(1), Prep, Opt);
true ->
Prep
end.
@@ -3772,6 +3777,15 @@ grd(Fun, Arg) ->
false
end.
+anno0() ->
+ anno(0).
+
+anno1() ->
+ anno(1).
+
+anno(L) ->
+ erl_anno:new(L).
+
family(L) ->
sofs:to_external(sofs:relation_to_family(sofs:relation(L))).
diff --git a/lib/stdlib/src/qlc_pt.erl b/lib/stdlib/src/qlc_pt.erl
index b6bb758dfb..a4d2157b35 100644
--- a/lib/stdlib/src/qlc_pt.erl
+++ b/lib/stdlib/src/qlc_pt.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2004-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,7 +39,12 @@
opt % #qlc_opt
}).
--record(state, {imp, maxargs, records, xwarnings = []}).
+-record(state, {imp,
+ maxargs,
+ records,
+ xwarnings = [],
+ intro_vars,
+ node_info}).
%-define(debug, true).
@@ -66,37 +71,49 @@
Options :: [Option],
Option :: type_checker | compile:option()).
-parse_transform(Forms, Options) ->
+parse_transform(Forms0, Options) ->
?DEBUG("qlc Parse Transform~n", []),
- State = #state{imp = is_qlc_q_imported(Forms),
- maxargs = ?COMPILE_MAX_NUM_OF_ARGS,
- records = record_attributes(Forms)},
- case called_from_type_checker(Options) of
- true ->
- %% The returned value should conform to the types, but
- %% need not evaluate to anything meaningful.
- L = 0,
- {tuple,_,Fs0} = abstr(#qlc_lc{}, L),
- F = fun(_Id, LC, A) ->
- Init = simple(L, 'V', LC, L),
- {{tuple,L,set_field(#qlc_lc.lc, Fs0, Init)}, A}
- end,
- {Forms1,ok} = qlc_mapfold(F, ok, Forms, State),
- Forms1;
- false ->
- FormsNoShadows = no_shadows(Forms, State),
- case compile_messages(Forms, FormsNoShadows, Options, State) of
- {[],[],Warnings} ->
- {NewForms, State1} = transform(FormsNoShadows, State),
- ExtraWs = State1#state.xwarnings,
- {[],WForms} = no_duplicates(NewForms, [], Warnings,
- ExtraWs, Options),
- WForms ++ NewForms;
- {E0,Errors,Warnings} ->
- {EForms,WForms} = no_duplicates(Forms, E0++Errors,
- Warnings, [], Options),
- EForms ++ WForms ++ Forms
- end
+ Imported = is_qlc_q_imported(Forms0),
+ {Forms, FormsNoShadows, State} = initiate(Forms0, Imported),
+ NodeInfo = State#state.node_info,
+ try
+ case called_from_type_checker(Options) of
+ true ->
+ %% The returned value should conform to the types, but
+ %% need not evaluate to anything meaningful.
+ L = anno0(),
+ {tuple,_,Fs0} = abstr(#qlc_lc{}, L),
+ F = fun(_Id, LC, A) ->
+ Init = simple(L, 'V', LC, L),
+ {{tuple,L,set_field(#qlc_lc.lc, Fs0, Init)}, A}
+ end,
+ {Forms1,ok} = qlc_mapfold(F, ok, Forms, State),
+ Forms1;
+ false ->
+ case
+ compile_messages(Forms, FormsNoShadows, Options, State)
+ of
+ {[],Warnings} ->
+ ?DEBUG("node info1 ~p~n",
+ [lists:sort(ets:tab2list(NodeInfo))]),
+ {NewForms, State1} =
+ transform(FormsNoShadows, State),
+ ExtraWs = State1#state.xwarnings,
+ {[],WForms} = no_duplicates(NewForms, [], Warnings,
+ ExtraWs, Options),
+ (restore_locations(WForms, State) ++
+ restore_anno(NewForms, NodeInfo));
+ {Errors,Warnings} ->
+ ?DEBUG("node info2 ~p~n",
+ [lists:sort(ets:tab2list(NodeInfo))]),
+ {EForms,WForms} = no_duplicates(FormsNoShadows, Errors,
+ Warnings, [],
+ Options),
+ restore_locations(EForms ++ WForms, State) ++ Forms0
+ end
+ end
+ after
+ true = ets:delete(NodeInfo)
end.
-spec(transform_from_evaluator(LC, Bs) -> Expr when
@@ -124,30 +141,78 @@ called_from_type_checker(Options) ->
lists:member(type_checker, Options).
transform_expression(LC, Bs0, WithLintErrors) ->
- L = 1,
+ L = anno1(),
As = [{var,L,V} || {V,_Val} <- Bs0],
Ar = length(As),
F = {function,L,bar,Ar,[{clause,L,As,[],[?QLC_Q(L, L, L, L, LC, [])]}]},
- Forms = [{attribute,L,file,{"foo",L}},
- {attribute,L,module,foo}, F],
- State = #state{imp = false,
- maxargs = ?EVAL_MAX_NUM_OF_ARGS,
- records = record_attributes(Forms)},
+ Forms0 = [{attribute,L,file,{"foo",L}},
+ {attribute,L,module,foo}, F],
+ {Forms, FormsNoShadows, State} = initiate(Forms0, false),
+ NodeInfo = State#state.node_info,
Options = [],
- FormsNoShadows = no_shadows(Forms, State),
- case compile_messages(Forms, FormsNoShadows, Options, State) of
- {[],[],_Warnings} ->
- {NewForms,_State1} = transform(FormsNoShadows, State),
- {function,L,bar,Ar,[{clause,L,As,[],[NF]}]} =
- lists:last(NewForms),
- {ok,NF};
- {E0,Errors,_Warnings} when WithLintErrors ->
- {not_ok,mforms(error, E0 ++ Errors)};
- {E0,Errors0,_Warnings} ->
- [{error,Reason} | _] = mforms(error, E0++Errors0),
- {not_ok, {error, ?APIMOD, Reason}}
+ try compile_messages(Forms, FormsNoShadows, Options, State) of
+ {Errors0,_Warnings} ->
+ case restore_locations(Errors0, State) of
+ [] ->
+ {NewForms,_State1} = transform(FormsNoShadows, State),
+ NewForms1 = restore_anno(NewForms, NodeInfo),
+ {function,L,bar,Ar,[{clause,L,As,[],[NF]}]} =
+ lists:last(NewForms1),
+ {ok,NF};
+ Errors when WithLintErrors ->
+ {not_ok,mforms(error, Errors)};
+ Errors ->
+ [{error,Reason} | _] = mforms(error, Errors),
+ {not_ok, {error, ?APIMOD, Reason}}
+ end
+ after
+ true = ets:delete(NodeInfo)
end.
+-ifdef(DEBUG).
+-define(ILIM, 0).
+-else.
+-define(ILIM, 255).
+-endif.
+
+initiate(Forms0, Imported) ->
+ NodeInfo = ets:new(?APIMOD, []),
+ true = ets:insert(NodeInfo, {var_n, ?ILIM}),
+ exclude_integers_from_unique_line_numbers(Forms0, NodeInfo),
+ ?DEBUG("node info0 ~p~n",
+ [lists:sort(ets:tab2list(NodeInfo))]),
+ State0 = #state{imp = Imported,
+ maxargs = ?EVAL_MAX_NUM_OF_ARGS,
+ records = record_attributes(Forms0),
+ node_info = NodeInfo},
+ Forms = save_anno(Forms0, NodeInfo),
+ FormsNoShadows = no_shadows(Forms, State0),
+ IntroVars = intro_variables(FormsNoShadows, State0),
+ State = State0#state{intro_vars = IntroVars},
+ {Forms, FormsNoShadows, State}.
+
+%% Make sure restore_locations() does not confuse integers with (the
+%% unique) line numbers.
+exclude_integers_from_unique_line_numbers(Forms, NodeInfo) ->
+ Integers = find_integers(Forms),
+ lists:foreach(fun(I) -> ets:insert(NodeInfo, {I}) end, Integers).
+
+find_integers(Forms) ->
+ F = fun(A) ->
+ Fs1 = erl_parse:map_anno(fun(_) -> A end, Forms),
+ ordsets:from_list(integers(Fs1, []))
+ end,
+ ordsets:to_list(ordsets:intersection(F(anno0()), F(anno1()))).
+
+integers([E | Es], L) ->
+ integers(Es, integers(E, L));
+integers(T, L) when is_tuple(T) ->
+ integers(tuple_to_list(T), L);
+integers(I, L) when is_integer(I), I > ?ILIM ->
+ [I | L];
+integers(_, L) ->
+ L.
+
-define(I(I), {integer, L, I}).
-define(A(A), {atom, L, A}).
-define(V(V), {var, L, V}).
@@ -164,9 +229,15 @@ mforms(Tag, L) ->
%% Avoid duplicated lint warnings and lint errors. Care has been taken
%% not to introduce unused variables in the transformed code.
%%
-no_duplicates(Forms, Errors, Warnings0, ExtraWarnings, Options) ->
+no_duplicates(Forms, Errors, Warnings0, ExtraWarnings0, Options) ->
%% Some mistakes such as "{X} =:= {}" are found by strong
%% validation as well as by qlc. Prefer the warnings from qlc:
+ %% The Compiler and qlc do not agree on the location of errors.
+ %% For now, qlc's messages about failing patterns and filters
+ %% are ignored.
+ ExtraWarnings = [W || W={_File,[{_,qlc,Tag}]} <-
+ ExtraWarnings0,
+ not lists:member(Tag, [nomatch_pattern,nomatch_filter])],
Warnings1 = mforms(Warnings0) --
([{File,[{L,v3_core,nomatch}]} ||
{File,[{L,qlc,M}]} <- mforms(ExtraWarnings),
@@ -185,13 +256,22 @@ mforms(L) ->
lists:sort([{File,[M]} || {File,Ms} <- L, M <- Ms]).
mforms2(Tag, L) ->
- Line = 0,
+ Line = anno0(),
ML = lists:flatmap(fun({File,Ms}) ->
- [[{attribute,Line,file,{File,Line}}, {Tag,M}] ||
+ [[{attribute,Line,file,{File,0}}, {Tag,M}] ||
M <- Ms]
end, lists:sort(L)),
lists:flatten(lists:sort(ML)).
+restore_locations([T | Ts], State) ->
+ [restore_locations(T, State) | restore_locations(Ts, State)];
+restore_locations(T, State) when is_tuple(T) ->
+ list_to_tuple(restore_locations(tuple_to_list(T), State));
+restore_locations(I, State) when I > ?ILIM ->
+ restore_loc(I, State);
+restore_locations(T, _State) ->
+ T.
+
is_qlc_q_imported(Forms) ->
[[] || {attribute,_,import,{?APIMOD,FAs}} <- Forms, {?Q,1} <- FAs] =/= [].
@@ -212,13 +292,20 @@ compile_messages(Forms, FormsNoShadows, Options, State) ->
(_QId, Q, GA, A) ->
{Q,GA,A}
end,
- {_,BGens} = qual_fold(BGenF, [], [], FormsNoShadows, State),
+ {_,BGens} = qual_fold(BGenF, [], [], Forms, State),
GenForm = used_genvar_check(FormsNoShadows, State),
?DEBUG("GenForm = ~ts~n", [catch erl_pp:form(GenForm)]),
- WarnFun = fun(Id, LC, A) -> {tag_lines(LC, get_lcid_no(Id)), A} end,
+ {GEs,_} = compile_forms([GenForm], Options),
+ UsedGenVarMsgs = used_genvar_messages(GEs, State),
+ NodeInfo = State#state.node_info,
+ WarnFun = fun(_Id, LC, A) -> {lc_nodes(LC, NodeInfo), A} end,
{WForms,ok} = qlc_mapfold(WarnFun, ok, Forms, State),
- {Es,Ws} = compile_forms(WForms ++ [GenForm], Options),
- {badarg(Forms, State),tagged_messages(Es)++BGens,tagged_messages(Ws)}.
+ {Es,Ws} = compile_forms(WForms, Options),
+ LcEs = lc_messages(Es, NodeInfo),
+ LcWs = lc_messages(Ws, NodeInfo),
+ Errors = badarg(Forms, State) ++ UsedGenVarMsgs++LcEs++BGens,
+ Warnings = LcWs,
+ {Errors,Warnings}.
badarg(Forms, State) ->
F = fun(_Id, {lc,_L,_E,_Qs}=LC, Es) ->
@@ -230,54 +317,39 @@ badarg(Forms, State) ->
{_,E0} = qlc_mapfold(F, [], Forms, State),
E0.
-tag_lines(E, No) ->
- map_lines(fun(Id) ->
- case is_lcid(Id) of
- true -> Id;
- false -> make_lcid(Id, No)
- end
- end, E).
-
-map_lines(F, E) ->
- erl_lint:modify_line(E, F).
-
-tagged_messages(MsL) ->
- [{File,
- [{Loc,Mod,untag(T)} || {Loc0,Mod,T} <- Ms,
- {true,Loc} <- [tloc(Loc0)]]}
- || {File,Ms} <- MsL]
- ++
+lc_nodes(E, NodeInfo) ->
+ erl_parse:map_anno(fun(Anno) ->
+ N = erl_anno:line(Anno),
+ [{N, Data}] = ets:lookup(NodeInfo, N),
+ NData = Data#{inside_lc => true},
+ true = ets:insert(NodeInfo, {N, NData}),
+ Anno
+ end, E).
+
+used_genvar_messages(MsL, S) ->
[{File,[{Loc,?APIMOD,{used_generator_variable,V}}]}
- || {_, Ms} <- MsL,
+ || {_, Ms} <- MsL,
{XLoc,erl_lint,{unbound_var,_}} <- Ms,
- {Loc,File,V} <- [extra(XLoc)]].
-
-tloc({Id,Column}) ->
- {IsLcid,T} = tloc(Id),
- {IsLcid,{T,Column}};
-tloc(Id) ->
- IsLcid = is_lcid(Id),
- {IsLcid,case IsLcid of
- true -> get_lcid_line(Id);
- false -> any
- end}.
-
-extra({extra,Line,File,V}) ->
- {Line,File,V};
-extra({Line,Column}) ->
- case extra(Line) of
- {L,File,V} -> {{L,Column},File,V};
- Else -> Else
- end;
-extra(Else) ->
- Else.
-
-untag([E | Es]) -> [untag(E) | untag(Es)];
-untag(T) when is_tuple(T) -> list_to_tuple(untag(tuple_to_list(T)));
-untag(E) ->
- case is_lcid(E) of
- true -> get_lcid_line(E);
- false -> E
+ {Loc,File,V} <- [genvar_pos(XLoc, S)]].
+
+lc_messages(MsL, NodeInfo) ->
+ [{File,[{Loc,Mod,T} || {Loc,Mod,T} <- Ms, lc_loc(Loc, NodeInfo)]} ||
+ {File,Ms} <- MsL].
+
+lc_loc(N, NodeInfo) ->
+ case ets:lookup(NodeInfo, N) of
+ [{N, #{inside_lc := true}}] ->
+ true;
+ [{N, _}] ->
+ false
+ end.
+
+genvar_pos(Location, S) ->
+ case ets:lookup(S#state.node_info, Location) of
+ [{Location, #{genvar_pos := Pos}}] ->
+ Pos;
+ [] ->
+ Location
end.
%% -> [{Qid,[variable()]}].
@@ -293,6 +365,7 @@ untag(E) ->
%% variables (unless they are unsafe).
%%
intro_variables(FormsNoShadows, State) ->
+ NodeInfo = State#state.node_info,
Fun = fun(QId, {T,_L,P0,_E0}=Q, {GVs,QIds}, Foo) when T =:= b_generate;
T =:= generate ->
PVs = qlc:var_ufold(fun({var,_,V}) -> {QId,V} end, P0),
@@ -302,10 +375,11 @@ intro_variables(FormsNoShadows, State) ->
%% where E is an LC expression consisting of a
%% template mentioning all variables occurring in F.
Vs = ordsets:to_list(qlc:vars(Filter0)),
- Id = QId#qid.lcid,
- LC1 = embed_vars(intro_set_line({QId,f1}, Vs), Id),
- LC2 = embed_vars(intro_set_line({QId,f2}, Vs), Id),
- AnyLine = -1,
+ AnyLine = anno0(),
+ Vars = [{var,AnyLine,V} || V <- Vs],
+ LC = embed_vars(Vars, AnyLine),
+ LC1 = intro_anno(LC, before, QId, NodeInfo),
+ LC2 = intro_anno(LC, 'after', QId, NodeInfo),
Filter = {block,AnyLine,[LC1,Filter0,LC2]},
{Filter,{GVs,[{QId,[]} | QIds]},Foo}
end,
@@ -317,9 +391,15 @@ intro_variables(FormsNoShadows, State) ->
Es0 = compile_errors(FForms),
%% A variable is bound inside the filter if it is not bound before
%% the filter, but it is bound after the filter (obviously).
- Before = [{QId,V} || {{QId,f1},erl_lint,{unbound_var,V}} <- Es0],
- After = [{QId,V} || {{QId,f2},erl_lint,{unbound_var,V}} <- Es0],
- Unsafe = [{QId,V} || {{QId,f2},erl_lint,{unsafe_var,V,_Where}} <- Es0],
+ Before = [{QId,V} ||
+ {L,erl_lint,{unbound_var,V}} <- Es0,
+ {_L,{QId,before}} <- ets:lookup(NodeInfo, L)],
+ After = [{QId,V} ||
+ {L,erl_lint,{unbound_var,V}} <- Es0,
+ {_L,{QId,'after'}} <- ets:lookup(NodeInfo, L)],
+ Unsafe = [{QId,V} ||
+ {L,erl_lint,{unsafe_var,V,_Where}} <- Es0,
+ {_L,{QId,'after'}} <- ets:lookup(NodeInfo, L)],
?DEBUG("Before = ~p~n", [Before]),
?DEBUG("After = ~p~n", [After]),
?DEBUG("Unsafe = ~p~n", [Unsafe]),
@@ -328,9 +408,14 @@ intro_variables(FormsNoShadows, State) ->
I1 = family(IV ++ GenVars),
sofs:to_external(sofs:family_union(sofs:family(QIds), I1)).
-intro_set_line(Tag, Vars) ->
- L = erl_parse:set_line(1, fun(_) -> Tag end),
- [{var,L,V} || V <- Vars].
+intro_anno(LC, Where, QId, NodeInfo) ->
+ Data = {QId,Where},
+ Fun = fun(Anno) ->
+ Location = erl_anno:location(Anno),
+ true = ets:insert(NodeInfo, {Location,Data}),
+ Anno
+ end,
+ erl_parse:map_anno(Fun, save_anno(LC, NodeInfo)).
compile_errors(FormsNoShadows) ->
case compile_forms(FormsNoShadows, []) of
@@ -341,11 +426,8 @@ compile_errors(FormsNoShadows) ->
lists:flatmap(fun({_File,Es}) -> Es end, Errors)
end.
--define(MAX_NUM_OF_LINES, 23). % assume max 1^23 lines (> 8 millions)
-
compile_forms(Forms0, Options) ->
- Forms = [F || F <- Forms0, element(1, F) =/= eof] ++
- [{eof,1 bsl ?MAX_NUM_OF_LINES}],
+ Forms = [F || F <- Forms0, element(1, F) =/= eof] ++ [{eof,anno0()}],
try
case compile:noenv_forms(Forms, compile_options(Options)) of
{ok, _ModName, Ws0} ->
@@ -384,20 +466,23 @@ bitstr_options() ->
%% for each ListExpr. The expression mentions all introduced variables
%% occurring in ListExpr. Running the function through the compiler
%% yields error messages for erroneous use of introduced variables.
-%% The messages have the form
-%% {{extra,LineNo,File,Var},Module,{unbound_var,V}}, where Var is the
-%% original variable name and V is the name invented by no_shadows/2.
%%
used_genvar_check(FormsNoShadows, State) ->
- F = fun(QId, {T, Ln, _P, LE}=Q, {QsIVs0, Exprs0}, IVsSoFar0)
+ NodeInfo = State#state.node_info,
+ F = fun(QId, {T, Ln, _P, LE}=Q, {QsIVs0, Exprs0}, IVsSoFar0)
when T =:= b_generate; T =:= generate ->
- F = fun({var, _, V}=Var) ->
- {var, L, OrigVar} = undo_no_shadows(Var),
- AF = fun(Line) ->
- {extra, Line, get(?QLC_FILE), OrigVar}
- end,
- L2 = erl_parse:set_line(L, AF),
- {var, L2, V}
+ F = fun(Var) ->
+ {var, Anno0, OrigVar} =
+ undo_no_shadows(Var, State),
+ {var, Anno, _} = NewVar = save_anno(Var, NodeInfo),
+ Location0 = erl_anno:location(Anno0),
+ Location = erl_anno:location(Anno),
+ [{Location, Data}] =
+ ets:lookup(NodeInfo, Location),
+ Pos = {Location0,get(?QLC_FILE),OrigVar},
+ NData = Data#{genvar_pos => Pos},
+ true = ets:insert(NodeInfo, {Location, NData}),
+ NewVar
end,
Vs = [Var || {var, _, V}=Var <- qlc:var_fold(F, [], LE),
lists:member(V, IVsSoFar0)],
@@ -411,12 +496,12 @@ used_genvar_check(FormsNoShadows, State) ->
{QsIVs, IVsSoFar} = q_intro_vars(QId, QsIVs0, IVsSoFar0),
{Filter, {QsIVs, Exprs}, IVsSoFar}
end,
- IntroVars = intro_variables(FormsNoShadows, State),
- Acc0 = {IntroVars, [{atom, 0, true}]},
+ Acc0 = {State#state.intro_vars, [{atom, anno0(), true}]},
{_, {[], Exprs}} = qual_fold(F, Acc0, [], FormsNoShadows, State),
FunctionNames = [Name || {function, _, Name, _, _} <- FormsNoShadows],
UniqueFName = qlc:aux_name(used_genvar, 1, sets:from_list(FunctionNames)),
- {function,0,UniqueFName,0,[{clause,0,[],[],lists:reverse(Exprs)}]}.
+ A = anno0(),
+ {function,A,UniqueFName,0,[{clause,A,[],[],lists:reverse(Exprs)}]}.
q_intro_vars(QId, [{QId, IVs} | QsIVs], IVsSoFar) -> {QsIVs, IVs ++ IVsSoFar}.
@@ -514,7 +599,8 @@ q_intro_vars(QId, [{QId, IVs} | QsIVs], IVsSoFar) -> {QsIVs, IVs ++ IVsSoFar}.
%% (calling LEf returns the objects generated by LE).
transform(FormsNoShadows, State) ->
- IntroVars = intro_variables(FormsNoShadows, State),
+ _ = erlang:system_flag(backtrace_depth, 500),
+ IntroVars = State#state.intro_vars,
AllVars = sets:from_list(ordsets:to_list(qlc:vars(FormsNoShadows))),
?DEBUG("AllVars = ~p~n", [sets:to_list(AllVars)]),
F1 = fun(QId, {generate,_,P,LE}, Foo, {GoI,SI}) ->
@@ -588,8 +674,8 @@ transform(FormsNoShadows, State) ->
[{match,L,{var,L,Fun},FunC},
{call,L,{var,L,Fun},As0}]}]}},
{ok, OrigE0} = dict:find(Id, Source),
- OrigE = undo_no_shadows(OrigE0),
- QCode = qcode(OrigE, XQCs, Source, L),
+ OrigE = undo_no_shadows(OrigE0, State),
+ QCode = qcode(OrigE, XQCs, Source, L, State),
Qdata = qdata(XQCs, L),
TemplateInfo =
template_columns(Qs, E, AllIVs, Dependencies, State),
@@ -598,7 +684,7 @@ transform(FormsNoShadows, State) ->
Opt = opt_info(TemplateInfo, SizeInfo, JoinInfo, MSQs, L,
EqColumnConstants, EqualColumnConstants),
LCTuple =
- case qlc_kind(OrigE, Qs) of
+ case qlc_kind(OrigE, Qs, State) of
qlc ->
{tuple,L,[?A(qlc_v1),FunW,QCode,Qdata,Opt]};
{simple, PL, LE, V} ->
@@ -612,7 +698,7 @@ transform(FormsNoShadows, State) ->
end,
{NForms,{[],XW}} = qlc_mapfold(F2, {IntroVars,[]}, ModifiedForms1, State),
display_forms(NForms),
- {restore_line_numbers(NForms), State#state{xwarnings = XW}}.
+ {NForms, State#state{xwarnings = XW}}.
join_kind(Qs, LcL, AllIVs, Dependencies, State) ->
{EqualCols2, EqualColsN} = equal_columns(Qs, AllIVs, Dependencies, State),
@@ -623,20 +709,21 @@ join_kind(Qs, LcL, AllIVs, Dependencies, State) ->
if
EqualColsN =/= []; MatchColsN =/= [] ->
{[],
- [{get(?QLC_FILE),[{abs(LcL),?APIMOD,too_complex_join}]}]};
+ [{get(?QLC_FILE),[{LcL,?APIMOD,too_complex_join}]}]};
EqualCols2 =:= [], MatchCols2 =:= [] ->
{[], []};
length(Tables) > 2 ->
{[],
- [{get(?QLC_FILE),[{abs(LcL),?APIMOD,too_many_joins}]}]};
+ [{get(?QLC_FILE),[{LcL,?APIMOD,too_many_joins}]}]};
EqualCols2 =:= MatchCols2 ->
{EqualCols2, []};
true ->
{{EqualCols2, MatchCols2}, []}
end.
-qlc_kind(OrigE, Qs) ->
- {OrigFilterData, OrigGeneratorData} = qual_data(undo_no_shadows(Qs)),
+qlc_kind(OrigE, Qs, State) ->
+ {OrigFilterData, OrigGeneratorData} =
+ qual_data(undo_no_shadows(Qs, State)),
OrigAllFilters = filters_as_one(OrigFilterData),
{_FilterData, GeneratorData} = qual_data(Qs),
case {OrigE, OrigAllFilters, OrigGeneratorData} of
@@ -663,12 +750,12 @@ warn_failing_qualifiers(Qualifiers, AllIVs, Dependencies, State) ->
lists:foldl(fun({_QId,{fil,_Filter}}, {[]=Frames,Warnings}) ->
{Frames,Warnings};
({_QId,{fil,Filter}}, {Frames,Warnings}) ->
- case filter(set_line(Filter, 0), Frames, BindFun,
+ case filter(reset_anno(Filter), Frames, BindFun,
State, Imported) of
[] ->
{[],
[{get(?QLC_FILE),
- [{abs_loc(element(2, Filter)),?APIMOD,
+ [{loc(element(2, Filter)),?APIMOD,
nomatch_filter}]} | Warnings]};
Frames1 ->
{Frames1,Warnings}
@@ -678,7 +765,7 @@ warn_failing_qualifiers(Qualifiers, AllIVs, Dependencies, State) ->
{failed, _, _} ->
{Frames,
[{get(?QLC_FILE),
- [{abs_loc(element(2, Pattern)),?APIMOD,
+ [{loc(element(2, Pattern)),?APIMOD,
nomatch_pattern}]} | Warnings]};
_ ->
{Frames,Warnings}
@@ -751,8 +838,8 @@ opt_constants(L, ColumnConstants) ->
|| IdNo <- Ns]
++ [{clause,L,[?V('_')],[],[?A(no_column_fun)]}].
-abstr(Term, Line) ->
- erl_parse:abstract(Term, Line).
+abstr(Term, Anno) ->
+ erl_parse:abstract(Term, loc(Anno)).
%% Extra generators are introduced for join.
join_quals(JoinInfo, QCs, L, LcNo, ExtraConstants, AllVars) ->
@@ -837,9 +924,10 @@ join_handle(AP, L, [F, H, O, C], Constants) ->
{{var, _, _}, []} ->
{'fun',L,{clauses,[{clause,L,[H],[],[H]}]}};
_ ->
+ A = anno0(),
G0 = [begin
- Call = {call,0,{atom,0,element},[{integer,0,Col},O]},
- list2op([{op,0,Op,Con,Call} || {Con,Op} <- Cs], 'or')
+ Call = {call,A,{atom,A,element},[{integer,A,Col},O]},
+ list2op([{op,A,Op,Con,Call} || {Con,Op} <- Cs], 'or')
end || {Col,Cs} <- Constants],
G = if G0 =:= [] -> G0; true -> [G0] end,
CC1 = {clause,L,[AP],G,[{cons,L,O,closure({call,L,F,[F,C]},L)}]},
@@ -876,14 +964,15 @@ join_handle_constants(QId, ExtraConstants) ->
%% order the traverse fun would return them.
column_fun(Columns, QualifierNumber, LcL) ->
+ A = anno0(),
ColCls0 =
[begin
true = Vs0 =/= [], % at least one value to look up
Vs1 = list2cons(Vs0),
- Fils1 = {tuple,0,[{atom,0,FTag},
+ Fils1 = {tuple,A,[{atom,A,FTag},
lists:foldr
- (fun(F, A) -> {cons,0,{integer,0,F},A}
- end, {nil,0}, Fils)]},
+ (fun(F, Ac) -> {cons,A,{integer,A,F},Ac}
+ end, {nil,A}, Fils)]},
Tag = case ordsets:to_list(qlc:vars(Vs1)) of
Imp when length(Imp) > 0, % imported vars
length(Vs0) > 1 ->
@@ -891,13 +980,13 @@ column_fun(Columns, QualifierNumber, LcL) ->
_ ->
values
end,
- Vs = {tuple,0,[{atom,0,Tag},Vs1,Fils1]},
- {clause,0,[erl_parse:abstract(Col)],[],[Vs]}
+ Vs = {tuple,A,[{atom,A,Tag},Vs1,Fils1]},
+ {clause,A,[erl_parse:abstract(Col)],[],[Vs]}
end ||
{{CIdNo,Col}, Vs0, {FTag,Fils}} <- Columns,
CIdNo =:= QualifierNumber]
- ++ [{clause,0,[{var,0,'_'}],[],[{atom,0,false}]}],
- ColCls = set_line(ColCls0, LcL),
+ ++ [{clause,A,[{var,A,'_'}],[],[{atom,A,false}]}],
+ ColCls = set_anno(ColCls0, LcL),
{'fun', LcL, {clauses, ColCls}}.
%% Tries to find columns of the template that (1) are equal to (or
@@ -920,7 +1009,7 @@ template_columns(Qs0, E0, AllIVs, Dependencies, State) ->
MatchColumns = eq_columns2(Qs, AllIVs, Dependencies, State),
Equal = template_cols(EqualColumns),
Match = template_cols(MatchColumns),
- L = 0,
+ L = anno0(),
if
Match =:= Equal ->
[{?V('_'), Match}];
@@ -947,7 +1036,7 @@ template_cols(ColumnClasses) ->
template_as_pattern(E) ->
P = simple_template(E),
- {?TID,foo,foo,{gen,P,{nil,0}}}.
+ {?TID,foo,foo,{gen,P,{nil,anno0()}}}.
simple_template({call,L,{remote,_,{atom,_,erlang},{atom,_,element}}=Call,
[{integer,_,I}=A1,A2]}) when I > 0 ->
@@ -1004,10 +1093,10 @@ match_spec_quals(Template, Dependencies, Qualifiers, State) ->
GQId =:= QId2,
{FQId,{fil,F}}=Filter <- Filters, % guard filters only
FQId =:= QId]
- ++ [{GId#qid.no,Pattern,[],{atom,0,true}} ||
+ ++ [{GId#qid.no,Pattern,[],{atom,anno0(),true}} ||
{GId,{gen,Pattern,_}} <- GeneratorData,
lists:member(GId, NoFilterGIds)],
- E = {nil, 0},
+ E = {nil, anno0()},
GF = [{{GNum,Pattern},Filter} ||
{GNum,Pattern,Filter,F} <- Candidates,
no =/= try_ms(E, Pattern, F, State)],
@@ -1024,7 +1113,7 @@ match_spec_quals(Template, Dependencies, Qualifiers, State) ->
%% expressione can be replaced by a match specification.
[{GNum, AbstrMS, all}]
catch _:_ ->
- {TemplVar, _} = anon_var({var,0,'_'}, 0),
+ {TemplVar, _} = anon_var({var,anno0(),'_'}, 0),
[one_gen_match_spec(GNum, Pattern, GFilterData, State, TemplVar) ||
{{GNum,Pattern},GFilterData} <- GFFL]
end.
@@ -1038,7 +1127,7 @@ gen_ms(E, Pattern, GFilterData, State) ->
{ok, MS, AMS} = try_ms(E, Pattern, filters_as_one(GFilterData), State),
case MS of
[{'$1',[true],['$1']}] ->
- {atom, 0, no_match_spec};
+ {atom, anno0(), no_match_spec};
_ ->
AMS
end.
@@ -1060,7 +1149,7 @@ pattern_as_template({match,_,_E,{var,_,_}=V}=P, _TemplVar) ->
pattern_as_template({match,_,{var,_,_}=V,_E}=P, _TemplVar) ->
{V, P};
pattern_as_template(E, TemplVar) ->
- L = 0,
+ L = anno0(),
{TemplVar, {match, L, E, TemplVar}}.
%% Tries to find columns which are compared or matched against
@@ -1203,7 +1292,7 @@ lu_skip(ColConstants, FilterData, PatternFrame, PatternVars,
ColFil = [{Column, FId#qid.no} ||
{FId,{fil,Fil}} <-
filter_list(FilterData, Dependencies, State),
- [] =/= (SFs = safe_filter(set_line(Fil, 0), PatternFrames,
+ [] =/= (SFs = safe_filter(reset_anno(Fil), PatternFrames,
BindFun, State, Imported)),
{GId,PV} <- PatternVars,
[] =/=
@@ -1392,7 +1481,7 @@ join_skip(JoinClasses, FilterData, PatternFrame, PatternVars, Dependencies,
JF = unify(JoinOp, V1, V2, JF2, BindFun, Imported),
%% "Run" the filter:
- SFs = safe_filter(set_line(Fil, 0), PatternFrames,
+ SFs = safe_filter(reset_anno(Fil), PatternFrames,
BindFun, State, Imported),
JImp = qlc:vars([SFs, JF]), % kludge
lists:all(fun(Frame) ->
@@ -1403,7 +1492,7 @@ join_skip(JoinClasses, FilterData, PatternFrame, PatternVars, Dependencies,
filter_info(FilterData, AllIVs, Dependencies, State) ->
FilterList = filter_list(FilterData, Dependencies, State),
- Filter0 = set_line(filters_as_one(FilterList), 0),
+ Filter0 = reset_anno(filters_as_one(FilterList)),
Anon0 = 0,
{Filter, Anon1} = anon_var(Filter0, Anon0),
Imported = ordsets:subtract(qlc:vars(Filter), % anonymous too
@@ -1510,7 +1599,7 @@ pattern(P0, AnonI, Frame0, BindFun, State) ->
catch _:_ -> P0 % template, records already expanded
end,
%% Makes test for equality simple:
- P2 = set_line(P1, 0),
+ P2 = reset_anno(P1),
{P3, AnonN} = anon_var(P2, AnonI),
{P4, F1} = match_in_pattern(tuple2cons(P3), Frame0, BindFun),
{P, F2} = element_calls(P4, F1, BindFun, _Imp=[]), % kludge for templates
@@ -1550,8 +1639,11 @@ anon_var(E, AnonI) ->
(Var, N) -> {Var, N}
end, AnonI, E).
-set_line(T, L) ->
- map_lines(fun(_L) -> L end, T).
+reset_anno(T) ->
+ set_anno(T, anno0()).
+
+set_anno(T, A) ->
+ erl_parse:map_anno(fun(_L) -> A end, T).
-record(fstate, {state, bind_fun, imported}).
@@ -1673,7 +1765,7 @@ frames_to_columns(Fs, PatternVars, DerefFun, SelectorFun, Imp, CompOp) ->
%% same variables have to be the representatives in every frame.)
SizesVarsL =
[begin
- PatVar = {var,0,PV},
+ PatVar = {var,anno0(),PV},
PatternSizes = [pattern_size([F], PatVar, false) ||
F <- Fs],
MaxPZ = lists:max([0 | PatternSizes -- [undefined]]),
@@ -1692,8 +1784,8 @@ frames_to_columns(Fs, PatternVars, DerefFun, SelectorFun, Imp, CompOp) ->
frames2cols(Fs, PatN, PatSizes, Vars, DerefFun, SelectorFun, CompOp) ->
Rs = [ begin
RL = [{{PatN,Col},cons2tuple(element(2, Const))} ||
- {V, Col} <- lists:zip(sublist(Vars, PatSz),
- seq(1, PatSz)),
+ {V, Col} <- lists:zip(lists:sublist(Vars, PatSz),
+ lists:seq(1, PatSz)),
%% Do not handle the case where several
%% values compare equal, e.g. "X =:= 1
%% andalso X == 1.0". Looking up both
@@ -1722,11 +1814,11 @@ frames2cols(Fs, PatN, PatSizes, Vars, DerefFun, SelectorFun, CompOp) ->
[C || {_,Vs}=C <- sofs:to_external(Cs), not col_ignore(Vs, CompOp)].
pat_vars(N) ->
- [unique_var() || _ <- seq(1, N)].
+ [unique_var() || _ <- lists:seq(1, N)].
pat_tuple(Sz, Vars) when is_integer(Sz), Sz > 0 ->
TupleTail = unique_var(),
- {cons_tuple, list2cons(sublist(Vars, Sz) ++ TupleTail)};
+ {cons_tuple, list2cons(lists:sublist(Vars, Sz) ++ TupleTail)};
pat_tuple(_, _Vars) ->
unique_var().
@@ -1740,7 +1832,7 @@ col_ignore(Vs, '==') ->
pattern_sizes(PatternVars, Fs) ->
[{QId#qid.no, Size} ||
{QId,PV} <- PatternVars,
- undefined =/= (Size = pattern_size(Fs, {var,0,PV}, true))].
+ undefined =/= (Size = pattern_size(Fs, {var,anno0(),PV}, true))].
pattern_size(Fs, PatternVar, Exact) ->
Fun = fun(F) -> (deref_pattern(_Imported = []))(PatternVar, F) end,
@@ -1768,7 +1860,8 @@ prep_expr(E, F, S, BF, Imported) ->
element_calls(tuple2cons(expand_expr_records(E, S)), F, BF, Imported).
unify_column(Frame, Var, Col, BindFun, Imported) ->
- Call = {call,0,{atom,0,element},[{integer,0,Col}, {var,0,Var}]},
+ A = anno0(),
+ Call = {call,A,{atom,A,element},[{integer,A,Col}, {var,A,Var}]},
element_calls(Call, Frame, BindFun, Imported).
%% cons_tuple is used for representing {V1, ..., Vi | TupleTail}.
@@ -1800,19 +1893,21 @@ element_calls(E, F, _BF, _Imported) ->
{E, F}.
unique_var() ->
- {var, 0, make_ref()}.
+ {var, anno0(), make_ref()}.
is_unique_var({var, _L, V}) ->
is_reference(V).
expand_pattern_records(P, State) ->
- E = {'case',0,{atom,0,true},[{clause,0,[P],[],[{atom,0,true}]}]},
- {'case',_,_,[{clause,0,[NP],_,_}]} = expand_expr_records(E, State),
+ A = anno0(),
+ E = {'case',A,{atom,A,true},[{clause,A,[P],[],[{atom,A,true}]}]},
+ {'case',_,_,[{clause,A,[NP],_,_}]} = expand_expr_records(E, State),
NP.
expand_expr_records(E, State) ->
RecordDefs = State#state.records,
- Forms = RecordDefs ++ [{function,1,foo,0,[{clause,1,[],[],[pe(E)]}]}],
+ A = anno1(),
+ Forms = RecordDefs ++ [{function,A,foo,0,[{clause,A,[],[],[pe(E)]}]}],
[{function,_,foo,0,[{clause,_,[],[],[NE]}]}] =
erl_expand_records:module(Forms, [no_strict_record_tests]),
NE.
@@ -2126,15 +2221,15 @@ tuple2cons(E) ->
E.
list2cons([E | Es]) ->
- {cons, 0, E, list2cons(Es)};
+ {cons, anno0(), E, list2cons(Es)};
list2cons([]) ->
- {nil, 0};
+ {nil, anno0()};
list2cons(E) ->
E.
%% Returns {..., Variable} if Variable is a tuple tail.
cons2tuple({cons_tuple, Es}) ->
- {tuple, 0, cons2list(Es)};
+ {tuple, anno0(), cons2list(Es)};
cons2tuple(T) when is_tuple(T) ->
list_to_tuple(cons2tuple(tuple_to_list(T)));
cons2tuple([E | Es]) ->
@@ -2173,11 +2268,10 @@ bindings_subset(F1, F2, Imp) ->
%% not to have guard semantics, affected filters will have to be
%% recognized and excluded here as well.
try_ms(E, P, Fltr, State) ->
- L = 1,
+ L = anno1(),
Fun = {'fun',L,{clauses,[{clause,L,[P],[[Fltr]],[E]}]}},
Expr = {call,L,{remote,L,{atom,L,ets},{atom,L,fun2ms}},[Fun]},
- Form0 = {function,L,foo,0,[{clause,L,[],[],[Expr]}]},
- Form = restore_line_numbers(Form0),
+ Form = {function,L,foo,0,[{clause,L,[],[],[Expr]}]},
X = ms_transform:parse_transform(State#state.records ++ [Form], []),
case catch
begin
@@ -2194,11 +2288,11 @@ try_ms(E, P, Fltr, State) ->
end.
filters_as_one([]) ->
- {atom, 0, true};
+ {atom, anno0(), true};
filters_as_one(FilterData) ->
[{_,{fil,Filter1}} | Filters] = lists:reverse(FilterData),
lists:foldr(fun({_QId,{fil,Filter}}, AbstF) ->
- {op,0,'andalso',Filter,AbstF}
+ {op,anno0(),'andalso',Filter,AbstF}
end, Filter1, Filters).
qual_data(Qualifiers) ->
@@ -2233,38 +2327,40 @@ qdata([], L) ->
{nil,L}.
qcon(Cs) ->
- list2cons([{tuple,0,[{integer,0,Col},list2cons(qcon1(ConstOps))]} ||
+ A = anno0(),
+ list2cons([{tuple,A,[{integer,A,Col},list2cons(qcon1(ConstOps))]} ||
{Col,ConstOps} <- Cs]).
qcon1(ConstOps) ->
- [{tuple,0,[Const,abstr(Op, 0)]} || {Const,Op} <- ConstOps].
+ A = anno0(),
+ [{tuple,A,[Const,abstr(Op, A)]} || {Const,Op} <- ConstOps].
%% The original code (in Source) is used for filters and the template
%% since the translated code can have QLCs and we don't want them to
%% be visible.
-qcode(E, QCs, Source, L) ->
+qcode(E, QCs, Source, L, State) ->
CL = [begin
Bin = term_to_binary(C, [compressed]),
{bin, L, [{bin_element, L,
{string, L, binary_to_list(Bin)},
default, default}]}
end || {_,C} <- lists:keysort(1, [{qlc:template_state(),E} |
- qcode(QCs, Source)])],
+ qcode(QCs, Source, State)])],
{'fun', L, {clauses, [{clause, L, [], [], [{tuple, L, CL}]}]}}.
-qcode([{_QId, {_QIvs, {{gen,P,_LE,_GV}, GoI, _SI}}} | QCs], Source) ->
- [{GoI,undo_no_shadows(P)} | qcode(QCs, Source)];
-qcode([{QId, {_QIVs, {{fil,_F}, GoI, _SI}}} | QCs], Source) ->
+qcode([{_QId, {_QIvs, {{gen,P,_LE,_GV}, GoI, _SI}}} | QCs], Source, State) ->
+ [{GoI,undo_no_shadows(P, State)} | qcode(QCs, Source, State)];
+qcode([{QId, {_QIVs, {{fil,_F}, GoI, _SI}}} | QCs], Source, State) ->
{ok,OrigF} = dict:find(QId, Source),
- [{GoI,undo_no_shadows(OrigF)} | qcode(QCs, Source)];
-qcode([], _Source) ->
+ [{GoI,undo_no_shadows(OrigF, State)} | qcode(QCs, Source, State)];
+qcode([], _Source, _State) ->
[].
closure(Code, L) ->
{'fun',L,{clauses,[{clause,L,[],[],[Code]}]}}.
-simple(L, Var, Init, Line) ->
- {tuple,L,[?A(simple_v1),?A(Var),Init,?I(Line)]}.
+simple(L, Var, Init, Anno) ->
+ {tuple,L,[?A(simple_v1),?A(Var),Init,abstr(loc(Anno), Anno)]}.
clauses([{QId,{QIVs,{QualData,GoI,S}}} | QCs], RL, Fun, Go, NGV, E, IVs,St) ->
?DEBUG("QIVs = ~p~n", [QIVs]),
@@ -2426,19 +2522,22 @@ aux_var(Name, LcN, QN, N, AllVars) ->
qlc:aux_name(lists:concat([Name, LcN, '_', QN, '_']), N, AllVars).
no_compiler_warning(L) ->
- erl_parse:set_line(L, fun(Line) -> -abs(Line) end).
+ Anno = erl_anno:new(L),
+ erl_anno:set_generated(true, Anno).
-abs_loc(L) ->
- loc(erl_parse:set_line(L, fun(Line) -> abs(Line) end)).
-
-loc(L) ->
- {location,Location} = erl_parse:get_attribute(L, location),
- Location.
+loc(A) ->
+ erl_anno:location(A).
list2op([E], _Op) ->
E;
list2op([E | Es], Op) ->
- {op,0,Op,E,list2op(Es, Op)}.
+ {op,anno0(),Op,E,list2op(Es, Op)}.
+
+anno0() ->
+ erl_anno:new(0).
+
+anno1() ->
+ erl_anno:new(1).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -2491,13 +2590,61 @@ qlcmf(T, _F, _Imp, A, No) ->
occ_vars(E) ->
qlc:var_fold(fun({var,_L,V}) -> V end, [], E).
+%% Every Anno is replaced by a unique number. The number is used in a
+%% table that holds data about the abstract node where Anno resides.
+%% In particular, the original location is kept there, so that the
+%% original abstract code can be re-created.
+save_anno(Abstr, NodeInfo) ->
+ F = fun(Anno) ->
+ N = next_slot(NodeInfo),
+ Location = erl_anno:location(Anno),
+ Data = {N, #{location => Location}},
+ true = ets:insert(NodeInfo, Data),
+ erl_anno:new(N)
+ end,
+ erl_parse:map_anno(F, Abstr).
+
+next_slot(T) ->
+ I = ets:update_counter(T, var_n, 1),
+ case ets:lookup(T, I) of
+ [] ->
+ I;
+ _ ->
+ next_slot(T)
+ end.
+
+restore_anno(Abstr, NodeInfo) ->
+ F = fun(Anno) ->
+ Location = erl_anno:location(Anno),
+ case ets:lookup(NodeInfo, Location) of
+ [{Location, Data}] ->
+ OrigLocation = maps:get(location, Data),
+ erl_anno:set_location(OrigLocation, Anno);
+ [{Location}] -> % generated code
+ Anno;
+ [] ->
+ Anno
+ end
+ end,
+ erl_parse:map_anno(F, Abstr).
+
+restore_loc(Location, #state{node_info = NodeInfo}) ->
+ case ets:lookup(NodeInfo, Location) of
+ [{Location, #{location := OrigLocation}}] ->
+ OrigLocation;
+ [{Location}] ->
+ Location;
+ [] ->
+ Location
+ end.
+
no_shadows(Forms0, State) ->
%% Variables that may shadow other variables are introduced in
%% LCs and Funs. Such variables (call them SV, Shadowing
%% Variables) are now renamed. Each (new) occurrence in a pattern
%% is assigned an index (integer), unique in the file.
%%
- %% The state {LastIndex,ActiveVars,UsedVars,AllVars,Singletons}
+ %% The state {LastIndex,ActiveVars,UsedVars,AllVars,Singletons,State}
%% holds the last index used for each SV (LastIndex), the SVs in
%% the current scope (ActiveVars), used SVs (UsedVars, the indexed
%% name is the key), all variables occurring in the file
@@ -2507,16 +2654,15 @@ no_shadows(Forms0, State) ->
%% the indexed name of an SV occurs in the file, next index is
%% tried (to avoid mixing up introduced names with existing ones).
%%
- %% The original names of variables are kept in the line number
- %% position of the abstract code: {var, {nos, OriginalName, L},
- %% NewName}. undo_no_shadows/1 re-creates the original code.
+ %% The original names of variables are kept in a table in State.
+ %% undo_no_shadows/2 re-creates the original code.
AllVars = sets:from_list(ordsets:to_list(qlc:vars(Forms0))),
?DEBUG("nos AllVars = ~p~n", [sets:to_list(AllVars)]),
VFun = fun(_Id, LC, Vs) -> nos(LC, Vs) end,
LI = ets:new(?APIMOD,[]),
UV = ets:new(?APIMOD,[]),
D0 = dict:new(),
- S1 = {LI, D0, UV, AllVars, []},
+ S1 = {LI, D0, UV, AllVars, [], State},
_ = qlc_mapfold(VFun, S1, Forms0, State),
?DEBUG("UsedIntroVars = ~p~n", [ets:match_object(UV, '_')]),
Singletons = ets:select(UV, ets:fun2ms(fun({K,0}) -> K end)),
@@ -2524,7 +2670,7 @@ no_shadows(Forms0, State) ->
true = ets:delete_all_objects(LI),
true = ets:delete_all_objects(UV),
%% Do it again, this time we know which variables are singletons.
- S2 = {LI, D0, UV, AllVars, Singletons},
+ S2 = {LI, D0, UV, AllVars, Singletons, State},
{Forms,_} = qlc_mapfold(VFun, S2, Forms0, State),
true = ets:delete(LI),
true = ets:delete(UV),
@@ -2568,11 +2714,11 @@ nos({lc,L,E0,Qs0}, S) ->
{Qs, S1} = lists:mapfoldl(F, S, Qs0),
{E, _} = nos(E0, S1),
{{lc,L,E,Qs}, S};
-nos({var,L,V}=Var, {_LI,Vs,UV,_A,_Sg}=S) when V =/= '_' ->
+nos({var,L,V}=Var, {_LI,Vs,UV,_A,_Sg,State}=S) when V =/= '_' ->
case used_var(V, Vs, UV) of
{true, VN} ->
- NL = nos_var(L, V),
- {{var,NL,VN}, S};
+ nos_var(L, V, State),
+ {{var,L,VN}, S};
false ->
{Var, S}
end;
@@ -2590,7 +2736,7 @@ nos_pattern([P0 | Ps0], S0, PVs0) ->
{P, S1, PVs1} = nos_pattern(P0, S0, PVs0),
{Ps, S, PVs} = nos_pattern(Ps0, S1, PVs1),
{[P | Ps], S, PVs};
-nos_pattern({var,L,V}, {LI,Vs0,UV,A,Sg}, PVs0) when V =/= '_' ->
+nos_pattern({var,L,V}, {LI,Vs0,UV,A,Sg,State}, PVs0) when V =/= '_' ->
{Name, Vs, PVs} =
case lists:keyfind(V, 1, PVs0) of
{V, VN} ->
@@ -2604,16 +2750,25 @@ nos_pattern({var,L,V}, {LI,Vs0,UV,A,Sg}, PVs0) when V =/= '_' ->
end,
{N, Vs1, [{V,VN} | PVs0]}
end,
- NL = nos_var(L, V),
- {{var,NL,Name}, {LI,Vs,UV,A,Sg}, PVs};
+ nos_var(L, V, State),
+ {{var,L,Name}, {LI,Vs,UV,A,Sg,State}, PVs};
nos_pattern(T, S0, PVs0) when is_tuple(T) ->
{TL, S, PVs} = nos_pattern(tuple_to_list(T), S0, PVs0),
{list_to_tuple(TL), S, PVs};
nos_pattern(T, S, PVs) ->
{T, S, PVs}.
-nos_var(L, Name) ->
- erl_parse:set_line(L, fun(Line) -> {nos,Name,Line} end).
+nos_var(Anno, Name, State) ->
+ NodeInfo = State#state.node_info,
+ Location = erl_anno:location(Anno),
+ case ets:lookup(NodeInfo, Location) of
+ [{Location, #{name := _}}] ->
+ true;
+ [{Location, Data}] ->
+ true = ets:insert(NodeInfo, {Location, Data#{name => Name}});
+ [] -> % cannot happen
+ true
+ end.
used_var(V, Vs, UV) ->
case dict:find(V, Vs) of
@@ -2638,69 +2793,30 @@ next_var(V, Vs, AllVars, LI, UV) ->
{VN, NVs}
end.
-undo_no_shadows(E) ->
- var_map(fun undo_no_shadows1/1, E).
-
-undo_no_shadows1({var, L, _}=Var) ->
- case erl_parse:get_attribute(L, line) of
- {line,{nos,V,_VL}} ->
- NL = erl_parse:set_line(L, fun({nos,_V,VL}) -> VL end),
- undo_no_shadows1({var, NL, V});
- _Else ->
- Var
- end.
-
-restore_line_numbers(E) ->
- var_map(fun restore_line_numbers1/1, E).
+undo_no_shadows(E, State) ->
+ var_map(fun(Anno) -> undo_no_shadows1(Anno, State) end, E).
-restore_line_numbers1({var, L, V}=Var) ->
- case erl_parse:get_attribute(L, line) of
- {line,{nos,_,_}} ->
- NL = erl_parse:set_line(L, fun({nos,_V,VL}) -> VL end),
- restore_line_numbers1({var, NL, V});
- _Else ->
+undo_no_shadows1({var, Anno, _}=Var, State) ->
+ Location = erl_anno:location(Anno),
+ NodeInfo = State#state.node_info,
+ case ets:lookup(NodeInfo, Location) of
+ [{Location, #{name := Name}}] ->
+ {var, Anno, Name};
+ _ ->
Var
end.
%% QLC identifier.
%% The first one encountered in the file has No=1.
-make_lcid(Attrs, No) when is_integer(No), No > 0 ->
- F = fun(Line) when is_integer(Line), Line < (1 bsl ?MAX_NUM_OF_LINES) ->
- sgn(Line) * ((No bsl ?MAX_NUM_OF_LINES) + sgn(Line) * Line)
- end,
- erl_parse:set_line(Attrs, F).
-
-is_lcid(Attrs) ->
- try
- {line,Id} = erl_parse:get_attribute(Attrs, line),
- is_integer(Id) andalso (abs(Id) > (1 bsl ?MAX_NUM_OF_LINES))
- catch _:_ ->
- false
- end.
-
-get_lcid_no(IdAttrs) ->
- {line,Id} = erl_parse:get_attribute(IdAttrs, line),
- abs(Id) bsr ?MAX_NUM_OF_LINES.
-
-get_lcid_line(IdAttrs) ->
- {line,Id} = erl_parse:get_attribute(IdAttrs, line),
- sgn(Id) * (abs(Id) band ((1 bsl ?MAX_NUM_OF_LINES) - 1)).
+make_lcid(Anno, No) when is_integer(No), No > 0 ->
+ {No, erl_anno:line(Anno)}.
-sgn(X) when X >= 0 ->
- 1;
-sgn(X) when X < 0 ->
- -1.
+get_lcid_no({No, _Line}) ->
+ No.
-seq(S, E) when S - E =:= 1 ->
- [];
-seq(S, E) ->
- lists:seq(S, E).
-
-sublist(_, 0) ->
- [];
-sublist(L, N) ->
- lists:sublist(L, N).
+get_lcid_line({_No, Line}) ->
+ Line.
qid(LCId, No) ->
#qid{no = No, lcid = LCId}.
diff --git a/lib/stdlib/src/shell.erl b/lib/stdlib/src/shell.erl
index 679c13f0cf..c6ba574ff4 100644
--- a/lib/stdlib/src/shell.erl
+++ b/lib/stdlib/src/shell.erl
@@ -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
@@ -314,7 +314,8 @@ prompt(N, Eval0, Bs0, RT, Ds0) ->
case get_prompt_func() of
{M,F} ->
L = [{history,N}],
- C = {call,1,{remote,1,{atom,1,M},{atom,1,F}},[{value,1,L}]},
+ A = erl_anno:new(1),
+ C = {call,A,{remote,A,{atom,A,M},{atom,A,F}},[{value,A,L}]},
{V,Eval,Bs,Ds} = shell_cmd([C], Eval0, Bs0, RT, Ds0, pmt),
{Eval,Bs,Ds,case V of
{pmt,Val} ->
@@ -416,7 +417,7 @@ expand_expr({call,_L,{atom,_,v},[N]}, C) ->
{_,undefined,_} ->
no_command(N);
{Ces,V,CommandN} when is_list(Ces) ->
- {value,CommandN,V}
+ {value,erl_anno:new(CommandN),V}
end;
expand_expr({call,L,F,Args}, C) ->
{call,L,expand_expr(F, C),expand_exprs(Args, C)};
@@ -901,7 +902,7 @@ prep_check({call,Line,{atom,_,f},[{var,_,_Name}]}) ->
{atom,Line,ok};
prep_check({value,_CommandN,_Val}) ->
%% erl_lint cannot handle the history expansion {value,_,_}.
- {atom,0,ok};
+ {atom,a0(),ok};
prep_check(T) when is_tuple(T) ->
list_to_tuple(prep_check(tuple_to_list(T)));
prep_check([E | Es]) ->
@@ -913,7 +914,7 @@ expand_records([], E0) ->
E0;
expand_records(UsedRecords, E0) ->
RecordDefs = [Def || {_Name,Def} <- UsedRecords],
- L = 1,
+ L = erl_anno:new(1),
E = prep_rec(E0),
Forms = RecordDefs ++ [{function,L,foo,0,[{clause,L,[],[],[E]}]}],
[{function,L,foo,0,[{clause,L,[],[],[NE]}]}] =
@@ -1320,13 +1321,15 @@ list_bindings([{Name,Val}|Bs], RT) ->
case erl_eval:fun_data(Val) of
{fun_data,_FBs,FCs0} ->
FCs = expand_value(FCs0), % looks nicer
- F = {'fun',0,{clauses,FCs}},
- M = {match,0,{var,0,Name},F},
+ A = a0(),
+ F = {'fun',A,{clauses,FCs}},
+ M = {match,A,{var,A,Name},F},
io:fwrite(<<"~ts\n">>, [erl_pp:expr(M, enc())]);
{named_fun_data,_FBs,FName,FCs0} ->
FCs = expand_value(FCs0), % looks nicer
- F = {named_fun,0,FName,FCs},
- M = {match,0,{var,0,Name},F},
+ A = a0(),
+ F = {named_fun,A,FName,FCs},
+ M = {match,A,{var,A,Name},F},
io:fwrite(<<"~ts\n">>, [erl_pp:expr(M, enc())]);
false ->
Namel = io_lib:fwrite(<<"~s = ">>, [Name]),
@@ -1356,13 +1359,18 @@ expand_value(E) ->
%% There is no abstract representation of funs.
try_abstract(V, CommandN) ->
try erl_parse:abstract(V)
- catch _:_ -> {call,0,{atom,0,v},[{integer,0,CommandN}]}
+ catch
+ _:_ ->
+ A = a0(),
+ {call,A,{atom,A,v},[{integer,A,CommandN}]}
end.
%% Rather than listing possibly huge results the calls to v/1 are shown.
prep_list_commands(E) ->
- substitute_v1(fun({value,CommandN,_V}) ->
- {call,0,{atom,0,v},[{integer,0,CommandN}]}
+ A = a0(),
+ substitute_v1(fun({value,Anno,_V}) ->
+ CommandN = erl_anno:line(Anno),
+ {call,A,{atom,A,v},[{integer,A,CommandN}]}
end, E).
substitute_v1(F, {value,_,_}=Value) ->
@@ -1374,6 +1382,9 @@ substitute_v1(F, [E | Es]) ->
substitute_v1(_F, E) ->
E.
+a0() ->
+ erl_anno:new(0).
+
check_and_get_history_and_results() ->
check_env(shell_history_length),
check_env(shell_saved_results),
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,
diff --git a/lib/stdlib/test/Makefile b/lib/stdlib/test/Makefile
index a271229c59..9bf10ea494 100644
--- a/lib/stdlib/test/Makefile
+++ b/lib/stdlib/test/Makefile
@@ -23,6 +23,7 @@ MODULES= \
dummy_via \
edlin_expand_SUITE \
epp_SUITE \
+ erl_anno_SUITE \
erl_eval_SUITE \
erl_expand_records_SUITE \
erl_internal_SUITE \
diff --git a/lib/stdlib/test/epp_SUITE.erl b/lib/stdlib/test/epp_SUITE.erl
index b17e8bd186..9ab170c826 100644
--- a/lib/stdlib/test/epp_SUITE.erl
+++ b/lib/stdlib/test/epp_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1998-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
@@ -211,7 +211,7 @@ predef_mac(Config) when is_list(Config) ->
?line File = filename:join(?config(data_dir, Config), "mac3.erl"),
?line {ok, List} = epp:parse_file(File, [], []),
?line [_,
- {attribute, LineCol1, l, Line1},
+ {attribute, Anno, l, Line1},
{attribute, _, f, File},
{attribute, _, machine1, _},
{attribute, _, module, mac3},
@@ -219,13 +219,9 @@ predef_mac(Config) when is_list(Config) ->
{attribute, _, ms, "mac3"},
{attribute, _, machine2, _}
| _] = List,
- ?line case LineCol1 of
- Line1 -> ok;
- {Line1,_} -> ok
- end,
+ Line1 = erl_anno:line(Anno),
ok.
-
variable_1(doc) ->
[];
variable_1(suite) ->
@@ -553,11 +549,7 @@ otp_7702(Config) when is_list(Config) ->
{ok, AC} = beam_lib:chunks(BeamFile, [abstract_code]),
{file_7702,[{abstract_code,{_,Forms}}]} = AC,
- Fun = fun(Attrs) ->
- {line, L} = erl_parse:get_attribute(Attrs, line),
- L
- end,
- Forms2 = [erl_lint:modify_line(Form, Fun) || Form <- Forms],
+ Forms2 = unopaque_forms(Forms),
?line
[{attribute,1,file,_},
_,
@@ -1395,9 +1387,10 @@ otp_10820(Config) when is_list(Config) ->
do_otp_10820(File, C, PC) ->
{ok,Node} = start_node(erl_pp_helper, "+fnu " ++ PC),
ok = rpc:call(Node, file, write_file, [File, C]),
- {ok,[{attribute,1,file,{File,1}},
- {attribute,2,module,any},
- {eof,2}]} = rpc:call(Node, epp, parse_file, [File, [],[]]),
+ {ok, Forms} = rpc:call(Node, epp, parse_file, [File, [],[]]),
+ [{attribute,1,file,{File,1}},
+ {attribute,2,module,any},
+ {eof,2}] = unopaque_forms(Forms),
true = test_server:stop_node(Node),
ok.
@@ -1440,15 +1433,15 @@ encoding(Config) when is_list(Config) ->
{attribute,1,module,encoding},
{error,_},
{error,{2,epp,cannot_parse}},
- {eof,2}]} = epp:parse_file(ErlFile, []),
+ {eof,2}]} = epp_parse_file(ErlFile, []),
{ok,[{attribute,1,file,_},
{attribute,1,module,encoding},
{eof,3}]} =
- epp:parse_file(ErlFile, [{default_encoding,latin1}]),
+ epp_parse_file(ErlFile, [{default_encoding,latin1}]),
{ok,[{attribute,1,file,_},
{attribute,1,module,encoding},
{eof,3}],[{encoding,none}]} =
- epp:parse_file(ErlFile, [{default_encoding,latin1},extra]),
+ epp_parse_file(ErlFile, [{default_encoding,latin1},extra]),
%% Try a latin-1 file with encoding given in a comment.
C2 = <<"-module(encoding).
@@ -1459,27 +1452,27 @@ encoding(Config) when is_list(Config) ->
{ok,[{attribute,1,file,_},
{attribute,1,module,encoding},
{eof,4}]} =
- epp:parse_file(ErlFile, []),
+ epp_parse_file(ErlFile, []),
{ok,[{attribute,1,file,_},
{attribute,1,module,encoding},
{eof,4}]} =
- epp:parse_file(ErlFile, [{default_encoding,latin1}]),
+ epp_parse_file(ErlFile, [{default_encoding,latin1}]),
{ok,[{attribute,1,file,_},
{attribute,1,module,encoding},
{eof,4}]} =
- epp:parse_file(ErlFile, [{default_encoding,utf8}]),
+ epp_parse_file(ErlFile, [{default_encoding,utf8}]),
{ok,[{attribute,1,file,_},
{attribute,1,module,encoding},
{eof,4}],[{encoding,latin1}]} =
- epp:parse_file(ErlFile, [extra]),
+ epp_parse_file(ErlFile, [extra]),
{ok,[{attribute,1,file,_},
{attribute,1,module,encoding},
{eof,4}],[{encoding,latin1}]} =
- epp:parse_file(ErlFile, [{default_encoding,latin1},extra]),
+ epp_parse_file(ErlFile, [{default_encoding,latin1},extra]),
{ok,[{attribute,1,file,_},
{attribute,1,module,encoding},
{eof,4}],[{encoding,latin1}]} =
- epp:parse_file(ErlFile, [{default_encoding,utf8},extra]),
+ epp_parse_file(ErlFile, [{default_encoding,utf8},extra]),
ok.
@@ -1552,6 +1545,17 @@ errs([_|L], File) ->
errs([], _File) ->
[].
+epp_parse_file(File, Opts) ->
+ case epp:parse_file(File, Opts) of
+ {ok, Forms} ->
+ {ok, unopaque_forms(Forms)};
+ {ok, Forms, Other} ->
+ {ok, unopaque_forms(Forms), Other}
+ end.
+
+unopaque_forms(Forms) ->
+ [erl_parse:anno_to_term(Form) || Form <- Forms].
+
run_test(Config, Test0) ->
Test = [<<"-module(epp_test). -compile(export_all). ">>, Test0],
Filename = "epp_test.erl",
diff --git a/lib/stdlib/test/erl_anno_SUITE.erl b/lib/stdlib/test/erl_anno_SUITE.erl
new file mode 100644
index 0000000000..7632fbd324
--- /dev/null
+++ b/lib/stdlib/test/erl_anno_SUITE.erl
@@ -0,0 +1,569 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-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_SUITE).
+
+%-define(debug, true).
+
+-ifdef(debug).
+-include_lib("test_server/include/test_server.hrl").
+-define(format(S, A), io:format(S, A)).
+-else.
+-include_lib("test_server/include/test_server.hrl").
+-define(format(S, A), ok).
+-endif.
+
+-export([all/0, suite/0, groups/0, init_per_suite/1, end_per_suite/1,
+ init_per_group/2, end_per_group/2,
+ init_per_testcase/2, end_per_testcase/2]).
+
+-export([new/1, is_anno/1, generated/1, end_location/1, file/1,
+ line/1, location/1, record/1, text/1, bad/1, neg_line/1]).
+
+-export([parse_abstract/1, mapfold_anno/1]).
+
+all() ->
+ [{group, anno}, {group, parse}].
+
+groups() ->
+ [{anno, [], [new, is_anno, generated, end_location, file,
+ line, location, record, text, bad, neg_line]},
+ {parse, [], [parse_abstract, mapfold_anno]}].
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+init_per_testcase(_Case, Config) ->
+ Dog=?t:timetrap(?t:minutes(1)),
+ [{watchdog, Dog}|Config].
+
+end_per_testcase(_Case, _Config) ->
+ Dog=?config(watchdog, _Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+-define(INFO(T, V), {T, V}).
+
+-dialyzer({no_fail_call, new/1}).
+new(doc) ->
+ ["Test erl_anno:new/1"];
+new(_Config) ->
+ {'EXIT', {badarg, _}} =
+ (catch erl_anno:new([{location,1},{text, "text"}])), % badarg
+ ok.
+
+is_anno(doc) ->
+ ["Test erl_anno:is_anno/1"];
+is_anno(_Config) ->
+ false = erl_anno:is_anno(a),
+ false = erl_anno:is_anno({a}),
+ false = erl_anno:is_anno([]),
+ false = erl_anno:is_anno([{location, 1}|{generated, true}]),
+ false = erl_anno:is_anno([{generated,false}]),
+ false = erl_anno:is_anno([{generated,true}]),
+ false = erl_anno:is_anno([{location,1},{file,nofile}]),
+ false = erl_anno:is_anno([{location,1},{text,notext}]),
+ false = erl_anno:is_anno([{location,1},{text,[a,b,c]}]),
+
+ true = erl_anno:is_anno(erl_anno:new(1)),
+ A0 = erl_anno:new({1, 17}),
+ true = erl_anno:is_anno(A0),
+ A1 = erl_anno:set_generated(true, A0),
+ true = erl_anno:is_anno(A1),
+ A2 = erl_anno:set_file("", A1),
+ true = erl_anno:is_anno(A2),
+ A3 = erl_anno:set_record(true, A2),
+ true = erl_anno:is_anno(A3),
+ A4 = erl_anno:set_text("text", A3),
+ true = erl_anno:is_anno(A4),
+ A5 = erl_anno:set_file(<<"filename">>, A4),
+ true = erl_anno:is_anno(A5),
+ ok.
+
+generated(doc) ->
+ ["Test 'generated'"];
+generated(_Config) ->
+ test(1, [{generated, true}, {generated, false}]),
+ test(1, [{generated, false}, {generated, true}, {generated, false}]),
+ test({1, 17}, [{generated, false},
+ {generated, true},
+ {generated, false}]),
+ test({1, 17}, [{text, "text", [{end_location, {1, 21}}, {length, 4}]},
+ {generated, false},
+ {generated, true},
+ {generated, false}]),
+ test(1, [{generated, false},
+ {generated, true},
+ {generated, false}]),
+ test(1, [{text, "text", [{end_location, 1}, {length, 4}]},
+ {generated, false},
+ {generated, true},
+ {generated, false}]),
+ ok.
+
+end_location(doc) ->
+ ["Test 'end_location'"];
+end_location(_Config) ->
+ test({1, 17}, [{text, "TEXT", [{end_location, {1, 21}}, {length, 4}]},
+ {text, "TEXT\n", [{end_location, {2, 1}}, {length, 5}]},
+ {text, "TEXT\ntxt", [{end_location, {2, 4}}, {length, 8}]}]),
+ test(1, [{text, "TEXT", [{end_location, 1}, {length, 4}]},
+ {text, "TEXT\n", [{end_location, 2}, {length, 5}]},
+ {text, "TEXT\ntxt", [{end_location, 2}, {length, 8}]}]),
+ ok.
+
+file(doc) ->
+ ["Test 'file'"];
+file(_Config) ->
+ test(1, [{file, "name"}, {file, ""}]),
+ test({1, 17}, [{file, "name"}, {file, ""}]),
+ ok.
+
+line(doc) ->
+ ["Test 'line'"];
+line(_Config) ->
+ test(1, [{line, 17, [{location, 17}]},
+ {location, {9, 8}, [{line, 9}, {column, 8}]},
+ {line, 14, [{location, {14, 8}}]}]),
+ ok.
+
+location(doc) ->
+ ["Test 'location'"];
+location(_Config) ->
+ test(1, [{location, 2, [{line,2}]},
+ {location, {1, 17}, [{line, 1}, {column, 17}]},
+ {location, {9, 6}, [{line, 9}, {column, 6}]},
+ {location, 9, [{column, undefined}]}]),
+ test(1, [{generated, true},
+ {location, 2, [{line,2}]},
+ {location, {1, 17}, [{line, 1}, {column, 17}]},
+ {location, {9, 6}, [{line, 9}, {column, 6}]},
+ {location, 9, [{column, undefined}]}]),
+ test(1, [{record, true},
+ {location, 2, [{line,2}]},
+ {location, {1, 17}, [{line, 1}, {column, 17}]},
+ {location, {9, 6}, [{line, 9}, {column, 6}]},
+ {location, 9, [{column, undefined}]}]),
+ ok.
+
+record(doc) ->
+ ["Test 'record'"];
+record(_Config) ->
+ test({1, 17}, [{record, true}, {record, false}]),
+ test(1, [{record, true}, {record, false}]),
+ test({1, 17}, [{generated, false},
+ {generated, true},
+ {generated, false}]),
+ test({1, 17}, [{text, "text", [{end_location, {1, 21}}, {length, 4}]},
+ {generated, false},
+ {generated, true},
+ {generated, false}]),
+ test(1, [{generated, false},
+ {generated, true},
+ {generated, false}]),
+ test(1, [{text, "text", [{end_location, 1}, {length, 4}]},
+ {generated, false},
+ {generated, true},
+ {generated, false}]),
+ ok.
+
+text(doc) ->
+ ["Test 'text'"];
+text(_Config) ->
+ test(1, [{text, "text", [{end_location, 1}, {length, 4}]},
+ {text, "", [{end_location, 1}, {length, 0}]}]),
+ test({1, 17}, [{text, "text", [{end_location, {1,21}}, {length, 4}]},
+ {text, "", [{end_location, {1,17}}, {length, 0}]}]),
+ ok.
+
+-dialyzer({[no_opaque, no_fail_call], bad/1}).
+bad(doc) ->
+ ["Test bad annotations"];
+bad(_Config) ->
+ Line = erl_anno:new(1),
+ LineColumn = erl_anno:new({1, 17}),
+ {'EXIT', {badarg, _}} =
+ (catch erl_anno:set_generated(true, bad)), % 3rd arg not opaque
+ {'EXIT', {badarg, _}} =
+ (catch erl_anno:set_generated(false, bad)), % 3rd arg not opaque
+ {'EXIT', {badarg, _}} =
+ (catch erl_anno:set_generated(19, Line)),
+ {'EXIT', {badarg, _}} =
+ (catch erl_anno:set_generated(19, LineColumn)),
+
+ {'EXIT', {badarg, _}} =
+ (catch erl_anno:generated(bad)), % 1st arg not opaque
+ {'EXIT', {badarg, _}} =
+ (catch erl_anno:end_location(bad)), % 1st arg not opaque
+ {'EXIT', {badarg, _}} =
+ (catch erl_anno:file(bad)), % 1st arg not opaque
+ {'EXIT', {badarg, _}} =
+ (catch erl_anno:text(bad)), % 1st arg not opaque
+ {'EXIT', {badarg, _}} =
+ (catch erl_anno:record(bad)), % 1st arg not opaque
+ ok.
+
+neg_line(doc) ->
+ ["Test negative line numbers (OTP 18)"];
+neg_line(_Config) ->
+ neg_line1(false),
+ neg_line1(true),
+ ok.
+
+neg_line1(TextToo) ->
+ Minus8_0 = erl_anno:new(-8),
+ Plus8_0 = erl_anno:new(8),
+ Minus8C_0 = erl_anno:new({-8, 17}),
+ Plus8C_0 = erl_anno:new({8, 17}),
+
+ [Minus8, Plus8, Minus8C, Plus8C] =
+ [case TextToo of
+ true ->
+ erl_anno:set_text("foo", A);
+ false ->
+ A
+ end || A <- [Minus8_0, Plus8_0, Minus8C_0, Plus8C_0]],
+
+ tst(-3, erl_anno:set_location(3, Minus8)),
+ tst(-3, erl_anno:set_location(-3, Plus8)),
+ tst(-3, erl_anno:set_location(-3, Minus8)),
+ tst({-3,9}, erl_anno:set_location({3, 9}, Minus8)),
+ tst({-3,9}, erl_anno:set_location({-3, 9}, Plus8)),
+ tst({-3,9}, erl_anno:set_location({-3, 9}, Minus8)),
+ tst(-3, erl_anno:set_location(3, Minus8C)),
+ tst(-3, erl_anno:set_location(-3, Plus8C)),
+ tst(-3, erl_anno:set_location(-3, Minus8C)),
+ tst({-3,9}, erl_anno:set_location({3, 9}, Minus8C)),
+ tst({-3,9}, erl_anno:set_location({-3, 9}, Plus8C)),
+ tst({-3,9}, erl_anno:set_location({-3, 9}, Minus8C)),
+
+ tst(-8, erl_anno:set_generated(true, Plus8)),
+ tst(-8, erl_anno:set_generated(true, Minus8)),
+ tst({-8,17}, erl_anno:set_generated(true, Plus8C)),
+ tst({-8,17}, erl_anno:set_generated(true, Minus8C)),
+ tst(8, erl_anno:set_generated(false, Plus8)),
+ tst(8, erl_anno:set_generated(false, Minus8)),
+ tst({8,17}, erl_anno:set_generated(false, Plus8C)),
+ tst({8,17}, erl_anno:set_generated(false, Minus8C)),
+
+ tst(-3, erl_anno:set_line(3, Minus8)),
+ tst(-3, erl_anno:set_line(-3, Plus8)),
+ tst(-3, erl_anno:set_line(-3, Minus8)),
+ tst({-3,17}, erl_anno:set_line(3, Minus8C)),
+ tst({-3,17}, erl_anno:set_line(-3, Plus8C)),
+ tst({-3,17}, erl_anno:set_line(-3, Minus8C)),
+ ok.
+
+tst(Term, Anno) ->
+ ?format("Term: ~p\n", [Term]),
+ ?format("Anno: ~p\n", [Anno]),
+ case anno_to_term(Anno) of
+ Term ->
+ ok;
+ Else ->
+ case lists:keyfind(location, 1, Else) of
+ {location, Term} ->
+ ok;
+ _Else2 ->
+ ?format("Else2 ~p\n", [_Else2]),
+ io:format("expected ~p\n got ~p\n", [Term, Else]),
+ exit({Term, Else})
+ end
+ end.
+
+parse_abstract(doc) ->
+ ["Test erl_parse:new_anno/1, erl_parse:anno_to_term/1"
+ ", and erl_parse:anno_from_term/1"];
+parse_abstract(_Config) ->
+ T = sample_term(),
+ A = erl_parse:abstract(T, [{line,17}]),
+ T1 = erl_parse:anno_to_term(A),
+ Abstr = erl_parse:new_anno(T1),
+ T = erl_parse:normalise(Abstr),
+ Abstr2 = erl_parse:anno_from_term(T1),
+ T = erl_parse:normalise(Abstr2),
+ ok.
+
+mapfold_anno(doc) ->
+ ["Test erl_parse:{map_anno/2,fold_anno/3, and mapfold_anno/3}"];
+mapfold_anno(_Config) ->
+ T = sample_term(),
+ Abstr = erl_parse:abstract(T),
+ CF = fun(Anno, {L, D}) ->
+ {erl_anno:new(L), {L+1, dict:store(L, Anno, D)}}
+ end,
+ {U, {N, D}} = erl_parse:mapfold_anno(CF, {1, dict:new()}, Abstr),
+ SeqA = erl_parse:fold_anno(fun(Anno, Acc) -> [Anno|Acc] end, [], U),
+ Seq = [erl_anno:location(A) || A <- SeqA],
+ Seq = lists:seq(N-1, 1, -1),
+ NF = fun(Anno) ->
+ L = erl_anno:location(Anno),
+ dict:fetch(L, D)
+ end,
+ Abstr = erl_parse:map_anno(NF, U),
+ ok.
+
+sample_term() ->
+ %% This is just a sample.
+ {3,a,4.0,"foo",<<"bar">>,#{a => <<19:64/unsigned-little>>},
+ [1000,2000]}.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+test(StartLocation, Updates) ->
+ S0 = init(StartLocation),
+ A0 = erl_anno:new(StartLocation),
+ chk(S0, A0, []),
+ eval(Updates, S0, A0).
+
+eval([], _S0, _A0) ->
+ ok;
+eval([{Item, Value}|Updates], S0, A0) ->
+ {S, A} = set(Item, Value, A0, S0, []),
+ eval(Updates, S, A);
+eval([{Item, Value, Secondary}|Updates], S0, A0) ->
+ {S, A} = set(Item, Value, A0, S0, Secondary),
+ eval(Updates, S, A).
+
+init({Line, Column}) ->
+ lists:sort([{location, {Line, Column}} | default()]);
+init(Line) when is_integer(Line) ->
+ lists:sort([{location, Line} | default()]).
+
+set(Item, Value, Anno0, State0, Secondary) ->
+ true = lists:member(Item, primary_items()),
+ ?format("Set '~w' to ~p\n", [Item, Value]),
+ State = set_value(Item, Value, State0),
+ Anno = anno_set(Item, Value, Anno0),
+ ?format("State0 ~p\n", [State0]),
+ ?format("State ~p\n", [State]),
+ ?format("Anno0 ~p\n", [anno_to_term(Anno0)]),
+ ?format("Anno ~p\n", [anno_to_term(Anno)]),
+ chk(State, Anno, Secondary),
+ ok = frame(Anno0, Anno, Secondary),
+ {State, Anno}.
+
+frame(OldAnno, NewAnno, Secondary) ->
+ SecItems = [I || {I, _} <- Secondary],
+ Frame = secondary_items() -- (SecItems ++ primary_items()),
+ ?format("Frame items ~p\n", [Frame]),
+ frame1(Frame, OldAnno, NewAnno).
+
+frame1([], _OldAnno, _NewAnno) ->
+ ok;
+frame1([Item|Items], OldAnno, NewAnno) ->
+ V1 = anno_info(OldAnno, Item),
+ V2 = anno_info(NewAnno, Item),
+ ok = check_value(Item, V1, V2),
+ frame1(Items, OldAnno, NewAnno).
+
+chk(State, Anno, Secondary) ->
+ ok = check_simple(Anno),
+ ok = chk_primary(State, Anno),
+ ok = check_secondary(Secondary, State, Anno).
+
+chk_primary(State, Anno) ->
+ chk_primary(primary_items(), State, Anno).
+
+chk_primary([], _State, _Anno) ->
+ ok;
+chk_primary([Item | Items], State, Anno) ->
+ V1 = primary_value(Item, State),
+ V2 = anno_info(Anno, Item),
+ ok = check_value(Item, V1, V2),
+ chk_primary(Items, State, Anno).
+
+check_secondary([], _State, _Anno) ->
+ ok;
+check_secondary([{Item, _}=V1 | Secondary], State, Anno) ->
+ V2 = anno_info(Anno, Item),
+ case {V1, V2} of
+ {{Item, undefined}, undefined} ->
+ ok;
+ _ ->
+ ok = check_value(Item, V1, V2)
+ end,
+ check_secondary(Secondary, State, Anno).
+
+check_value(Item, V1, V2) ->
+ ?format("~w: V1 ~p\n", [Item, V1]),
+ ?format("~w: V2 ~p\n", [Item, V2]),
+ case V1 =:= V2 of
+ true ->
+ ok;
+ false ->
+ io:format("~w: expected ~p\n got ~p\n", [Item, V1, V2]),
+ exit({V1, V2})
+ end.
+
+check_simple(Anno) ->
+ Term = anno_to_term(Anno),
+ case find_defaults(Term) of
+ [] ->
+ ok;
+ Ds ->
+ io:format("found default values ~w in ~p\n", [Ds, Anno]),
+ exit({defaults, Anno})
+ end,
+ case check_simple1(Term) of
+ true ->
+ ok;
+ false ->
+ io:format("not simple ~p\n", [Anno]),
+ exit({not_simple, Anno})
+ end.
+
+check_simple1(L) when is_integer(L) ->
+ true;
+check_simple1({L, C}) when is_integer(L), is_integer(C) ->
+ true;
+check_simple1(List) ->
+ case lists:sort(List) of
+ [{location, _}] ->
+ false;
+ _ ->
+ true
+ end.
+
+find_defaults(L) when is_list(L) ->
+ [I ||
+ I <- default_items(),
+ {I1, Value} <- L,
+ I =:= I1,
+ Value =:= default_value(I)];
+find_defaults(_) ->
+ [].
+
+anno_to_term(Anno) ->
+ T = erl_anno:to_term(Anno),
+ maybe_sort(T).
+
+maybe_sort(L) when is_list(L) ->
+ lists:sort(L);
+maybe_sort(T) ->
+ T.
+
+anno_set(file, Value, Anno) ->
+ erl_anno:set_file(Value, Anno);
+anno_set(generated, Value, Anno) ->
+ erl_anno:set_generated(Value, Anno);
+anno_set(line, Value, Anno) ->
+ erl_anno:set_line(Value, Anno);
+anno_set(location, Value, Anno) ->
+ erl_anno:set_location(Value, Anno);
+anno_set(record, Value, Anno) ->
+ erl_anno:set_record(Value, Anno);
+anno_set(text, Value, Anno) ->
+ erl_anno:set_text(Value, Anno).
+
+anno_info(Anno, Item) ->
+ Value =
+ case Item of
+ column ->
+ erl_anno:column(Anno);
+ generated ->
+ erl_anno:generated(Anno);
+ end_location ->
+ erl_anno:end_location(Anno);
+ file ->
+ erl_anno:file(Anno);
+ length ->
+ case erl_anno:text(Anno) of
+ undefined ->
+ undefined;
+ Text ->
+ length(Text)
+ end;
+ line ->
+ erl_anno:line(Anno);
+ location ->
+ erl_anno:location(Anno);
+ record ->
+ erl_anno:record(Anno);
+ text ->
+ erl_anno:text(Anno);
+ _ ->
+ erlang:error(badarg, [Anno, Item])
+ end,
+ if
+ Value =:= undefined ->
+ undefined;
+ true ->
+ {Item, Value}
+ end.
+
+%%% Originally 'location' was primary while 'line' and 'column' were
+%%% secondary (their values are determined by 'location'). But since
+%%% set_line() is used kind of frequently, 'line' is also primary,
+%%% and 'location' secondary (depends on 'line'). 'line' need to be
+%%% handled separately.
+
+set_value(line, Line, State) ->
+ {location, Location} = primary_value(location, State),
+ NewLocation = case Location of
+ {_, Column} ->
+ {Line, Column};
+ _ ->
+ Line
+ end,
+ set_value(location, NewLocation, State);
+set_value(Item, Value, State) ->
+ lists:ukeymerge(1, [{Item, Value}], State).
+
+primary_value(line, State) ->
+ {location, Location} = primary_value(location, State),
+ {line, case Location of
+ {Line, _} ->
+ Line;
+ Line ->
+ Line
+ end};
+primary_value(Item, State) ->
+ case lists:keyfind(Item, 1, State) of
+ false ->
+ undefined;
+ Tuple ->
+ Tuple
+ end.
+
+default() ->
+ [{Tag, default_value(Tag)} || Tag <- default_items()].
+
+primary_items() ->
+ [file, generated, line, location, record, text].
+
+secondary_items() ->
+ %% 'length' has not been implemented
+ [column, end_location, length, line, location].
+
+default_items() ->
+ [generated, record].
+
+default_value(generated) -> false;
+default_value(record) -> false.
diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl
index a7c3fd3c2e..c0d9b7c466 100644
--- a/lib/stdlib/test/erl_lint_SUITE.erl
+++ b/lib/stdlib/test/erl_lint_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1999-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
@@ -64,7 +64,7 @@
too_many_arguments/1,
basic_errors/1,bin_syntax_errors/1,
predef/1,
- maps/1,maps_type/1,otp_11851/1
+ maps/1,maps_type/1,otp_11851/1,otp_12195/1
]).
% Default timetrap timeout (set in init_per_testcase).
@@ -93,7 +93,7 @@ all() ->
bif_clash, behaviour_basic, behaviour_multiple, otp_11861,
otp_7550, otp_8051, format_warn, {group, on_load},
too_many_arguments, basic_errors, bin_syntax_errors, predef,
- maps, maps_type, otp_11851].
+ maps, maps_type, otp_11851, otp_12195].
groups() ->
[{unused_vars_warn, [],
@@ -3834,6 +3834,40 @@ otp_11851(Config) when is_list(Config) ->
[] = run(Config, Ts),
ok.
+otp_12195(doc) ->
+ "OTP-12195: Check obsolete types (tailor made for OTP 18).";
+otp_12195(Config) when is_list(Config) ->
+ Ts = [{otp_12195_1,
+ <<"-export_type([r1/0]).
+ -type r1() :: erl_scan:line()
+ | erl_scan:column()
+ | erl_scan:location()
+ | erl_anno:line().">>,
+ [],
+ {warnings,[{2,erl_lint,
+ {deprecated_type,{erl_scan,line,0},
+ "deprecated (will be removed in OTP 19); "
+ "use erl_anno:line() instead"}},
+ {3,erl_lint,
+ {deprecated_type,{erl_scan,column,0},
+ "deprecated (will be removed in OTP 19); use "
+ "erl_anno:column() instead"}},
+ {4,erl_lint,
+ {deprecated_type,{erl_scan,location,0},
+ "deprecated (will be removed in OTP 19); "
+ "use erl_anno:location() instead"}}]}},
+ {otp_12195_2,
+ <<"-export_type([r1/0]).
+ -compile(nowarn_deprecated_type).
+ -type r1() :: erl_scan:line()
+ | erl_scan:column()
+ | erl_scan:location()
+ | erl_anno:line().">>,
+ [],
+ []}],
+ [] = run(Config, Ts),
+ ok.
+
run(Config, Tests) ->
F = fun({N,P,Ws,E}, BadL) ->
case catch run_test(Config, P, Ws) of
diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl
index f71446dd64..1d63c8e17e 100644
--- a/lib/stdlib/test/erl_pp_SUITE.erl
+++ b/lib/stdlib/test/erl_pp_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2006-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
@@ -490,7 +490,7 @@ cond1(Config) when is_list(Config) ->
[{cons,3,{atom,3,a},{cons,3,{atom,3,b},{nil,3}}}]},
{clause,4,[],[[{atom,4,true}]],
[{tuple,5,[{atom,5,x},{atom,5,y}]}]}]},
- ?line CChars = lists:flatten(erl_pp:expr(C)),
+ CChars = flat_expr1(C),
% ?line "cond {foo,bar} -> [a,b]; true -> {x,y} end" = CChars,
?line "cond\n"
" {foo,bar} ->\n"
@@ -557,7 +557,7 @@ messages(Config) when is_list(Config) ->
lists:flatten(erl_pp:form({error,{some,"error"}})),
?line true = "{warning,{some,\"warning\"}}\n" =:=
lists:flatten(erl_pp:form({warning,{some,"warning"}})),
- ?line true = "\n" =:= lists:flatten(erl_pp:form({eof,0})),
+ "\n" = flat_form({eof,0}),
ok.
import_export(suite) ->
@@ -616,27 +616,29 @@ hook(Config) when is_list(Config) ->
do_hook(HookFun) ->
Lc = parse_expr(binary_to_list(<<"[X || X <- [1,2,3]].">>)),
H = HookFun(fun hook/4),
- Expr = {call,0,{atom,0,fff},[{foo,Lc},{foo,Lc},{foo,Lc}]},
+ A0 = erl_anno:new(0),
+ Expr = {call,A0,{atom,A0,fff},[{foo,Lc},{foo,Lc},{foo,Lc}]},
EChars = lists:flatten(erl_pp:expr(Expr, 0, H)),
- Call = {call,0,{atom,0,foo},[Lc]},
- Expr2 = {call,0,{atom,0,fff},[Call,Call,Call]},
+ Call = {call,A0,{atom,A0,foo},[Lc]},
+ Expr2 = {call,A0,{atom,A0,fff},[Call,Call,Call]},
EChars2 = erl_pp:exprs([Expr2]),
?line true = EChars =:= lists:flatten(EChars2),
EsChars = erl_pp:exprs([Expr], H),
?line true = EChars =:= lists:flatten(EsChars),
- F = {function,1,ffff,0,[{clause,1,[],[],[Expr]}]},
+ A1 = erl_anno:new(1),
+ F = {function,A1,ffff,0,[{clause,A1,[],[],[Expr]}]},
FuncChars = lists:flatten(erl_pp:function(F, H)),
- F2 = {function,1,ffff,0,[{clause,1,[],[],[Expr2]}]},
+ F2 = {function,A1,ffff,0,[{clause,A1,[],[],[Expr2]}]},
FuncChars2 = erl_pp:function(F2),
?line true = FuncChars =:= lists:flatten(FuncChars2),
FFormChars = erl_pp:form(F, H),
?line true = FuncChars =:= lists:flatten(FFormChars),
- A = {attribute,1,record,{r,[{record_field,1,{atom,1,a},Expr}]}},
+ A = {attribute,A1,record,{r,[{record_field,A1,{atom,A1,a},Expr}]}},
AChars = lists:flatten(erl_pp:attribute(A, H)),
- A2 = {attribute,1,record,{r,[{record_field,1,{atom,1,a},Expr2}]}},
+ A2 = {attribute,A1,record,{r,[{record_field,A1,{atom,A1,a},Expr2}]}},
AChars2 = erl_pp:attribute(A2),
?line true = AChars =:= lists:flatten(AChars2),
AFormChars = erl_pp:form(A, H),
@@ -645,10 +647,10 @@ do_hook(HookFun) ->
?line "INVALID-FORM:{foo,bar}:" = lists:flatten(erl_pp:expr({foo,bar})),
%% A list (as before R6), not a list of lists.
- G = [{op,1,'>',{atom,1,a},{foo,{atom,1,b}}}], % not a proper guard
+ G = [{op,A1,'>',{atom,A1,a},{foo,{atom,A1,b}}}], % not a proper guard
GChars = lists:flatten(erl_pp:guard(G, H)),
- G2 = [{op,1,'>',{atom,1,a},
- {call,0,{atom,0,foo},[{atom,1,b}]}}], % not a proper guard
+ G2 = [{op,A1,'>',{atom,A1,a},
+ {call,A0,{atom,A0,foo},[{atom,A1,b}]}}], % not a proper guard
GChars2 = erl_pp:guard(G2),
?line true = GChars =:= lists:flatten(GChars2),
@@ -659,14 +661,14 @@ do_hook(HookFun) ->
?line true = EChars =:= lists:flatten(XEChars2),
%% Note: no leading spaces before "begin".
- Block = {block,0,[{match,0,{var,0,'A'},{integer,0,3}},
- {atom,0,true}]},
+ Block = {block,A0,[{match,A0,{var,A0,'A'},{integer,A0,3}},
+ {atom,A0,true}]},
?line "begin\n A =" ++ _ =
lists:flatten(erl_pp:expr(Block, 17, none)),
%% Special...
?line true =
- "{some,value}" =:= lists:flatten(erl_pp:expr({value,0,{some,value}})),
+ "{some,value}" =:= lists:flatten(erl_pp:expr({value,A0,{some,value}})),
%% Silly...
?line true =
@@ -674,8 +676,8 @@ do_hook(HookFun) ->
flat_expr({'if',0,[{clause,0,[],[],[{atom,0,0}]}]}),
%% More compatibility: before R6
- OldIf = {'if',0,[{clause,0,[],[{atom,0,true}],[{atom,0,b}]}]},
- NewIf = {'if',0,[{clause,0,[],[[{atom,0,true}]],[{atom,0,b}]}]},
+ OldIf = {'if',A0,[{clause,A0,[],[{atom,A0,true}],[{atom,A0,b}]}]},
+ NewIf = {'if',A0,[{clause,A0,[],[[{atom,A0,true}]],[{atom,A0,b}]}]},
OldIfChars = lists:flatten(erl_pp:expr(OldIf)),
NewIfChars = lists:flatten(erl_pp:expr(NewIf)),
?line true = OldIfChars =:= NewIfChars,
@@ -691,7 +693,8 @@ ehook(HE, I, P, H, foo, bar) ->
hook(HE, I, P, H).
hook({foo,E}, I, P, H) ->
- erl_pp:expr({call,0,{atom,0,foo},[E]}, I, P, H).
+ A = erl_anno:new(0),
+ erl_pp:expr({call,A,{atom,A,foo},[E]}, I, P, H).
neg_indent(suite) ->
[];
@@ -774,7 +777,7 @@ otp_6911(Config) when is_list(Config) ->
{var,6,'X'},
[{clause,7,[{atom,7,true}],[],[{integer,7,12}]},
{clause,8,[{atom,8,false}],[],[{integer,8,14}]}]}]}]},
- ?line Chars = lists:flatten(erl_pp:form(F)),
+ Chars = flat_form(F),
?line "thomas(X) ->\n"
" case X of\n"
" true ->\n"
@@ -1084,10 +1087,11 @@ otp_10302(Config) when is_list(Config) ->
Opts = [{hook, fun unicode_hook/4},{encoding,unicode}],
Lc = parse_expr("[X || X <- [\"\x{400}\",\"\xFF\"]]."),
- Expr = {call,0,{atom,0,fff},[{foo,{foo,Lc}},{foo,{foo,Lc}}]},
+ A0 = erl_anno:new(0),
+ Expr = {call,A0,{atom,A0,fff},[{foo,{foo,Lc}},{foo,{foo,Lc}}]},
EChars = lists:flatten(erl_pp:expr(Expr, 0, Opts)),
- Call = {call,0,{atom,0,foo},[{call,0,{atom,0,foo},[Lc]}]},
- Expr2 = {call,0,{atom,0,fff},[Call,Call]},
+ Call = {call,A0,{atom,A0,foo},[{call,A0,{atom,A0,foo},[Lc]}]},
+ Expr2 = {call,A0,{atom,A0,fff},[Call,Call]},
EChars2 = erl_pp:exprs([Expr2], U),
EChars = lists:flatten(EChars2),
[$\x{400},$\x{400}] = [C || C <- EChars, C > 255],
@@ -1097,7 +1101,8 @@ otp_10302(Config) when is_list(Config) ->
ok.
unicode_hook({foo,E}, I, P, H) ->
- erl_pp:expr({call,0,{atom,0,foo},[E]}, I, P, H).
+ A = erl_anno:new(0),
+ erl_pp:expr({call,A,{atom,A,foo},[E]}, I, P, H).
otp_10820(doc) ->
"OTP-10820. Unicode filenames.";
@@ -1137,29 +1142,30 @@ otp_11100(Config) when is_list(Config) ->
%% Cannot trigger the use of the hook function with export/import.
"-export([{fy,a}/b]).\n" =
pf({attribute,1,export,[{{fy,a},b}]}),
+ A1 = erl_anno:new(1),
"-type foo() :: integer(INVALID-FORM:{foo,bar}:).\n" =
- pf({attribute,1,type,{foo,{type,1,integer,[{foo,bar}]},[]}}),
- pf({attribute,1,type,
- {a,{type,1,range,[{integer,1,1},{foo,bar}]},[]}}),
+ pf({attribute,A1,type,{foo,{type,A1,integer,[{foo,bar}]},[]}}),
+ pf({attribute,A1,type,
+ {a,{type,A1,range,[{integer,A1,1},{foo,bar}]},[]}}),
"-type foo(INVALID-FORM:{foo,bar}:) :: A.\n" =
- pf({attribute,1,type,{foo,{var,1,'A'},[{foo,bar}]}}),
+ pf({attribute,A1,type,{foo,{var,A1,'A'},[{foo,bar}]}}),
"-type foo() :: (INVALID-FORM:{foo,bar}: :: []).\n" =
- pf({attribute,1,type,
- {foo,{paren_type,1,
- [{ann_type,1,[{foo,bar},{type,1,nil,[]}]}]},
+ pf({attribute,A1,type,
+ {foo,{paren_type,A1,
+ [{ann_type,A1,[{foo,bar},{type,A1,nil,[]}]}]},
[]}}),
"-type foo() :: <<_:INVALID-FORM:{foo,bar}:>>.\n" =
- pf({attribute,1,type,
- {foo,{type,1,binary,[{foo,bar},{integer,1,0}]},[]}}),
+ pf({attribute,A1,type,
+ {foo,{type,A1,binary,[{foo,bar},{integer,A1,0}]},[]}}),
"-type foo() :: <<_:10, _:_*INVALID-FORM:{foo,bar}:>>.\n" =
- pf({attribute,1,type,
- {foo,{type,1,binary,[{integer,1,10},{foo,bar}]},[]}}),
+ pf({attribute,A1,type,
+ {foo,{type,A1,binary,[{integer,A1,10},{foo,bar}]},[]}}),
"-type foo() :: #r{INVALID-FORM:{foo,bar}: :: integer()}.\n" =
- pf({attribute,1,type,
- {foo,{type,1,record,
- [{atom,1,r},
- {type,1,field_type,
- [{foo,bar},{type,1,integer,[]}]}]},
+ pf({attribute,A1,type,
+ {foo,{type,A1,record,
+ [{atom,A1,r},
+ {type,A1,field_type,
+ [{foo,bar},{type,A1,integer,[]}]}]},
[]}}),
ok.
@@ -1239,9 +1245,18 @@ strip_module_info(Bin) ->
<<R:Start/binary,_/binary>> = Bin,
R.
-flat_expr(Expr) ->
+flat_expr1(Expr0) ->
+ Expr = erl_parse:new_anno(Expr0),
+ lists:flatten(erl_pp:expr(Expr)).
+
+flat_expr(Expr0) ->
+ Expr = erl_parse:new_anno(Expr0),
lists:flatten(erl_pp:expr(Expr, -1, none)).
+flat_form(Form0) ->
+ Form = erl_parse:new_anno(Form0),
+ lists:flatten(erl_pp:form(Form)).
+
pp_forms(Bin) ->
pp_forms(Bin, none).
diff --git a/lib/stdlib/test/erl_scan_SUITE.erl b/lib/stdlib/test/erl_scan_SUITE.erl
index 6ef947f0e3..fb85055b6c 100644
--- a/lib/stdlib/test/erl_scan_SUITE.erl
+++ b/lib/stdlib/test/erl_scan_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1998-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
@@ -138,7 +138,7 @@ iso88591(Config) when is_list(Config) ->
A1s = [$h,$ä,$r],
A2s = [$ö,$r,$e],
%% Test parsing atom and variable characters.
- {ok,Ts1,_} = erl_scan:string(V1s ++ " " ++ V2s ++
+ {ok,Ts1,_} = erl_scan_string(V1s ++ " " ++ V2s ++
"\327" ++
A1s ++ " " ++ A2s),
V1s = atom_to_list(element(3, nth(1, Ts1))),
@@ -151,7 +151,7 @@ iso88591(Config) when is_list(Config) ->
%% Test parsing and printing strings.
S1 = V1s ++ "\327" ++ A1s ++ "\250" ++ A2s,
S1s = "\"" ++ S1 ++ "\"",
- {ok,Ts2,_} = erl_scan:string(S1s),
+ {ok,Ts2,_} = erl_scan_string(S1s),
S1 = element(3, nth(1, Ts2)),
S1s = flatten(print(element(3, nth(1, Ts2)))),
ok %It all worked
@@ -219,7 +219,7 @@ atoms() ->
test_string([39,65,200,39], [{atom,{1,1},'AÈ'}]),
test_string("ärlig östen", [{atom,{1,1},ärlig},{atom,{1,7},östen}]),
?line {ok,[{atom,_,'$a'}],{1,6}} =
- erl_scan:string("'$\\a'", {1,1}),
+ erl_scan_string("'$\\a'", {1,1}),
?line test("'$\\a'"),
ok.
@@ -268,24 +268,24 @@ punctuations() ->
comments() ->
?line test("a %%\n b"),
- ?line {ok,[],1} = erl_scan:string("%"),
+ {ok,[],1} = erl_scan_string("%"),
?line test("a %%\n b"),
{ok,[{atom,{1,1},a},{atom,{2,2},b}],{2,3}} =
- erl_scan:string("a %%\n b",{1,1}),
+ erl_scan_string("a %%\n b", {1,1}),
{ok,[{atom,{1,1},a},{comment,{1,3},"%%"},{atom,{2,2},b}],{2,3}} =
- erl_scan:string("a %%\n b",{1,1}, [return_comments]),
+ erl_scan_string("a %%\n b",{1,1}, [return_comments]),
{ok,[{atom,{1,1},a},
{white_space,{1,2}," "},
{white_space,{1,5},"\n "},
{atom,{2,2},b}],
{2,3}} =
- erl_scan:string("a %%\n b",{1,1},[return_white_spaces]),
+ erl_scan_string("a %%\n b",{1,1},[return_white_spaces]),
{ok,[{atom,{1,1},a},
{white_space,{1,2}," "},
{comment,{1,3},"%%"},
{white_space,{1,5},"\n "},
{atom,{2,2},b}],
- {2,3}} = erl_scan:string("a %%\n b",{1,1},[return]),
+ {2,3}} = erl_scan_string("a %%\n b",{1,1},[return]),
ok.
errors() ->
@@ -337,11 +337,11 @@ base_integers() ->
erl_scan:string(Str)
end || {BS,S} <- [{"3","3"},{"15","f"}, {"12","c"}] ],
- ?line {ok,[{integer,1,239},{'@',1}],1} = erl_scan:string("16#ef@"),
+ {ok,[{integer,1,239},{'@',1}],1} = erl_scan_string("16#ef@"),
{ok,[{integer,{1,1},239},{'@',{1,6}}],{1,7}} =
- erl_scan:string("16#ef@", {1,1}, []),
+ erl_scan_string("16#ef@", {1,1}, []),
{ok,[{integer,{1,1},14},{atom,{1,5},g@}],{1,7}} =
- erl_scan:string("16#eg@", {1,1}, []),
+ erl_scan_string("16#eg@", {1,1}, []),
ok.
@@ -382,8 +382,8 @@ dots() ->
{ok,[{'.',{1,1}},{atom,{1,2},a}],{1,3}}}
],
[begin
- R = erl_scan:string(S),
- R2 = erl_scan:string(S, {1,1}, [])
+ R = erl_scan_string(S),
+ R2 = erl_scan_string(S, {1,1}, [])
end || {S, R, R2} <- Dot],
?line {ok,[{dot,_}=T1],{1,2}} = erl_scan:string(".", {1,1}, text),
@@ -417,7 +417,7 @@ dots() ->
{white_space,{1,4},"\n"},
{dot,{2,1}}],
{2,3}}, ""} =
- erl_scan:tokens(C, "\n. ", {1,1}, return), % any loc, any options
+ erl_scan_tokens(C, "\n. ", {1,1}, return), % any loc, any options
?line [test_string(S, R) ||
{S, R} <- [{".$\n", [{'.',{1,1}},{char,{1,2},$\n}]},
@@ -511,7 +511,7 @@ eof() ->
%% An error before R13A.
%% ?line {done,Err={error,{1,erl_scan,scan},1},eof} =
?line {done,{ok,[{atom,1,abra}],1},eof} =
- erl_scan:tokens(C2, eof, 1),
+ erl_scan_tokens(C2, eof, 1),
%% With column.
?line {more, C3} = erl_scan:tokens([]," \n",{1,1}),
@@ -520,7 +520,7 @@ eof() ->
%% An error before R13A.
%% ?line {done,{error,{{1,1},erl_scan,scan},{1,5}},eof} =
?line {done,{ok,[{atom,_,abra}],{1,5}},eof} =
- erl_scan:tokens(C4, eof, 1),
+ erl_scan_tokens(C4, eof, 1),
%% Robert's scanner returns "" as LeftoverChars;
%% the R12B scanner returns eof as LeftoverChars: (eof is correct)
@@ -528,26 +528,26 @@ eof() ->
%% An error before R13A.
%% ?line {done,{error,{1,erl_scan,scan},1},eof} =
?line {done,{ok,[{atom,1,a}],1},eof} =
- erl_scan:tokens(C5,eof,1),
+ erl_scan_tokens(C5,eof,1),
%% With column.
{more, C6} = erl_scan:tokens([], "a", {1,1}),
%% An error before R13A.
%% {done,{error,{1,erl_scan,scan},1},eof} =
{done,{ok,[{atom,{1,1},a}],{1,2}},eof} =
- erl_scan:tokens(C6,eof,1),
+ erl_scan_tokens(C6,eof,1),
%% A dot followed by eof is special:
?line {more, C} = erl_scan:tokens([], "a.", 1),
- ?line {done,{ok,[{atom,1,a},{dot,1}],1},eof} = erl_scan:tokens(C,eof,1),
- ?line {ok,[{atom,1,foo},{dot,1}],1} = erl_scan:string("foo."),
+ {done,{ok,[{atom,1,a},{dot,1}],1},eof} = erl_scan_tokens(C,eof,1),
+ {ok,[{atom,1,foo},{dot,1}],1} = erl_scan_string("foo."),
%% With column.
{more, CCol} = erl_scan:tokens([], "a.", {1,1}),
{done,{ok,[{atom,{1,1},a},{dot,{1,2}}],{1,3}},eof} =
- erl_scan:tokens(CCol,eof,1),
+ erl_scan_tokens(CCol,eof,1),
{ok,[{atom,{1,1},foo},{dot,{1,4}}],{1,5}} =
- erl_scan:string("foo.", {1,1}, []),
+ erl_scan_string("foo.", {1,1}, []),
ok.
@@ -628,23 +628,23 @@ crashes() ->
options() ->
%% line and column are not options, but tested here
?line {ok,[{atom,1,foo},{white_space,1," "},{comment,1,"% bar"}], 1} =
- erl_scan:string("foo % bar", 1, return),
+ erl_scan_string("foo % bar", 1, return),
?line {ok,[{atom,1,foo},{white_space,1," "}],1} =
- erl_scan:string("foo % bar", 1, return_white_spaces),
+ erl_scan_string("foo % bar", 1, return_white_spaces),
?line {ok,[{atom,1,foo},{comment,1,"% bar"}],1} =
- erl_scan:string("foo % bar", 1, return_comments),
+ erl_scan_string("foo % bar", 1, return_comments),
?line {ok,[{atom,17,foo}],17} =
- erl_scan:string("foo % bar", 17),
+ erl_scan_string("foo % bar", 17),
?line {'EXIT',{function_clause,_}} =
(catch {foo,
erl_scan:string("foo % bar", {a,1}, [])}), % type error
?line {ok,[{atom,_,foo}],{17,18}} =
- erl_scan:string("foo % bar", {17,9}, []),
+ erl_scan_string("foo % bar", {17,9}, []),
?line {'EXIT',{function_clause,_}} =
(catch {foo,
erl_scan:string("foo % bar", {1,0}, [])}), % type error
?line {ok,[{foo,1}],1} =
- erl_scan:string("foo % bar",1, [{reserved_word_fun,
+ erl_scan_string("foo % bar",1, [{reserved_word_fun,
fun(W) -> W =:= foo end}]),
?line {'EXIT',{badarg,_}} =
(catch {foo,
@@ -706,8 +706,9 @@ token_info() ->
attributes_info() ->
?line {'EXIT',_} =
(catch {foo,erl_scan:attributes_info(foo)}), % type error
- ?line [{line,18}] = erl_scan:attributes_info(18),
- ?line {location,19} = erl_scan:attributes_info(19, location),
+ [{line,18}] = erl_scan:attributes_info(erl_anno:new(18)),
+ {location,19} =
+ erl_scan:attributes_info(erl_anno:new(19), location),
?line {ok,[{atom,A0,foo}],_} = erl_scan:string("foo", 19, [text]),
?line {location,19} = erl_scan:attributes_info(A0, location),
@@ -735,7 +736,9 @@ attributes_info() ->
set_attribute() ->
F = fun(Line) -> -Line end,
- ?line -2 = erl_scan:set_attribute(line, 2, F),
+ Anno2 = erl_anno:new(2),
+ A0 = erl_scan:set_attribute(line, Anno2, F),
+ {line, -2} = erl_scan:attributes_info(A0, line),
?line {ok,[{atom,A1,foo}],_} = erl_scan:string("foo", {9,17}),
?line A2 = erl_scan:set_attribute(line, A1, F),
?line {line,-9} = erl_scan:attributes_info(A2, line),
@@ -765,10 +768,15 @@ set_attribute() ->
?line {ok,[{atom,A6,foo}],_} = erl_scan:string("foo", 11, [text]),
?line A7 = erl_scan:set_attribute(line, A6, F2),
- ?line {line,{17,11}} = erl_scan:attributes_info(A7, line),
+ %% Incompatible with pre 18:
+ %% {line,{17,11}} = erl_scan:attributes_info(A7, line),
+ {line,17} = erl_scan:attributes_info(A7, line),
?line {location,{17,11}} = % mixed up
erl_scan:attributes_info(A7, location),
- ?line [{line,{17,11}},{text,"foo"}] =
+ %% Incompatible with pre 18:
+ %% [{line,{17,11}},{text,"foo"}] =
+ %% erl_scan:attributes_info(A7, [line,column,text]),
+ [{line,17},{column,11},{text,"foo"}] =
erl_scan:attributes_info(A7, [line,column,text]),
?line {'EXIT',_} =
@@ -776,9 +784,13 @@ set_attribute() ->
?line {'EXIT',{badarg,_}} =
(catch {foo, erl_scan:set_attribute(column, [], F2)}), % type error
+ Attr10 = erl_anno:new(8),
+ Attr20 = erl_scan:set_attribute(line, Attr10,
+ fun(L) -> {nos,'X',L} end),
%% OTP-9412
- ?line 8 = erl_scan:set_attribute(line, [{line,{nos,'X',8}}],
- fun({nos,_V,VL}) -> VL end),
+ Attr30 = erl_scan:set_attribute(line, Attr20,
+ fun({nos,_V,VL}) -> VL end),
+ 8 = erl_anno:to_term(Attr30),
ok.
column_errors() ->
@@ -812,7 +824,7 @@ white_spaces() ->
{white_space,_," "},
{atom,_,a},
{white_space,_,"\n"}],
- _} = erl_scan:string("\r a\n", {1,1}, return),
+ _} = erl_scan_string("\r a\n", {1,1}, return),
?line test("\r a\n"),
L = "{\"a\nb\", \"a\\nb\",\nabc\r,def}.\n\n",
?line {ok,[{'{',_},
@@ -829,7 +841,7 @@ white_spaces() ->
{'}',_},
{dot,_},
{white_space,_,"\n"}],
- _} = erl_scan:string(L, {1,1}, return),
+ _} = erl_scan_string(L, {1,1}, return),
?line test(L),
?line test("\"\n\"\n"),
?line test("\n\r\n"),
@@ -846,7 +858,7 @@ white_spaces() ->
unicode() ->
?line {ok,[{char,1,83},{integer,1,45}],1} =
- erl_scan:string("$\\12345"), % not unicode
+ erl_scan_string("$\\12345"), % not unicode
?line {error,{1,erl_scan,{illegal,character}},1} =
erl_scan:string([1089]),
@@ -858,7 +870,7 @@ unicode() ->
erl_scan:string("'a"++[1089]++"b'", {1,1}),
?line test("\"a"++[1089]++"b\""),
{ok,[{char,1,1}],1} =
- erl_scan:string([$$,$\\,$^,1089], 1),
+ erl_scan_string([$$,$\\,$^,1089], 1),
{error,{1,erl_scan,Error},1} =
erl_scan:string("\"qa\x{aaa}", 1),
@@ -870,13 +882,13 @@ unicode() ->
erl_scan:string("'qa\\x{aaa}'",{1,1}),
{ok,[{char,1,1089}],1} =
- erl_scan:string([$$,1089], 1),
+ erl_scan_string([$$,1089], 1),
{ok,[{char,1,1089}],1} =
- erl_scan:string([$$,$\\,1089], 1),
+ erl_scan_string([$$,$\\,1089], 1),
Qs = "$\\x{aaa}",
{ok,[{char,1,$\x{aaa}}],1} =
- erl_scan:string(Qs, 1),
+ erl_scan_string(Qs, 1),
{ok,[Q2],{1,9}} =
erl_scan:string("$\\x{aaa}", {1,1}, [text]),
[{category,char},{column,1},{length,8},
@@ -884,19 +896,19 @@ unicode() ->
erl_scan:token_info(Q2),
U1 = "\"\\x{aaa}\"",
- {ok,
- [{string,[{line,1},{column,1},{text,"\"\\x{aaa}\""}],[2730]}],
- {1,10}} = erl_scan:string(U1, {1,1}, [text]),
- {ok,[{string,1,[2730]}],1} = erl_scan:string(U1, 1),
+ {ok,[{string,A1,[2730]}],{1,10}} = erl_scan:string(U1, {1,1}, [text]),
+ [{line,1},{column,1},{text,"\"\\x{aaa}\""}] =
+ erl_scan:attributes_info(A1, [line, column, text]),
+ {ok,[{string,1,[2730]}],1} = erl_scan_string(U1, 1),
U2 = "\"\\x41\\x{fff}\\x42\"",
- {ok,[{string,1,[$\x41,$\x{fff},$\x42]}],1} = erl_scan:string(U2, 1),
+ {ok,[{string,1,[$\x41,$\x{fff},$\x42]}],1} = erl_scan_string(U2, 1),
U3 = "\"a\n\\x{fff}\n\"",
- {ok,[{string,1,[$a,$\n,$\x{fff},$\n]}],3} = erl_scan:string(U3, 1),
+ {ok,[{string,1,[$a,$\n,$\x{fff},$\n]}],3} = erl_scan_string(U3, 1),
U4 = "\"\\^\n\\x{aaa}\\^\n\"",
- {ok,[{string,1,[$\n,$\x{aaa},$\n]}],3} = erl_scan:string(U4, 1),
+ {ok,[{string,1,[$\n,$\x{aaa},$\n]}],3} = erl_scan_string(U4, 1),
%% Keep these tests:
?line test(Qs),
@@ -906,15 +918,15 @@ unicode() ->
?line test(U4),
Str1 = "\"ab" ++ [1089] ++ "cd\"",
- {ok,[{string,1,[$a,$b,1089,$c,$d]}],1} = erl_scan:string(Str1, 1),
+ {ok,[{string,1,[$a,$b,1089,$c,$d]}],1} = erl_scan_string(Str1, 1),
{ok,[{string,{1,1},[$a,$b,1089,$c,$d]}],{1,8}} =
- erl_scan:string(Str1, {1,1}),
+ erl_scan_string(Str1, {1,1}),
?line test(Str1),
Comment = "%% "++[1089],
{ok,[{comment,1,[$%,$%,$\s,1089]}],1} =
- erl_scan:string(Comment, 1, [return]),
+ erl_scan_string(Comment, 1, [return]),
{ok,[{comment,{1,1},[$%,$%,$\s,1089]}],{1,5}} =
- erl_scan:string(Comment, {1,1}, [return]),
+ erl_scan_string(Comment, {1,1}, [return]),
ok.
more_chars() ->
@@ -923,12 +935,12 @@ more_chars() ->
%% All kinds of tests...
?line {ok,[{char,_,123}],{1,4}} =
- erl_scan:string("$\\{",{1,1}),
+ erl_scan_string("$\\{",{1,1}),
?line {more, C1} = erl_scan:tokens([], "$\\{", {1,1}),
?line {done,{ok,[{char,_,123}],{1,4}},eof} =
- erl_scan:tokens(C1, eof, 1),
+ erl_scan_tokens(C1, eof, 1),
?line {ok,[{char,1,123},{atom,1,a},{'}',1}],1} =
- erl_scan:string("$\\{a}"),
+ erl_scan_string("$\\{a}"),
?line {error,{{1,1},erl_scan,char},{1,4}} =
erl_scan:string("$\\x", {1,1}),
@@ -993,11 +1005,11 @@ otp_10302(Config) when is_list(Config) ->
{error,{{1,1},erl_scan,{illegal,atom}},{1,12}} =
erl_scan:string("'qa\\x{aaa}'",{1,1}),
- {ok,[{char,1,1089}],1} = erl_scan:string([$$,1089], 1),
- {ok,[{char,1,1089}],1} = erl_scan:string([$$,$\\,1089],1),
+ {ok,[{char,1,1089}],1} = erl_scan_string([$$,1089], 1),
+ {ok,[{char,1,1089}],1} = erl_scan_string([$$,$\\,1089],1),
Qs = "$\\x{aaa}",
- {ok,[{char,1,2730}],1} = erl_scan:string(Qs,1),
+ {ok,[{char,1,2730}],1} = erl_scan_string(Qs, 1),
{ok,[Q2],{1,9}} = erl_scan:string(Qs,{1,1},[text]),
[{category,char},{column,1},{length,8},
{line,1},{symbol,16#aaa},{text,Qs}] =
@@ -1011,19 +1023,19 @@ otp_10302(Config) when is_list(Config) ->
{symbol,[16#aaa]},{text,U1}] = erl_scan:token_info(T1, Tags),
U2 = "\"\\x41\\x{fff}\\x42\"",
- {ok,[{string,1,[65,4095,66]}],1} = erl_scan:string(U2, 1),
+ {ok,[{string,1,[65,4095,66]}],1} = erl_scan_string(U2, 1),
U3 = "\"a\n\\x{fff}\n\"",
- {ok,[{string,1,[97,10,4095,10]}],3} = erl_scan:string(U3, 1),
+ {ok,[{string,1,[97,10,4095,10]}],3} = erl_scan_string(U3, 1),
U4 = "\"\\^\n\\x{aaa}\\^\n\"",
- {ok,[{string,1,[10,2730,10]}],3} = erl_scan:string(U4, 1,[]),
+ {ok,[{string,1,[10,2730,10]}],3} = erl_scan_string(U4, 1,[]),
Str1 = "\"ab" ++ [1089] ++ "cd\"",
{ok,[{string,1,[97,98,1089,99,100]}],1} =
- erl_scan:string(Str1,1),
+ erl_scan_string(Str1,1),
{ok,[{string,{1,1},[97,98,1089,99,100]}],{1,8}} =
- erl_scan:string(Str1, {1,1}),
+ erl_scan_string(Str1, {1,1}),
OK1 = 16#D800-1,
OK2 = 16#DFFF+1,
@@ -1038,19 +1050,19 @@ otp_10302(Config) when is_list(Config) ->
IllegalL = [Illegal1,Illegal2,Illegal3,Illegal4],
[{ok,[{comment,1,[$%,$%,$\s,OK]}],1} =
- erl_scan:string("%% "++[OK], 1, [return]) ||
+ erl_scan_string("%% "++[OK], 1, [return]) ||
OK <- OKL],
{ok,[{comment,_,[$%,$%,$\s,OK1]}],{1,5}} =
- erl_scan:string("%% "++[OK1], {1,1}, [return]),
+ erl_scan_string("%% "++[OK1], {1,1}, [return]),
[{error,{1,erl_scan,{illegal,character}},1} =
erl_scan:string("%% "++[Illegal], 1, [return]) ||
Illegal <- IllegalL],
{error,{{1,1},erl_scan,{illegal,character}},{1,5}} =
erl_scan:string("%% "++[Illegal1], {1,1}, [return]),
- [{ok,[],1} = erl_scan:string("%% "++[OK], 1, []) ||
+ [{ok,[],1} = erl_scan_string("%% "++[OK], 1, []) ||
OK <- OKL],
- {ok,[],{1,5}} = erl_scan:string("%% "++[OK1], {1,1}, []),
+ {ok,[],{1,5}} = erl_scan_string("%% "++[OK1], {1,1}, []),
[{error,{1,erl_scan,{illegal,character}},1} =
erl_scan:string("%% "++[Illegal], 1, []) ||
Illegal <- IllegalL],
@@ -1058,7 +1070,7 @@ otp_10302(Config) when is_list(Config) ->
erl_scan:string("%% "++[Illegal1], {1,1}, []),
[{ok,[{string,{1,1},[OK]}],{1,4}} =
- erl_scan:string("\""++[OK]++"\"",{1,1}) ||
+ erl_scan_string("\""++[OK]++"\"",{1,1}) ||
OK <- OKL],
[{error,{{1,2},erl_scan,{illegal,character}},{1,3}} =
erl_scan:string("\""++[OK]++"\"",{1,1}) ||
@@ -1069,93 +1081,93 @@ otp_10302(Config) when is_list(Config) ->
Illegal <- IllegalL],
{ok,[{char,{1,1},OK1}],{1,3}} =
- erl_scan:string([$$,OK1],{1,1}),
+ erl_scan_string([$$,OK1],{1,1}),
{error,{{1,1},erl_scan,{illegal,character}},{1,2}} =
erl_scan:string([$$,Illegal1],{1,1}),
{ok,[{char,{1,1},OK1}],{1,4}} =
- erl_scan:string([$$,$\\,OK1],{1,1}),
+ erl_scan_string([$$,$\\,OK1],{1,1}),
{error,{{1,1},erl_scan,{illegal,character}},{1,4}} =
erl_scan:string([$$,$\\,Illegal1],{1,1}),
{ok,[{string,{1,1},[55295]}],{1,5}} =
- erl_scan:string("\"\\"++[OK1]++"\"",{1,1}),
+ erl_scan_string("\"\\"++[OK1]++"\"",{1,1}),
{error,{{1,2},erl_scan,{illegal,character}},{1,4}} =
erl_scan:string("\"\\"++[Illegal1]++"\"",{1,1}),
{ok,[{char,{1,1},OK1}],{1,10}} =
- erl_scan:string("$\\x{D7FF}",{1,1}),
+ erl_scan_string("$\\x{D7FF}",{1,1}),
{error,{{1,1},erl_scan,{illegal,character}},{1,10}} =
erl_scan:string("$\\x{D800}",{1,1}),
%% Not erl_scan, but erl_parse.
- {integer,0,1} = erl_parse:abstract(1),
- Float = 3.14, {float,0,Float} = erl_parse:abstract(Float),
- {nil,0} = erl_parse:abstract([]),
+ {integer,0,1} = erl_parse_abstract(1),
+ Float = 3.14, {float,0,Float} = erl_parse_abstract(Float),
+ {nil,0} = erl_parse_abstract([]),
{bin,0,
[{bin_element,0,{integer,0,1},default,default},
{bin_element,0,{integer,0,2},default,default}]} =
- erl_parse:abstract(<<1,2>>),
+ erl_parse_abstract(<<1,2>>),
{cons,0,{tuple,0,[{atom,0,a}]},{atom,0,b}} =
- erl_parse:abstract([{a} | b]),
- {string,0,"str"} = erl_parse:abstract("str"),
+ erl_parse_abstract([{a} | b]),
+ {string,0,"str"} = erl_parse_abstract("str"),
{cons,0,
{integer,0,$a},
{cons,0,{integer,0,55296},{string,0,"c"}}} =
- erl_parse:abstract("a"++[55296]++"c"),
+ erl_parse_abstract("a"++[55296]++"c"),
Line = 17,
- {integer,Line,1} = erl_parse:abstract(1, Line),
- Float = 3.14, {float,Line,Float} = erl_parse:abstract(Float, Line),
- {nil,Line} = erl_parse:abstract([], Line),
+ {integer,Line,1} = erl_parse_abstract(1, Line),
+ Float = 3.14, {float,Line,Float} = erl_parse_abstract(Float, Line),
+ {nil,Line} = erl_parse_abstract([], Line),
{bin,Line,
[{bin_element,Line,{integer,Line,1},default,default},
{bin_element,Line,{integer,Line,2},default,default}]} =
- erl_parse:abstract(<<1,2>>, Line),
+ erl_parse_abstract(<<1,2>>, Line),
{cons,Line,{tuple,Line,[{atom,Line,a}]},{atom,Line,b}} =
- erl_parse:abstract([{a} | b], Line),
- {string,Line,"str"} = erl_parse:abstract("str", Line),
+ erl_parse_abstract([{a} | b], Line),
+ {string,Line,"str"} = erl_parse_abstract("str", Line),
{cons,Line,
{integer,Line,$a},
{cons,Line,{integer,Line,55296},{string,Line,"c"}}} =
- erl_parse:abstract("a"++[55296]++"c", Line),
+ erl_parse_abstract("a"++[55296]++"c", Line),
Opts1 = [{line,17}],
- {integer,Line,1} = erl_parse:abstract(1, Opts1),
- Float = 3.14, {float,Line,Float} = erl_parse:abstract(Float, Opts1),
- {nil,Line} = erl_parse:abstract([], Opts1),
+ {integer,Line,1} = erl_parse_abstract(1, Opts1),
+ Float = 3.14, {float,Line,Float} = erl_parse_abstract(Float, Opts1),
+ {nil,Line} = erl_parse_abstract([], Opts1),
{bin,Line,
[{bin_element,Line,{integer,Line,1},default,default},
{bin_element,Line,{integer,Line,2},default,default}]} =
- erl_parse:abstract(<<1,2>>, Opts1),
+ erl_parse_abstract(<<1,2>>, Opts1),
{cons,Line,{tuple,Line,[{atom,Line,a}]},{atom,Line,b}} =
- erl_parse:abstract([{a} | b], Opts1),
- {string,Line,"str"} = erl_parse:abstract("str", Opts1),
+ erl_parse_abstract([{a} | b], Opts1),
+ {string,Line,"str"} = erl_parse_abstract("str", Opts1),
{cons,Line,
{integer,Line,$a},
{cons,Line,{integer,Line,55296},{string,Line,"c"}}} =
- erl_parse:abstract("a"++[55296]++"c", Opts1),
+ erl_parse_abstract("a"++[55296]++"c", Opts1),
[begin
- {integer,Line,1} = erl_parse:abstract(1, Opts2),
- Float = 3.14, {float,Line,Float} = erl_parse:abstract(Float, Opts2),
- {nil,Line} = erl_parse:abstract([], Opts2),
+ {integer,Line,1} = erl_parse_abstract(1, Opts2),
+ Float = 3.14, {float,Line,Float} = erl_parse_abstract(Float, Opts2),
+ {nil,Line} = erl_parse_abstract([], Opts2),
{bin,Line,
[{bin_element,Line,{integer,Line,1},default,default},
{bin_element,Line,{integer,Line,2},default,default}]} =
- erl_parse:abstract(<<1,2>>, Opts2),
+ erl_parse_abstract(<<1,2>>, Opts2),
{cons,Line,{tuple,Line,[{atom,Line,a}]},{atom,Line,b}} =
- erl_parse:abstract([{a} | b], Opts2),
- {string,Line,"str"} = erl_parse:abstract("str", Opts2),
+ erl_parse_abstract([{a} | b], Opts2),
+ {string,Line,"str"} = erl_parse_abstract("str", Opts2),
{string,Line,[97,1024,99]} =
- erl_parse:abstract("a"++[1024]++"c", Opts2)
+ erl_parse_abstract("a"++[1024]++"c", Opts2)
end || Opts2 <- [[{encoding,unicode},{line,Line}],
[{encoding,utf8},{line,Line}]]],
{cons,0,
{integer,0,97},
{cons,0,{integer,0,1024},{string,0,"c"}}} =
- erl_parse:abstract("a"++[1024]++"c", [{encoding,latin1}]),
+ erl_parse_abstract("a"++[1024]++"c", [{encoding,latin1}]),
ok.
otp_10990(doc) ->
@@ -1172,13 +1184,13 @@ otp_10992(suite) ->
[];
otp_10992(Config) when is_list(Config) ->
{cons,0,{float,0,42.0},{nil,0}} =
- erl_parse:abstract([42.0], [{encoding,unicode}]),
+ erl_parse_abstract([42.0], [{encoding,unicode}]),
{cons,0,{float,0,42.0},{nil,0}} =
- erl_parse:abstract([42.0], [{encoding,utf8}]),
+ erl_parse_abstract([42.0], [{encoding,utf8}]),
{cons,0,{integer,0,65},{cons,0,{float,0,42.0},{nil,0}}} =
- erl_parse:abstract([$A,42.0], [{encoding,unicode}]),
+ erl_parse_abstract([$A,42.0], [{encoding,unicode}]),
{cons,0,{integer,0,65},{cons,0,{float,0,42.0},{nil,0}}} =
- erl_parse:abstract([$A,42.0], [{encoding,utf8}]),
+ erl_parse_abstract([$A,42.0], [{encoding,utf8}]),
ok.
otp_11807(doc) ->
@@ -1187,29 +1199,72 @@ otp_11807(suite) ->
[];
otp_11807(Config) when is_list(Config) ->
{cons,0,{integer,0,97},{cons,0,{integer,0,98},{nil,0}}} =
- erl_parse:abstract("ab", [{encoding,none}]),
+ erl_parse_abstract("ab", [{encoding,none}]),
{cons,0,{integer,0,-1},{nil,0}} =
- erl_parse:abstract([-1], [{encoding,latin1}]),
+ erl_parse_abstract([-1], [{encoding,latin1}]),
ASCII = fun(I) -> I >= 0 andalso I < 128 end,
- {string,0,"xyz"} = erl_parse:abstract("xyz", [{encoding,ASCII}]),
+ {string,0,"xyz"} = erl_parse_abstract("xyz", [{encoding,ASCII}]),
{cons,0,{integer,0,228},{nil,0}} =
- erl_parse:abstract([228], [{encoding,ASCII}]),
+ erl_parse_abstract([228], [{encoding,ASCII}]),
{cons,0,{integer,0,97},{atom,0,a}} =
- erl_parse:abstract("a"++a, [{encoding,latin1}]),
+ erl_parse_abstract("a"++a, [{encoding,latin1}]),
{'EXIT', {{badarg,bad},_}} = % minor backward incompatibility
(catch erl_parse:abstract("string", [{encoding,bad}])),
ok.
test_string(String, ExpectedWithCol) ->
- {ok, ExpectedWithCol, _EndWithCol} = erl_scan:string(String, {1, 1}, []),
+ {ok, ExpectedWithCol, _EndWithCol} = erl_scan_string(String, {1, 1}, []),
Expected = [ begin
{L,_C} = element(2, T),
setelement(2, T, L)
end
|| T <- ExpectedWithCol ],
- {ok, Expected, _End} = erl_scan:string(String),
+ {ok, Expected, _End} = erl_scan_string(String),
test(String).
+erl_scan_string(String) ->
+ erl_scan_string(String, 1, []).
+
+erl_scan_string(String, StartLocation) ->
+ erl_scan_string(String, StartLocation, []).
+
+erl_scan_string(String, StartLocation, Options) ->
+ case erl_scan:string(String, StartLocation, Options) of
+ {ok, Tokens, EndLocation} ->
+ {ok, unopaque_tokens(Tokens), EndLocation};
+ Else ->
+ Else
+ end.
+
+erl_scan_tokens(C, S, L) ->
+ erl_scan_tokens(C, S, L, []).
+
+erl_scan_tokens(C, S, L, O) ->
+ case erl_scan:tokens(C, S, L, O) of
+ {done, {ok, Ts, End}, R} ->
+ {done, {ok, unopaque_tokens(Ts), End}, R};
+ Else ->
+ Else
+ end.
+
+unopaque_tokens([]) ->
+ [];
+unopaque_tokens([Token|Tokens]) ->
+ Attrs = element(2, Token),
+ Term = erl_anno:to_term(Attrs),
+ T = setelement(2, Token, Term),
+ [T | unopaque_tokens(Tokens)].
+
+erl_parse_abstract(Term) ->
+ erl_parse_abstract(Term, []).
+
+erl_parse_abstract(Term, Options) ->
+ Abstr = erl_parse:abstract(Term, Options),
+ unopaque_abstract(Abstr).
+
+unopaque_abstract(Abstr) ->
+ erl_parse:anno_to_term(Abstr).
+
%% test_string(String, Expected, StartLocation, Options) ->
%% {ok, Expected, _End} = erl_scan:string(String, StartLocation, Options),
%% test(String).
@@ -1359,7 +1414,7 @@ select_tokens(Tokens, Tags) ->
simplify([Token|Tokens]) ->
{line,Line} = erl_scan:token_info(Token, line),
- [setelement(2, Token, Line) | simplify(Tokens)];
+ [setelement(2, Token, erl_anno:new(Line)) | simplify(Tokens)];
simplify([]) ->
[].
diff --git a/lib/stdlib/test/qlc_SUITE.erl b/lib/stdlib/test/qlc_SUITE.erl
index 0a1b6dd2ba..348c308f5d 100644
--- a/lib/stdlib/test/qlc_SUITE.erl
+++ b/lib/stdlib/test/qlc_SUITE.erl
@@ -396,7 +396,8 @@ nomatch(Config) when is_list(Config) ->
qlc:q([3 || {3=4} <- []]).
">>,
[],
- {warnings,[{{2,27},qlc,nomatch_pattern}]}},
+ %% {warnings,[{{2,27},qlc,nomatch_pattern}]}},
+ {warnings,[{2,v3_core,nomatch}]}},
{nomatch2,
<<"nomatch() ->
@@ -407,7 +408,8 @@ nomatch(Config) when is_list(Config) ->
end, [{1},{2}]).
">>,
[],
- {warnings,[{{3,33},qlc,nomatch_pattern}]}},
+ %% {warnings,[{{3,33},qlc,nomatch_pattern}]}},
+ {warnings,[{3,v3_core,nomatch}]}},
{nomatch3,
<<"nomatch() ->
@@ -419,7 +421,8 @@ nomatch(Config) when is_list(Config) ->
end, [{1,2},{2,3}]).
">>,
[],
- {warnings,[{{3,52},qlc,nomatch_pattern}]}},
+ %% {warnings,[{{3,52},qlc,nomatch_pattern}]}},
+ {warnings,[{3,v3_core,nomatch}]}},
{nomatch4,
<<"nomatch() ->
@@ -2487,8 +2490,11 @@ info(Config) when is_list(Config) ->
(catch qlc:info([X || {X} <- []], {n_elements, 0})),
L = lists:seq(1, 1000),
\"[1,2,3,4,5,6,7,8,9,10|'...']\" = qlc:info(L, {n_elements, 10}),
- {cons,1,{integer,1,1},{atom,1,'...'}} =
+ {cons,A1,{integer,A2,1},{atom,A3,'...'}} =
qlc:info(L, [{n_elements, 1},{format,abstract_code}]),
+ 1 = erl_anno:line(A1),
+ 1 = erl_anno:line(A2),
+ 1 = erl_anno:line(A3),
Q = qlc:q([{X} || X <- [a,b,c,d,e,f]]),
{call,_,_,[{cons,_,{atom,_,a},{cons,_,{atom,_,b},{cons,_,{atom,_,c},
{atom,_,'...'}}}},
@@ -2905,7 +2911,8 @@ lookup1(Config) when is_list(Config) ->
[] = qlc:e(Q),
false = lookup_keys(Q)
end, [{1},{a}])">>,
- {warnings,[{{2,37},qlc,nomatch_pattern}]}},
+ %% {warnings,[{{2,37},qlc,nomatch_pattern}]}},
+ []},
<<"etsc(fun(E) ->
Q = qlc:q([X || {X=X,Y=Y}={Y=Y,X=X} <- ets:table(E),
@@ -2933,7 +2940,8 @@ lookup1(Config) when is_list(Config) ->
[] = qlc:e(Q),
false = lookup_keys(Q)
end, [{a},{b}])">>,
- {warnings,[{{2,35},qlc,nomatch_pattern}]}},
+ %% {warnings,[{{2,35},qlc,nomatch_pattern}]}},
+ []},
{cres,
<<"etsc(fun(E) ->
@@ -2941,7 +2949,8 @@ lookup1(Config) when is_list(Config) ->
[] = qlc:e(Q),
false = lookup_keys(Q)
end, [{a},{b}])">>,
- {warnings,[{{2,35},qlc,nomatch_pattern}]}},
+ %% {warnings,[{{2,35},qlc,nomatch_pattern}]}},
+ []},
<<"etsc(fun(E) ->
Q = qlc:q([X || X = <<X>> <- ets:table(E)]),
@@ -2988,7 +2997,8 @@ lookup1(Config) when is_list(Config) ->
[] = qlc:e(Q),
false = lookup_keys(Q)
end, [{a,b,c},{d,e,f}])">>,
- {warnings,[{{2,34},qlc,nomatch_pattern}]}}
+ %% {warnings,[{{2,34},qlc,nomatch_pattern}]}}
+ []}
],
?line run(Config, Ts),
@@ -3052,7 +3062,8 @@ lookup2(Config) when is_list(Config) ->
[] = qlc:e(Q),
false = lookup_keys(Q)
end, [{1}, {2}])">>,
- {warnings,[{{3,46},qlc,nomatch_filter}]}},
+ %% {warnings,[{{3,46},qlc,nomatch_filter}]}},
+ []},
{cres,
<<"etsc(fun(E) ->
@@ -3061,7 +3072,8 @@ lookup2(Config) when is_list(Config) ->
[] = qlc:e(Q),
false = lookup_keys(Q)
end, [{1}, {2}])">>,
- {warnings,[{{3,43},qlc,nomatch_filter}]}},
+ %% {warnings,[{{3,43},qlc,nomatch_filter}]}},
+ []},
{cres,
<<"etsc(fun(E) ->
@@ -3070,7 +3082,8 @@ lookup2(Config) when is_list(Config) ->
[] = qlc:e(Q),
false = lookup_keys(Q)
end, [{1}, {2}])">>,
- {warnings,[{{3,48},qlc,nomatch_filter}]}},
+ %% {warnings,[{{3,48},qlc,nomatch_filter}]}},
+ []},
<<"etsc(fun(E) ->
Q = qlc:q([{X,Y} || {X,Y} <- ets:table(E),
@@ -3085,7 +3098,8 @@ lookup2(Config) when is_list(Config) ->
[] = qlc:e(Q),
false = lookup_keys(Q)
end, [{[3]},{[3,4]}])">>,
- {warnings,[{{2,61},qlc,nomatch_filter}]}},
+ %% {warnings,[{{2,61},qlc,nomatch_filter}]}},
+ []},
<<"etsc(fun(E) ->
U = 18,
@@ -3117,7 +3131,8 @@ lookup2(Config) when is_list(Config) ->
[] = lists:sort(qlc:e(Q)),
false = lookup_keys(Q)
end, [{2},{3},{4},{8}])">>,
- {warnings,[{{4,44},qlc,nomatch_filter}]}},
+ %% {warnings,[{{4,44},qlc,nomatch_filter}]}},
+ []},
{cres,
<<"etsc(fun(E) ->
@@ -3127,7 +3142,8 @@ lookup2(Config) when is_list(Config) ->
[] = lists:sort(qlc:e(Q)),
false = lookup_keys(Q)
end, [{2},{3},{4},{8}])">>,
- {warnings,[{{4,35},qlc,nomatch_filter}]}},
+ %% {warnings,[{{4,35},qlc,nomatch_filter}]}},
+ []},
<<"F = fun(U) ->
Q = qlc:q([X || {X} <- [a,b,c],
@@ -3143,7 +3159,8 @@ lookup2(Config) when is_list(Config) ->
[] = qlc:e(Q),
false = lookup_keys(Q)
end, [{1,1},{2,1}])">>,
- {warnings,[{{2,61},qlc,nomatch_filter}]}},
+ %% {warnings,[{{2,61},qlc,nomatch_filter}]}},
+ []},
<<"Two = 2.0,
etsc(fun(E) ->
@@ -3204,8 +3221,10 @@ lookup2(Config) when is_list(Config) ->
[] = qlc:e(Q),
false = lookup_keys(Q)
end, [{1,b},{2,3}])">>,
+ %% {warnings,[{2,sys_core_fold,nomatch_guard},
+ %% {3,qlc,nomatch_filter},
+ %% {3,sys_core_fold,{eval_failure,badarg}}]}},
{warnings,[{2,sys_core_fold,nomatch_guard},
- {3,qlc,nomatch_filter},
{3,sys_core_fold,{eval_failure,badarg}}]}},
<<"etsc(fun(E) ->
@@ -3228,7 +3247,8 @@ lookup2(Config) when is_list(Config) ->
[] = qlc:e(Q),
false = lookup_keys(Q)
end, [{{1}},{{2}}])">>,
- {warnings,[{{4,47},qlc,nomatch_filter}]}},
+ %% {warnings,[{{4,47},qlc,nomatch_filter}]}},
+ []},
{cres,
<<"etsc(fun(E) ->
@@ -3238,7 +3258,8 @@ lookup2(Config) when is_list(Config) ->
[] = qlc:e(Q),
false = lookup_keys(Q)
end, [{{1}},{{2}}])">>,
- {warnings,[{{4,47},qlc,nomatch_filter}]}},
+ %% {warnings,[{{4,47},qlc,nomatch_filter}]}},
+ []},
<<"etsc(fun(E) ->
Q = qlc:q([X || {X} <- ets:table(E),
@@ -3298,7 +3319,8 @@ lookup2(Config) when is_list(Config) ->
[] = qlc:e(Q),
false = lookup_keys(Q)
end, [{3}, {4}])">>,
- {warnings,[{{3,44},qlc,nomatch_filter}]}},
+ %% {warnings,[{{3,44},qlc,nomatch_filter}]}},
+ []},
<<"etsc(fun(E) ->
Q = qlc:q([X || {{X,Y}} <- ets:table(E),
@@ -3703,7 +3725,8 @@ lookup_rec(Config) when is_list(Config) ->
[] = qlc:e(Q),
false = lookup_keys(Q)
end, [{keypos,2}], [#r{a = 17}, #r{a = 3}, #r{a = 5}])">>,
- {warnings,[{{4,44},qlc,nomatch_filter}]}},
+ %% {warnings,[{{4,44},qlc,nomatch_filter}]}},
+ []},
<<"%% Compares an integer and a float.
etsc(fun(E) ->
@@ -4007,7 +4030,8 @@ skip_filters(Config) when is_list(Config) ->
[] = qlc:e(Q),
false = lookup_keys(Q)
end, [{1,1},{2,0}])">>,
- {warnings,[{{4,37},qlc,nomatch_filter}]}},
+ %% {warnings,[{{4,37},qlc,nomatch_filter}]}},
+ []},
<<"etsc(fun(E) ->
Q = qlc:q([{A,B,C} ||
@@ -6220,8 +6244,9 @@ otp_7238(Config) when is_list(Config) ->
<<"nomatch_1() ->
{qlc:q([X || X={X} <- []]), [t || \"a\"=\"b\" <- []]}.">>,
[],
- {warnings,[{{2,30},qlc,nomatch_pattern},
- {{2,44},v3_core,nomatch}]}},
+ %% {warnings,[{{2,30},qlc,nomatch_pattern},
+ %% {{2,44},v3_core,nomatch}]}},
+ {warnings,[{2,v3_core,nomatch}]}},
%% Not found by qlc...
{nomatch_2,
@@ -6234,7 +6259,8 @@ otp_7238(Config) when is_list(Config) ->
<<"nomatch_3() ->
qlc:q([t || [$a, $b] = \"ba\" <- []]).">>,
[],
- {warnings,[{{2,37},qlc,nomatch_pattern}]}},
+ %% {warnings,[{{2,37},qlc,nomatch_pattern}]}},
+ {warnings,[{2,v3_core,nomatch}]}},
%% Not found by qlc...
{nomatch_4,
@@ -6255,44 +6281,51 @@ otp_7238(Config) when is_list(Config) ->
qlc:q([X || X <- [],
X =:= {X}]).">>,
[],
- {warnings,[{{3,30},qlc,nomatch_filter}]}},
+ %% {warnings,[{{3,30},qlc,nomatch_filter}]}},
+ []},
{nomatch_7,
<<"nomatch_7() ->
qlc:q([X || {X=Y,{Y}=X} <- []]).">>,
[],
- {warnings,[{{2,28},qlc,nomatch_pattern}]}},
+ %% {warnings,[{{2,28},qlc,nomatch_pattern}]}},
+ []},
{nomatch_8,
<<"nomatch_8() ->
qlc:q([X || {X={},X=[]} <- []]).">>,
[],
- {warnings,[{{2,28},qlc,nomatch_pattern}]}},
+ %% {warnings,[{{2,28},qlc,nomatch_pattern}]}},
+ []},
{nomatch_9,
<<"nomatch_9() ->
qlc:q([X || X <- [], X =:= {}, X =:= []]).">>,
[],
- {warnings,[{{2,49},qlc,nomatch_filter}]}},
+ %% {warnings,[{{2,49},qlc,nomatch_filter}]}},
+ []},
{nomatch_10,
<<"nomatch_10() ->
qlc:q([X || X <- [],
((X =:= 1) or (X =:= 2)) and (X =:= 3)]).">>,
[],
- {warnings,[{{3,53},qlc,nomatch_filter}]}},
+ %% {warnings,[{{3,53},qlc,nomatch_filter}]}},
+ []},
{nomatch_11,
<<"nomatch_11() ->
qlc:q([X || X <- [], x =:= []]).">>,
[],
- {warnings,[{{2,39},qlc,nomatch_filter}]}},
+ %% {warnings,[{{2,39},qlc,nomatch_filter}]}},
+ {warnings,[{2,sys_core_fold,nomatch_guard}]}},
{nomatch_12,
<<"nomatch_12() ->
qlc:q([X || X={} <- [], X =:= []]).">>,
[],
- {warnings,[{{2,42},qlc,nomatch_filter}]}},
+ %% {warnings,[{{2,42},qlc,nomatch_filter}]}},
+ []},
{nomatch_13,
<<"nomatch_13() ->
@@ -6300,8 +6333,9 @@ otp_7238(Config) when is_list(Config) ->
X={X} <- [],
Y={Y} <- []]).">>,
[],
- {warnings,[{{3,29},qlc,nomatch_pattern},
- {{4,29},qlc,nomatch_pattern}]}},
+ %% {warnings,[{{3,29},qlc,nomatch_pattern},
+ %% {{4,29},qlc,nomatch_pattern}]}},
+ []},
{nomatch_14,
<<"nomatch_14() ->
@@ -6309,7 +6343,8 @@ otp_7238(Config) when is_list(Config) ->
1 > 0,
1 > X]).">>,
[],
- {warnings,[{{2,29},qlc,nomatch_pattern}]}},
+ %% {warnings,[{{2,29},qlc,nomatch_pattern}]}},
+ []},
{nomatch_15,
<<"nomatch_15() ->
@@ -6318,7 +6353,8 @@ otp_7238(Config) when is_list(Config) ->
1 > 0,
1 > X]).">>,
[],
- {warnings,[{{2,32},qlc,nomatch_pattern}]}},
+ %% {warnings,[{{2,32},qlc,nomatch_pattern}]}},
+ []},
%% Template warning.
{nomatch_template1,
@@ -6556,18 +6592,19 @@ otp_7238(Config) when is_list(Config) ->
?line run(Config, T2),
T3 = [
- {nomatch_6,
- <<"nomatch_6() ->
- qlc:q([X || X <- [],
- X =:= {X}]).">>,
- [],
- {[],["filter evaluates to 'false'"]}},
-
- {nomatch_7,
- <<"nomatch_7() ->
- qlc:q([X || {X=Y,{Y}=X} <- []]).">>,
- [],
- {[],["pattern cannot possibly match"]}}],
+%% {nomatch_6,
+%% <<"nomatch_6() ->
+%% qlc:q([X || X <- [],
+%% X =:= {X}]).">>,
+%% [],
+%% {[],["filter evaluates to 'false'"]}},
+
+%% {nomatch_7,
+%% <<"nomatch_7() ->
+%% qlc:q([X || {X=Y,{Y}=X} <- []]).">>,
+%% [],
+%% {[],["pattern cannot possibly match"]}}
+ ],
?line compile_format(Config, T3),
%% *Very* simple test - just check that it doesn't crash.
@@ -6825,7 +6862,8 @@ otp_6674(Config) when is_list(Config) ->
A == 192, B =:= 192.0,
{Y} <- [{0},{1},{2}],
X == Y]),
- {block,0,
+ A0 = erl_anno:new(0),
+ {block,A0,
[{match,_,_,
{call,_,_,
[{lc,_,_,
@@ -7395,7 +7433,8 @@ try_old_join_info(Config) ->
{ok, M} = compile:file(File, [{outdir, ?datadir}]),
{module, M} = code:load_abs(filename:rootname(File)),
H = M:create_handle(),
- {block,0,
+ A0 = erl_anno:new(0),
+ {block,A0,
[{match,_,_,
{call,_,_,
[{lc,_,_,
@@ -7775,8 +7814,8 @@ table(List, Indices, KeyPos, ParentFun) ->
end,
FormatFun = fun(all) ->
- L = 17,
- {call,L,{remote,L,{atom,1,?MODULE},{atom,L,the_list}},
+ L = erl_anno:new(17),
+ {call,L,{remote,L,{atom,L,?MODULE},{atom,L,the_list}},
[erl_parse:abstract(List, 17)]};
({lookup, Column, Values}) ->
{?MODULE, list_keys, [Values, Column, List]}
diff --git a/lib/stdlib/test/shell_SUITE.erl b/lib/stdlib/test/shell_SUITE.erl
index f841e2c4a6..7c18560498 100644
--- a/lib/stdlib/test/shell_SUITE.erl
+++ b/lib/stdlib/test/shell_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2004-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
@@ -404,13 +404,14 @@ records(Config) when is_list(Config) ->
?line ok = file:write_file(Test, Contents),
RR5 = "rr(\"" ++ Test ++ "\", '_', {d,test1}), rl([test1,test2]).",
- ?line [{attribute,1,record,{test1,_}},ok] = scan(RR5),
+ A1 = erl_anno:new(1),
+ [{attribute,A1,record,{test1,_}},ok] = scan(RR5),
RR6 = "rr(\"" ++ Test ++ "\", '_', {d,test2}), rl([test1,test2]).",
- ?line [{attribute,1,record,{test2,_}},ok] = scan(RR6),
+ [{attribute,A1,record,{test2,_}},ok] = scan(RR6),
RR7 = "rr(\"" ++ Test ++
"\", '_', [{d,test1},{d,test2,17}]), rl([test1,test2]).",
- ?line [{attribute,1,record,{test1,_}},{attribute,1,record,{test2,_}},
- ok] = scan(RR7),
+ [{attribute,A1,record,{test1,_}},{attribute,A1,record,{test2,_}},ok] =
+ scan(RR7),
?line PreReply = scan(<<"rr(prim_file).">>), % preloaded...
?line true = is_list(PreReply),
?line Dir = filename:join(?config(priv_dir, Config), "*.erl"),
diff --git a/lib/syntax_tools/src/epp_dodger.erl b/lib/syntax_tools/src/epp_dodger.erl
index 3ca7a8197e..39c522fd11 100644
--- a/lib/syntax_tools/src/epp_dodger.erl
+++ b/lib/syntax_tools/src/epp_dodger.erl
@@ -454,7 +454,7 @@ io_error(L, Desc) ->
{L, ?MODULE, Desc}.
start_pos([T | _Ts], _L) ->
- element(2, T);
+ erl_anno:line(element(2, T));
start_pos([], L) ->
L.
diff --git a/lib/syntax_tools/src/erl_recomment.erl b/lib/syntax_tools/src/erl_recomment.erl
index 7b2f9f7adb..72e1e2d2f5 100644
--- a/lib/syntax_tools/src/erl_recomment.erl
+++ b/lib/syntax_tools/src/erl_recomment.erl
@@ -123,7 +123,6 @@ recomment_forms(Tree, Cs, Insert) ->
form_list ->
Tree1 = erl_syntax:flatten_form_list(Tree),
Node = build_tree(Tree1),
-
%% Here we make a small assumption about the substructure of
%% a `form_list' tree: it has exactly one group of subtrees.
[Node1] = node_subtrees(Node),
@@ -753,7 +752,13 @@ get_line(Node) ->
{_, L, _} when is_integer(L) ->
L;
Pos ->
- exit({bad_position, Pos})
+ try erl_anno:line(Pos) of
+ Line ->
+ Line
+ catch
+ _:_ ->
+ exit({bad_position, Pos})
+ end
end.
diff --git a/lib/test_server/doc/src/Makefile b/lib/test_server/doc/src/Makefile
index 8c7fa99886..421079ac94 100644
--- a/lib/test_server/doc/src/Makefile
+++ b/lib/test_server/doc/src/Makefile
@@ -27,6 +27,10 @@ include ../../vsn.mk
VSN=$(TEST_SERVER_VSN)
APPLICATION=test_server
+DOC_EXTRA_FRONT_PAGE_INFO=Important note: \
+The Test Server application is obsolete and will be removed \
+in the next major OTP release
+
# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
diff --git a/lib/test_server/src/erl2html2.erl b/lib/test_server/src/erl2html2.erl
index 7cfaa2c325..83e4dbc3eb 100644
--- a/lib/test_server/src/erl2html2.erl
+++ b/lib/test_server/src/erl2html2.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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
@@ -118,8 +118,9 @@ parse_preprocessed_file(Epp,File,InCorrectFile) ->
{attribute,_,file,{_OtherFile,_}} ->
parse_preprocessed_file(Epp,File,false);
{function,L,F,A,[_|C]} when InCorrectFile ->
- Clauses = [{clause,CL} || {clause,CL,_,_,_} <- C],
- [{atom_to_list(F),A,L} | Clauses] ++
+ Clauses = [{clause,get_line(CL)} ||
+ {clause,CL,_,_,_} <- C],
+ [{atom_to_list(F),A,get_line(L)} | Clauses] ++
parse_preprocessed_file(Epp,File,true);
_ ->
parse_preprocessed_file(Epp,File,InCorrectFile)
@@ -147,8 +148,9 @@ parse_non_preprocessed_file(Epp, File, Location) ->
{ok,Tree,Location1} ->
try erl_syntax:revert(Tree) of
{function,L,F,A,[_|C]} ->
- Clauses = [{clause,CL} || {clause,CL,_,_,_} <- C],
- [{atom_to_list(F),A,L} | Clauses] ++
+ Clauses = [{clause,get_line(CL)} ||
+ {clause,CL,_,_,_} <- C],
+ [{atom_to_list(F),A,get_line(L)} | Clauses] ++
parse_non_preprocessed_file(Epp, File, Location1);
_ ->
parse_non_preprocessed_file(Epp, File, Location1)
@@ -161,6 +163,9 @@ parse_non_preprocessed_file(Epp, File, Location) ->
[]
end.
+get_line(Anno) ->
+ erl_anno:line(Anno).
+
%%%-----------------------------------------------------------------
%%% Add a link target for each line and one for each function definition.
build_html(SFd,DFd,Encoding,Functions) ->
diff --git a/lib/test_server/src/test_server_ctrl.erl b/lib/test_server/src/test_server_ctrl.erl
index bef0658b6d..d0c8a1ebe8 100644
--- a/lib/test_server/src/test_server_ctrl.erl
+++ b/lib/test_server/src/test_server_ctrl.erl
@@ -4776,17 +4776,25 @@ collect_case_subcases(Mod, Case, SubCases, St0, Mode) ->
collect_files(Dir, Pattern, St, Mode) ->
{ok,Cwd} = file:get_cwd(),
Dir1 = filename:join(Cwd, Dir),
- Wc = filename:join([Dir1,Pattern++code:objfile_extension()]),
+ Wc = filename:join([Dir1,Pattern++"{.erl,"++code:objfile_extension()++"}"]),
case catch filelib:wildcard(Wc) of
{'EXIT', Reason} ->
io:format("Could not collect files: ~p~n", [Reason]),
{error,{collect_fail,Dir,Pattern}};
- Mods0 ->
- Mods = [{path_to_module(Mod),all} || Mod <- lists:sort(Mods0)],
- collect_cases(Mods, St, Mode)
+ Files ->
+ %% convert to module names and remove duplicates
+ Mods = lists:foldl(fun(File, Acc) ->
+ Mod = fullname_to_mod(File),
+ case lists:member(Mod, Acc) of
+ true -> Acc;
+ false -> [Mod | Acc]
+ end
+ end, [], Files),
+ Tests = [{Mod,all} || Mod <- lists:sort(Mods)],
+ collect_cases(Tests, St, Mode)
end.
-path_to_module(Path) when is_list(Path) ->
+fullname_to_mod(Path) when is_list(Path) ->
%% If this is called with a binary, then we are probably in +fnu
%% mode and have found a beam file with name encoded as latin1. We
%% will let this crash since it can not work to load such a module
diff --git a/lib/test_server/src/ts.erl b/lib/test_server/src/ts.erl
index d6d2e865e2..469593e947 100644
--- a/lib/test_server/src/ts.erl
+++ b/lib/test_server/src/ts.erl
@@ -24,15 +24,20 @@
-module(ts).
--export([run/0, run/1, run/2, run/3, run/4, run/5,
- tests/0, tests/1,
+-export([cl_run/1,
+ run/0, run/1, run/2, run/3, run/4, run/5,
+ run_category/1, run_category/2, run_category/3,
+ tests/0, tests/1, suites/1, categories/1,
install/0, install/1,
- bench/0, bench/1, bench/2, benchmarks/0,
- smoke_test/0, smoke_test/1,smoke_test/2, smoke_tests/0,
estone/0, estone/1,
cross_cover_analyse/1,
compile_testcases/0, compile_testcases/1,
help/0]).
+
+%% Functions kept for backwards compatibility
+-export([bench/0, bench/1, bench/2, benchmarks/0,
+ smoke_test/0, smoke_test/1,smoke_test/2, smoke_tests/0]).
+
-export([i/0, l/1, r/0, r/1, r/2, r/3]).
%%%----------------------------------------------------------------------
@@ -82,10 +87,13 @@
-define(
install_help,
[
- " ts:install() - Install TS with no Options.\n"
- " ts:install([Options]) - Install TS with Options\n"
+ " ts:install()\n",
+ " Install ts with no options.\n",
+ "\n",
+ " ts:install(Options)\n",
+ " Install ts with a list of options, see below.\n",
"\n",
- "Installation options supported:\n",
+ "Installation options supported:\n\n",
" {longnames, true} - Use fully qualified hostnames\n",
" {verbose, Level} - Sets verbosity level for TS output (0,1,2), 0 is\n"
" quiet(default).\n"
@@ -110,21 +118,64 @@ help() ->
end.
help(uninstalled) ->
- H = ["TS is not installed yet. To install use:\n\n"],
+ H = ["ts is not yet installed. To install use:\n\n"],
show_help([H,?install_help]);
help(installed) ->
- H = ["Run functions:\n",
- " ts:run() - Run all available tests.\n",
- " ts:run(Spec) - Run all tests in given test spec file.\n",
- " The spec file is actually ../*_test/Spec.spec\n",
- " ts:run([Specs]) - Run all tests in all given test spec files.\n",
- " ts:run(Spec, Mod) - Run a single test suite.\n",
- " ts:run(Spec, Mod, Case)\n",
- " - Run a single test case.\n",
- " All above run functions can have an additional Options argument\n",
- " which is a list of options.\n",
+ H = ["\n",
+ "Run functions:\n\n",
+ " ts:run()\n",
+ " Run the tests for all apps. The tests are defined by the\n",
+ " main test specification for each app: ../App_test/App.spec.\n",
+ "\n",
+ " ts:run(Apps)\n",
+ " Apps = atom() | [atom()]\n",
+ " Run the tests for an app, or set of apps. The tests are\n",
+ " defined by the main test specification for each app:\n",
+ " ../App_test/App.spec.\n",
+ "\n",
+ " ts:run(App, Suites)\n",
+ " App = atom(), Suites = atom() | [atom()]\n",
+ " Run one or more test suites for App (i.e. modules named\n",
+ " *_SUITE.erl, located in ../App_test/).\n",
+ "\n",
+ " ts:run(App, Suite, TestCases)\n",
+ " App = atom(), Suite = atom(),\n",
+ " TestCases = TCs | {testcase,TCs}, TCs = atom() | [atom()]\n",
+ " Run one or more test cases (functions) in Suite.\n",
+ "\n",
+ " ts:run(App, Suite, {group,Groups})\n",
+ " App = atom(), Suite = atom(), Groups = atom() | [atom()]\n",
+ " Run one or more test case groups in Suite.\n",
+ "\n",
+ " ts:run(App, Suite, {group,Group}, {testcase,TestCases})\n",
+ " App = atom(), Suite = atom(), Group = atom(),\n",
+ " TestCases = atom() | [atom()]\n",
+ " Run one or more test cases in a test case group in Suite.\n",
+ "\n",
+ " ts:run_category(TestCategory)\n",
+ " TestCategory = smoke | essential | bench | atom()\n",
+ " Run the specified category of tests for all apps.\n",
+ " For each app, the tests are defined by the specification:\n",
+ " ../App_test/App_TestCategory.spec.\n",
+ "\n",
+ " ts:run_category(Apps, TestCategory)\n",
+ " Apps = atom() | [atom()],\n",
+ " TestCategory = smoke | essential | bench | atom()\n",
+ " Run the specified category of tests for the given app or apps.\n",
"\n",
- "Run options supported:\n",
+ " Note that the test category parameter may have arbitrary value,\n",
+ " but should correspond to an existing test specification with file\n",
+ " name: ../App_test/App_TestCategory.spec.\n",
+ " Predefined categories exist for smoke tests, essential tests and\n",
+ " benchmark tests. The corresponding specs are:\n",
+ " ../*_test/Spec_smoke.spec, ../*_test/Spec_essential.spec and\n",
+ " ../*_test/Spec_bench.spec.\n",
+ "\n",
+ " All above run functions can take an additional last argument,\n",
+ " Options, which is a list of options (e.g. ts:run(App, Options),\n",
+ " or ts:run_category(Apps, TestCategory, Options)).\n",
+ "\n",
+ "Run options supported:\n\n",
" batch - Do not start a new xterm\n",
" {verbose, Level} - Same as the verbosity option for install\n",
" verbose - Same as {verbose, 1}\n",
@@ -143,47 +194,46 @@ help(installed) ->
" files are. The default location is\n"
" tests/test_server/.\n"
"\n",
- "Supported trace information elements\n",
+ "Supported trace information elements:\n\n",
" {tp | tpl, Mod, [] | match_spec()}\n",
" {tp | tpl, Mod, Func, [] | match_spec()}\n",
" {tp | tpl, Mod, Func, Arity, [] | match_spec()}\n",
" {ctp | ctpl, Mod}\n",
" {ctp | ctpl, Mod, Func}\n",
" {ctp | ctpl, Mod, Func, Arity}\n",
+ "\n\n",
+ "Support functions:\n\n",
+ " ts:tests()\n",
+ " Returns all apps available for testing.\n",
+ "\n",
+ " ts:tests(TestCategory)\n",
+ " Returns all apps that provide tests in the given category.\n",
+ "\n",
+ " ts:suites(App)\n",
+ " Returns all available test suites for App,\n",
+ " i.e. ../App_test/*_SUITE.erl\n",
+ "\n",
+ " ts:categories(App)\n",
+ " Returns all test categories available for App.\n",
"\n",
- "Support functions:\n",
- " ts:tests() - Shows all available families of tests.\n",
- " ts:tests(Spec) - Shows all available test modules in Spec,\n",
- " i.e. ../Spec_test/*_SUITE.erl\n",
- " ts:estone() - Run estone_SUITE in kernel application with\n"
- " no run options\n",
- " ts:estone(Opts) - Run estone_SUITE in kernel application with\n"
- " the given run options\n",
- " ts:cross_cover_analyse(Level)\n"
- " - Used after ts:run with option cover or \n"
- " cover_details. Analyses modules specified with\n"
- " a 'cross' statement in the cover spec file.\n"
- " Level can be 'overview' or 'details'.\n",
- " ts:compile_testcases()~n"
- " ts:compile_testcases(Apps)~n"
- " - Compile all testcases for usage in a cross ~n"
- " compile environment."
- " \n"
- "Benchmark functions:\n"
- " ts:benchmarks() - Get all available families of benchmarks\n"
- " ts:bench() - Runs all benchmarks\n"
- " ts:bench(Spec) - Runs all benchmarks in the given spec file.\n"
- " The spec file is actually ../*_test/Spec_bench.spec\n\n"
- " ts:bench can take the same Options argument as ts:run.\n"
- "Smoke test functions:\n"
- " ts:smoke_tests() - Get all available families of smoke tests\n"
- " ts:smoke_test() - Runs all smoke tests\n"
- " ts:smoke_test(Spec)\n"
- " - Runs all smoke tests in the given spec file.\n"
- " The spec file is actually ../*_test/Spec_smoke.spec\n\n"
- " ts:smoke_test can take the same Options argument as ts:run.\n"
- "\n"
- "Installation (already done):\n"
+ " ts:estone()\n",
+ " Runs estone_SUITE in the kernel application with no run options\n",
+ "\n",
+ " ts:estone(Opts)\n",
+ " Runs estone_SUITE in the kernel application with the given\n",
+ " run options\n",
+ "\n",
+ " ts:cross_cover_analyse(Level)\n",
+ " Use after ts:run with option cover or cover_details. Analyses\n",
+ " modules specified with a 'cross' statement in the cover spec file.\n",
+ " Level can be 'overview' or 'details'.\n",
+ "\n",
+ " ts:compile_testcases()\n",
+ " ts:compile_testcases(Apps)\n",
+ " Compiles all test cases for the given apps, for usage in a\n",
+ " cross compilation environment.\n",
+ "\n\n",
+ "Installation (already done):\n\n"
],
show_help([H,?install_help]).
@@ -212,86 +262,128 @@ run_all(_Vars) ->
run_some([], _Opts) ->
ok;
-run_some([{Spec,Mod}|Specs], Opts) ->
- case run(Spec, Mod, Opts) of
+run_some([{App,Mod}|Apps], Opts) ->
+ case run(App, Mod, Opts) of
ok -> ok;
- Error -> io:format("~p: ~p~n",[{Spec,Mod},Error])
+ Error -> io:format("~p: ~p~n",[{App,Mod},Error])
end,
- run_some(Specs, Opts);
-run_some([Spec|Specs], Opts) ->
- case run(Spec, Opts) of
+ run_some(Apps, Opts);
+run_some([App|Apps], Opts) ->
+ case run(App, Opts) of
ok -> ok;
- Error -> io:format("~p: ~p~n",[Spec,Error])
+ Error -> io:format("~p: ~p~n",[App,Error])
end,
- run_some(Specs, Opts).
+ run_some(Apps, Opts).
+
+%% This can be used from command line. Both App and
+%% TestCategory must be specified. App may be 'all'
+%% and TestCategory may be 'main'. Examples:
+%% erl -s ts cl_run kernel smoke <options>
+%% erl -s ts cl_run kernel main <options>
+%% erl -s ts cl_run all essential <options>
+%% erl -s ts cl_run all main <options>
+%% When using the 'main' category and running with cover,
+%% one can also use the cross_cover_analysis flag.
+cl_run([App,Cat|Options0]) when is_atom(App) ->
-%% Runs one test spec (interactive).
-run(Testspec) when is_atom(Testspec) ->
- Options=check_test_get_opts(Testspec, []),
- File = atom_to_list(Testspec),
- run_test(File, [{spec,[File++".spec"]}], Options);
-
-%% This can be used from command line, e.g.
-%% erl -s ts run all_tests <config>
-%% When using the all_tests flag and running with cover, one can also
-%% use the cross_cover_analysis flag.
-run([all_tests|Config0]) ->
AllAtomsFun = fun(X) when is_atom(X) -> true;
(_) -> false
end,
- Config1 =
- case lists:all(AllAtomsFun,Config0) of
+ Options1 =
+ case lists:all(AllAtomsFun, Options0) of
true ->
%% Could be from command line
- lists:map(fun(Conf)->to_erlang_term(Conf) end,Config0)--[batch];
+ lists:map(fun(Opt) ->
+ to_erlang_term(Opt)
+ end, Options0) -- [batch];
false ->
- Config0--[batch]
+ Options0 -- [batch]
end,
%% Make sure there is exactly one occurence of 'batch'
- Config2 = [batch|Config1],
-
- R = run(tests(),Config2),
-
- case check_for_cross_cover_analysis_flag(Config2) of
+ Options2 = [batch|Options1],
+
+ Result =
+ case {App,Cat} of
+ {all,main} ->
+ run(tests(), Options2);
+ {all,Cat} ->
+ run_category(Cat, Options2);
+ {_,main} ->
+ run(App, Options2);
+ {_,Cat} ->
+ run_category(App, Cat, Options2)
+ end,
+ case check_for_cross_cover_analysis_flag(Options2) of
false ->
ok;
Level ->
cross_cover_analyse(Level)
end,
+ Result.
- R;
+%% run/1
+%% Runs tests for one app (interactive).
+run(App) when is_atom(App) ->
+ Options = check_test_get_opts(App, []),
+ File = atom_to_list(App),
+ run_test(File, [{spec,[File++".spec"]},{allow_user_terms,true}], Options);
-%% ts:run(ListOfTests)
-run(List) when is_list(List) ->
- run(List, [batch]).
-
-run(List, Opts) when is_list(List), is_list(Opts) ->
- run_some(List, Opts);
+%% This can be used from command line, e.g.
+%% erl -s ts run all <options>
+%% erl -s ts run main <options>
+run([all,main|Opts]) ->
+ cl_run([all,main|Opts]);
+run([all|Opts]) ->
+ cl_run([all,main|Opts]);
+run([main|Opts]) ->
+ cl_run([all,main|Opts]);
+%% Backwards compatible
+run([all_tests|Opts]) ->
+ cl_run([all,main|Opts]);
+
+%% run/1
+%% Runs the main tests for all available apps
+run(Apps) when is_list(Apps) ->
+ run(Apps, [batch]).
%% run/2
-%% Runs one test spec with list of suites or with options
-run(Testspec, ModsOrConfig) when is_atom(Testspec),
- is_list(ModsOrConfig) ->
- case is_list_of_suites(ModsOrConfig) of
+%% Runs the main tests for all available apps
+run(Apps, Opts) when is_list(Apps), is_list(Opts) ->
+ run_some(Apps, Opts);
+
+%% Runs tests for one app with list of suites or with options
+run(App, ModsOrOpts) when is_atom(App),
+ is_list(ModsOrOpts) ->
+ case is_list_of_suites(ModsOrOpts) of
false ->
- run(Testspec, {config_list,ModsOrConfig});
+ run(App, {opts_list,ModsOrOpts});
true ->
- run_some([{Testspec,M} || M <- ModsOrConfig],
+ run_some([{App,M} || M <- ModsOrOpts],
[batch])
end;
-run(Testspec, {config_list,Config}) ->
- Options=check_test_get_opts(Testspec, Config),
- IsSmoke=proplists:get_value(smoke,Config),
- File=atom_to_list(Testspec),
+
+run(App, {opts_list,Opts}) ->
+ Options = check_test_get_opts(App, Opts),
+ File = atom_to_list(App),
+
+ %% check if other test category than main has been specified
+ {CatSpecName,TestCat} =
+ case proplists:get_value(test_category, Opts) of
+ undefined ->
+ {"",main};
+ Cat ->
+ {"_" ++ atom_to_list(Cat),Cat}
+ end,
+
WhatToDo =
- case Testspec of
+ case App of
%% Known to exist but fails generic tests below
emulator -> test;
system -> test;
erl_interface -> test;
epmd -> test;
_ ->
- case code:lib_dir(Testspec) of
+ case code:lib_dir(App) of
{error,bad_name} ->
%% Application does not exist
skip;
@@ -313,92 +405,167 @@ run(Testspec, {config_list,Config}) ->
end
end
end,
- Spec =
- case WhatToDo of
- skip ->
- create_skip_spec(Testspec, tests(Testspec));
- test when IsSmoke ->
- File++"_smoke.spec";
- test ->
- File++".spec"
- end,
- run_test(File, [{spec,[Spec]}], Options);
-%% Runs one module in a spec (interactive)
-run(Testspec, Mod) when is_atom(Testspec), is_atom(Mod) ->
- run_test({atom_to_list(Testspec),Mod},
+ case WhatToDo of
+ skip ->
+ SkipSpec = create_skip_spec(App, suites(App)),
+ run_test(File, [{spec,[SkipSpec]}], Options);
+ test when TestCat == bench ->
+ check_and_run(fun(Vars) ->
+ ts_benchmark:run([App], Options, Vars)
+ end);
+ test ->
+ Spec = File ++ CatSpecName ++ ".spec",
+ run_test(File, [{spec,[Spec]},{allow_user_terms,true}], Options)
+ end;
+
+%% Runs one module for an app (interactive)
+run(App, Mod) when is_atom(App), is_atom(Mod) ->
+ run_test({atom_to_list(App),Mod},
[{suite,Mod}],
[interactive]).
%% run/3
-%% Run one module in a spec with Config
-run(Testspec, Mod, Config) when is_atom(Testspec),
- is_atom(Mod),
- is_list(Config) ->
- Options=check_test_get_opts(Testspec, Config),
- run_test({atom_to_list(Testspec),Mod},
+%% Run one module for an app with Opts
+run(App, Mod, Opts) when is_atom(App),
+ is_atom(Mod),
+ is_list(Opts) ->
+ Options = check_test_get_opts(App, Opts),
+ run_test({atom_to_list(App),Mod},
[{suite,Mod}], Options);
-%% Run multiple modules with Config
-run(Testspec, Mods, Config) when is_atom(Testspec),
- is_list(Mods),
- is_list(Config) ->
- run_some([{Testspec,M} || M <- Mods], Config);
+
+%% Run multiple modules with Opts
+run(App, Mods, Opts) when is_atom(App),
+ is_list(Mods),
+ is_list(Opts) ->
+ run_some([{App,M} || M <- Mods], Opts);
+
%% Runs one test case in a module.
-run(Testspec, Mod, Case) when is_atom(Testspec),
- is_atom(Mod),
- is_atom(Case) ->
- Options=check_test_get_opts(Testspec, []),
+run(App, Mod, Case) when is_atom(App),
+ is_atom(Mod),
+ is_atom(Case) ->
+ Options = check_test_get_opts(App, []),
Args = [{suite,Mod},{testcase,Case}],
- run_test(atom_to_list(Testspec), Args, Options);
+ run_test(atom_to_list(App), Args, Options);
+
%% Runs one or more groups in a module.
-run(Testspec, Mod, Grs={group,_Groups}) when is_atom(Testspec),
- is_atom(Mod) ->
- Options=check_test_get_opts(Testspec, []),
+run(App, Mod, Grs={group,_Groups}) when is_atom(App),
+ is_atom(Mod) ->
+ Options = check_test_get_opts(App, []),
Args = [{suite,Mod},Grs],
- run_test(atom_to_list(Testspec), Args, Options);
+ run_test(atom_to_list(App), Args, Options);
+
%% Runs one or more test cases in a module.
-run(Testspec, Mod, TCs={testcase,_Cases}) when is_atom(Testspec),
- is_atom(Mod) ->
- Options=check_test_get_opts(Testspec, []),
+run(App, Mod, TCs={testcase,_Cases}) when is_atom(App),
+ is_atom(Mod) ->
+ Options = check_test_get_opts(App, []),
Args = [{suite,Mod},TCs],
- run_test(atom_to_list(Testspec), Args, Options).
+ run_test(atom_to_list(App), Args, Options).
%% run/4
%% Run one test case in a module with Options.
-run(Testspec, Mod, Case, Config) when is_atom(Testspec),
- is_atom(Mod),
- is_atom(Case),
- is_list(Config) ->
- Options=check_test_get_opts(Testspec, Config),
+run(App, Mod, Case, Opts) when is_atom(App),
+ is_atom(Mod),
+ is_atom(Case),
+ is_list(Opts) ->
+ Options = check_test_get_opts(App, Opts),
Args = [{suite,Mod},{testcase,Case}],
- run_test(atom_to_list(Testspec), Args, Options);
+ run_test(atom_to_list(App), Args, Options);
+
%% Run one or more test cases in a module with Options.
-run(Testspec, Mod, {testcase,Cases}, Config) when is_atom(Testspec),
- is_atom(Mod) ->
- run(Testspec, Mod, Cases, Config);
-run(Testspec, Mod, Cases, Config) when is_atom(Testspec),
- is_atom(Mod),
- is_list(Cases),
- is_list(Config) ->
- Options=check_test_get_opts(Testspec, Config),
+run(App, Mod, {testcase,Cases}, Opts) when is_atom(App),
+ is_atom(Mod) ->
+ run(App, Mod, Cases, Opts);
+run(App, Mod, Cases, Opts) when is_atom(App),
+ is_atom(Mod),
+ is_list(Cases),
+ is_list(Opts) ->
+ Options = check_test_get_opts(App, Opts),
Args = [{suite,Mod},Cases],
- run_test(atom_to_list(Testspec), Args, Options);
+ run_test(atom_to_list(App), Args, Options);
+
+%% Run one or more test cases in a group.
+run(App, Mod, Gr={group,_Group}, {testcase,Cases}) when is_atom(App),
+ is_atom(Mod) ->
+ run(App, Mod, Gr, Cases, [batch]);
+
+
%% Run one or more groups in a module with Options.
-run(Testspec, Mod, Grs={group,_Groups}, Config) when is_atom(Testspec),
- is_atom(Mod) ->
- Options=check_test_get_opts(Testspec, Config),
+run(App, Mod, Grs={group,_Groups}, Opts) when is_atom(App),
+ is_atom(Mod),
+ is_list(Opts) ->
+ Options = check_test_get_opts(App, Opts),
Args = [{suite,Mod},Grs],
- run_test(atom_to_list(Testspec), Args, Options).
+ run_test(atom_to_list(App), Args, Options).
%% run/5
%% Run one or more test cases in a group with Options.
-run(Testspec, Mod, Group, Cases, Config) when is_atom(Testspec),
- is_atom(Mod),
- is_list(Config) ->
+run(App, Mod, Group, Cases, Opts) when is_atom(App),
+ is_atom(Mod),
+ is_list(Opts) ->
Group1 = if is_tuple(Group) -> Group; true -> {group,Group} end,
Cases1 = if is_tuple(Cases) -> Cases; true -> {testcase,Cases} end,
- Options=check_test_get_opts(Testspec, Config),
+ Options = check_test_get_opts(App, Opts),
Args = [{suite,Mod},Group1,Cases1],
- run_test(atom_to_list(Testspec), Args, Options).
+ run_test(atom_to_list(App), Args, Options).
+
+%% run_category/1
+run_category(TestCategory) when is_atom(TestCategory) ->
+ run_category(TestCategory, [batch]).
+
+%% run_category/2
+run_category(TestCategory, Opts) when is_atom(TestCategory),
+ is_list(Opts) ->
+ case ts:tests(TestCategory) of
+ [] ->
+ {error, no_tests_available};
+ Apps ->
+ Opts1 = [{test_category,TestCategory} | Opts],
+ run_some(Apps, Opts1)
+ end;
+
+run_category(Apps, TestCategory) when is_atom(TestCategory) ->
+ run_category(Apps, TestCategory, [batch]).
+
+%% run_category/3
+run_category(App, TestCategory, Opts) ->
+ Apps = if is_atom(App) -> [App];
+ is_list(App) -> App
+ end,
+ Opts1 = [{test_category,TestCategory} | Opts],
+ run_some(Apps, Opts1).
+
+%%-----------------------------------------------------------------
+%% Functions kept for backwards compatibility
+
+bench() ->
+ run_category(bench, []).
+bench(Opts) when is_list(Opts) ->
+ run_category(bench, Opts);
+bench(App) ->
+ run_category(App, bench, []).
+bench(App, Opts) when is_atom(App) ->
+ run_category(App, bench, Opts);
+bench(Apps, Opts) when is_list(Apps) ->
+ run_category(Apps, bench, Opts).
+
+benchmarks() ->
+ tests(bench).
+
+smoke_test() ->
+ run_category(smoke, []).
+smoke_test(Opts) when is_list(Opts) ->
+ run_category(smoke, Opts);
+smoke_test(App) ->
+ run_category(App, smoke, []).
+smoke_test(App, Opts) when is_atom(App) ->
+ run_category(App, smoke, Opts);
+smoke_test(Apps, Opts) when is_list(Apps) ->
+ run_category(Apps, smoke, Opts).
+
+smoke_tests() ->
+ tests(smoke).
+
+%%-----------------------------------------------------------------
is_list_of_suites(List) ->
lists:all(fun(Suite) ->
@@ -416,29 +583,29 @@ is_list_of_suites(List) ->
%% Create a spec to skip all SUITES, this is used when the application
%% to be tested is not part of the OTP release to be tested.
-create_skip_spec(Testspec, SuitesToSkip) ->
+create_skip_spec(App, SuitesToSkip) ->
{ok,Cwd} = file:get_cwd(),
- TestspecString = atom_to_list(Testspec),
- Specname = TestspecString++"_skip.spec",
+ AppString = atom_to_list(App),
+ Specname = AppString++"_skip.spec",
{ok,D} = file:open(filename:join([filename:dirname(Cwd),
- TestspecString++"_test",Specname]),
+ AppString++"_test",Specname]),
[write]),
- TestDir = "\"../"++TestspecString++"_test\"",
+ TestDir = "\"../"++AppString++"_test\"",
io:format(D,"{suites, "++TestDir++", all}.~n",[]),
io:format(D,"{skip_suites, "++TestDir++", ~w, \"Skipped as application"
" is not in path!\"}.",[SuitesToSkip]),
Specname.
-%% Check testspec to be valid and get possible Options
-%% from the config.
-check_test_get_opts(Testspec, Config) ->
- validate_test(Testspec),
- Mode = configmember(batch, {batch, interactive}, Config),
- Vars = configvars(Config),
- Trace = get_config(trace,Config),
- ConfigPath = get_config(config,Config),
- KeepTopcase = configmember(keep_topcase, {keep_topcase,[]}, Config),
- Cover = configcover(Testspec,Config),
+%% Check testspec for App to be valid and get possible options
+%% from the list.
+check_test_get_opts(App, Opts) ->
+ validate_test(App),
+ Mode = configmember(batch, {batch, interactive}, Opts),
+ Vars = configvars(Opts),
+ Trace = get_config(trace,Opts),
+ ConfigPath = get_config(config,Opts),
+ KeepTopcase = configmember(keep_topcase, {keep_topcase,[]}, Opts),
+ Cover = configcover(App,Opts),
lists:flatten([Vars,Mode,Trace,KeepTopcase,Cover,ConfigPath]).
to_erlang_term(Atom) ->
@@ -447,7 +614,7 @@ to_erlang_term(Atom) ->
{ok, Term} = erl_parse:parse_term(Tokens),
Term.
-%% Validate that a Testspec really is a testspec,
+%% Validate that Testspec really is a testspec,
%% and exit if not.
validate_test(Testspec) ->
case lists:member(Testspec, tests()) of
@@ -460,10 +627,10 @@ validate_test(Testspec) ->
exit(self(), {error, test_not_available})
end.
-configvars(Config) ->
- case lists:keysearch(vars, 1, Config) of
+configvars(Opts) ->
+ case lists:keysearch(vars, 1, Opts) of
{value, {vars, List}} ->
- List0 = special_vars(Config),
+ List0 = special_vars(Opts),
Key = fun(T) -> element(1,T) end,
DelDupList =
lists:filter(fun(V) ->
@@ -474,17 +641,17 @@ configvars(Config) ->
end, List),
{vars, [List0|DelDupList]};
_ ->
- {vars, special_vars(Config)}
+ {vars, special_vars(Opts)}
end.
-%% Allow some shortcuts in the Options...
-special_vars(Config) ->
+%% Allow some shortcuts in the options...
+special_vars(Opts) ->
SpecVars =
- case lists:member(verbose, Config) of
+ case lists:member(verbose, Opts) of
true ->
[{verbose, 1}];
false ->
- case lists:keysearch(verbose, 1, Config) of
+ case lists:keysearch(verbose, 1, Opts) of
{value, {verbose, Lvl}} ->
[{verbose, Lvl}];
_ ->
@@ -492,13 +659,13 @@ special_vars(Config) ->
end
end,
SpecVars1 =
- case lists:keysearch(diskless, 1, Config) of
+ case lists:keysearch(diskless, 1, Opts) of
{value,{diskless, true}} ->
[{diskless, true} | SpecVars];
_ ->
SpecVars
end,
- case lists:keysearch(testcase_callback, 1, Config) of
+ case lists:keysearch(testcase_callback, 1, Opts) of
{value,{testcase_callback, CBM, CBF}} ->
[{ts_testcase_callback, {CBM,CBF}} | SpecVars1];
{value,{testcase_callback, CB}} ->
@@ -566,50 +733,31 @@ check_for_cross_cover_analysis_flag([_|Config],Level,CrossFlag) ->
check_for_cross_cover_analysis_flag([],_,_) ->
false.
-%% Returns a list of available test suites.
+%% Returns all available apps.
tests() ->
{ok, Cwd} = file:get_cwd(),
ts_lib:specs(Cwd).
-tests(Spec) ->
+%% Returns all apps that provide tests in the given test category
+tests(main) ->
{ok, Cwd} = file:get_cwd(),
- ts_lib:suites(Cwd, atom_to_list(Spec)).
-
-%% Benchmark related functions
-
-bench() ->
- bench([]).
-
-bench(Opts) when is_list(Opts) ->
- bench(benchmarks(),Opts);
-bench(Spec) ->
- bench([Spec],[]).
-
-bench(Spec, Opts) when is_atom(Spec) ->
- bench([Spec],Opts);
-bench(Specs, Opts) ->
- check_and_run(fun(Vars) -> ts_benchmark:run(Specs, Opts, Vars) end).
-
-benchmarks() ->
- ts_benchmark:benchmarks().
-
-smoke_test() ->
- smoke_test([]).
-
-smoke_test(Opts) when is_list(Opts) ->
- smoke_test(smoke_tests(),Opts);
-smoke_test(Spec) ->
- smoke_test([Spec],[]).
-
-smoke_test(Spec, Opts) when is_atom(Spec) ->
- smoke_test([Spec],Opts);
-smoke_test(Specs, Opts) ->
- run(Specs, [{smoke,true}|Opts]).
+ ts_lib:specs(Cwd);
+tests(bench) ->
+ ts_benchmark:benchmarks();
+tests(TestCategory) ->
+ {ok, Cwd} = file:get_cwd(),
+ ts_lib:specialized_specs(Cwd, atom_to_list(TestCategory)).
+
+%% Returns a list of available test suites for App.
+suites(App) ->
+ {ok, Cwd} = file:get_cwd(),
+ ts_lib:suites(Cwd, atom_to_list(App)).
-smoke_tests() ->
+%% Returns all available test categories for App
+categories(App) ->
{ok, Cwd} = file:get_cwd(),
- ts_lib:specialized_specs(Cwd,"smoke").
+ ts_lib:test_categories(Cwd, atom_to_list(App)).
%%
%% estone/0, estone/1
diff --git a/lib/test_server/src/ts_lib.erl b/lib/test_server/src/ts_lib.erl
index 5368960446..d27bc55b3a 100644
--- a/lib/test_server/src/ts_lib.erl
+++ b/lib/test_server/src/ts_lib.erl
@@ -27,7 +27,7 @@
erlang_type/1,
initial_capital/1,
specs/1, suites/2,
- specialized_specs/2,
+ test_categories/2, specialized_specs/2,
subst_file/3, subst/2, print_data/1,
make_non_erlang/2,
maybe_atom_to_list/1, progress/4,
@@ -96,26 +96,47 @@ specialized_specs(Dir,PostFix) ->
Specs = filelib:wildcard(filename:join([filename:dirname(Dir),
"*_test", "*_"++PostFix++".spec"])),
sort_tests([begin
- Base = filename:basename(Name),
- list_to_atom(string:substr(Base,1,string:rstr(Base,"_")-1))
+ DirPart = filename:dirname(Name),
+ AppTest = hd(lists:reverse(filename:split(DirPart))),
+ list_to_atom(string:substr(AppTest, 1, length(AppTest)-5))
end || Name <- Specs]).
specs(Dir) ->
Specs = filelib:wildcard(filename:join([filename:dirname(Dir),
"*_test", "*.{dyn,}spec"])),
- % Filter away all spec which end with {_bench,_smoke}.spec
- NoBench = fun(SpecName) ->
- case lists:reverse(SpecName) of
- "ceps.hcneb_"++_ -> false;
- "ceps.ekoms_"++_ -> false;
- _ -> true
- end
- end,
-
- sort_tests([filename_to_atom(Name) || Name <- Specs, NoBench(Name)]).
-
-suites(Dir, Spec) ->
- Glob=filename:join([filename:dirname(Dir), Spec++"_test",
+ %% Make sure only to include the main spec for each application
+ MainSpecs =
+ lists:flatmap(fun(FullName) ->
+ [Spec,TestDir|_] =
+ lists:reverse(filename:split(FullName)),
+ [_TestSuffix|TDParts] =
+ lists:reverse(string:tokens(TestDir,[$_,$.])),
+ [_SpecSuffix|SParts] =
+ lists:reverse(string:tokens(Spec,[$_,$.])),
+ if TDParts == SParts ->
+ [filename_to_atom(FullName)];
+ true ->
+ []
+ end
+ end, Specs),
+ sort_tests(MainSpecs).
+
+test_categories(Dir, App) ->
+ Specs = filelib:wildcard(filename:join([filename:dirname(Dir),
+ App++"_test", "*.spec"])),
+ lists:flatmap(fun(FullName) ->
+ [Spec,_TestDir|_] =
+ lists:reverse(filename:split(FullName)),
+ case filename:rootname(Spec -- App) of
+ "" ->
+ [];
+ [_Sep | Cat] ->
+ [list_to_atom(Cat)]
+ end
+ end, Specs).
+
+suites(Dir, App) ->
+ Glob=filename:join([filename:dirname(Dir), App++"_test",
"*_SUITE.erl"]),
Suites=filelib:wildcard(Glob),
[filename_to_atom(Name) || Name <- Suites].
diff --git a/lib/tools/src/cover.erl b/lib/tools/src/cover.erl
index 6c32c47069..71e17e0ba1 100644
--- a/lib/tools/src/cover.erl
+++ b/lib/tools/src/cover.erl
@@ -136,7 +136,7 @@
-define(SERVER, cover_server).
%% Line doesn't matter.
--define(BLOCK(Expr), {block,0,[Expr]}).
+-define(BLOCK(Expr), {block,erl_anno:new(0),[Expr]}).
-define(BLOCK1(Expr),
if
element(1, Expr) =:= block ->
@@ -1626,18 +1626,18 @@ expand({clause,Line,Pattern,Guards,Body}, Vs, N) ->
expand({op,_Line,'andalso',ExprL,ExprR}, Vs, N) ->
{ExpandedExprL,N2} = expand(ExprL, Vs, N),
{ExpandedExprR,N3} = expand(ExprR, Vs, N2),
- LineL = element(2, ExpandedExprL),
+ Anno = element(2, ExpandedExprL),
{bool_switch(ExpandedExprL,
ExpandedExprR,
- {atom,LineL,false},
+ {atom,Anno,false},
Vs, N3),
N3 + 1};
expand({op,_Line,'orelse',ExprL,ExprR}, Vs, N) ->
{ExpandedExprL,N2} = expand(ExprL, Vs, N),
{ExpandedExprR,N3} = expand(ExprR, Vs, N2),
- LineL = element(2, ExpandedExprL),
+ Anno = element(2, ExpandedExprL),
{bool_switch(ExpandedExprL,
- {atom,LineL,true},
+ {atom,Anno,true},
ExpandedExprR,
Vs, N3),
N3 + 1};
@@ -1746,7 +1746,7 @@ munge_body(Expr, Vars) ->
munge_body([Expr|Body], Vars, MungedBody, LastExprBumpLines) ->
%% Here is the place to add a call to cover:bump/6!
- Line = element(2, Expr),
+ Line = erl_anno:line(element(2, Expr)),
Lines = Vars#vars.lines,
case lists:member(Line,Lines) of
true -> % already a bump at this line
@@ -1882,17 +1882,18 @@ fix_cls([Cl | Cls], Line, Bump) ->
false ->
{clause,CL,P,G,Body} = Cl,
UniqueVarName = list_to_atom(lists:concat(["$cover$ ",Line])),
- V = {var,0,UniqueVarName},
+ A = erl_anno:new(0),
+ V = {var,A,UniqueVarName},
[Last|Rest] = lists:reverse(Body),
- Body1 = lists:reverse(Rest, [{match,0,V,Last},Bump,V]),
+ Body1 = lists:reverse(Rest, [{match,A,V,Last},Bump,V]),
[{clause,CL,P,G,Body1} | fix_cls(Cls, Line, Bump)]
end.
bumps_line(E, L) ->
try bumps_line1(E, L) catch true -> true end.
-bumps_line1({call,0,{remote,0,{atom,0,ets},{atom,0,update_counter}},
- [{atom,0,?COVER_TABLE},{tuple,0,[_,_,_,_,_,{integer,0,Line}]},_]},
+bumps_line1({call,_,{remote,_,{atom,_,ets},{atom,_,update_counter}},
+ [{atom,_,?COVER_TABLE},{tuple,_,[_,_,_,_,_,{integer,_,Line}]},_]},
Line) ->
throw(true);
bumps_line1([E | Es], Line) ->
@@ -1906,15 +1907,16 @@ bumps_line1(_, _) ->
%%% End of fix of last expression.
bump_call(Vars, Line) ->
- {call,0,{remote,0,{atom,0,ets},{atom,0,update_counter}},
- [{atom,0,?COVER_TABLE},
- {tuple,0,[{atom,0,?BUMP_REC_NAME},
- {atom,0,Vars#vars.module},
- {atom,0,Vars#vars.function},
- {integer,0,Vars#vars.arity},
- {integer,0,Vars#vars.clause},
- {integer,0,Line}]},
- {integer,0,1}]}.
+ A = erl_anno:new(0),
+ {call,A,{remote,A,{atom,A,ets},{atom,A,update_counter}},
+ [{atom,A,?COVER_TABLE},
+ {tuple,A,[{atom,A,?BUMP_REC_NAME},
+ {atom,A,Vars#vars.module},
+ {atom,A,Vars#vars.function},
+ {integer,A,Vars#vars.arity},
+ {integer,A,Vars#vars.clause},
+ {integer,A,Line}]},
+ {integer,A,1}]}.
munge_expr({match,Line,ExprL,ExprR}, Vars) ->
{MungedExprL, Vars2} = munge_expr(ExprL, Vars),
diff --git a/lib/tools/src/xref.hrl b/lib/tools/src/xref.hrl
index fa8c5c746d..5e79c477f3 100644
--- a/lib/tools/src/xref.hrl
+++ b/lib/tools/src/xref.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2000-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
@@ -22,6 +22,8 @@
-define(VAR_EXPR, '$F_EXPR').
-define(MOD_EXPR, '$M_EXPR').
+-define(XREF_END_LINE, (1 bsl 23)).
+
%%% Filenames are stored as directory and basename. A lot of heap can
%%% be saved by keeping only one (or few) copy of the directory name.
diff --git a/lib/tools/src/xref_compiler.erl b/lib/tools/src/xref_compiler.erl
index c4b5c04c12..c914a76bf0 100644
--- a/lib/tools/src/xref_compiler.erl
+++ b/lib/tools/src/xref_compiler.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2000-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
@@ -924,7 +924,7 @@ format_parse_error(["invalid_operator", Op], Line) ->
format_parse_error(Error, Line) ->
io_lib:format("Parse error~s: ~ts~n", [Line, lists:flatten(Error)]).
-format_line(-1) ->
+format_line(?XREF_END_LINE) ->
" at end of string";
format_line(0) ->
"";
diff --git a/lib/tools/src/xref_reader.erl b/lib/tools/src/xref_reader.erl
index 142d28ebe6..723fb729cd 100644
--- a/lib/tools/src/xref_reader.erl
+++ b/lib/tools/src/xref_reader.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2000-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
@@ -77,17 +77,18 @@ forms([], S) ->
form({attribute, Line, xref, Calls}, S) -> % experimental
#xrefr{module = M, function = Fun,
lattrs = L, xattrs = X, battrs = B} = S,
- attr(Calls, Line, M, Fun, L, X, B, S);
+ attr(Calls, erl_anno:line(Line), M, Fun, L, X, B, S);
form({attribute, _Line, _Attr, _Val}, S) ->
S;
-form({function, 0, module_info, 0, _Clauses}, S) ->
+form({function, _, module_info, 0, _Clauses}, S) ->
S;
-form({function, 0, module_info, 1, _Clauses}, S) ->
+form({function, _, module_info, 1, _Clauses}, S) ->
S;
-form({function, Line, Name, Arity, Clauses}, S) ->
+form({function, Anno, Name, Arity, Clauses}, S) ->
MFA0 = {S#xrefr.module, Name, Arity},
MFA = adjust_arity(S, MFA0),
S1 = S#xrefr{function = MFA},
+ Line = erl_anno:line(Anno),
S2 = S1#xrefr{def_at = [{MFA,Line} | S#xrefr.def_at]},
S3 = clauses(Clauses, S2),
S3#xrefr{function = []}.
@@ -305,10 +306,14 @@ fun_args(apply2, [FunArg, Args]) -> {FunArg, Args};
fun_args(1, [FunArg | Args]) -> {FunArg, Args};
fun_args(2, [_Node, FunArg | Args]) -> {FunArg, Args}.
-list2term([A | As]) ->
- {cons, 0, A, list2term(As)};
-list2term([]) ->
- {nil, 0}.
+list2term(L) ->
+ A = erl_anno:new(0),
+ list2term(L, A).
+
+list2term([A | As], Anno) ->
+ {cons, Anno, A, list2term(As)};
+list2term([], Anno) ->
+ {nil, Anno}.
term2list({cons, _Line, H, T}, L, S) ->
term2list(T, [H | L], S);
@@ -335,10 +340,11 @@ handle_call(Locality, Module, Name, Arity, Line, S) ->
handle_call(Locality, To, Line, S, false)
end.
-handle_call(Locality, To0, Line, S, IsUnres) ->
+handle_call(Locality, To0, Anno, S, IsUnres) ->
From = S#xrefr.function,
To = adjust_arity(S, To0),
Call = {From, To},
+ Line = erl_anno:line(Anno),
CallAt = {Call, Line},
S1 = if
IsUnres ->
diff --git a/lib/tools/src/xref_scanner.erl b/lib/tools/src/xref_scanner.erl
index 990f8aa87b..4c93033d7c 100644
--- a/lib/tools/src/xref_scanner.erl
+++ b/lib/tools/src/xref_scanner.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2000-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
@@ -19,6 +19,8 @@
-module(xref_scanner).
+-include("xref.hrl").
+
-export([scan/1]).
scan(Chars) ->
@@ -77,7 +79,7 @@ lex([V={var,N,Var} | L]) ->
lex([T | Ts]) ->
[T | lex(Ts)];
lex([]) ->
- [{'$end', -1}].
+ [{'$end', erl_anno:new(?XREF_END_LINE)}].
is_type('Rel') -> true;
is_type('App') -> true;
diff --git a/lib/webtool/doc/src/Makefile b/lib/webtool/doc/src/Makefile
index 32269e9424..08292fcca8 100644
--- a/lib/webtool/doc/src/Makefile
+++ b/lib/webtool/doc/src/Makefile
@@ -25,6 +25,10 @@ include ../../vsn.mk
VSN=$(WEBTOOL_VSN)
APPLICATION=webtool
+DOC_EXTRA_FRONT_PAGE_INFO=Important note: \
+The Webtool application is obsolete and will be removed \
+in the next major OTP release
+
# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
diff --git a/lib/wx/api_gen/wx_gen_cpp.erl b/lib/wx/api_gen/wx_gen_cpp.erl
index 720526b3b9..8e32aeddc8 100644
--- a/lib/wx/api_gen/wx_gen_cpp.erl
+++ b/lib/wx/api_gen/wx_gen_cpp.erl
@@ -197,8 +197,8 @@ gen_funcs(Defs) ->
w(" if(recurse_level > 1 && refd->type != 4) {~n"),
w(" delayed_delete->Append(Ecmd.Save());~n"),
w(" } else {~n"),
- w(" ((WxeApp *) wxTheApp)->clearPtr(This);~n"),
- w(" delete_object(This, refd); }~n"),
+ w(" delete_object(This, refd);~n"),
+ w(" ((WxeApp *) wxTheApp)->clearPtr(This);}~n"),
w(" } } break;~n"),
w(" case WXE_REGISTER_OBJECT: {~n"
" registerPid(bp, Ecmd.caller, memenv);~n"
diff --git a/lib/wx/api_gen/wxapi.conf b/lib/wx/api_gen/wxapi.conf
index 09f21af0f3..bbf9add59e 100644
--- a/lib/wx/api_gen/wxapi.conf
+++ b/lib/wx/api_gen/wxapi.conf
@@ -1358,7 +1358,8 @@
wxEVT_SCROLL_THUMBRELEASE,wxEVT_SCROLL_CHANGED]}],
['GetOrientation','GetPosition']}.
{class, wxScrollWinEvent,wxEvent,
- [{event,
+ [{acc, [{m_commandInt, "GetPosition()"}, {m_extraLong, "GetOrientation()"}]},
+ {event,
[wxEVT_SCROLLWIN_TOP,wxEVT_SCROLLWIN_BOTTOM,wxEVT_SCROLLWIN_LINEUP,
wxEVT_SCROLLWIN_LINEDOWN,wxEVT_SCROLLWIN_PAGEUP,
wxEVT_SCROLLWIN_PAGEDOWN,wxEVT_SCROLLWIN_THUMBTRACK,
@@ -1383,7 +1384,9 @@
'ShiftDown'
]}.
-{class, wxSetCursorEvent, wxEvent, [{event,[wxEVT_SET_CURSOR]}],
+{class, wxSetCursorEvent, wxEvent,
+ [{acc, [{m_x, "GetX()"}, {m_y, "GetY()"}, {m_cursor, "GetCursor()"}]},
+ {event,[wxEVT_SET_CURSOR]}],
['GetCursor','GetX','GetY','HasCursor','SetCursor']}.
{class, wxKeyEvent, wxEvent,
@@ -1398,7 +1401,7 @@
{class, wxSizeEvent, wxEvent, [{event,[wxEVT_SIZE]}],
['GetSize']}.
-{class, wxMoveEvent, wxEvent, [{event,[wxEVT_MOVE]}],
+{class, wxMoveEvent, wxEvent, [{acc, [{m_pos, "GetPosition()"}, {m_rect, "GetRect()"}]}, {event,[wxEVT_MOVE]}],
['GetPosition']}.
{class, wxPaintEvent, wxEvent, [{event,[wxEVT_PAINT]}],[]}.
%%{class, wxNcPaintEvent, wxEvent, [{event,[wxEVT_NC_PAINT]}],[]}.
@@ -1407,28 +1410,28 @@
{event, [wxEVT_ERASE_BACKGROUND]}],
['GetDC']}.
{class, wxFocusEvent, wxEvent,
- [{event,[wxEVT_SET_FOCUS,wxEVT_KILL_FOCUS]}],
+ [{acc, [{m_win, "GetWindow()"}]},
+ {event,[wxEVT_SET_FOCUS,wxEVT_KILL_FOCUS]}],
['GetWindow']}.
{class,wxChildFocusEvent,wxCommandEvent,
[{event,[wxEVT_CHILD_FOCUS]}],
['GetWindow']}.
-%% {class, wxActivateEvent, wxEvent, [{event,
-%% [wxEVT_ACTIVATE,wxEVT_ACTIVATE_APP,wxEVT_HIBERNATE]}],[]}.
-
-%%{class, wxInitDialogEvent, wxEvent, [{event, []}],[]}.
-
-{class, wxMenuEvent, wxEvent,
- [{event, [wxEVT_MENU_OPEN,wxEVT_MENU_CLOSE,wxEVT_MENU_HIGHLIGHT]}],
+{class, wxMenuEvent, wxEvent,
+ [{acc, [{m_menuId, "GetMenuId()"}, {m_menu, "GetMenu()"}]},
+ {event, [wxEVT_MENU_OPEN,wxEVT_MENU_CLOSE,wxEVT_MENU_HIGHLIGHT]}],
['GetMenu','GetMenuId','IsPopup']}.
{class, wxCloseEvent, wxEvent,
[{event, [wxEVT_CLOSE_WINDOW,wxEVT_END_SESSION,wxEVT_QUERY_END_SESSION]}],
['CanVeto','GetLoggingOff','SetCanVeto','SetLoggingOff','Veto']}.
-{class, wxShowEvent, wxEvent, [{event,[wxEVT_SHOW]}],['SetShow','GetShow']}.
-{class, wxIconizeEvent, wxEvent, [{event,[wxEVT_ICONIZE]}],['Iconized']}.
+{class, wxShowEvent, wxEvent, [{acc, [{m_show, "GetShow()"}]},{event,[wxEVT_SHOW]}],['SetShow','GetShow']}.
+{class, wxIconizeEvent, wxEvent, [{acc, [{m_iconized, "Iconized()"}]},{event,[wxEVT_ICONIZE]}],['Iconized']}.
{class, wxMaximizeEvent, wxEvent, [{event,[wxEVT_MAXIMIZE]}],[]}.
-{class, wxJoystickEvent, wxEvent,
- [{event,[wxEVT_JOY_BUTTON_DOWN,wxEVT_JOY_BUTTON_UP,
+{class, wxJoystickEvent, wxEvent,
+ [{acc, [{m_pos, "GetPosition()"},{m_zPosition, "GetZPosition()"},
+ {m_buttonChange, "GetButtonChange()"}, {m_buttonState, "GetButtonState()"},
+ {m_joyStick, "GetJoystick()"}]},
+ {event,[wxEVT_JOY_BUTTON_DOWN,wxEVT_JOY_BUTTON_UP,
wxEVT_JOY_MOVE,wxEVT_JOY_ZMOVE]}],
['ButtonDown','ButtonIsDown','ButtonUp','GetButtonChange','GetButtonState',
'GetJoystick','GetPosition','GetZPosition','IsButton','IsMove','IsZMove']}.
@@ -1466,7 +1469,8 @@
'SetOrigin',
'SetPosition']}.
-{class, wxContextMenuEvent, wxCommandEvent, [{event,[wxEVT_CONTEXT_MENU]}],
+{class, wxContextMenuEvent, wxCommandEvent,
+ [{acc, [{m_pos, "GetPosition()"}]}, {event,[wxEVT_CONTEXT_MENU]}],
['GetPosition','SetPosition']}.
{enum, wxIdleMode, "wxIDLE_"}.
{class, wxIdleEvent, wxEvent, [{event,[wxEVT_IDLE]}],
@@ -1525,7 +1529,8 @@
]}.
{class, wxCalendarEvent, wxDateEvent,
- [{event,[wxEVT_CALENDAR_SEL_CHANGED, wxEVT_CALENDAR_DAY_CHANGED,
+ [{acc, [{m_date, "GetDate()"}, {m_wday, "GetWeekDay()"}]},
+ {event,[wxEVT_CALENDAR_SEL_CHANGED, wxEVT_CALENDAR_DAY_CHANGED,
wxEVT_CALENDAR_MONTH_CHANGED, wxEVT_CALENDAR_YEAR_CHANGED,
wxEVT_CALENDAR_DOUBLECLICKED, wxEVT_CALENDAR_WEEKDAY_CLICKED]}],
[
@@ -1730,8 +1735,9 @@
['GetKeyCode','GetItem','GetKeyEvent','GetLabel','GetOldItem','GetPoint',
'IsEditCancelled','SetToolTip']}.
-{class, wxNotebookEvent, wxNotifyEvent,
- [{event, [wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,
+{class, wxNotebookEvent, wxNotifyEvent,
+ [{acc, [{m_nSel, "GetSelection()"}, {m_nOldSel, "GetOldSelection()"}]},
+ {event, [wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,
wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING]}],
['GetOldSelection','GetSelection','SetOldSelection','SetSelection']}.
diff --git a/lib/wx/c_src/gen/wxe_events.cpp b/lib/wx/c_src/gen/wxe_events.cpp
index ae85931d8d..e042b4d890 100644
--- a/lib/wx/c_src/gen/wxe_events.cpp
+++ b/lib/wx/c_src/gen/wxe_events.cpp
@@ -375,10 +375,13 @@ case 165: {// wxScrollEvent or wxSpinEvent
break;
}
case 166: {// wxScrollWinEvent
+ wxScrollWinEvent * ev = (wxScrollWinEvent *) event;
evClass = (char*)"wxScrollWinEvent";
rt.addAtom((char*)"wxScrollWin");
rt.addAtom(Etype->eName);
- rt.addTupleCount(2);
+ rt.addInt(ev->GetPosition());
+ rt.addInt(ev->GetOrientation());
+ rt.addTupleCount(4);
break;
}
case 167: {// wxMouseEvent
@@ -406,10 +409,16 @@ case 167: {// wxMouseEvent
break;
}
case 168: {// wxSetCursorEvent
+ wxSetCursorEvent * ev = (wxSetCursorEvent *) event;
+ wxCursor * GetCursor = new wxCursor(ev->GetCursor());
+ app->newPtr((void *) GetCursor,3, memenv);
evClass = (char*)"wxSetCursorEvent";
rt.addAtom((char*)"wxSetCursor");
rt.addAtom(Etype->eName);
- rt.addTupleCount(2);
+ rt.addInt(ev->GetX());
+ rt.addInt(ev->GetY());
+ rt.addRef(getRef((void *)GetCursor,memenv), "wxCursor");
+ rt.addTupleCount(5);
break;
}
case 169: {// wxKeyEvent
@@ -450,10 +459,13 @@ case 170: {// wxSizeEvent
break;
}
case 171: {// wxMoveEvent
+ wxMoveEvent * ev = (wxMoveEvent *) event;
evClass = (char*)"wxMoveEvent";
rt.addAtom((char*)"wxMove");
rt.addAtom(Etype->eName);
- rt.addTupleCount(2);
+ rt.add(ev->GetPosition());
+ rt.add(ev->GetRect());
+ rt.addTupleCount(4);
break;
}
case 172: {// wxPaintEvent
@@ -474,10 +486,13 @@ case 173: {// wxEraseEvent
break;
}
case 174: {// wxFocusEvent
+ wxFocusEvent * ev = (wxFocusEvent *) event;
+ wxWindow * GetWindow = ev->GetWindow();
evClass = (char*)"wxFocusEvent";
rt.addAtom((char*)"wxFocus");
rt.addAtom(Etype->eName);
- rt.addTupleCount(2);
+ rt.addRef(getRef((void *)GetWindow,memenv), "wxWindow");
+ rt.addTupleCount(3);
break;
}
case 175: {// wxChildFocusEvent
@@ -488,10 +503,14 @@ case 175: {// wxChildFocusEvent
break;
}
case 176: {// wxMenuEvent
+ wxMenuEvent * ev = (wxMenuEvent *) event;
+ wxMenu * GetMenu = ev->GetMenu();
evClass = (char*)"wxMenuEvent";
rt.addAtom((char*)"wxMenu");
rt.addAtom(Etype->eName);
- rt.addTupleCount(2);
+ rt.addInt(ev->GetMenuId());
+ rt.addRef(getRef((void *)GetMenu,memenv), "wxMenu");
+ rt.addTupleCount(4);
break;
}
case 177: {// wxCloseEvent
@@ -502,17 +521,21 @@ case 177: {// wxCloseEvent
break;
}
case 178: {// wxShowEvent
+ wxShowEvent * ev = (wxShowEvent *) event;
evClass = (char*)"wxShowEvent";
rt.addAtom((char*)"wxShow");
rt.addAtom(Etype->eName);
- rt.addTupleCount(2);
+ rt.addBool(ev->GetShow());
+ rt.addTupleCount(3);
break;
}
case 179: {// wxIconizeEvent
+ wxIconizeEvent * ev = (wxIconizeEvent *) event;
evClass = (char*)"wxIconizeEvent";
rt.addAtom((char*)"wxIconize");
rt.addAtom(Etype->eName);
- rt.addTupleCount(2);
+ rt.addBool(ev->Iconized());
+ rt.addTupleCount(3);
break;
}
case 180: {// wxMaximizeEvent
@@ -523,10 +546,16 @@ case 180: {// wxMaximizeEvent
break;
}
case 181: {// wxJoystickEvent
+ wxJoystickEvent * ev = (wxJoystickEvent *) event;
evClass = (char*)"wxJoystickEvent";
rt.addAtom((char*)"wxJoystick");
rt.addAtom(Etype->eName);
- rt.addTupleCount(2);
+ rt.add(ev->GetPosition());
+ rt.addInt(ev->GetZPosition());
+ rt.addInt(ev->GetButtonChange());
+ rt.addInt(ev->GetButtonState());
+ rt.addInt(ev->GetJoystick());
+ rt.addTupleCount(7);
break;
}
case 182: {// wxUpdateUIEvent
@@ -603,10 +632,12 @@ case 191: {// wxHelpEvent
break;
}
case 192: {// wxContextMenuEvent
+ wxContextMenuEvent * ev = (wxContextMenuEvent *) event;
evClass = (char*)"wxContextMenuEvent";
rt.addAtom((char*)"wxContextMenu");
rt.addAtom(Etype->eName);
- rt.addTupleCount(2);
+ rt.add(ev->GetPosition());
+ rt.addTupleCount(3);
break;
}
case 193: {// wxIdleEvent
@@ -667,10 +698,13 @@ case 198: {// wxDateEvent
break;
}
case 199: {// wxCalendarEvent
+ wxCalendarEvent * ev = (wxCalendarEvent *) event;
evClass = (char*)"wxCalendarEvent";
rt.addAtom((char*)"wxCalendar");
rt.addAtom(Etype->eName);
- rt.addTupleCount(2);
+ rt.addInt(ev->GetWeekDay());
+ rt.add(ev->GetDate());
+ rt.addTupleCount(4);
break;
}
case 200: {// wxFileDirPickerEvent
@@ -742,10 +776,13 @@ case 209: {// wxTreeEvent
break;
}
case 210: {// wxNotebookEvent
+ wxNotebookEvent * ev = (wxNotebookEvent *) event;
evClass = (char*)"wxNotebookEvent";
rt.addAtom((char*)"wxNotebook");
rt.addAtom(Etype->eName);
- rt.addTupleCount(2);
+ rt.addInt(ev->GetSelection());
+ rt.addInt(ev->GetOldSelection());
+ rt.addTupleCount(4);
break;
}
case 216: {// wxClipboardTextEvent
diff --git a/lib/wx/c_src/gen/wxe_funcs.cpp b/lib/wx/c_src/gen/wxe_funcs.cpp
index 91ce5d810c..3b11c0642e 100644
--- a/lib/wx/c_src/gen/wxe_funcs.cpp
+++ b/lib/wx/c_src/gen/wxe_funcs.cpp
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2014. All Rights Reserved.
+ * Copyright Ericsson AB 2008-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
@@ -51,8 +51,8 @@ void WxeApp::wxe_dispatch(wxeCommand& Ecmd)
if(recurse_level > 1 && refd->type != 4) {
delayed_delete->Append(Ecmd.Save());
} else {
- ((WxeApp *) wxTheApp)->clearPtr(This);
- delete_object(This, refd); }
+ delete_object(This, refd);
+ ((WxeApp *) wxTheApp)->clearPtr(This);}
} } break;
case WXE_REGISTER_OBJECT: {
registerPid(bp, Ecmd.caller, memenv);
diff --git a/lib/wx/c_src/wxe_gl.cpp b/lib/wx/c_src/wxe_gl.cpp
index a9feb23831..26b45d219e 100644
--- a/lib/wx/c_src/wxe_gl.cpp
+++ b/lib/wx/c_src/wxe_gl.cpp
@@ -135,8 +135,12 @@ void deleteActiveGL(wxGLCanvas *canvas)
void gl_dispatch(int op, char *bp,ErlDrvTermData caller,WXEBinRef *bins[]){
if(caller != gl_active) {
wxGLCanvas * current = glc[caller];
- if(current) { gl_active = caller; current->SetCurrent();}
- else {
+ if(current) {
+ if(current != glc[gl_active]) {
+ gl_active = caller;
+ current->SetCurrent();
+ }
+ } else {
ErlDrvTermData rt[] = // Error msg
{ERL_DRV_ATOM, driver_mk_atom((char *) "_egl_error_"),
ERL_DRV_INT, (ErlDrvTermData) op,
diff --git a/lib/wx/c_src/wxe_helpers.cpp b/lib/wx/c_src/wxe_helpers.cpp
index 15d75080d9..120919e7aa 100644
--- a/lib/wx/c_src/wxe_helpers.cpp
+++ b/lib/wx/c_src/wxe_helpers.cpp
@@ -24,23 +24,96 @@
* Erlang Commands
* ****************************************************************************/
-wxeCommand::wxeCommand(int fc,char * cbuf,int buflen, wxe_data *sd)
- : wxObject()
+wxeCommand::wxeCommand()
{
+}
+
+wxeCommand::~wxeCommand()
+{
+ Delete();
+}
+
+void wxeCommand::Delete()
+{
+ int n = 0;
+
+ if(buffer) {
+ while(bin[n]) {
+ if(bin[n]->bin)
+ driver_free_binary(bin[n]->bin);
+ driver_free(bin[n++]);
+ }
+ if(len > 64)
+ driver_free(buffer);
+ buffer = NULL;
+ op = -1;
+ }
+}
+
+/* ****************************************************************************
+ * wxeFifo
+ * ****************************************************************************/
+wxeFifo::wxeFifo(unsigned int sz)
+{
+ m_q = (wxeCommand *) driver_alloc(sizeof(wxeCommand) * sz);
+ m_orig_sz = sz;
+ m_max = sz;
+ m_n = 0;
+ m_first = 0;
+ m_old = NULL;
+ for(unsigned int i = 0; i < sz; i++) {
+ m_q[i].buffer = NULL;
+ m_q[i].op = -1;
+ }
+}
+
+wxeFifo::~wxeFifo() {
+ // dealloc all memory buffers
+ driver_free(m_q);
+}
+
+wxeCommand * wxeFifo::Get()
+{
+ unsigned int pos;
+ if(m_n > 0) {
+ pos = m_first++;
+ m_n--;
+ m_first %= m_max;
+ return &m_q[pos];
+ }
+ return NULL;
+}
+
+void wxeFifo::Add(int fc, char * cbuf,int buflen, wxe_data *sd)
+{
+ unsigned int pos;
+ wxeCommand *curr;
+
WXEBinRef *temp, *start, *prev;
int n = 0;
- ref_count = 1;
- caller = driver_caller(sd->port_handle);
- port = sd->port;
- op = fc;
- len = buflen;
- bin[0] = NULL;
- bin[1] = NULL;
- bin[2] = NULL;
+
+ if(m_n == (m_max-1)) { // resize
+ Realloc();
+ }
+
+ pos = (m_first + m_n) % m_max;
+ m_n++;
+
+ curr = &m_q[pos];
+ curr->caller = driver_caller(sd->port_handle);
+ curr->port = sd->port;
+ curr->op = fc;
+ curr->len = buflen;
+ curr->bin[0] = NULL;
+ curr->bin[1] = NULL;
+ curr->bin[2] = NULL;
if(cbuf) {
- buffer = (char *) driver_alloc(len);
- memcpy((void *) buffer, (void *) cbuf, len);;
+ if(buflen > 64)
+ curr->buffer = (char *) driver_alloc(buflen);
+ else
+ curr->buffer = curr->c_buf;
+ memcpy((void *) curr->buffer, (void *) cbuf, buflen);
temp = sd->bin;
@@ -48,8 +121,8 @@ wxeCommand::wxeCommand(int fc,char * cbuf,int buflen, wxe_data *sd)
start = temp;
while(temp) {
- if(caller == temp->from) {
- bin[n++] = temp;
+ if(curr->caller == temp->from) {
+ curr->bin[n++] = temp;
if(prev) {
prev->next = temp->next;
} else {
@@ -63,20 +136,68 @@ wxeCommand::wxeCommand(int fc,char * cbuf,int buflen, wxe_data *sd)
}
sd->bin = start;
} else { // No-op only PING currently
- buffer = NULL;
+ curr->buffer = NULL;
}
}
-wxeCommand::~wxeCommand() {
- int n = 0;
- if(buffer) {
- while(bin[n]) {
- if(bin[n]->bin)
- driver_free_binary(bin[n]->bin);
- driver_free(bin[n++]);
+void wxeFifo::Append(wxeCommand *orig)
+{
+ unsigned int pos;
+ wxeCommand *curr;
+ if(m_n == (m_max-1)) { // resize
+ Realloc();
+ }
+
+ pos = (m_first + m_n) % m_max;
+ m_n++;
+ curr = &m_q[pos];
+ curr->caller = orig->caller;
+ curr->port = orig->port;
+ curr->op = orig->op;
+ curr->len = orig->len;
+ curr->bin[0] = orig->bin[0];
+ curr->bin[1] = orig->bin[1];
+ curr->bin[2] = orig->bin[2];
+
+ if(orig->len > 64)
+ curr->buffer = orig->buffer;
+ else {
+ curr->buffer = curr->c_buf;
+ memcpy((void *) curr->buffer, (void *) orig->buffer, orig->len);
+ }
+ orig->op = -1;
+ orig->buffer = NULL;
+ orig->bin[0] = NULL;
+}
+
+void wxeFifo::Realloc()
+{
+ unsigned int i;
+ unsigned int growth = m_orig_sz / 2;
+ unsigned int new_sz = growth + m_max;
+ unsigned int max = m_max;
+ unsigned int first = m_first;
+ unsigned int n = m_n;
+ wxeCommand * old = m_q;
+ wxeCommand * queue = (wxeCommand *)driver_alloc(new_sz*sizeof(wxeCommand));
+
+ m_max=new_sz;
+ m_first = 0;
+ m_n=0;
+ m_q = queue;
+
+ for(i=0; i < n; i++) {
+ unsigned int pos = i+first;
+ if(old[pos%max].op >= 0) {
+ Append(&old[pos%max]);
}
- driver_free(buffer);
}
+ for(i = m_n; i < new_sz; i++) { // Reset the rest
+ m_q[i].buffer = NULL;
+ m_q[i].op = -1;
+ }
+ // Can not free old queue here it can be used in the wx thread
+ m_old = old;
}
/* ****************************************************************************
diff --git a/lib/wx/c_src/wxe_helpers.h b/lib/wx/c_src/wxe_helpers.h
index 659bc666c6..ec3a5debdb 100644
--- a/lib/wx/c_src/wxe_helpers.h
+++ b/lib/wx/c_src/wxe_helpers.h
@@ -39,14 +39,14 @@ class wxeMetaCommand : public wxEvent
ErlDrvPDL pdl;
};
-class wxeCommand : public wxObject
+class wxeCommand
{
public:
- wxeCommand(int fc,char * cbuf,int buflen, wxe_data *);
+ wxeCommand();
virtual ~wxeCommand(); // Use Delete()
- wxeCommand * Save() {ref_count++; return this; };
- void Delete() {if(--ref_count < 1) delete this;};
+ wxeCommand * Save() { return this; };
+ void Delete();
ErlDrvTermData caller;
ErlDrvTermData port;
@@ -54,7 +54,27 @@ class wxeCommand : public wxObject
char * buffer;
int len;
int op;
- int ref_count;
+ char c_buf[64]; // 64b covers 90% of usage
+};
+
+class wxeFifo {
+ public:
+ wxeFifo(unsigned int size);
+ virtual ~wxeFifo();
+
+ void Add(int fc, char * cbuf,int buflen, wxe_data *);
+ void Append(wxeCommand *Other);
+
+ wxeCommand * Get();
+
+ void Realloc();
+
+ unsigned int m_max;
+ unsigned int m_first;
+ unsigned int m_n;
+ unsigned int m_orig_sz;
+ wxeCommand *m_q;
+ wxeCommand *m_old;
};
class intListElement {
diff --git a/lib/wx/c_src/wxe_impl.cpp b/lib/wx/c_src/wxe_impl.cpp
index 0ee52e3af2..ef648e008c 100644
--- a/lib/wx/c_src/wxe_impl.cpp
+++ b/lib/wx/c_src/wxe_impl.cpp
@@ -55,8 +55,9 @@ extern ErlDrvCond * wxe_batch_locker_c;
extern ErlDrvTermData init_caller;
extern int wxe_status;
-wxList * wxe_batch = NULL;
-wxList * wxe_batch_cb_saved = NULL;
+wxeFifo * wxe_queue = NULL;
+wxeFifo * wxe_queue_cb_saved = NULL;
+
int wxe_batch_caller = 0; // inside batch if larger than 0
/* ************************************************************
@@ -68,30 +69,30 @@ void push_command(int op,char * buf,int len, wxe_data *sd)
{
/* fprintf(stderr, "Op %d %d [%ld] %d\r\n", op, (int) driver_caller(sd->port_handle),
wxe_batch->size(), wxe_batch_caller),fflush(stderr); */
- wxeCommand *Cmd = new wxeCommand(op, buf, len, sd);
erl_drv_mutex_lock(wxe_batch_locker_m);
- wxe_batch->Append(Cmd);
+ wxe_queue->Add(op, buf, len, sd);
if(wxe_batch_caller > 0) {
// wx-thread is waiting on batch end in cond_wait
erl_drv_cond_signal(wxe_batch_locker_c);
+ erl_drv_mutex_unlock(wxe_batch_locker_m);
} else {
// wx-thread is waiting gui-events
if(op == WXE_BATCH_BEGIN) {
wxe_batch_caller = 1;
}
erl_drv_cond_signal(wxe_batch_locker_c);
+ erl_drv_mutex_unlock(wxe_batch_locker_m);
wxWakeUpIdle();
}
- erl_drv_mutex_unlock(wxe_batch_locker_m);
+
}
void meta_command(int what, wxe_data *sd) {
if(what == PING_PORT) {
erl_drv_mutex_lock(wxe_batch_locker_m);
if(wxe_batch_caller > 0) {
- wxeCommand *Cmd = new wxeCommand(WXE_DEBUG_PING, NULL, 0, sd);
- wxe_batch->Append(Cmd);
+ wxe_queue->Add(WXE_DEBUG_PING, NULL, 0, sd);
erl_drv_cond_signal(wxe_batch_locker_c);
}
wxWakeUpIdle();
@@ -121,12 +122,12 @@ bool WxeApp::OnInit()
{
global_me = new wxeMemEnv();
- wxe_batch = new wxList;
- wxe_batch_cb_saved = new wxList;
+ wxe_queue = new wxeFifo(1000);
+ wxe_queue_cb_saved = new wxeFifo(200);
cb_buff = NULL;
recurse_level = 0;
- delayed_cleanup = new wxList;
- delayed_delete = new wxList;
+ delayed_delete = new wxeFifo(10);
+ delayed_cleanup = new wxList;
wxe_ps_init2();
// wxIdleEvent::SetMode(wxIDLE_PROCESS_SPECIFIED); // Hmm printpreview doesn't work in 2.9 with this
@@ -169,6 +170,8 @@ void WxeApp::MacOpenFile(const wxString &filename) {
void WxeApp::shutdown(wxeMetaCommand& Ecmd) {
ExitMainLoop();
+ delete wxe_queue;
+ delete wxe_queue_cb_saved;
}
void WxeApp::dummy_close(wxEvent& Ev) {
@@ -201,11 +204,11 @@ void handle_event_callback(ErlDrvPort port, ErlDrvTermData process)
if(driver_monitor_process(port, process, &monitor) == 0) {
// Should we be able to handle commands when recursing? probably
erl_drv_mutex_lock(wxe_batch_locker_m);
- //fprintf(stderr, "\r\nCB EV Start %lu \r\n", process);fflush(stderr);
+ // fprintf(stderr, "\r\nCB EV Start %lu \r\n", process);fflush(stderr);
app->recurse_level++;
- app->dispatch_cb(wxe_batch, wxe_batch_cb_saved, process);
+ app->dispatch_cb(wxe_queue, wxe_queue_cb_saved, process);
app->recurse_level--;
- //fprintf(stderr, "CB EV done %lu \r\n", process);fflush(stderr);
+ // fprintf(stderr, "CB EV done %lu \r\n", process);fflush(stderr);
wxe_batch_caller = 0;
erl_drv_mutex_unlock(wxe_batch_locker_m);
driver_demonitor_process(port, &monitor);
@@ -216,22 +219,22 @@ void WxeApp::dispatch_cmds()
{
erl_drv_mutex_lock(wxe_batch_locker_m);
recurse_level++;
- int level = dispatch(wxe_batch_cb_saved, 0, WXE_STORED);
- dispatch(wxe_batch, level, WXE_NORMAL);
+ int level = dispatch(wxe_queue_cb_saved, 0, WXE_STORED);
+ dispatch(wxe_queue, level, WXE_NORMAL);
recurse_level--;
wxe_batch_caller = 0;
+ if(wxe_queue->m_old) {
+ driver_free(wxe_queue->m_old);
+ wxe_queue->m_old = NULL;
+ }
erl_drv_mutex_unlock(wxe_batch_locker_m);
// Cleanup old memenv's and deleted objects
if(recurse_level == 0) {
- if(delayed_delete->size() > 0)
- for( wxList::compatibility_iterator node = delayed_delete->GetFirst();
- node;
- node = delayed_delete->GetFirst()) {
- wxeCommand *event = (wxeCommand *)node->GetData();
- delayed_delete->Erase(node);
- wxe_dispatch(*event);
- event->Delete();
- }
+ wxeCommand *curr;
+ while((curr = delayed_delete->Get()) != NULL) {
+ wxe_dispatch(*curr);
+ curr->Delete();
+ }
if(delayed_cleanup->size() > 0)
for( wxList::compatibility_iterator node = delayed_cleanup->GetFirst();
node;
@@ -241,158 +244,145 @@ void WxeApp::dispatch_cmds()
destroyMemEnv(*event);
delete event;
}
+ if(wxe_queue_cb_saved->m_old) {
+ driver_free(wxe_queue_cb_saved->m_old);
+ wxe_queue_cb_saved->m_old = NULL;
+ }
+ if(delayed_delete->m_old) {
+ driver_free(delayed_delete->m_old);
+ delayed_delete->m_old = NULL;
+ }
}
}
// Should have erl_drv_mutex_lock(wxe_batch_locker_m);
// when entering this function and it should be released
// afterwards
-int WxeApp::dispatch(wxList * batch, int blevel, int list_type)
+int WxeApp::dispatch(wxeFifo * batch, int blevel, int list_type)
{
int ping = 0;
// erl_drv_mutex_lock(wxe_batch_locker_m); must be locked already
- while(true)
- {
- if (batch->size() > 0) {
- for( wxList::compatibility_iterator node = batch->GetFirst();
- node;
- node = batch->GetFirst())
- {
- wxeCommand *event = (wxeCommand *)node->GetData();
- batch->Erase(node);
- switch(event->op) {
- case WXE_BATCH_END:
- {--blevel; }
- break;
- case WXE_BATCH_BEGIN:
- {blevel++; }
- break;
- case WXE_DEBUG_PING:
- // When in debugger we don't want to hang waiting for a BATCH_END
- // that never comes, because a breakpoint have hit.
- ping++;
- if(ping > 2)
- blevel = 0;
- break;
- case WXE_CB_RETURN:
- // erl_drv_mutex_unlock(wxe_batch_locker_m); should be called after
- // whatever cleaning is necessary
- if(event->len > 0) {
- cb_buff = (char *) driver_alloc(event->len);
- memcpy(cb_buff, event->buffer, event->len);
- }
- return blevel;
- default:
- erl_drv_mutex_unlock(wxe_batch_locker_m);
- if(event->op < OPENGL_START) {
- // fprintf(stderr, " c %d (%d) \r\n", event->op, blevel);
- wxe_dispatch(*event);
- } else {
- gl_dispatch(event->op,event->buffer,event->caller,event->bin);
- }
- erl_drv_mutex_lock(wxe_batch_locker_m);
- break;
- }
- event->Delete();
- }
- } else {
- if((list_type == WXE_STORED) || (blevel <= 0 && list_type == WXE_NORMAL)) {
- // erl_drv_mutex_unlock(wxe_batch_locker_m); should be called after
- // whatever cleaning is necessary
- return blevel;
+ wxeCommand *event;
+ while(true) {
+ while((event = batch->Get()) != NULL) {
+ switch(event->op) {
+ case -1:
+ break;
+ case WXE_BATCH_END:
+ {--blevel; }
+ break;
+ case WXE_BATCH_BEGIN:
+ {blevel++; }
+ break;
+ case WXE_DEBUG_PING:
+ // When in debugger we don't want to hang waiting for a BATCH_END
+ // that never comes, because a breakpoint have hit.
+ ping++;
+ if(ping > 2)
+ blevel = 0;
+ break;
+ case WXE_CB_RETURN:
+ // erl_drv_mutex_unlock(wxe_batch_locker_m); should be called after
+ // whatever cleaning is necessary
+ if(event->len > 0) {
+ cb_buff = (char *) driver_alloc(event->len);
+ memcpy(cb_buff, event->buffer, event->len);
}
- // sleep until something happens
- //fprintf(stderr, "%s:%d sleep %d %d %d %d \r\n", __FILE__, __LINE__, batch->size(), callback_returned, blevel, is_callback);fflush(stderr);
- wxe_batch_caller++;
- while(batch->size() == 0) {
- erl_drv_cond_wait(wxe_batch_locker_c, wxe_batch_locker_m);
+ event->Delete();
+ return blevel;
+ default:
+ erl_drv_mutex_unlock(wxe_batch_locker_m);
+ if(event->op < OPENGL_START) {
+ // fprintf(stderr, " c %d (%d) \r\n", event->op, blevel);
+ wxe_dispatch(*event);
+ } else {
+ gl_dispatch(event->op,event->buffer,event->caller,event->bin);
}
+ erl_drv_mutex_lock(wxe_batch_locker_m);
+ break;
}
+ event->Delete();
+ }
+ if((list_type == WXE_STORED) || (blevel <= 0 && list_type == WXE_NORMAL)) {
+ // erl_drv_mutex_unlock(wxe_batch_locker_m); should be called after
+ // whatever cleaning is necessary
+ return blevel;
}
+ // sleep until something happens
+ //fprintf(stderr, "%s:%d sleep %d %d\r\n", __FILE__, __LINE__, batch->size(), blevel);fflush(stderr);
+ wxe_batch_caller++;
+ while(batch->m_n == 0) {
+ erl_drv_cond_wait(wxe_batch_locker_c, wxe_batch_locker_m);
+ }
+ }
}
-void WxeApp::dispatch_cb(wxList * batch, wxList * temp, ErlDrvTermData process) {
- int callback_returned = 0;
+void WxeApp::dispatch_cb(wxeFifo * batch, wxeFifo * temp, ErlDrvTermData process) {
+ wxeCommand *event;
while(true) {
- if (batch->size() > 0) {
- for( wxList::compatibility_iterator node = batch->GetFirst();
- node;
- node = batch->GetFirst())
- {
- wxeCommand *event = (wxeCommand *)node->GetData();
- wxeMemEnv *memenv = getMemEnv(event->port);
- batch->Erase(node);
- // fprintf(stderr, " Ev %d %lu\r\n", event->op, event->caller);
- if(event->caller == process || // Callbacks from CB process only
- event->op == WXE_CB_START || // Event callback start change process
- event->op == WXE_CB_DIED || // Event callback process died
- // Allow connect_cb during CB i.e. msg from wxe_server.
- (memenv && event->caller == memenv->owner))
- {
- switch(event->op) {
- case WXE_BATCH_END:
- case WXE_BATCH_BEGIN:
- case WXE_DEBUG_PING:
- break;
- case WXE_CB_RETURN:
- if(event->len > 0) {
- cb_buff = (char *) driver_alloc(event->len);
- memcpy(cb_buff, event->buffer, event->len);
- } // continue
- case WXE_CB_DIED:
- callback_returned = 1;
- return;
- case WXE_CB_START:
- // CB start from now accept message from CB process only
- process = event->caller;
- break;
- default:
- erl_drv_mutex_unlock(wxe_batch_locker_m);
- size_t start=temp->GetCount();
- if(event->op < OPENGL_START) {
- // fprintf(stderr, " cb %d \r\n", event->op);
- wxe_dispatch(*event);
- } else {
- gl_dispatch(event->op,event->buffer,event->caller,event->bin);
- }
- erl_drv_mutex_lock(wxe_batch_locker_m);
- if(temp->GetCount() > start) {
- // We have recursed dispatch_cb and messages for this
- // callback may be saved on temp list move them
- // to orig list
- for(wxList::compatibility_iterator node = temp->Item(start);
- node;
- node = node->GetNext()) {
- wxeCommand *ev = (wxeCommand *)node->GetData();
- if(ev->caller == process) {
- batch->Append(ev);
- temp->Erase(node);
- }
- }
- }
- if(callback_returned)
- return;
- break;
+ while((event = batch->Get()) != NULL) {
+ wxeMemEnv *memenv = getMemEnv(event->port);
+ // fprintf(stderr, " Ev %d %lu\r\n", event->op, event->caller);
+ if(event->caller == process || // Callbacks from CB process only
+ event->op == WXE_CB_START || // Event callback start change process
+ event->op == WXE_CB_DIED || // Event callback process died
+ // Allow connect_cb during CB i.e. msg from wxe_server.
+ (memenv && event->caller == memenv->owner)) {
+ switch(event->op) {
+ case -1:
+ case WXE_BATCH_END:
+ case WXE_BATCH_BEGIN:
+ case WXE_DEBUG_PING:
+ break;
+ case WXE_CB_RETURN:
+ if(event->len > 0) {
+ cb_buff = (char *) driver_alloc(event->len);
+ memcpy(cb_buff, event->buffer, event->len);
+ } // continue
+ case WXE_CB_DIED:
+ event->Delete();
+ return;
+ case WXE_CB_START:
+ // CB start from now accept message from CB process only
+ process = event->caller;
+ break;
+ default:
+ erl_drv_mutex_unlock(wxe_batch_locker_m);
+ size_t start=temp->m_n;
+ if(event->op < OPENGL_START) {
+ // fprintf(stderr, " cb %d \r\n", event->op);
+ wxe_dispatch(*event);
+ } else {
+ gl_dispatch(event->op,event->buffer,event->caller,event->bin);
+ }
+ erl_drv_mutex_lock(wxe_batch_locker_m);
+ if(temp->m_n > start) {
+ // We have recursed dispatch_cb and messages for this
+ // callback may be saved on temp list move them
+ // to orig list
+ for(unsigned int i=start; i < temp->m_n; i++) {
+ wxeCommand *ev = &temp->m_q[(temp->m_first+i) % temp->m_max];
+ if(ev->caller == process) {
+ batch->Append(ev);
}
- event->Delete();
- } else {
- // fprintf(stderr, " save %d \r\n", event->op);
- temp->Append(event);
+ }
}
+ break;
}
- } else {
- if(callback_returned) {
- return;
- }
- // sleep until something happens
- //fprintf(stderr, "%s:%d sleep %d %d %d %d \r\n", __FILE__, __LINE__, batch->size(), callback_returned, blevel, is_callback);fflush(stderr);
- while(batch->size() == 0) {
- erl_drv_cond_wait(wxe_batch_locker_c, wxe_batch_locker_m);
+ event->Delete();
+ } else {
+ // fprintf(stderr, " save %d %lu\r\n", event->op, event->caller);
+ temp->Append(event);
}
}
+ // sleep until something happens
+ // fprintf(stderr, "%s:%d sleep %d %d\r\n", __FILE__, __LINE__,
+ // batch->m_n, temp->m_n);fflush(stderr);
+ while(batch->m_n == 0) {
+ erl_drv_cond_wait(wxe_batch_locker_c, wxe_batch_locker_m);
+ }
}
}
-
/* Memory handling */
void WxeApp::newMemEnv(wxeMetaCommand& Ecmd) {
diff --git a/lib/wx/c_src/wxe_impl.h b/lib/wx/c_src/wxe_impl.h
index 57bf2e2dba..a0a1c84718 100644
--- a/lib/wx/c_src/wxe_impl.h
+++ b/lib/wx/c_src/wxe_impl.h
@@ -60,8 +60,8 @@ public:
#endif
void shutdown(wxeMetaCommand& event);
- int dispatch(wxList *, int, int);
- void dispatch_cb(wxList * batch, wxList * temp, ErlDrvTermData process);
+ int dispatch(wxeFifo *, int, int);
+ void dispatch_cb(wxeFifo * batch, wxeFifo * temp, ErlDrvTermData process);
void wxe_dispatch(wxeCommand& event);
@@ -93,7 +93,7 @@ public:
int recurse_level;
wxList * delayed_cleanup;
- wxList * delayed_delete;
+ wxeFifo * delayed_delete;
// Temp container for callbacks
char *cb_buff;
int cb_len;
diff --git a/lib/wx/examples/demo/demo_html_tagger.erl b/lib/wx/examples/demo/demo_html_tagger.erl
index 7bb6736fdc..b119f0e226 100644
--- a/lib/wx/examples/demo/demo_html_tagger.erl
+++ b/lib/wx/examples/demo/demo_html_tagger.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2009-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
@@ -267,8 +267,10 @@ normalize_toks(Toks) ->
normalize_tok(Tok) ->
%% this is the portable way ...
- [{_,Type},{_,Line},{_,Col},{_,Txt}] =
- erl_scan:token_info(Tok, [category,line,column,text]),
+ Type = erl_scan:category(Tok),
+ Line = erl_scan:line(Tok),
+ Col = erl_scan:column(Tok),
+ Txt = erl_scan:text(Tok),
Val = {Type,{Line,Col},Txt},
%% io:format("here:X=~p ~p~n",[Tok,Val]),
Val.
diff --git a/lib/wx/include/wx.hrl b/lib/wx/include/wx.hrl
index 9b913c7c00..97cb689374 100644
--- a/lib/wx/include/wx.hrl
+++ b/lib/wx/include/wx.hrl
@@ -54,7 +54,9 @@
-type wxListEventType() :: command_list_begin_drag | command_list_begin_rdrag | command_list_begin_label_edit | command_list_end_label_edit | command_list_delete_item | command_list_delete_all_items | command_list_key_down | command_list_insert_item | command_list_col_click | command_list_col_right_click | command_list_col_begin_drag | command_list_col_dragging | command_list_col_end_drag | command_list_item_selected | command_list_item_deselected | command_list_item_right_click | command_list_item_middle_click | command_list_item_activated | command_list_item_focused | command_list_cache_hint.
-type wxList() :: #wxList{}. %% Callback event: {@link wxListEvent}
--record(wxNotebook, {type :: wxNotebookEventType()}). %% Callback event: {@link wxNotebookEvent}
+-record(wxNotebook,{type :: wxNotebookEventType(), %% Callback event: {@link wxNotebookEvent}
+ nSel :: integer(),
+ nOldSel :: integer()}).
-type wxNotebookEventType() :: command_notebook_page_changed | command_notebook_page_changing.
-type wxNotebook() :: #wxNotebook{}. %% Callback event: {@link wxNotebookEvent}
@@ -86,7 +88,9 @@
-type wxWindowDestroyEventType() :: destroy.
-type wxWindowDestroy() :: #wxWindowDestroy{}. %% Callback event: {@link wxWindowDestroyEvent}
--record(wxCalendar, {type :: wxCalendarEventType()}). %% Callback event: {@link wxCalendarEvent}
+-record(wxCalendar,{type :: wxCalendarEventType(), %% Callback event: {@link wxCalendarEvent}
+ wday :: wx:wx_enum(),
+ date :: wx:wx_datetime()}).
-type wxCalendarEventType() :: calendar_sel_changed | calendar_day_changed | calendar_month_changed | calendar_year_changed | calendar_doubleclicked | calendar_weekday_clicked.
-type wxCalendar() :: #wxCalendar{}. %% Callback event: {@link wxCalendarEvent}
@@ -100,15 +104,19 @@
-type wxScrollEventType() :: scroll_top | scroll_bottom | scroll_lineup | scroll_linedown | scroll_pageup | scroll_pagedown | scroll_thumbtrack | scroll_thumbrelease | scroll_changed.
-type wxScroll() :: #wxScroll{}. %% Callback event: {@link wxScrollEvent}
--record(wxMenu, {type :: wxMenuEventType()}). %% Callback event: {@link wxMenuEvent}
+-record(wxMenu,{type :: wxMenuEventType(), %% Callback event: {@link wxMenuEvent}
+ menuId :: integer(),
+ menu :: wxMenu:wxMenu()}).
-type wxMenuEventType() :: menu_open | menu_close | menu_highlight.
-type wxMenu() :: #wxMenu{}. %% Callback event: {@link wxMenuEvent}
--record(wxContextMenu, {type :: wxContextMenuEventType()}). %% Callback event: {@link wxContextMenuEvent}
+-record(wxContextMenu,{type :: wxContextMenuEventType(), %% Callback event: {@link wxContextMenuEvent}
+ pos :: {X::integer(), Y::integer()}}).
-type wxContextMenuEventType() :: context_menu.
-type wxContextMenu() :: #wxContextMenu{}. %% Callback event: {@link wxContextMenuEvent}
--record(wxShow, {type :: wxShowEventType()}). %% Callback event: {@link wxShowEvent}
+-record(wxShow,{type :: wxShowEventType(), %% Callback event: {@link wxShowEvent}
+ show :: boolean()}).
-type wxShowEventType() :: show.
-type wxShow() :: #wxShow{}. %% Callback event: {@link wxShowEvent}
@@ -117,7 +125,10 @@
-type wxSpinEventType() :: command_spinctrl_updated | spin_up | spin_down | spin.
-type wxSpin() :: #wxSpin{}. %% Callback event: {@link wxSpinEvent}
--record(wxSetCursor, {type :: wxSetCursorEventType()}). %% Callback event: {@link wxSetCursorEvent}
+-record(wxSetCursor,{type :: wxSetCursorEventType(), %% Callback event: {@link wxSetCursorEvent}
+ x :: integer(),
+ y :: integer(),
+ cursor :: wxCursor:wxCursor()}).
-type wxSetCursorEventType() :: set_cursor.
-type wxSetCursor() :: #wxSetCursor{}. %% Callback event: {@link wxSetCursorEvent}
@@ -126,7 +137,9 @@
-type wxFontPickerEventType() :: command_fontpicker_changed.
-type wxFontPicker() :: #wxFontPicker{}. %% Callback event: {@link wxFontPickerEvent}
--record(wxScrollWin, {type :: wxScrollWinEventType()}). %% Callback event: {@link wxScrollWinEvent}
+-record(wxScrollWin,{type :: wxScrollWinEventType(), %% Callback event: {@link wxScrollWinEvent}
+ commandInt :: integer(),
+ extraLong :: integer()}).
-type wxScrollWinEventType() :: scrollwin_top | scrollwin_bottom | scrollwin_lineup | scrollwin_linedown | scrollwin_pageup | scrollwin_pagedown | scrollwin_thumbtrack | scrollwin_thumbrelease.
-type wxScrollWin() :: #wxScrollWin{}. %% Callback event: {@link wxScrollWinEvent}
@@ -147,7 +160,8 @@
-type wxFileDirPickerEventType() :: command_filepicker_changed | command_dirpicker_changed.
-type wxFileDirPicker() :: #wxFileDirPicker{}. %% Callback event: {@link wxFileDirPickerEvent}
--record(wxFocus, {type :: wxFocusEventType()}). %% Callback event: {@link wxFocusEvent}
+-record(wxFocus,{type :: wxFocusEventType(), %% Callback event: {@link wxFocusEvent}
+ win :: wxWindow:wxWindow()}).
-type wxFocusEventType() :: set_focus | kill_focus.
-type wxFocus() :: #wxFocus{}. %% Callback event: {@link wxFocusEvent}
@@ -225,7 +239,8 @@
-type wxSizeEventType() :: size.
-type wxSize() :: #wxSize{}. %% Callback event: {@link wxSizeEvent}
--record(wxIconize, {type :: wxIconizeEventType()}). %% Callback event: {@link wxIconizeEvent}
+-record(wxIconize,{type :: wxIconizeEventType(), %% Callback event: {@link wxIconizeEvent}
+ iconized :: boolean()}).
-type wxIconizeEventType() :: iconize.
-type wxIconize() :: #wxIconize{}. %% Callback event: {@link wxIconizeEvent}
@@ -289,7 +304,12 @@
-type wxCommandEventType() :: command_button_clicked | command_checkbox_clicked | command_choice_selected | command_listbox_selected | command_listbox_doubleclicked | command_text_updated | command_text_enter | command_menu_selected | command_slider_updated | command_radiobox_selected | command_radiobutton_selected | command_scrollbar_updated | command_vlbox_selected | command_combobox_selected | command_tool_rclicked | command_tool_enter | command_checklistbox_toggled | command_togglebutton_clicked | command_left_click | command_left_dclick | command_right_click | command_set_focus | command_kill_focus | command_enter.
-type wxCommand() :: #wxCommand{}. %% Callback event: {@link wxCommandEvent}
--record(wxJoystick, {type :: wxJoystickEventType()}). %% Callback event: {@link wxJoystickEvent}
+-record(wxJoystick,{type :: wxJoystickEventType(), %% Callback event: {@link wxJoystickEvent}
+ pos :: {X::integer(), Y::integer()},
+ zPosition :: integer(),
+ buttonChange :: integer(),
+ buttonState :: integer(),
+ joyStick :: integer()}).
-type wxJoystickEventType() :: joy_button_down | joy_button_up | joy_move | joy_zmove.
-type wxJoystick() :: #wxJoystick{}. %% Callback event: {@link wxJoystickEvent}
@@ -297,7 +317,9 @@
-type wxQueryNewPaletteEventType() :: query_new_palette.
-type wxQueryNewPalette() :: #wxQueryNewPalette{}. %% Callback event: {@link wxQueryNewPaletteEvent}
--record(wxMove, {type :: wxMoveEventType()}). %% Callback event: {@link wxMoveEvent}
+-record(wxMove,{type :: wxMoveEventType(), %% Callback event: {@link wxMoveEvent}
+ pos :: {X::integer(), Y::integer()},
+ rect :: {X::integer(), Y::integer(), W::integer(), H::integer()}}).
-type wxMoveEventType() :: move.
-type wxMove() :: #wxMove{}. %% Callback event: {@link wxMoveEvent}
diff --git a/lib/wx/test/wx_class_SUITE.erl b/lib/wx/test/wx_class_SUITE.erl
index b127e6b71d..45ab0f3a32 100644
--- a/lib/wx/test/wx_class_SUITE.erl
+++ b/lib/wx/test/wx_class_SUITE.erl
@@ -231,8 +231,15 @@ staticBoxSizer(Config) ->
clipboard(TestInfo) when is_atom(TestInfo) -> wx_test_lib:tc_info(TestInfo);
-clipboard(_Config) ->
- wx:new(),
+clipboard(Config) ->
+ Wx = wx:new(),
+ Frame = wxFrame:new(Wx, ?wxID_ANY, "Main Frame"),
+ Ctrl = wxTextCtrl:new(Frame, ?wxID_ANY, [{size, {600,400}}, {style, ?wxTE_MULTILINE}]),
+ wxTextCtrl:connect(Ctrl, command_text_copy, [{skip, true}]),
+ wxTextCtrl:connect(Ctrl, command_text_cut, [{skip, true}]),
+ wxTextCtrl:connect(Ctrl, command_text_paste, [{skip, true}]),
+ wxWindow:show(Frame),
+
CB = ?mt(wxClipboard, wxClipboard:get()),
wxClipboard:usePrimarySelection(CB),
?m(false, wx:is_null(CB)),
@@ -271,7 +278,8 @@ clipboard(_Config) ->
?log("Flushing ~n",[]),
wxClipboard:flush(CB),
?log("Stopping ~n",[]),
- ok.
+ wx_test_lib:wx_destroy(Frame,Config).
+
helpFrame(TestInfo) when is_atom(TestInfo) -> wx_test_lib:tc_info(TestInfo);
helpFrame(Config) ->
diff --git a/lib/wx/test/wx_event_SUITE.erl b/lib/wx/test/wx_event_SUITE.erl
index 3252547c9b..6bcd88e4fb 100644
--- a/lib/wx/test/wx_event_SUITE.erl
+++ b/lib/wx/test/wx_event_SUITE.erl
@@ -379,25 +379,29 @@ recursive(Config) ->
Frame = wxFrame:new(Wx, ?wxID_ANY, "Connect in callback"),
Panel = wxPanel:new(Frame, []),
Sz = wxBoxSizer:new(?wxVERTICAL),
- ListBox = wxListBox:new(Panel, ?wxID_ANY, [{choices, ["foo", "bar", "baz"]}]),
- wxSizer:add(Sz, ListBox, [{proportion, 1},{flag, ?wxEXPAND}]),
- wxWindow:setSizer(Panel, Sz),
- wxListBox:connect(ListBox, command_listbox_selected,
- [{callback,
- fun(#wx{event=#wxCommand{commandInt=Id}}, _) ->
- io:format("Selected ~p~n",[Id])
- end}]),
- wxListBox:setSelection(ListBox, 0),
- wxListBox:connect(ListBox, size,
- [{callback,
- fun(#wx{event=#wxSize{}}, _) ->
- io:format("Size init ~n",[]),
- case wxListBox:getCount(ListBox) > 0 of
- true -> wxListBox:delete(ListBox, 0);
- false -> ok
- end,
- io:format("Size done ~n",[])
- end}]),
+ Ctrl1 = wxTextCtrl:new(Panel, ?wxID_ANY, [{size, {300, -1}}]),
+ Ctrl2 = wxTextCtrl:new(Panel, ?wxID_ANY, [{size, {300, -1}}]),
+ wxSizer:add(Sz, Ctrl1, [{proportion, 1},{flag, ?wxEXPAND}]),
+ wxSizer:add(Sz, Ctrl2, [{proportion, 1},{flag, ?wxEXPAND}]),
+ wxWindow:setSizerAndFit(Panel, Sz),
+
+ CB1 = fun(#wx{event=#wxCommand{cmdString=String}}, _) ->
+ io:format(" CB1: ~s~n",[String]),
+ wxTextCtrl:setValue(Ctrl2, io_lib:format("from CB1 ~s", [String]))
+ end,
+ CB2 = fun(#wx{event=#wxCommand{cmdString=String}}, _) ->
+ io:format(" CB2: ~s~n",[String]),
+ ok
+ end,
+ wxTextCtrl:connect(Ctrl1, command_text_updated, [{callback,CB1}]),
+ wxTextCtrl:connect(Ctrl2, command_text_updated, [{callback,CB2}]),
+ wxFrame:connect(Frame, size,
+ [{callback,
+ fun(#wx{event=#wxSize{size=Size}}, _) ->
+ io:format("Size init: ~s ~n",[wxTextCtrl:getValue(Ctrl2)]),
+ wxTextCtrl:setValue(Ctrl1, io_lib:format("Size ~p", [Size])),
+ io:format("Size done: ~s ~n",[wxTextCtrl:getValue(Ctrl2)])
+ end}]),
wxFrame:show(Frame),
wx_test_lib:flush(),