|
|
@ -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]). |
|
|
|
">>. |