1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19
20-module(epp).
21
22%% An Erlang code preprocessor.
23
24-export([open/1,open/2,open/3,close/1,format_error/1]).
25-export([scan_erl_form/1,parse_erl_form/1,macro_defs/1]).
26-export([scan_file/1, scan_file/2, parse_file/1, parse_file/2, parse_file/3]).
27-export([default_encoding/0, encoding_to_string/1,
28         read_encoding_from_binary/1, read_encoding_from_binary/2,
29         set_encoding/1, set_encoding/2, read_encoding/1, read_encoding/2]).
30-export([interpret_file_attribute/1]).
31-export([normalize_typed_record_fields/1,restore_typed_record_fields/1]).
32
33%%------------------------------------------------------------------------
34
35-export_type([source_encoding/0]).
36
37-type macros() :: [atom() | {atom(), term()} | {atom(), term(), 'redefine'}].
38-type epp_handle() :: pid().
39-type source_encoding() :: latin1 | utf8.
40
41-type ifdef() :: 'ifdef' | 'ifndef' | 'if' | 'else'.
42
43-type name() :: atom().
44-type argspec() :: 'none'                       %No arguments
45                 | non_neg_integer().           %Number of arguments
46-type argnames() :: [atom()].
47-type tokens() :: [erl_scan:token()].
48-type predef() :: 'undefined' | {'none', tokens()}.
49-type userdef() :: {argspec(), {argnames(), tokens()}}.
50-type used() :: {name(), argspec()}.
51
52-type function_name_type() :: 'undefined'
53			    | {atom(),non_neg_integer()}
54			    | tokens().
55
56-type warning_info() :: {erl_anno:location(), module(), term()}.
57
58-define(DEFAULT_ENCODING, utf8).
59
60%% Epp state record.
61-record(epp, {file :: file:io_device()
62                    | 'undefined',              %Current file
63	      location=1,         		%Current location
64              delta=0 :: non_neg_integer(),     %Offset from Location (-file)
65              name="" :: file:name(),           %Current file name
66              name2="" :: file:name(),          %-"-, modified by -file
67              istk=[] :: [ifdef()],             %Ifdef stack
68              sstk=[] :: [#epp{}],              %State stack
69              path=[] :: [file:name()],         %Include-path
70              macs = #{}		        %Macros (don't care locations)
71	            :: #{name() => predef() | [userdef()]},
72              uses = #{}			%Macro use structure
73	            :: #{name() => [{argspec(), [used()]}]},
74              default_encoding = ?DEFAULT_ENCODING :: source_encoding(),
75	      pre_opened = false :: boolean(),
76              fname = [] :: function_name_type()
77	     }).
78
79%% open(Options)
80%% open(FileName, IncludePath)
81%% open(FileName, IncludePath, PreDefMacros)
82%% close(Epp)
83%% scan_erl_form(Epp)
84%% parse_erl_form(Epp)
85%% scan_file(Epp)
86%% scan_file(FileName, Options)
87%% parse_file(Epp)
88%% parse_file(FileName, Options)
89%% parse_file(FileName, IncludePath, PreDefMacros)
90%% macro_defs(Epp)
91
92-spec open(FileName, IncludePath) ->
93	{'ok', Epp} | {'error', ErrorDescriptor} when
94      FileName :: file:name(),
95      IncludePath :: [DirectoryName :: file:name()],
96      Epp :: epp_handle(),
97      ErrorDescriptor :: term().
98
99open(Name, Path) ->
100    open(Name, Path, []).
101
102-spec open(FileName, IncludePath, PredefMacros) ->
103	{'ok', Epp} | {'error', ErrorDescriptor} when
104      FileName :: file:name(),
105      IncludePath :: [DirectoryName :: file:name()],
106      PredefMacros :: macros(),
107      Epp :: epp_handle(),
108      ErrorDescriptor :: term().
109
110open(Name, Path, Pdm) ->
111    open([{name, Name}, {includes, Path}, {macros, Pdm}]).
112
113-spec open(Options) ->
114		  {'ok', Epp} | {'ok', Epp, Extra} | {'error', ErrorDescriptor} when
115      Options :: [{'default_encoding', DefEncoding :: source_encoding()} |
116		  {'includes', IncludePath :: [DirectoryName :: file:name()]} |
117		  {'source_name', SourceName :: file:name()} |
118		  {'macros', PredefMacros :: macros()} |
119		  {'name',FileName :: file:name()} |
120		  {'location',StartLocation :: erl_anno:location()} |
121		  {'fd',FileDescriptor :: file:io_device()} |
122		  'extra'],
123      Epp :: epp_handle(),
124      Extra :: [{'encoding', source_encoding() | 'none'}],
125      ErrorDescriptor :: term().
126
127open(Options) ->
128    case proplists:get_value(name, Options) of
129        undefined ->
130            erlang:error(badarg);
131        Name ->
132            Self = self(),
133            Epp = spawn(fun() -> server(Self, Name, Options) end),
134            case epp_request(Epp) of
135                {ok, Pid, Encoding} ->
136                    case proplists:get_bool(extra, Options) of
137                        true -> {ok, Pid, [{encoding, Encoding}]};
138                        false -> {ok, Pid}
139                    end;
140                Other ->
141                    Other
142            end
143    end.
144
145-spec close(Epp) -> 'ok' when
146      Epp :: epp_handle().
147
148close(Epp) ->
149    %% Make sure that close is synchronous as a courtesy to test
150    %% cases that test for resource leaks.
151    Ref = erlang:monitor(process, Epp),
152    R = epp_request(Epp, close),
153    receive {'DOWN',Ref,_,_,_} -> ok end,
154    R.
155
156-spec scan_erl_form(Epp) ->
157    {'ok', Tokens} | {error, ErrorInfo} |
158    {'warning',WarningInfo} | {'eof',Line} when
159      Epp :: epp_handle(),
160      Tokens :: erl_scan:tokens(),
161      Line :: erl_anno:line(),
162      ErrorInfo :: erl_scan:error_info() | erl_parse:error_info(),
163      WarningInfo :: warning_info().
164
165scan_erl_form(Epp) ->
166    epp_request(Epp, scan_erl_form).
167
168-spec parse_erl_form(Epp) ->
169    {'ok', AbsForm} | {error, ErrorInfo} |
170    {'warning',WarningInfo} | {'eof',Location} when
171      Epp :: epp_handle(),
172      AbsForm :: erl_parse:abstract_form(),
173      Location :: erl_anno:location(),
174      ErrorInfo :: erl_scan:error_info() | erl_parse:error_info(),
175      WarningInfo :: warning_info().
176
177parse_erl_form(Epp) ->
178    case epp_request(Epp, scan_erl_form) of
179	{ok,Toks} ->
180	    erl_parse:parse_form(Toks);
181	Other ->
182	    Other
183    end.
184
185macro_defs(Epp) ->
186    epp_request(Epp, macro_defs).
187
188%% format_error(ErrorDescriptor) -> String
189%%  Return a string describing the error.
190
191-spec format_error(ErrorDescriptor) -> io_lib:chars() when
192      ErrorDescriptor :: term().
193
194format_error(cannot_parse) ->
195    io_lib:format("cannot parse file, giving up", []);
196format_error({bad,W}) ->
197    io_lib:format("badly formed '~s'", [W]);
198format_error({duplicated_argument, Arg}) ->
199    io_lib:format("argument '~ts' already used", [Arg]);
200format_error(missing_parenthesis) ->
201    io_lib:format("badly formed define: missing closing right parenthesis",[]);
202format_error(missing_comma) ->
203    io_lib:format("badly formed define: missing comma",[]);
204format_error(premature_end) ->
205    "premature end";
206format_error({call,What}) ->
207    io_lib:format("illegal macro call '~ts'",[What]);
208format_error({undefined,M,none}) ->
209    io_lib:format("undefined macro '~ts'", [M]);
210format_error({undefined,M,A}) ->
211    io_lib:format("undefined macro '~ts/~p'", [M,A]);
212format_error({depth,What}) ->
213    io_lib:format("~s too deep",[What]);
214format_error({mismatch,M}) ->
215    io_lib:format("argument mismatch for macro '~ts'", [M]);
216format_error({arg_error,M}) ->
217    io_lib:format("badly formed argument for macro '~ts'", [M]);
218format_error({redefine,M}) ->
219    io_lib:format("redefining macro '~ts'", [M]);
220format_error({redefine_predef,M}) ->
221    io_lib:format("redefining predefined macro '~s'", [M]);
222format_error({circular,M,none}) ->
223    io_lib:format("circular macro '~ts'", [M]);
224format_error({circular,M,A}) ->
225    io_lib:format("circular macro '~ts/~p'", [M,A]);
226format_error({include,W,F}) ->
227    io_lib:format("can't find include ~s \"~ts\"", [W,F]);
228format_error({illegal,How,What}) ->
229    io_lib:format("~s '-~s'", [How,What]);
230format_error({illegal_function,Macro}) ->
231    io_lib:format("?~s can only be used within a function", [Macro]);
232format_error({illegal_function_usage,Macro}) ->
233    io_lib:format("?~s must not begin a form", [Macro]);
234format_error(elif_after_else) ->
235    "'elif' following 'else'";
236format_error({'NYI',What}) ->
237    io_lib:format("not yet implemented '~s'", [What]);
238format_error({error,Term}) ->
239    io_lib:format("-error(~tp).", [Term]);
240format_error({warning,Term}) ->
241    io_lib:format("-warning(~tp).", [Term]);
242format_error(E) -> file:format_error(E).
243
244-spec scan_file(FileName, Options) ->
245        {'ok', [Form], Extra} | {error, OpenError} when
246      FileName :: file:name(),
247      Options :: [{'includes', IncludePath :: [DirectoryName :: file:name()]} |
248		  {'source_name', SourceName :: file:name()} |
249		  {'macros', PredefMacros :: macros()} |
250		  {'default_encoding', DefEncoding :: source_encoding()}],
251      Form :: erl_scan:tokens() | {'error', ErrorInfo} | {'eof', Loc},
252      Loc :: erl_anno:location(),
253      ErrorInfo :: erl_scan:error_info(),
254      Extra :: [{'encoding', source_encoding() | 'none'}],
255      OpenError :: file:posix() | badarg | system_limit.
256
257scan_file(Ifile, Options) ->
258    case open([{name, Ifile}, extra | Options]) of
259	{ok,Epp,Extra} ->
260	    Forms = scan_file(Epp),
261	    close(Epp),
262	    {ok,Forms,Extra};
263	{error,E} ->
264	    {error,E}
265    end.
266
267scan_file(Epp) ->
268    case scan_erl_form(Epp) of
269	{ok,Toks} ->
270            [Toks|scan_file(Epp)];
271	{error,E} ->
272	    [{error,E}|scan_file(Epp)];
273	{eof,Location} ->
274	    [{eof,Location}]
275    end.
276
277-spec parse_file(FileName, IncludePath, PredefMacros) ->
278                {'ok', [Form]} | {error, OpenError} when
279      FileName :: file:name(),
280      IncludePath :: [DirectoryName :: file:name()],
281      Form :: erl_parse:abstract_form()
282            | {'error', ErrorInfo}
283            | {'eof',Location},
284      PredefMacros :: macros(),
285      Location :: erl_anno:location(),
286      ErrorInfo :: erl_scan:error_info() | erl_parse:error_info(),
287      OpenError :: file:posix() | badarg | system_limit.
288
289parse_file(Ifile, Path, Predefs) ->
290    parse_file(Ifile, [{includes, Path}, {macros, Predefs}]).
291
292-spec parse_file(FileName, Options) ->
293        {'ok', [Form]} | {'ok', [Form], Extra} | {error, OpenError} when
294      FileName :: file:name(),
295      Options :: [{'includes', IncludePath :: [DirectoryName :: file:name()]} |
296		  {'source_name', SourceName :: file:name()} |
297		  {'macros', PredefMacros :: macros()} |
298		  {'default_encoding', DefEncoding :: source_encoding()} |
299		  {'location',StartLocation :: erl_anno:location()} |
300		  'extra'],
301      Form :: erl_parse:abstract_form()
302            | {'error', ErrorInfo}
303            | {'eof',Location},
304      Location :: erl_anno:location(),
305      ErrorInfo :: erl_scan:error_info() | erl_parse:error_info(),
306      Extra :: [{'encoding', source_encoding() | 'none'}],
307      OpenError :: file:posix() | badarg | system_limit.
308
309parse_file(Ifile, Options) ->
310    case open([{name, Ifile} | Options]) of
311	{ok,Epp} ->
312	    Forms = parse_file(Epp),
313	    close(Epp),
314	    {ok,Forms};
315	{ok,Epp,Extra} ->
316	    Forms = parse_file(Epp),
317	    close(Epp),
318	    {ok,Forms,Extra};
319	{error,E} ->
320	    {error,E}
321    end.
322
323-spec parse_file(Epp) -> [Form] when
324      Epp :: epp_handle(),
325      Form :: erl_parse:abstract_form() | {'error', ErrorInfo} |
326	      {'warning',WarningInfo} | {'eof',Location},
327      Location :: erl_anno:location(),
328      ErrorInfo :: erl_scan:error_info() | erl_parse:error_info(),
329      WarningInfo :: warning_info().
330
331parse_file(Epp) ->
332    case parse_erl_form(Epp) of
333	{ok,Form} ->
334            [Form|parse_file(Epp)];
335	{error,E} ->
336	    [{error,E}|parse_file(Epp)];
337	{warning,W} ->
338	    [{warning,W}|parse_file(Epp)];
339	{eof,Location} ->
340	    [{eof,Location}]
341    end.
342
343-spec default_encoding() -> source_encoding().
344
345default_encoding() ->
346    ?DEFAULT_ENCODING.
347
348-spec encoding_to_string(Encoding) -> string() when
349      Encoding :: source_encoding().
350
351encoding_to_string(latin1) -> "coding: latin-1";
352encoding_to_string(utf8) -> "coding: utf-8".
353
354-spec read_encoding(FileName) -> source_encoding() | none when
355      FileName :: file:name().
356
357read_encoding(Name) ->
358    read_encoding(Name, []).
359
360-spec read_encoding(FileName, Options) -> source_encoding() | none when
361      FileName :: file:name(),
362      Options :: [Option],
363      Option :: {in_comment_only, boolean()}.
364
365read_encoding(Name, Options) ->
366    InComment = proplists:get_value(in_comment_only, Options, true),
367    case file:open(Name, [read]) of
368        {ok,File} ->
369            try read_encoding_from_file(File, InComment)
370            after ok = file:close(File)
371            end;
372        _Error ->
373            none
374    end.
375
376-spec set_encoding(File) -> source_encoding() | none when
377      File :: io:device(). % pid(); raw files don't work
378
379set_encoding(File) ->
380    set_encoding(File, ?DEFAULT_ENCODING).
381
382-spec set_encoding(File, Default) -> source_encoding() | none when
383      Default :: source_encoding(),
384      File :: io:device(). % pid(); raw files don't work
385
386set_encoding(File, Default) ->
387    Encoding = read_encoding_from_file(File, true),
388    Enc = case Encoding of
389              none -> Default;
390              Encoding -> Encoding
391          end,
392    ok = io:setopts(File, [{encoding, Enc}]),
393    Encoding.
394
395-spec read_encoding_from_binary(Binary) -> source_encoding() | none when
396      Binary :: binary().
397
398-define(ENC_CHUNK, 32).
399-define(N_ENC_CHUNK, 16). % a total of 512 bytes
400
401read_encoding_from_binary(Binary) ->
402    read_encoding_from_binary(Binary, []).
403
404-spec read_encoding_from_binary(Binary, Options) ->
405                                       source_encoding() | none when
406      Binary :: binary(),
407      Options :: [Option],
408      Option :: {in_comment_only, boolean()}.
409
410read_encoding_from_binary(Binary, Options) ->
411    InComment = proplists:get_value(in_comment_only, Options, true),
412    try
413        com_nl(Binary, fake_reader(0), 0, InComment)
414    catch
415        throw:no ->
416            none
417    end.
418
419fake_reader(N) ->
420    fun() when N =:= ?N_ENC_CHUNK ->
421            throw(no);
422       () ->
423            {<<>>, fake_reader(N+1)}
424    end.
425
426-spec read_encoding_from_file(File, InComment) -> source_encoding() | none when
427      File :: io:device(),
428      InComment :: boolean().
429
430read_encoding_from_file(File, InComment) ->
431    {ok, Pos0} = file:position(File, cur),
432    Opts = io:getopts(File),
433    Encoding0 = lists:keyfind(encoding, 1, Opts),
434    Binary0 = lists:keyfind(binary, 1, Opts),
435    ok = io:setopts(File, [binary, {encoding, latin1}]),
436    try
437        {B, Fun} = (reader(File, 0))(),
438        com_nl(B, Fun, 0, InComment)
439    catch
440        throw:no ->
441            none
442    after
443        {ok, Pos0} = file:position(File, Pos0),
444        ok = io:setopts(File, [Binary0, Encoding0])
445    end.
446
447reader(Fd, N) ->
448    fun() when N =:= ?N_ENC_CHUNK ->
449            throw(no);
450       () ->
451            case file:read(Fd, ?ENC_CHUNK) of
452                eof ->
453                    {<<>>, reader(Fd, N+1)};
454                {ok, Bin} ->
455                    {Bin, reader(Fd, N+1)};
456                {error, _} ->
457                    throw(no) % ignore errors
458            end
459    end.
460
461com_nl(_, _, 2, _) ->
462    throw(no);
463com_nl(B, Fun, N, false=Com) ->
464    com_c(B, Fun, N, Com);
465com_nl(B, Fun, N, true=Com) ->
466    com(B, Fun, N, Com).
467
468com(<<"\n",B/binary>>, Fun, N, Com) ->
469    com_nl(B, Fun, N+1, Com);
470com(<<"%", B/binary>>, Fun, N, Com) ->
471    com_c(B, Fun, N, Com);
472com(<<_:1/unit:8,B/binary>>, Fun, N, Com) ->
473    com(B, Fun, N, Com);
474com(<<>>, Fun, N, Com) ->
475    {B, Fun1} = Fun(),
476    com(B, Fun1, N, Com).
477
478com_c(<<"c",B/binary>>, Fun, N, Com) ->
479    com_oding(B, Fun, N, Com);
480com_c(<<"\n",B/binary>>, Fun, N, Com) ->
481    com_nl(B, Fun, N+1, Com);
482com_c(<<_:1/unit:8,B/binary>>, Fun, N, Com) ->
483    com_c(B, Fun, N, Com);
484com_c(<<>>, Fun, N, Com) ->
485    {B, Fun1} = Fun(),
486    com_c(B, Fun1, N, Com).
487
488com_oding(<<"oding",B/binary>>, Fun, N, Com) ->
489    com_sep(B, Fun, N, Com);
490com_oding(B, Fun, N, Com) when byte_size(B) >= length("oding") ->
491    com_c(B, Fun, N, Com);
492com_oding(B, Fun, N, Com) ->
493    {B1, Fun1} = Fun(),
494    com_oding(list_to_binary([B, B1]), Fun1, N, Com).
495
496com_sep(<<":",B/binary>>, Fun, N, Com) ->
497    com_space(B, Fun, N, Com);
498com_sep(<<"=",B/binary>>, Fun, N, Com) ->
499    com_space(B, Fun, N, Com);
500com_sep(<<"\s",B/binary>>, Fun, N, Com) ->
501    com_sep(B, Fun, N, Com);
502com_sep(<<>>, Fun, N, Com) ->
503    {B, Fun1} = Fun(),
504    com_sep(B, Fun1, N, Com);
505com_sep(B, Fun, N, Com) ->
506    com_c(B, Fun, N, Com).
507
508com_space(<<"\s",B/binary>>, Fun, N, Com) ->
509    com_space(B, Fun, N, Com);
510com_space(<<>>, Fun, N, Com) ->
511    {B, Fun1} = Fun(),
512    com_space(B, Fun1, N, Com);
513com_space(B, Fun, N, _Com) ->
514    com_enc(B, Fun, N, [], []).
515
516com_enc(<<C:1/unit:8,B/binary>>, Fun, N, L, Ps) when C >= $a, C =< $z;
517                                                     C >= $A, C =< $Z;
518                                                     C >= $0, C =< $9 ->
519    com_enc(B, Fun, N, [C | L], Ps);
520com_enc(<<>>, Fun, N, L, Ps) ->
521    case Fun() of
522        {<<>>, _} ->
523            com_enc_end([L | Ps]);
524        {B, Fun1} ->
525            com_enc(B, Fun1, N, L, Ps)
526    end;
527com_enc(<<"-",B/binary>>, Fun, N, L, Ps) ->
528    com_enc(B, Fun, N, [], [L | Ps]);
529com_enc(_B, _Fun, _N, L, Ps) ->
530    com_enc_end([L | Ps]).
531
532com_enc_end(Ps0) ->
533    Ps = lists:reverse([lists:reverse(lowercase(P)) || P <- Ps0]),
534    com_encoding(Ps).
535
536com_encoding(["latin","1"|_]) ->
537    latin1;
538com_encoding(["utf","8"|_]) ->
539    utf8;
540com_encoding(_) ->
541    throw(no). % Don't try any further
542
543lowercase(S) ->
544    unicode:characters_to_list(string:lowercase(S)).
545
546normalize_typed_record_fields([]) ->
547    {typed, []};
548normalize_typed_record_fields(Fields) ->
549    normalize_typed_record_fields(Fields, [], false).
550
551normalize_typed_record_fields([], NewFields, Typed) ->
552    case Typed of
553	true -> {typed, lists:reverse(NewFields)};
554	false -> not_typed
555    end;
556normalize_typed_record_fields([{typed_record_field,Field,_}|Rest],
557			      NewFields, _Typed) ->
558    normalize_typed_record_fields(Rest, [Field|NewFields], true);
559normalize_typed_record_fields([Field|Rest], NewFields, Typed) ->
560    normalize_typed_record_fields(Rest, [Field|NewFields], Typed).
561
562restore_typed_record_fields([]) ->
563    [];
564restore_typed_record_fields([{attribute,A,record,{Record,_NewFields}},
565                             {attribute,A,type,{{record,Record},Fields,[]}}|
566                             Forms]) ->
567    [{attribute,A,record,{Record,Fields}}|
568     restore_typed_record_fields(Forms)];
569restore_typed_record_fields([{attribute,A,type,{{record,Record},Fields,[]}}|
570                             Forms]) ->
571    %% This clause is due to the compiler's 'E' option.
572    %% Record information kept by erl_expand_records.
573    [{attribute,A,record,{Record,Fields}}|
574     restore_typed_record_fields(Forms)];
575restore_typed_record_fields([Form|Forms]) ->
576    [Form|restore_typed_record_fields(Forms)].
577
578server(Pid, Name, Options) ->
579    process_flag(trap_exit, true),
580    St = #epp{},
581    case proplists:get_value(fd, Options) of
582        undefined ->
583            case file:open(Name, [read]) of
584                {ok,File} ->
585                    init_server(Pid, Name, Options, St#epp{file = File});
586                {error,E} ->
587                    epp_reply(Pid, {error,E})
588            end;
589        Fd ->
590            init_server(Pid, Name, Options, St#epp{file = Fd, pre_opened=true})
591    end.
592
593init_server(Pid, FileName, Options, St0) ->
594    SourceName = proplists:get_value(source_name, Options, FileName),
595    Pdm = proplists:get_value(macros, Options, []),
596    Ms0 = predef_macros(SourceName),
597    case user_predef(Pdm, Ms0) of
598	{ok,Ms1} ->
599            DefEncoding = proplists:get_value(default_encoding, Options,
600                                              ?DEFAULT_ENCODING),
601            Encoding = set_encoding(St0#epp.file, DefEncoding),
602            epp_reply(Pid, {ok,self(),Encoding}),
603            %% ensure directory of current source file is
604            %% first in path
605            Path = [filename:dirname(FileName) |
606                    proplists:get_value(includes, Options, [])],
607            %% the default location is 1 for backwards compatibility, not {1,1}
608            AtLocation = proplists:get_value(location, Options, 1),
609            St = St0#epp{delta=0, name=SourceName, name2=SourceName,
610			 path=Path, location=AtLocation, macs=Ms1,
611			 default_encoding=DefEncoding},
612            From = wait_request(St),
613            Anno = erl_anno:new(AtLocation),
614            enter_file_reply(From, file_name(SourceName), Anno,
615			     AtLocation, code),
616            wait_req_scan(St);
617	{error,E} ->
618	    epp_reply(Pid, {error,E})
619    end.
620
621%% predef_macros(FileName) -> Macrodict
622%%  Initialise the macro dictionary with the default predefined macros,
623%%  FILE, LINE, MODULE as undefined, MACHINE and MACHINE value.
624
625predef_macros(File) ->
626    Machine = list_to_atom(erlang:system_info(machine)),
627    Anno = line1(),
628    OtpVersion = list_to_integer(erlang:system_info(otp_release)),
629    Defs = [{'FILE', 	           {none,[{string,Anno,File}]}},
630	    {'FUNCTION_NAME',      undefined},
631	    {'FUNCTION_ARITY',     undefined},
632	    {'LINE',		   {none,[{integer,Anno,1}]}},
633	    {'MODULE',	           undefined},
634	    {'MODULE_STRING',      undefined},
635	    {'BASE_MODULE',	   undefined},
636	    {'BASE_MODULE_STRING', undefined},
637	    {'MACHINE',	           {none,[{atom,Anno,Machine}]}},
638	    {Machine,	           {none,[{atom,Anno,true}]}},
639	    {'OTP_RELEASE',	   {none,[{integer,Anno,OtpVersion}]}}
640	   ],
641    maps:from_list(Defs).
642
643%% user_predef(PreDefMacros, Macros) ->
644%%	{ok,MacroDict} | {error,E}
645%%  Add the predefined macros to the macros dictionary. A macro without a
646%%  value gets the value 'true'.
647
648user_predef([{M,Val,redefine}|Pdm], Ms) when is_atom(M) ->
649    Exp = erl_parse:tokens(erl_parse:abstract(Val)),
650    user_predef(Pdm, Ms#{M=>{none,Exp}});
651user_predef([{M,Val}|Pdm], Ms) when is_atom(M) ->
652    case Ms of
653	#{M:=Defs} when is_list(Defs) ->
654	     %% User defined macros.
655	    {error,{redefine,M}};
656	#{M:=_Defs} ->
657	    %% Predefined macros.
658	    {error,{redefine_predef,M}};
659	_ ->
660	    Exp = erl_parse:tokens(erl_parse:abstract(Val)),
661	    user_predef(Pdm, Ms#{M=>[{none,{none,Exp}}]})
662    end;
663user_predef([M|Pdm], Ms) when is_atom(M) ->
664    user_predef([{M,true}|Pdm], Ms);
665user_predef([Md|_Pdm], _Ms) -> {error,{bad,Md}};
666user_predef([], Ms) -> {ok,Ms}.
667
668%% wait_request(EppState) -> RequestFrom
669%% wait_req_scan(EppState)
670%% wait_req_skip(EppState, SkipIstack)
671%%  Handle requests, processing trivial requests directly. Either return
672%%  requestor or scan/skip tokens.
673
674wait_request(St) ->
675    receive
676	{epp_request,From,scan_erl_form} -> From;
677	{epp_request,From,macro_defs} ->
678	    %% Return the old format to avoid any incompability issues.
679	    Defs = [{{atom,K},V} || {K,V} <- maps:to_list(St#epp.macs)],
680	    epp_reply(From, Defs),
681	    wait_request(St);
682	{epp_request,From,close} ->
683	    close_file(St),
684	    epp_reply(From, ok),
685	    exit(normal);
686	{'EXIT',_,R} ->
687	    exit(R);
688	Other ->
689	    io:fwrite("Epp: unknown '~w'\n", [Other]),
690	    wait_request(St)
691    end.
692
693close_file(#epp{pre_opened = true}) ->
694    ok;
695close_file(#epp{pre_opened = false, file = File}) ->
696    ok = file:close(File).
697
698wait_req_scan(St) ->
699    From = wait_request(St),
700    scan_toks(From, St).
701
702wait_req_skip(St, Sis) ->
703    From = wait_request(St),
704    skip_toks(From, St, Sis).
705
706%% enter_file(FileName, IncludeToken, From, EppState)
707%% leave_file(From, EppState)
708%%  Handle entering and leaving included files. Notify caller when the
709%%  current file is changed. Note it is an error to exit a file if we are
710%%  in a conditional. These functions never return.
711
712enter_file(_NewName, Inc, From, St)
713  when length(St#epp.sstk) >= 8 ->
714    epp_reply(From, {error,{loc(Inc),epp,{depth,"include"}}}),
715    wait_req_scan(St);
716enter_file(NewName, Inc, From, St) ->
717    case file:path_open(St#epp.path, NewName, [read]) of
718	{ok,NewF,Pname} ->
719            Loc = start_loc(St#epp.location),
720	    wait_req_scan(enter_file2(NewF, Pname, From, St, Loc));
721	{error,_E} ->
722	    epp_reply(From, {error,{loc(Inc),epp,{include,file,NewName}}}),
723	    wait_req_scan(St)
724    end.
725
726%% enter_file2(File, FullName, From, EppState, AtLocation) -> EppState.
727%%  Set epp to use this file and "enter" it.
728
729enter_file2(NewF, Pname, From, St0, AtLocation) ->
730    Anno = erl_anno:new(AtLocation),
731    enter_file_reply(From, Pname, Anno, AtLocation, code),
732    #epp{macs = Ms0,
733         default_encoding = DefEncoding} = St0,
734    Ms = Ms0#{'FILE':={none,[{string,Anno,Pname}]}},
735    %% update the head of the include path to be the directory of the new
736    %% source file, so that an included file can always include other files
737    %% relative to its current location (this is also how C does it); note
738    %% that the directory of the parent source file (the previous head of
739    %% the path) must be dropped, otherwise the path used within the current
740    %% file will depend on the order of file inclusions in the parent files
741    Path = [filename:dirname(Pname) | tl(St0#epp.path)],
742    _ = set_encoding(NewF, DefEncoding),
743    #epp{file=NewF,location=AtLocation,name=Pname,name2=Pname,delta=0,
744         sstk=[St0|St0#epp.sstk],path=Path,macs=Ms,
745         default_encoding=DefEncoding}.
746
747enter_file_reply(From, Name, LocationAnno, AtLocation, Where) ->
748    Anno0 = erl_anno:new(AtLocation),
749    Anno = case Where of
750               code -> Anno0;
751               generated -> erl_anno:set_generated(true, Anno0)
752           end,
753    Rep = {ok, [{'-',Anno},{atom,Anno,file},{'(',Anno},
754		{string,Anno,Name},{',',Anno},
755		{integer,Anno,get_line(LocationAnno)},{')',LocationAnno},
756                {dot,Anno}]},
757    epp_reply(From, Rep).
758
759%% Flatten filename to a string. Must be a valid filename.
760
761file_name([C | T]) when is_integer(C), C > 0 ->
762    [C | file_name(T)];
763file_name([H|T]) ->
764    file_name(H) ++ file_name(T);
765file_name([]) ->
766    [];
767file_name(N) when is_atom(N) ->
768    atom_to_list(N).
769
770leave_file(From, St) ->
771    case St#epp.istk of
772	[I|Cis] ->
773	    epp_reply(From,
774		      {error,{St#epp.location,epp,
775                              {illegal,"unterminated",I}}}),
776	    leave_file(wait_request(St),St#epp{istk=Cis});
777	[] ->
778	    case St#epp.sstk of
779		[OldSt|Sts] ->
780		    close_file(St),
781                    #epp{location=OldLoc, delta=Delta, name=OldName,
782                         name2=OldName2} = OldSt,
783                    CurrLoc = add_line(OldLoc, Delta),
784                    Anno = erl_anno:new(CurrLoc),
785		    Ms0 = St#epp.macs,
786		    Ms = Ms0#{'FILE':={none,[{string,Anno,OldName2}]}},
787                    NextSt = OldSt#epp{sstk=Sts,macs=Ms,uses=St#epp.uses},
788		    enter_file_reply(From, OldName, Anno, CurrLoc, code),
789                    case OldName2 =:= OldName of
790                        true ->
791                            ok;
792                        false ->
793                            NFrom = wait_request(NextSt),
794                            OldAnno = erl_anno:new(OldLoc),
795                            enter_file_reply(NFrom, OldName2, OldAnno,
796                                             CurrLoc, generated)
797                        end,
798                    wait_req_scan(NextSt);
799		[] ->
800		    epp_reply(From, {eof,St#epp.location}),
801		    wait_req_scan(St)
802	    end
803    end.
804
805%% scan_toks(From, EppState)
806%% scan_toks(Tokens, From, EppState)
807
808scan_toks(From, St) ->
809    case io:scan_erl_form(St#epp.file, '', St#epp.location) of
810	{ok,Toks,Cl} ->
811	    scan_toks(Toks, From, St#epp{location=Cl});
812	{error,E,Cl} ->
813	    epp_reply(From, {error,E}),
814	    wait_req_scan(St#epp{location=Cl});
815	{eof,Cl} ->
816	    leave_file(From, St#epp{location=Cl});
817	{error,_E} ->
818            epp_reply(From, {error,{St#epp.location,epp,cannot_parse}}),
819	    leave_file(wait_request(St), St)	%This serious, just exit!
820    end.
821
822scan_toks([{'-',_Lh},{atom,_Ld,define}=Define|Toks], From, St) ->
823    scan_define(Toks, Define, From, St);
824scan_toks([{'-',_Lh},{atom,_Ld,undef}=Undef|Toks], From, St) ->
825    scan_undef(Toks, Undef, From, St);
826scan_toks([{'-',_Lh},{atom,_Ld,error}=Error|Toks], From, St) ->
827    scan_err_warn(Toks, Error, From, St);
828scan_toks([{'-',_Lh},{atom,_Ld,warning}=Warn|Toks], From, St) ->
829    scan_err_warn(Toks, Warn, From, St);
830scan_toks([{'-',_Lh},{atom,_Li,include}=Inc|Toks], From, St) ->
831    scan_include(Toks, Inc, From, St);
832scan_toks([{'-',_Lh},{atom,_Li,include_lib}=IncLib|Toks], From, St) ->
833    scan_include_lib(Toks, IncLib, From, St);
834scan_toks([{'-',_Lh},{atom,_Li,ifdef}=IfDef|Toks], From, St) ->
835    scan_ifdef(Toks, IfDef, From, St);
836scan_toks([{'-',_Lh},{atom,_Li,ifndef}=IfnDef|Toks], From, St) ->
837    scan_ifndef(Toks, IfnDef, From, St);
838scan_toks([{'-',_Lh},{atom,_Le,'else'}=Else|Toks], From, St) ->
839    scan_else(Toks, Else, From, St);
840scan_toks([{'-',_Lh},{'if',_Le}=If|Toks], From, St) ->
841    scan_if(Toks, If, From, St);
842scan_toks([{'-',_Lh},{atom,_Le,elif}=Elif|Toks], From, St) ->
843    scan_elif(Toks, Elif, From, St);
844scan_toks([{'-',_Lh},{atom,_Le,endif}=Endif|Toks], From, St) ->
845    scan_endif(Toks, Endif, From, St);
846scan_toks([{'-',_Lh},{atom,_Lf,file}=FileToken|Toks0], From, St) ->
847    case catch expand_macros(Toks0, St) of
848	Toks1 when is_list(Toks1) ->
849            scan_file(Toks1, FileToken, From, St);
850	{error,ErrL,What} ->
851	    epp_reply(From, {error,{ErrL,epp,What}}),
852	    wait_req_scan(St)
853    end;
854scan_toks(Toks0, From, St) ->
855    case catch expand_macros(Toks0, St#epp{fname=Toks0}) of
856	Toks1 when is_list(Toks1) ->
857	    epp_reply(From, {ok,Toks1}),
858	    wait_req_scan(St#epp{macs=scan_module(Toks1, St#epp.macs)});
859	{error,ErrL,What} ->
860	    epp_reply(From, {error,{ErrL,epp,What}}),
861	    wait_req_scan(St)
862    end.
863
864scan_module([{'-',_Ah},{atom,_Am,module},{'(',_Al}|Ts], Ms) ->
865    scan_module_1(Ts, Ms);
866scan_module([{'-',_Ah},{atom,_Am,extends},{'(',_Al}|Ts], Ms) ->
867    scan_extends(Ts, Ms);
868scan_module(_Ts, Ms) -> Ms.
869
870scan_module_1([{atom,_,_}=A,{',',Anno}|Ts], Ms) ->
871    %% Parameterized modules.
872    scan_module_1([A,{')',Anno}|Ts], Ms);
873scan_module_1([{atom,Anno,A}=ModAtom,{')',_Ar}|_Ts], Ms0) ->
874    ModString = atom_to_list(A),
875    Ms = Ms0#{'MODULE':={none,[ModAtom]}},
876    Ms#{'MODULE_STRING':={none,[{string,Anno,ModString}]}};
877scan_module_1(_Ts, Ms) -> Ms.
878
879scan_extends([{atom,Anno,A}=ModAtom,{')',_Ar}|_Ts], Ms0) ->
880    ModString = atom_to_list(A),
881    Ms = Ms0#{'BASE_MODULE':={none,[ModAtom]}},
882    Ms#{'BASE_MODULE_STRING':={none,[{string,Anno,ModString}]}};
883scan_extends(_Ts, Ms) -> Ms.
884
885scan_err_warn([{'(',_}|_]=Toks0, {atom,_,Tag}=Token, From, St) ->
886    try expand_macros(Toks0, St) of
887	Toks when is_list(Toks) ->
888	    case erl_parse:parse_term(Toks) of
889		{ok,Term} ->
890		    epp_reply(From, {Tag,{loc(Token),epp,{Tag,Term}}});
891		{error,_} ->
892		    epp_reply(From, {error,{loc(Token),epp,{bad,Tag}}})
893	    end
894    catch
895	_:_ ->
896	    epp_reply(From, {error,{loc(Token),epp,{bad,Tag}}})
897    end,
898    wait_req_scan(St);
899scan_err_warn(Toks, {atom,_,Tag}=Token, From, St) ->
900    T = no_match(Toks, Token),
901    epp_reply(From, {error,{loc(T),epp,{bad,Tag}}}),
902    wait_req_scan(St).
903
904%% scan_define(Tokens, DefineToken, From, EppState)
905
906scan_define([{'(',_Ap},{Type,_Am,_}=Mac|Toks], Def, From, St)
907  when Type =:= atom; Type =:= var ->
908    scan_define_1(Toks, Mac, Def, From, St);
909scan_define(Toks, Def, From, St) ->
910    T = find_mismatch(['(', var_or_atom], Toks, Def),
911    epp_reply(From, {error,{loc(T),epp,{bad,define}}}),
912    wait_req_scan(St).
913
914scan_define_1([{',',_}=Comma|Toks], Mac,_Def, From, St) ->
915    case catch macro_expansion(Toks, Comma) of
916        Expansion when is_list(Expansion) ->
917	    scan_define_2(none, {none,Expansion}, Mac, From, St);
918        {error,ErrL,What} ->
919            epp_reply(From, {error,{ErrL,epp,What}}),
920            wait_req_scan(St)
921    end;
922scan_define_1([{'(',_Ac}=T|Toks], Mac, _Def, From, St) ->
923    case catch macro_pars(Toks, [], T) of
924        {ok,{As,_}=MacroDef} ->
925            Len = length(As),
926	    scan_define_2(Len, MacroDef, Mac, From, St);
927	{error,ErrL,What} ->
928            epp_reply(From, {error,{ErrL,epp,What}}),
929            wait_req_scan(St)
930    end;
931scan_define_1(Toks, _Mac, Def, From, St) ->
932    T = no_match(Toks, Def),
933    epp_reply(From, {error,{loc(T),epp,{bad,define}}}),
934    wait_req_scan(St).
935
936scan_define_2(Arity, Def, {_,_,Key}=Mac, From, #epp{macs=Ms}=St) ->
937    case Ms of
938	#{Key:=Defs} when is_list(Defs) ->
939	    %% User defined macros: can be overloaded
940	    case proplists:is_defined(Arity, Defs) of
941		true ->
942		    epp_reply(From, {error,{loc(Mac),epp,{redefine,Key}}}),
943		    wait_req_scan(St);
944		false ->
945		    scan_define_cont(From, St, Key, Defs, Arity, Def)
946	    end;
947	#{Key:=_} ->
948	    %% Predefined macros: cannot be overloaded
949	    epp_reply(From, {error,{loc(Mac),epp,{redefine_predef,Key}}}),
950	    wait_req_scan(St);
951	_ ->
952	    scan_define_cont(From, St, Key, [], Arity, Def)
953    end.
954
955%%% Detection of circular macro expansions (which would either keep
956%%% the compiler looping forever, or run out of memory):
957%%% When a macro is defined, we store the names of other macros it
958%%% uses in St#epp.uses. If any macro is undef'ed, that information
959%%% becomes invalid, so we redo it for all remaining macros.
960%%% The circularity detection itself is done when a macro is expanded:
961%%% the information from St#epp.uses is traversed, and if a circularity
962%%% is detected, an error message is thrown.
963
964scan_define_cont(F, #epp{macs=Ms0}=St, M, Defs, Arity, Def) ->
965    Ms = Ms0#{M=>[{Arity,Def}|Defs]},
966    try macro_uses(Def) of
967        U ->
968	    Uses0 = St#epp.uses,
969	    Val = [{Arity,U}|case Uses0 of
970				 #{M:=UseList} -> UseList;
971				 _ -> []
972			     end],
973	    Uses = Uses0#{M=>Val},
974            scan_toks(F, St#epp{uses=Uses,macs=Ms})
975    catch
976        {error, Location, Reason} ->
977            epp_reply(F, {error,{Location,epp,Reason}}),
978            wait_req_scan(St)
979    end.
980
981macro_uses({_Args, Tokens}) ->
982    Uses0 = macro_ref(Tokens),
983    lists:usort(Uses0).
984
985macro_ref([]) ->
986    [];
987macro_ref([{'?', _}, {'?', _} | Rest]) ->
988    macro_ref(Rest);
989macro_ref([{'?', _}, {atom, _, A}=Atom | Rest]) ->
990    Lm = loc(Atom),
991    Arity = count_args(Rest, Lm, A),
992    [{A,Arity} | macro_ref(Rest)];
993macro_ref([{'?', _}, {var, _, A}=Var | Rest]) ->
994    Lm = loc(Var),
995    Arity = count_args(Rest, Lm, A),
996    [{A,Arity} | macro_ref(Rest)];
997macro_ref([_Token | Rest]) ->
998    macro_ref(Rest).
999
1000%% scan_undef(Tokens, UndefToken, From, EppState)
1001
1002scan_undef([{'(',_Alp},{atom,_Am,M},{')',_Arp},{dot,_Ad}], _Undef, From, St) ->
1003    Macs = maps:remove(M, St#epp.macs),
1004    Uses = maps:remove(M, St#epp.uses),
1005    scan_toks(From, St#epp{macs=Macs, uses=Uses});
1006scan_undef([{'(',_Alp},{var,_Am,M},{')',_Arp},{dot,_Ad}], _Undef, From,St) ->
1007    Macs = maps:remove(M, St#epp.macs),
1008    Uses = maps:remove(M, St#epp.uses),
1009    scan_toks(From, St#epp{macs=Macs, uses=Uses});
1010scan_undef(Toks, Undef, From, St) ->
1011    T = find_mismatch(['(',var_or_atom,')',dot], Toks, Undef),
1012    epp_reply(From, {error,{loc(T),epp,{bad,undef}}}),
1013    wait_req_scan(St).
1014
1015%% scan_include(Tokens, IncludeToken, From, St)
1016
1017scan_include(Tokens0, Inc, From, St) ->
1018    Tokens = coalesce_strings(Tokens0),
1019    scan_include1(Tokens, Inc, From, St).
1020
1021scan_include1([{'(',_Alp},{string,_Af,NewName0}=StringT,{')',_Arp},{dot,_Ad}],
1022              _Inc, From, St) ->
1023    NewName = expand_var(NewName0),
1024    enter_file(NewName, StringT, From, St);
1025scan_include1(Toks, Inc, From, St) ->
1026    T = find_mismatch(['(',string,')',dot], Toks, Inc),
1027    epp_reply(From, {error,{loc(T),epp,{bad,include}}}),
1028    wait_req_scan(St).
1029
1030%% scan_include_lib(Tokens, IncludeToken, From, EppState)
1031%%  For include_lib we first test if we can find the file through the
1032%%  normal search path, if not we assume that the first directory name
1033%%  is a library name, find its true directory and try with that.
1034
1035expand_lib_dir(Name) ->
1036    try
1037	[App|Path] = filename:split(Name),
1038	LibDir = code:lib_dir(list_to_atom(App)),
1039	{ok,fname_join([LibDir|Path])}
1040    catch
1041	_:_ ->
1042	    error
1043    end.
1044
1045scan_include_lib(Tokens0, Inc, From, St) ->
1046    Tokens = coalesce_strings(Tokens0),
1047    scan_include_lib1(Tokens, Inc, From, St).
1048
1049scan_include_lib1([{'(',_Alp},{string,_Af,_NewName0},{')',_Arp},{dot,_Ad}],
1050                  Inc, From, St)
1051  when length(St#epp.sstk) >= 8 ->
1052    epp_reply(From, {error,{loc(Inc),epp,{depth,"include_lib"}}}),
1053    wait_req_scan(St);
1054scan_include_lib1([{'(',_Alp},{string,_Af,NewName0}=N,{')',_Arp},{dot,_Ad}],
1055                  _Inc, From, St) ->
1056    NewName = expand_var(NewName0),
1057    Loc = start_loc(St#epp.location),
1058    case file:path_open(St#epp.path, NewName, [read]) of
1059	{ok,NewF,Pname} ->
1060	    wait_req_scan(enter_file2(NewF, Pname, From, St, Loc));
1061	{error,_E1} ->
1062	    case expand_lib_dir(NewName) of
1063		{ok,Header} ->
1064		    case file:open(Header, [read]) of
1065			{ok,NewF} ->
1066			    wait_req_scan(enter_file2(NewF, Header, From,
1067                                                      St, Loc));
1068			{error,_E2} ->
1069			    epp_reply(From,
1070				      {error,{loc(N),epp,
1071                                              {include,lib,NewName}}}),
1072			    wait_req_scan(St)
1073		    end;
1074		error ->
1075		    epp_reply(From, {error,{loc(N),epp,
1076                                            {include,lib,NewName}}}),
1077		    wait_req_scan(St)
1078	    end
1079    end;
1080scan_include_lib1(Toks, Inc, From, St) ->
1081    T = find_mismatch(['(',string,')',dot], Toks, Inc),
1082    epp_reply(From, {error,{loc(T),epp,{bad,include_lib}}}),
1083    wait_req_scan(St).
1084
1085%% scan_ifdef(Tokens, IfdefToken, From, EppState)
1086%% scan_ifndef(Tokens, IfdefToken, From, EppSate)
1087%%  Handle the conditional parsing of a file.
1088%%  Report a badly formed if[n]def test and then treat as undefined macro.
1089
1090scan_ifdef([{'(',_Alp},{atom,_Am,M},{')',_Arp},{dot,_Ad}], _IfD, From, St) ->
1091    case is_macro_defined(M, St) of
1092        true ->
1093	    scan_toks(From, St#epp{istk=[ifdef|St#epp.istk]});
1094        false ->
1095	    skip_toks(From, St, [ifdef])
1096    end;
1097scan_ifdef([{'(',_Alp},{var,_Am,M},{')',_Arp},{dot,_Ad}], _IfD, From, St) ->
1098    case is_macro_defined(M, St) of
1099        true ->
1100	    scan_toks(From, St#epp{istk=[ifdef|St#epp.istk]});
1101        false ->
1102	    skip_toks(From, St, [ifdef])
1103    end;
1104scan_ifdef(Toks, IfDef, From, St) ->
1105    T = find_mismatch(['(',var_or_atom,')',dot], Toks, IfDef),
1106    epp_reply(From, {error,{loc(T),epp,{bad,ifdef}}}),
1107    wait_req_skip(St, [ifdef]).
1108
1109scan_ifndef([{'(',_Alp},{atom,_Am,M},{')',_Arp},{dot,_Ad}], _IfnD, From, St) ->
1110    case is_macro_defined(M, St) of
1111        true ->
1112	    skip_toks(From, St, [ifndef]);
1113        false ->
1114	    scan_toks(From, St#epp{istk=[ifndef|St#epp.istk]})
1115    end;
1116scan_ifndef([{'(',_Alp},{var,_Am,M},{')',_Arp},{dot,_Ad}], _IfnD, From, St) ->
1117    case is_macro_defined(M, St) of
1118        true ->
1119	    skip_toks(From, St, [ifndef]);
1120        false ->
1121	    scan_toks(From, St#epp{istk=[ifndef|St#epp.istk]})
1122    end;
1123scan_ifndef(Toks, IfnDef, From, St) ->
1124    T = find_mismatch(['(',var_or_atom,')',dot], Toks, IfnDef),
1125    epp_reply(From, {error,{loc(T),epp,{bad,ifndef}}}),
1126    wait_req_skip(St, [ifndef]).
1127
1128is_macro_defined(Name, #epp{macs=Macs}) ->
1129    case Macs of
1130        #{Name := undefined} -> false;
1131        #{Name := _Def} -> true;
1132        #{} -> false
1133    end.
1134
1135%% scan_else(Tokens, ElseToken, From, EppState)
1136%%  If we are in an if body then convert to else and skip, if we are in an
1137%%  else or not in anything report an error.
1138
1139scan_else([{dot,_Ad}], Else, From, St) ->
1140    case St#epp.istk of
1141	['else'|Cis] ->
1142	    epp_reply(From, {error,{loc(Else),
1143                                    epp,{illegal,"repeated",'else'}}}),
1144	    wait_req_skip(St#epp{istk=Cis}, ['else']);
1145	[_I|Cis] ->
1146	    skip_toks(From, St#epp{istk=Cis}, ['else']);
1147	[] ->
1148	    epp_reply(From, {error,{loc(Else),epp,
1149                                    {illegal,"unbalanced",'else'}}}),
1150	    wait_req_scan(St)
1151    end;
1152scan_else(Toks, Else, From, St) ->
1153    T = no_match(Toks, Else),
1154    epp_reply(From, {error,{loc(T),epp,{bad,'else'}}}),
1155    wait_req_scan(St).
1156
1157%% scan_if(Tokens, IfToken, From, EppState)
1158%%  Handle the conditional parsing of a file.
1159
1160scan_if([{'(',_}|_]=Toks, If, From, St) ->
1161    try eval_if(Toks, St) of
1162	true ->
1163	    scan_toks(From, St#epp{istk=['if'|St#epp.istk]});
1164	_ ->
1165	    skip_toks(From, St, ['if'])
1166    catch
1167	throw:Error0 ->
1168	    Error = case Error0 of
1169			{_,erl_parse,_} ->
1170			    {error,Error0};
1171                        {error,ErrL,What} ->
1172                            {error,{ErrL,epp,What}};
1173			_ ->
1174			    {error,{loc(If),epp,Error0}}
1175		    end,
1176	    epp_reply(From, Error),
1177	    wait_req_skip(St, ['if'])
1178    end;
1179scan_if(Toks, If, From, St) ->
1180    T = no_match(Toks, If),
1181    epp_reply(From, {error,{loc(T),epp,{bad,'if'}}}),
1182    wait_req_skip(St, ['if']).
1183
1184eval_if(Toks0, St) ->
1185    Toks = expand_macros(Toks0, St),
1186    Es1 = case erl_parse:parse_exprs(Toks) of
1187	      {ok,Es0} -> Es0;
1188	      {error,E} -> throw(E)
1189	  end,
1190    Es = rewrite_expr(Es1, St),
1191    assert_guard_expr(Es),
1192    Bs = erl_eval:new_bindings(),
1193    LocalFun = fun(_Name, _Args) ->
1194		       error(badarg)
1195	       end,
1196    try erl_eval:exprs(Es, Bs, {value,LocalFun}) of
1197	{value,Res,_} ->
1198	    Res
1199    catch
1200	_:_ ->
1201	    false
1202    end.
1203
1204assert_guard_expr([E0]) ->
1205    E = rewrite_expr(E0, none),
1206    case erl_lint:is_guard_expr(E) of
1207	false ->
1208	    throw({bad,'if'});
1209	true ->
1210	    ok
1211    end;
1212assert_guard_expr(_) ->
1213    throw({bad,'if'}).
1214
1215%% Dual-purpose rewriting function. When the second argument is
1216%% an #epp{} record, calls to defined(Symbol) will be evaluated.
1217%% When the second argument is 'none', legal calls to our built-in
1218%% functions are eliminated in order to turn the expression into
1219%% a legal guard expression.
1220
1221rewrite_expr({call,_,{atom,_,defined},[N0]}, #epp{macs=Macs}) ->
1222    %% Evaluate defined(Symbol).
1223    N = case N0 of
1224	    {var,_,N1} -> N1;
1225	    {atom,_,N1} -> N1;
1226	    _ -> throw({bad,'if'})
1227	end,
1228    {atom,erl_anno:new(0),maps:is_key(N, Macs)};
1229rewrite_expr({call,_,{atom,_,Name},As0}, none) ->
1230    As = rewrite_expr(As0, none),
1231    Arity = length(As),
1232    case erl_internal:bif(Name, Arity) andalso
1233	not erl_internal:guard_bif(Name, Arity) of
1234	false ->
1235	    %% A guard BIF, an -if built-in, or an unknown function.
1236	    %% Eliminate the call so that erl_lint will not complain.
1237	    %% The call might fail later at evaluation time.
1238	    to_conses(As);
1239	true ->
1240	    %% An auto-imported BIF (not guard BIF). Not allowed.
1241	    throw({bad,'if'})
1242    end;
1243rewrite_expr([H|T], St) ->
1244    [rewrite_expr(H, St)|rewrite_expr(T, St)];
1245rewrite_expr(Tuple, St) when is_tuple(Tuple) ->
1246    list_to_tuple(rewrite_expr(tuple_to_list(Tuple), St));
1247rewrite_expr(Other, _) ->
1248    Other.
1249
1250to_conses([H|T]) ->
1251    {cons,erl_anno:new(0),H,to_conses(T)};
1252to_conses([]) ->
1253    {nil,erl_anno:new(0)}.
1254
1255%% scan_elif(Tokens, EndifToken, From, EppState)
1256%%  Handle the conditional parsing of a file.
1257%%  Report a badly formed if test and then treat as false macro.
1258
1259scan_elif(_Toks, Elif, From, St) ->
1260    case St#epp.istk of
1261	['else'|Cis] ->
1262	    epp_reply(From, {error,{loc(Elif),
1263                                    epp,{illegal,"unbalanced",'elif'}}}),
1264	    wait_req_skip(St#epp{istk=Cis}, ['else']);
1265	[_I|Cis] ->
1266	    skip_toks(From, St#epp{istk=Cis}, ['elif']);
1267	[] ->
1268	    epp_reply(From, {error,{loc(Elif),epp,
1269                                    {illegal,"unbalanced",elif}}}),
1270	    wait_req_scan(St)
1271    end.
1272
1273%% scan_endif(Tokens, EndifToken, From, EppState)
1274%%  If we are in an if body then exit it, else report an error.
1275
1276scan_endif([{dot,_Ad}], Endif, From, St) ->
1277    case St#epp.istk of
1278	[_I|Cis] ->
1279	    scan_toks(From, St#epp{istk=Cis});
1280	[] ->
1281	    epp_reply(From, {error,{loc(Endif),epp,
1282                                    {illegal,"unbalanced",endif}}}),
1283	    wait_req_scan(St)
1284    end;
1285scan_endif(Toks, Endif, From, St) ->
1286    T = no_match(Toks, Endif),
1287    epp_reply(From, {error,{loc(T),epp,{bad,endif}}}),
1288    wait_req_scan(St).
1289
1290%% scan_file(Tokens, FileToken, From, EppState)
1291%%  Set the current file and line to the given file and line.
1292%%  Note that the line of the attribute itself is kept.
1293
1294scan_file(Tokens0, Tf, From, St) ->
1295    Tokens = coalesce_strings(Tokens0),
1296    scan_file1(Tokens, Tf, From, St).
1297
1298scan_file1([{'(',_Alp},{string,_As,Name},{',',_Ac},{integer,_Ai,Ln},{')',_Arp},
1299            {dot,_Ad}], Tf, From, St) ->
1300    Anno = erl_anno:new(Ln),
1301    enter_file_reply(From, Name, Anno, loc(Tf), generated),
1302    Ms0 = St#epp.macs,
1303    Ms = Ms0#{'FILE':={none,[{string,line1(),Name}]}},
1304    Locf = loc(Tf),
1305    NewLoc = new_location(Ln, St#epp.location, Locf),
1306    Delta = get_line(element(2, Tf))-Ln + St#epp.delta,
1307    wait_req_scan(St#epp{name2=Name,location=NewLoc,delta=Delta,macs=Ms});
1308scan_file1(Toks, Tf, From, St) ->
1309    T = find_mismatch(['(', string, ',', integer, ')', dot], Toks, Tf),
1310    epp_reply(From, {error,{loc(T),epp,{bad,file}}}),
1311    wait_req_scan(St).
1312
1313new_location(Ln, Le, Lf) when is_integer(Lf) ->
1314    Ln+(Le-Lf);
1315new_location(Ln, {Le,_}, {Lf,_}) ->
1316    {Ln+(Le-Lf),1}.
1317
1318%% skip_toks(From, EppState, SkipIstack)
1319%%  Skip over forms until current conditional has been exited. Handle
1320%%  nested conditionals and repeated 'else's.
1321
1322skip_toks(From, St, [I|Sis]) ->
1323    case io:scan_erl_form(St#epp.file, '', St#epp.location) of
1324	{ok,[{'-',_Ah},{atom,_Ai,ifdef}|_Toks],Cl} ->
1325	    skip_toks(From, St#epp{location=Cl}, [ifdef,I|Sis]);
1326	{ok,[{'-',_Ah},{atom,_Ai,ifndef}|_Toks],Cl} ->
1327	    skip_toks(From, St#epp{location=Cl}, [ifndef,I|Sis]);
1328	{ok,[{'-',_Ah},{'if',_Ai}|_Toks],Cl} ->
1329	    skip_toks(From, St#epp{location=Cl}, ['if',I|Sis]);
1330	{ok,[{'-',_Ah},{atom,_Ae,'else'}=Else|_Toks],Cl}->
1331	    skip_else(Else, From, St#epp{location=Cl}, [I|Sis]);
1332	{ok,[{'-',_Ah},{atom,_Ae,'elif'}=Elif|Toks],Cl}->
1333	    skip_elif(Toks, Elif, From, St#epp{location=Cl}, [I|Sis]);
1334	{ok,[{'-',_Ah},{atom,_Ae,endif}|_Toks],Cl} ->
1335	    skip_toks(From, St#epp{location=Cl}, Sis);
1336	{ok,_Toks,Cl} ->
1337	    skip_toks(From, St#epp{location=Cl}, [I|Sis]);
1338	{error,E,Cl} ->
1339	    case E of
1340		{_,file_io_server,invalid_unicode} ->
1341		    %% The compiler needs to know that there was
1342		    %% invalid unicode characters in the file
1343		    %% (and there is no point in continuing anyway
1344		    %% since io server process has terminated).
1345		    epp_reply(From, {error,E}),
1346		    leave_file(wait_request(St), St);
1347		_ ->
1348		    %% Some other invalid token, such as a bad floating
1349		    %% point number. Just ignore it.
1350		    skip_toks(From, St#epp{location=Cl}, [I|Sis])
1351	    end;
1352	{eof,Cl} ->
1353	    leave_file(From, St#epp{location=Cl,istk=[I|Sis]});
1354	{error,_E} ->
1355            epp_reply(From, {error,{St#epp.location,epp,cannot_parse}}),
1356	    leave_file(wait_request(St), St)	%This serious, just exit!
1357    end;
1358skip_toks(From, St, []) ->
1359    scan_toks(From, St).
1360
1361skip_else(Else, From, St, ['else'|Sis]) ->
1362    epp_reply(From, {error,{loc(Else),epp,{illegal,"repeated",'else'}}}),
1363    wait_req_skip(St, ['else'|Sis]);
1364skip_else(_Else, From, St, ['elif'|Sis]) ->
1365    skip_toks(From, St, ['else'|Sis]);
1366skip_else(_Else, From, St, [_I]) ->
1367    scan_toks(From, St#epp{istk=['else'|St#epp.istk]});
1368skip_else(_Else, From, St, Sis) ->
1369    skip_toks(From, St, Sis).
1370
1371skip_elif(_Toks, Elif, From, St, ['else'|_]=Sis) ->
1372    epp_reply(From, {error,{loc(Elif),epp,elif_after_else}}),
1373    wait_req_skip(St, Sis);
1374skip_elif(Toks, Elif, From, St, [_I]) ->
1375    scan_if(Toks, Elif, From, St);
1376skip_elif(_Toks, _Elif, From, St, Sis) ->
1377    skip_toks(From, St, Sis).
1378
1379%% macro_pars(Tokens, ArgStack, Token)
1380%% macro_expansion(Tokens, Token)
1381%%  Extract the macro parameters and the expansion from a macro definition.
1382
1383macro_pars([{')',_Ap}=Par|Ex], Args, _T0) ->
1384    {ok, {lists:reverse(Args), macro_pars_end(Ex, Par)}};
1385macro_pars([{var,_,Name}=T|Ex], Args, _T0) ->
1386    check_macro_arg(Name, Args, T),
1387    macro_pars_cont(Ex, [Name|Args], T);
1388macro_pars(Toks, _Args, T0) ->
1389    T = no_match(Toks, T0),
1390    throw({error,loc(T),{bad,define}}).
1391
1392macro_pars_cont([{')',_Ap}=Par|Ex], Args, _T0) ->
1393    {ok, {lists:reverse(Args), macro_pars_end(Ex, Par)}};
1394macro_pars_cont([{',',_Ad},{var,_,Name}=T|Ex], Args, _T0) ->
1395    check_macro_arg(Name, Args, T),
1396    macro_pars_cont(Ex, [Name|Args], T);
1397macro_pars_cont(Toks, _Args, T0) ->
1398    T = no_match(Toks, T0),
1399    throw({error,loc(T),{bad,define}}).
1400
1401macro_pars_end([{',',_Ad}=Comma|Ex], _T0) ->
1402    macro_expansion(Ex, Comma);
1403macro_pars_end(Toks, T0) ->
1404    T = no_match(Toks, T0),
1405    throw({error,loc(T),missing_comma}).
1406
1407macro_expansion([{')',_Ap},{dot,_Ad}], _T0) -> [];
1408macro_expansion([{dot,_}=Dot], _T0) ->
1409    throw({error,loc(Dot),missing_parenthesis});
1410macro_expansion([T|Ts], _T0) ->
1411    [T|macro_expansion(Ts, T)];
1412macro_expansion([], T0) -> throw({error,loc(T0),premature_end}).
1413
1414check_macro_arg(Name, Args, T) ->
1415    case lists:member(Name, Args) of
1416        true ->
1417            throw({error,loc(T),{duplicated_argument,Name}});
1418        false ->
1419            ok
1420    end.
1421
1422%% expand_macros(Tokens, St)
1423%%  Expand the macros in a list of tokens, making sure that an expansion
1424%%  gets the same location as the macro call.
1425
1426expand_macros(MacT, M, Toks, St) ->
1427    #epp{macs=Ms,uses=U} = St,
1428    Lm = loc(MacT),
1429    Anno = element(2, MacT),
1430    case expand_macro1(Lm, M, Toks, Ms) of
1431	{ok,{none,Exp}} ->
1432	    check_uses([{M,none}], [], U, Lm),
1433	    Toks1 = expand_macros(expand_macro(Exp, Anno, [], #{}), St),
1434	    expand_macros(Toks1++Toks, St);
1435	{ok,{As,Exp}} ->
1436	    check_uses([{M,length(As)}], [], U, Lm),
1437	    {Bs,Toks1} = bind_args(Toks, Lm, M, As, #{}),
1438	    expand_macros(expand_macro(Exp, Anno, Toks1, Bs), St)
1439    end.
1440
1441expand_macro1(Lm, M, Toks, Ms) ->
1442    Arity = count_args(Toks, Lm, M),
1443    case Ms of
1444	#{M:=undefined} ->
1445	    %% Predefined macro without definition.
1446            throw({error,Lm,{undefined,M,Arity}});
1447	#{M:=[{none,Def}]} ->
1448            {ok,Def};
1449	#{M:=Defs} when is_list(Defs) ->
1450	    case proplists:get_value(Arity, Defs) of
1451                undefined ->
1452                    throw({error,Lm,{mismatch,M}});
1453                Def ->
1454                    {ok,Def}
1455            end;
1456        #{M:=PreDef} ->
1457	    %% Predefined macro.
1458            {ok,PreDef};
1459        _ ->
1460	    %% Macro not found.
1461            throw({error,Lm,{undefined,M,Arity}})
1462    end.
1463
1464check_uses([], _Anc, _U, _Lm) ->
1465    ok;
1466check_uses([M|Rest], Anc, U, Lm) ->
1467    case lists:member(M, Anc) of
1468	true ->
1469	    {Name,Arity} = M,
1470	    throw({error,Lm,{circular,Name,Arity}});
1471	false ->
1472	    L = get_macro_uses(M, U),
1473	    check_uses(L, [M|Anc], U, Lm),
1474	    check_uses(Rest, Anc, U, Lm)
1475    end.
1476
1477get_macro_uses({M,Arity}, U) ->
1478    case U of
1479	#{M:=L} ->
1480	    proplists:get_value(Arity, L, proplists:get_value(none, L, []));
1481	_ ->
1482	    []
1483    end.
1484
1485%% Macro expansion
1486%% Note: io:scan_erl_form() does not return comments or white spaces.
1487expand_macros([{'?',_Aq},{atom,_Am,M}=MacT|Toks], St) ->
1488    expand_macros(MacT, M, Toks, St);
1489%% Special macros
1490expand_macros([{'?',_Aq},{var,Lm,'FUNCTION_NAME'}=Token|Toks], St0) ->
1491    St = update_fun_name(Token, St0),
1492    case St#epp.fname of
1493	undefined ->
1494	    [{'?',_Aq},Token];
1495	{Name,_} ->
1496	    [{atom,Lm,Name}]
1497    end ++ expand_macros(Toks, St);
1498expand_macros([{'?',_Aq},{var,Lm,'FUNCTION_ARITY'}=Token|Toks], St0) ->
1499    St = update_fun_name(Token, St0),
1500    case St#epp.fname of
1501	undefined ->
1502	    [{'?',_Aq},Token];
1503	{_,Arity} ->
1504	    [{integer,Lm,Arity}]
1505    end ++ expand_macros(Toks, St);
1506expand_macros([{'?',_Aq},{var,Lm,'LINE'}=Tok|Toks], St) ->
1507    Line = erl_scan:line(Tok),
1508    [{integer,Lm,Line}|expand_macros(Toks, St)];
1509expand_macros([{'?',_Aq},{var,_Am,M}=MacT|Toks], St) ->
1510    expand_macros(MacT, M, Toks, St);
1511%% Illegal macros
1512expand_macros([{'?',_Aq},Token|_Toks], _St) ->
1513    T = case erl_scan:text(Token) of
1514            Text when is_list(Text) ->
1515                Text;
1516            undefined ->
1517                Symbol = erl_scan:symbol(Token),
1518                io_lib:fwrite(<<"~tp">>, [Symbol])
1519        end,
1520    throw({error,loc(Token),{call,[$?|T]}});
1521expand_macros([T|Ts], St) ->
1522    [T|expand_macros(Ts, St)];
1523expand_macros([], _St) -> [].
1524
1525%% bind_args(Tokens, MacroLocation, MacroName, ArgumentVars, Bindings)
1526%%  Collect the arguments to a macro call.
1527
1528bind_args([{'(',_Alp},{')',_Arp}|Toks], _Lm, _M, [], Bs) ->
1529    {Bs,Toks};
1530bind_args([{'(',_Alp}|Toks0], Lm, M, [A|As], Bs) ->
1531    {Arg,Toks1} = macro_arg(Toks0, [], []),
1532    macro_args(Toks1, Lm, M, As, store_arg(Lm, M, A, Arg, Bs));
1533bind_args(_Toks, Lm, M, _As, _Bs) ->
1534    throw({error,Lm,{mismatch,M}}). % Cannot happen.
1535
1536macro_args([{')',_Arp}|Toks], _Lm, _M, [], Bs) ->
1537    {Bs,Toks};
1538macro_args([{',',_Ac}|Toks0], Lm, M, [A|As], Bs) ->
1539    {Arg,Toks1} = macro_arg(Toks0, [], []),
1540    macro_args(Toks1, Lm, M, As, store_arg(Lm, M, A, Arg, Bs));
1541macro_args([], Lm, M, _As, _Bs) ->
1542    throw({error,Lm,{arg_error,M}}); % Cannot happen.
1543macro_args(_Toks, Lm, M, _As, _Bs) ->
1544    throw({error,Lm,{mismatch,M}}). % Cannot happen.
1545
1546store_arg(L, M, _A, [], _Bs) ->
1547    throw({error,L,{mismatch,M}});
1548store_arg(_L, _M, A, Arg, Bs) ->
1549    Bs#{A=>Arg}.
1550
1551%% count_args(Tokens, MacroLine, MacroName)
1552%%  Count the number of arguments in a macro call.
1553count_args([{'(', _Alp},{')',_Arp}|_Toks], _Lm, _M) ->
1554    0;
1555count_args([{'(', _Alp},{',',_Ac}|_Toks], Lm, M) ->
1556    throw({error,Lm,{arg_error,M}});
1557count_args([{'(',_Alp}|Toks0], Lm, M) ->
1558    {_Arg,Toks1} = macro_arg(Toks0, [], []),
1559    count_args(Toks1, Lm, M, 1);
1560count_args(_Toks, _Lm, _M) ->
1561    none.
1562
1563count_args([{')',_Arp}|_Toks], _Lm, _M, NbArgs) ->
1564    NbArgs;
1565count_args([{',',_Ac},{')',_Arp}|_Toks], Lm, M, _NbArgs) ->
1566    throw({error,Lm,{arg_error,M}});
1567count_args([{',',_Ac}|Toks0], Lm, M, NbArgs) ->
1568    {_Arg,Toks1} = macro_arg(Toks0, [], []),
1569    count_args(Toks1, Lm, M, NbArgs+1);
1570count_args([], Lm, M, _NbArgs) ->
1571    throw({error,Lm,{arg_error,M}});
1572count_args(_Toks, Lm, M, _NbArgs) ->
1573    throw({error,Lm,{mismatch,M}}). % Cannot happen.
1574
1575%% macro_arg([Tok], [ClosePar], [ArgTok]) -> {[ArgTok],[RestTok]}.
1576%%  Collect argument tokens until we hit a ',' or a ')'. We know a
1577%%  enough about syntax to recognise "open parentheses" and keep
1578%%  scanning until matching "close parenthesis".
1579
1580macro_arg([{',',Lc}|Toks], [], Arg) ->
1581    {lists:reverse(Arg),[{',',Lc}|Toks]};
1582macro_arg([{')',Lrp}|Toks], [], Arg) ->
1583    {lists:reverse(Arg),[{')',Lrp}|Toks]};
1584macro_arg([{'(',Llp}|Toks], E, Arg) ->
1585    macro_arg(Toks, [')'|E], [{'(',Llp}|Arg]);
1586macro_arg([{'<<',Lls}|Toks], E, Arg) ->
1587    macro_arg(Toks, ['>>'|E], [{'<<',Lls}|Arg]);
1588macro_arg([{'[',Lls}|Toks], E, Arg) ->
1589    macro_arg(Toks, [']'|E], [{'[',Lls}|Arg]);
1590macro_arg([{'{',Llc}|Toks], E, Arg) ->
1591    macro_arg(Toks, ['}'|E], [{'{',Llc}|Arg]);
1592macro_arg([{'begin',Lb}|Toks], E, Arg) ->
1593    macro_arg(Toks, ['end'|E], [{'begin',Lb}|Arg]);
1594macro_arg([{'if',Li}|Toks], E, Arg) ->
1595    macro_arg(Toks, ['end'|E], [{'if',Li}|Arg]);
1596macro_arg([{'case',Lc}|Toks], E, Arg) ->
1597    macro_arg(Toks, ['end'|E], [{'case',Lc}|Arg]);
1598macro_arg([{'fun',Lc}|[{'(',_}|_]=Toks], E, Arg) ->
1599    macro_arg(Toks, ['end'|E], [{'fun',Lc}|Arg]);
1600macro_arg([{'fun',_}=Fun,{var,_,_}=Name|[{'(',_}|_]=Toks], E, Arg) ->
1601    macro_arg(Toks, ['end'|E], [Name,Fun|Arg]);
1602macro_arg([{'receive',Lr}|Toks], E, Arg) ->
1603    macro_arg(Toks, ['end'|E], [{'receive',Lr}|Arg]);
1604macro_arg([{'try',Lr}|Toks], E, Arg) ->
1605    macro_arg(Toks, ['end'|E], [{'try',Lr}|Arg]);
1606macro_arg([{'cond',Lr}|Toks], E, Arg) ->
1607    macro_arg(Toks, ['end'|E], [{'cond',Lr}|Arg]);
1608macro_arg([{Rb,Lrb}|Toks], [Rb|E], Arg) ->	%Found matching close
1609    macro_arg(Toks, E, [{Rb,Lrb}|Arg]);
1610macro_arg([T|Toks], E, Arg) ->
1611    macro_arg(Toks, E, [T|Arg]);
1612macro_arg([], _E, Arg) ->
1613    {lists:reverse(Arg),[]}.
1614
1615%% expand_macro(MacroDef, MacroTokenAnno, RestTokens, Bindings)
1616%% expand_arg(Argtokens, MacroTokens, TokenAnno, RestTokens, Bindings)
1617%%  Insert the macro expansion replacing macro parameters with their
1618%%  argument values, inserting the location of first the macro call
1619%%  and then the macro arguments, i.e. simulate textual expansion.
1620
1621expand_macro([{var,_Av,V}|Ts], Anno, Rest, Bs) ->
1622    case Bs of
1623	#{V:=Val} ->
1624	    expand_arg(Val, Ts, Anno, Rest, Bs);
1625	_ ->
1626	    [{var,Anno,V}|expand_macro(Ts, Anno, Rest, Bs)]
1627    end;
1628expand_macro([{'?', _}, {'?', _}, {var,_Av,V}|Ts], Anno, Rest, Bs) ->
1629    case Bs of
1630	#{V:=Val} ->
1631            expand_arg(stringify(Val, Anno), Ts, Anno, Rest, Bs);
1632	_ ->
1633	    [{var,Anno,V}|expand_macro(Ts, Anno, Rest, Bs)]
1634    end;
1635expand_macro([T|Ts], Anno, Rest, Bs) ->
1636    [setelement(2, T, Anno)|expand_macro(Ts, Anno, Rest, Bs)];
1637expand_macro([], _Anno, Rest, _Bs) -> Rest.
1638
1639expand_arg([A|As], Ts, _Anno, Rest, Bs) ->
1640    %% It is not obvious that the annotation of arguments should
1641    %% replace _Anno.
1642    NextAnno = element(2, A),
1643    [A|expand_arg(As, Ts, NextAnno, Rest, Bs)];
1644expand_arg([], Ts, Anno, Rest, Bs) ->
1645    expand_macro(Ts, Anno, Rest, Bs).
1646
1647%%%
1648%%% Here follows support for the ?FUNCTION_NAME and ?FUNCTION_ARITY
1649%%% macros. Since the parser has not been run yet, we don't know the
1650%%% name and arity of the current function. Therefore, we will need to
1651%%% scan the beginning of the current form to extract the name and
1652%%% arity of the function.
1653%%%
1654
1655update_fun_name(Token, #epp{fname=Toks0}=St) when is_list(Toks0) ->
1656    %% ?FUNCTION_NAME or ?FUNCTION_ARITY is used for the first time in
1657    %% a function.  First expand macros (except ?FUNCTION_NAME and
1658    %% ?FUNCTION_ARITY) in the form.
1659
1660    Toks1 = (catch expand_macros(Toks0, St#epp{fname=undefined})),
1661
1662    %% Now extract the name and arity from the stream of tokens, and store
1663    %% the result in the #epp{} record so we don't have to do it
1664    %% again.
1665
1666    case Toks1 of
1667	[{atom,_,Name},{'(',_}|Toks] ->
1668	    %% This is the beginning of a function definition.
1669	    %% Scan the token stream up to the matching right
1670	    %% parenthesis and count the number of arguments.
1671	    FA = update_fun_name_1(Toks, 1, {Name,0}, St),
1672	    St#epp{fname=FA};
1673	[{'?',_}|_] ->
1674	    %% ?FUNCTION_NAME/?FUNCTION_ARITY used at the beginning
1675	    %% of a form. Does not make sense.
1676	    {var,_,Macro} = Token,
1677	    throw({error,loc(Token),{illegal_function_usage,Macro}});
1678	_ when is_list(Toks1) ->
1679	    %% Not the beginning of a function (an attribute or a
1680	    %% syntax error).
1681	    {var,_,Macro} = Token,
1682	    throw({error,loc(Token),{illegal_function,Macro}});
1683	_ ->
1684	    %% A macro expansion error. Return a dummy value and
1685	    %% let the caller notice and handle the error.
1686	    St#epp{fname={'_',0}}
1687    end;
1688update_fun_name(_Token, St) ->
1689    St.
1690
1691update_fun_name_1([Tok|Toks], L, FA, St) ->
1692    case classify_token(Tok) of
1693	comma ->
1694	    if
1695		L =:= 1 ->
1696		    {Name,Arity} = FA,
1697		    update_fun_name_1(Toks, L, {Name,Arity+1}, St);
1698		true ->
1699		    update_fun_name_1(Toks, L, FA, St)
1700	    end;
1701	left ->
1702	    update_fun_name_1(Toks, L+1, FA, St);
1703	right when L =:= 1 ->
1704	    FA;
1705	right ->
1706	    update_fun_name_1(Toks, L-1, FA, St);
1707	other ->
1708	    case FA of
1709		{Name,0} ->
1710		    update_fun_name_1(Toks, L, {Name,1}, St);
1711		{_,_} ->
1712		    update_fun_name_1(Toks, L, FA, St)
1713	    end
1714    end;
1715update_fun_name_1([], _, FA, _) ->
1716    %% Syntax error, but never mind.
1717    FA.
1718
1719classify_token({C,_}) -> classify_token_1(C);
1720classify_token(_) -> other.
1721
1722classify_token_1(',') -> comma;
1723classify_token_1('(') -> left;
1724classify_token_1('{') -> left;
1725classify_token_1('[') -> left;
1726classify_token_1('<<') -> left;
1727classify_token_1(')') -> right;
1728classify_token_1('}') -> right;
1729classify_token_1(']') -> right;
1730classify_token_1('>>') -> right;
1731classify_token_1(_) -> other.
1732
1733
1734%%% stringify(Ts, Anno) returns a list of one token: a string which when
1735%%% tokenized would yield the token list Ts.
1736
1737%% erl_scan:text(T) is not backward compatible with this.
1738%% Note that escaped characters will be replaced by themselves.
1739token_src({dot, _}) ->
1740    ".";
1741token_src({X, _}) when is_atom(X) ->
1742    atom_to_list(X);
1743token_src({var, _, X}) ->
1744    atom_to_list(X);
1745token_src({char,_,C}) ->
1746    io_lib:write_char(C);
1747token_src({string, _, X}) ->
1748    io_lib:write_string(X);
1749token_src({_, _, X}) ->
1750    io_lib:format("~w", [X]).
1751
1752stringify1([]) ->
1753    [];
1754stringify1([T | Tokens]) ->
1755    [io_lib:format(" ~ts", [token_src(T)]) | stringify1(Tokens)].
1756
1757stringify(Ts, Anno) ->
1758    [$\s | S] = lists:flatten(stringify1(Ts)),
1759    [{string, Anno, S}].
1760
1761coalesce_strings([{string,A,S} | Tokens]) ->
1762    coalesce_strings(Tokens, A, [S]);
1763coalesce_strings([T | Tokens]) ->
1764    [T | coalesce_strings(Tokens)];
1765coalesce_strings([]) ->
1766    [].
1767
1768coalesce_strings([{string,_,S}|Tokens], A, S0) ->
1769    coalesce_strings(Tokens, A, [S | S0]);
1770coalesce_strings(Tokens, A, S) ->
1771    [{string,A,lists:append(lists:reverse(S))} | coalesce_strings(Tokens)].
1772
1773find_mismatch([Tag|Tags], [{Tag,_A}=T|Ts], _T0) ->
1774    find_mismatch(Tags, Ts, T);
1775find_mismatch([Tag|Tags], [{Tag,_A,_V}=T|Ts], _T0) ->
1776    find_mismatch(Tags, Ts, T);
1777find_mismatch([var_or_atom|Tags], [{var,_A,_V}=T|Ts], _T0) ->
1778    find_mismatch(Tags, Ts, T);
1779find_mismatch([var_or_atom|Tags], [{atom,_A,_N}=T|Ts], _T0) ->
1780    find_mismatch(Tags, Ts, T);
1781find_mismatch(_, Ts, T0) ->
1782    no_match(Ts, T0).
1783
1784no_match([T|_], _T0) ->
1785    T;
1786no_match(_, T0) ->
1787    T0.
1788
1789%% epp_request(Epp)
1790%% epp_request(Epp, Request)
1791%% epp_reply(From, Reply)
1792%%  Handle communication with the epp.
1793
1794epp_request(Epp) ->
1795    wait_epp_reply(Epp, erlang:monitor(process, Epp)).
1796
1797epp_request(Epp, Req) ->
1798    Epp ! {epp_request,self(),Req},
1799    wait_epp_reply(Epp, erlang:monitor(process, Epp)).
1800
1801epp_reply(From, Rep) ->
1802    From ! {epp_reply,self(),Rep},
1803    ok.
1804
1805wait_epp_reply(Epp, Mref) ->
1806    receive
1807	{epp_reply,Epp,Rep} ->
1808	    erlang:demonitor(Mref, [flush]),
1809	    Rep;
1810	{'DOWN',Mref,_,_,E} ->
1811	    receive {epp_reply,Epp,Rep} -> Rep
1812	    after 0 -> exit(E)
1813	    end
1814    end.
1815
1816expand_var([$$ | _] = NewName) ->
1817    case catch expand_var1(NewName) of
1818	{ok, ExpName} ->
1819	    ExpName;
1820	_ ->
1821	    NewName
1822    end;
1823expand_var(NewName) ->
1824    NewName.
1825
1826expand_var1(NewName) ->
1827    [[$$ | Var] | Rest] = filename:split(NewName),
1828    Value = os:getenv(Var),
1829    true = Value =/= false,
1830    {ok, fname_join([Value | Rest])}.
1831
1832fname_join(["." | [_|_]=Rest]) ->
1833    fname_join(Rest);
1834fname_join(Components) ->
1835    filename:join(Components).
1836
1837loc(Token) ->
1838    erl_scan:location(Token).
1839
1840add_line(Line, Offset) when is_integer(Line) ->
1841    Line+Offset;
1842add_line({Line, Column}, Offset) ->
1843    {Line+Offset, Column}.
1844
1845start_loc(Line) when is_integer(Line) ->
1846    1;
1847start_loc({_Line, _Column}) ->
1848    {1, 1}.
1849
1850line1() ->
1851    erl_anno:new(1).
1852
1853get_line(Anno) ->
1854    erl_anno:line(Anno).
1855
1856%% epp has always output -file attributes when entering and leaving
1857%% included files (-include, -include_lib). Starting with R11B the
1858%% -file attribute is also recognized in the input file. This is
1859%% mainly aimed at yecc, the parser generator, which uses the -file
1860%% attribute to get correct lines in messages referring to code
1861%% supplied by the user (actions etc in .yrl files).
1862%%
1863%% In a perfect world (read: perfectly implemented applications such
1864%% as Xref, Cover, Debugger, etc.) it would not be necessary to
1865%% distinguish -file attributes from epp and the input file. The
1866%% Debugger for example could have one window for each referred file,
1867%% each window with its own set of breakpoints etc. The line numbers
1868%% of the abstract code would then point into different windows
1869%% depending on the -file attribute. [Note that if, as is the case for
1870%% yecc, code has been copied into the file, then it is possible that
1871%% the copied code differs from the one referred to by the -file
1872%% attribute, which means that line numbers can mismatch.] In practice
1873%% however it is very rare with Erlang functions in included files, so
1874%% only one window is used per module. This means that the line
1875%% numbers of the abstract code have to be adjusted to refer to the
1876%% top-most source file. The function interpret_file_attributes/1
1877%% below interprets the -file attribute and returns forms where line
1878%% numbers refer to the top-most file. The -file attribute forms that
1879%% have been output by epp (corresponding to -include and
1880%% -include_lib) are kept, but the user's -file attributes are
1881%% removed. This seems sufficient for now.
1882%%
1883%% It turns out to be difficult to distinguish -file attributes in the
1884%% input file from the ones added by epp unless some action is taken.
1885%% The solution employed is to let epp label the annotation of user
1886%% supplied -file attributes as 'generated'.
1887
1888interpret_file_attribute(Forms) ->
1889    interpret_file_attr(Forms, 0, []).
1890
1891interpret_file_attr([{attribute,Anno,file,{File,Line}}=Form | Forms],
1892                    Delta, Fs) ->
1893    L = get_line(Anno),
1894    Generated = erl_anno:generated(Anno),
1895    if
1896        Generated ->
1897            %% -file attribute
1898            interpret_file_attr(Forms, (L + Delta) - Line, Fs);
1899        not Generated ->
1900            %% -include or -include_lib
1901            % true = L =:= Line,
1902            case Fs of
1903                [_, File | Fs1] -> % end of included file
1904                    [Form | interpret_file_attr(Forms, 0, [File | Fs1])];
1905                _ -> % start of included file
1906                    [Form | interpret_file_attr(Forms, 0, [File | Fs])]
1907            end
1908    end;
1909interpret_file_attr([Form0 | Forms], Delta, Fs) ->
1910    F = fun(Anno) ->
1911                Line = erl_anno:line(Anno),
1912                erl_anno:set_line(Line + Delta, Anno)
1913        end,
1914    Form = erl_parse:map_anno(F, Form0),
1915    [Form | interpret_file_attr(Forms, Delta, Fs)];
1916interpret_file_attr([], _Delta, _Fs) ->
1917    [].
1918