summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorTristan Sloughter <t@crashfast.com>2018-11-23 14:56:03 -0700
committerGitHub <noreply@github.com>2018-11-23 14:56:03 -0700
commit37fdc7e515bd3db197cec92fa476923d19ec283a (patch)
tree6275dd5121b8a1bebb75482af4ee586c9d2aa447 /test
parent84d48ac09bfab62d50b8c4a2046a04ae1218f25a (diff)
fix base path used for yrl/xrl includefile configs (#1952)
Diffstat (limited to 'test')
-rw-r--r--test/rebar_compile_SUITE.erl150
1 files changed, 148 insertions, 2 deletions
diff --git a/test/rebar_compile_SUITE.erl b/test/rebar_compile_SUITE.erl
index 4d51f2a..9cbe8a2 100644
--- a/test/rebar_compile_SUITE.erl
+++ b/test/rebar_compile_SUITE.erl
@@ -852,7 +852,13 @@ dont_recompile_yrl_or_xrl(Config) ->
XrlBeam = filename:join([EbinDir, filename:basename(Xrl, ".xrl") ++ ".beam"]),
YrlBeam = filename:join([EbinDir, filename:basename(Yrl, ".yrl") ++ ".beam"]),
- rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
+ Hrl = filename:join([AppDir, "include", "some_header.hrl"]),
+ ok = filelib:ensure_dir(Hrl),
+ HrlBody = yeccpre_hrl(),
+ ok = ec_file:write(Hrl, HrlBody),
+ RebarConfig = [{yrl_opts, [{includefile, "include/some_header.hrl"}]}],
+
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, [{app, Name}]}),
XrlModTime = filelib:last_modified(XrlErl),
YrlModTime = filelib:last_modified(YrlErl),
@@ -862,7 +868,7 @@ dont_recompile_yrl_or_xrl(Config) ->
timer:sleep(1000),
- rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, [{app, Name}]}),
NewXrlModTime = filelib:last_modified(XrlErl),
NewYrlModTime = filelib:last_modified(YrlErl),
@@ -2208,3 +2214,143 @@ regex_filter_regression(Config) ->
{ok, [{file, Expected}]}),
ok.
+%%
+
+%% a copy of lib/parsetools/include/yeccpre.hrl so we can test yrl includefile
+yeccpre_hrl() ->
+ <<"-type yecc_ret() :: {'error', _} | {'ok', _}.
+
+-spec parse(Tokens :: list()) -> yecc_ret().
+parse(Tokens) ->
+ yeccpars0(Tokens, {no_func, no_line}, 0, [], []).
+
+-spec parse_and_scan({function() | {atom(), atom()}, [_]}
+ | {atom(), atom(), [_]}) -> yecc_ret().
+parse_and_scan({F, A}) ->
+ yeccpars0([], {{F, A}, no_line}, 0, [], []);
+parse_and_scan({M, F, A}) ->
+ Arity = length(A),
+ yeccpars0([], {{fun M:F/Arity, A}, no_line}, 0, [], []).
+
+-spec format_error(any()) -> [char() | list()].
+format_error(Message) ->
+ case io_lib:deep_char_list(Message) of
+ true ->
+ Message;
+ _ ->
+ io_lib:write(Message)
+ end.
+
+%% To be used in grammar files to throw an error message to the parser
+%% toplevel. Doesn't have to be exported!
+-compile({nowarn_unused_function, return_error/2}).
+-spec return_error(integer(), any()) -> no_return().
+return_error(Line, Message) ->
+ throw({error, {Line, ?MODULE, Message}}).
+
+-define(CODE_VERSION, \"1.4\").
+
+yeccpars0(Tokens, Tzr, State, States, Vstack) ->
+ try yeccpars1(Tokens, Tzr, State, States, Vstack)
+ catch
+ error:Error ->
+ try yecc_error_type(Error, []) of
+ Desc ->
+ erlang:raise(error, {yecc_bug, ?CODE_VERSION, Desc},
+ [])
+ catch _:_ -> erlang:raise(error, Error, [])
+ end;
+ %% Probably thrown from return_error/2:
+ throw: {error, {_Line, ?MODULE, _M}} = Error ->
+ Error
+ end.
+
+yecc_error_type(function_clause, _) ->
+ not_implemented.
+
+yeccpars1([Token | Tokens], Tzr, State, States, Vstack) ->
+ yeccpars2(State, element(1, Token), States, Vstack, Token, Tokens, Tzr);
+yeccpars1([], {{F, A},_Line}, State, States, Vstack) ->
+ case apply(F, A) of
+ {ok, Tokens, Endline} ->
+ yeccpars1(Tokens, {{F, A}, Endline}, State, States, Vstack);
+ {eof, Endline} ->
+ yeccpars1([], {no_func, Endline}, State, States, Vstack);
+ {error, Descriptor, _Endline} ->
+ {error, Descriptor}
+ end;
+yeccpars1([], {no_func, no_line}, State, States, Vstack) ->
+ Line = 999999,
+ yeccpars2(State, '$end', States, Vstack, yecc_end(Line), [],
+ {no_func, Line});
+yeccpars1([], {no_func, Endline}, State, States, Vstack) ->
+ yeccpars2(State, '$end', States, Vstack, yecc_end(Endline), [],
+ {no_func, Endline}).
+
+%% yeccpars1/7 is called from generated code.
+%%
+%% When using the {includefile, Includefile} option, make sure that
+%% yeccpars1/7 can be found by parsing the file without following
+%% include directives. yecc will otherwise assume that an old
+%% yeccpre.hrl is included (one which defines yeccpars1/5).
+yeccpars1(State1, State, States, Vstack, Token0, [Token | Tokens], Tzr) ->
+ yeccpars2(State, element(1, Token), [State1 | States],
+ [Token0 | Vstack], Token, Tokens, Tzr);
+yeccpars1(State1, State, States, Vstack, Token0, [], {{_F,_A}, _Line}=Tzr) ->
+ yeccpars1([], Tzr, State, [State1 | States], [Token0 | Vstack]);
+yeccpars1(State1, State, States, Vstack, Token0, [], {no_func, no_line}) ->
+ Line = yecctoken_end_location(Token0),
+ yeccpars2(State, '$end', [State1 | States], [Token0 | Vstack],
+ yecc_end(Line), [], {no_func, Line});
+yeccpars1(State1, State, States, Vstack, Token0, [], {no_func, Line}) ->
+ yeccpars2(State, '$end', [State1 | States], [Token0 | Vstack],
+ yecc_end(Line), [], {no_func, Line}).
+
+%% For internal use only.
+yecc_end({Line,_Column}) ->
+ {'$end', Line};
+yecc_end(Line) ->
+ {'$end', Line}.
+
+yecctoken_end_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}).
+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) ->
+ try erl_scan:text(Token) of
+ undefined -> yecctoken2string(Token);
+ Txt -> Txt
+ catch _:_ -> yecctoken2string(Token)
+ end.
+
+yecctoken_location(Token) ->
+ try erl_scan:location(Token)
+ catch _:_ -> element(2, Token)
+ end.
+
+-compile({nowarn_unused_function, yecctoken2string/1}).
+yecctoken2string({atom, _, A}) -> io_lib:write_atom(A);
+yecctoken2string({integer,_,N}) -> io_lib:write(N);
+yecctoken2string({float,_,F}) -> io_lib:write(F);
+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:format(\"~p\", [Val]);
+yecctoken2string({dot, _}) -> \"'.'\";
+yecctoken2string({'$end', _}) -> [];
+yecctoken2string({Other, _}) when is_atom(Other) ->
+ io_lib:write_atom(Other);
+yecctoken2string(Other) ->
+ io_lib:format(\"~p\", [Other]).
+">>.