From 37fdc7e515bd3db197cec92fa476923d19ec283a Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Fri, 23 Nov 2018 14:56:03 -0700 Subject: fix base path used for yrl/xrl includefile configs (#1952) --- test/rebar_compile_SUITE.erl | 150 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 148 insertions(+), 2 deletions(-) (limited to 'test') 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]). +">>. -- cgit v1.1