37
116
start(EscriptOptions) ->
39
%% Commands run using -run or -s are run in a process
40
%% trap_exit set to false. Because this behaviour is
41
%% surprising for users of escript, make sure to reset
42
%% trap_exit to false.
43
process_flag(trap_exit, false),
44
case init:get_plain_arguments() of
46
do_run(File, Args, EscriptOptions);
48
io:format("escript: Missing filename\n", []),
53
io:format("escript: ~s\n", [Str]),
56
io:format("escript: Internal error: ~p\n", [Reason]),
57
io:format("~p\n", [erlang:get_stacktrace()]),
62
%%% Internal functions follow.
65
do_run(File, Args, Options) ->
66
{Parse,Mode} = parse_file(File),
67
case lists:member("s", Options) of
68
true when Mode =:= run ->
72
case compile:forms(Parse, [report,strong_validation]) of
76
fatal("There were compilation errors.")
79
eval_module(Mode, Parse, File, Args)
82
eval_module(interpret, Parse, File, Args) ->
83
interpret(File, Parse, Args);
84
eval_module(compile, Parse, _File, Args) ->
86
eval_module(run, Module, _File, Args) ->
87
run_code(Module, Args).
89
interpret(File, Parse0, Args) ->
90
case erl_lint:module(Parse0) of
96
fatal("There were compilation errors.")
98
Parse = maybe_expand_records(Parse0),
99
Dict = parse_to_dict(Parse),
100
ArgsA = erl_parse:abstract(Args, 0),
101
Call = {call,0,{atom,0,main},[ArgsA]},
104
erl_eval:new_bindings(),
106
code_handler(I, J, Dict, File)
111
fatal(format_exception(Class, Reason))
114
compile(Parse, Args) ->
115
case compile:forms(Parse, [report]) of
116
{ok,Module,BeamCode} ->
117
{module, Module} = erlang:load_module(Module, BeamCode),
118
run_code(Module, Args);
120
fatal("There were compilation errors.")
123
run_code(Module, Args) ->
129
fatal(format_exception(Class, Reason))
132
format_exception(Class, Reason) ->
134
io_lib:format("~." ++ integer_to_list(I) ++ "P", [Term, 50])
136
StackTrace = erlang:get_stacktrace(),
137
StackFun = fun(M, _F, _A) -> (M =:= erl_eval) or (M =:= ?MODULE) end,
138
lib:format_exception(1, Class, Reason, StackTrace, StackFun, PF).
140
parse_to_dict(L) -> parse_to_dict(L, dict:new()).
142
parse_to_dict([{function,_,Name,Arity,Clauses}|T], Dict0) ->
143
Dict = dict:store({local, Name,Arity}, Clauses, Dict0),
144
parse_to_dict(T, Dict);
145
parse_to_dict([{attribute,_,import,{Mod,Funcs}}|T], Dict0) ->
146
Dict = lists:foldl(fun(I, D) ->
147
dict:store({remote,I}, Mod, D)
149
parse_to_dict(T, Dict);
150
parse_to_dict([_|T], Dict) ->
151
parse_to_dict(T, Dict);
152
parse_to_dict([], Dict) ->
155
%% make a temporary module name
158
{I,J,K} = erlang:now(),
159
Mod = list_to_atom("escript__" ++ integer_to_list(I) ++ integer_to_list(J) ++
161
{attribute,0,module, Mod}.
163
-define(PRETTY_APPLY(M, F, A), pretty_apply(?MODULE, ?LINE, M, F, A)).
166
parse_check_error(File, parse_file(File, 0, [], interpret)).
168
parse_file(File, Nerrs, L, Mode) ->
170
case file:open(File, [read]) of
174
fatal(lists:concat([file:format_error(R), ": '", File, "'"]))
176
{HeaderSz, BodyLineNo, FirstBodyLine} = skip_header(P),
177
case FirstBodyLine of
180
ok = ?PRETTY_APPLY(file, close, [P]),
181
{ok, <<_FirstLine:HeaderSz/binary, Bin/binary>>} =
182
?PRETTY_APPLY(file, read_file, [File]),
183
case code:set_primary_archive(File, Bin) of
186
case init:get_argument(escript) of
187
{ok, [["main", M]]} ->
190
Ext = init:archive_extension(),
191
list_to_atom(filename:basename(File, Ext))
195
fatal("Not an archive file");
199
[$F, $O, $R, $1 | _] ->
201
ok = ?PRETTY_APPLY(file, close, [P]),
202
{ok, <<_FirstLine:HeaderSz/binary, Bin/binary>>} =
203
?PRETTY_APPLY(file, read_file, [File]),
204
case beam_lib:version(Bin) of
205
{ok, {Mod, _Version}} ->
206
{module, Mod} = erlang:load_module(Mod, Bin),
208
{error, beam_lib, Reason} when is_tuple(Reason) ->
209
fatal(element(1, Reason));
210
{error, beam_lib, Reason} ->
215
{ok, _} = ?PRETTY_APPLY(file, position, [P, {bof, HeaderSz}]), % Goto prev pos
216
Ret = parse_loop(P, File, io:parse_erl_form(P, '', BodyLineNo), Nerrs, L, Mode),
217
ok = ?PRETTY_APPLY(file, close, [P]),
221
pretty_apply(Module, Line, M, F, A) ->
222
case apply(M, F, A) of
228
fatal({Module, Line, M, F, A, Reason})
118
%% Commands run using -run or -s are run in a process
119
%% trap_exit set to false. Because this behaviour is
120
%% surprising for users of escript, make sure to reset
121
%% trap_exit to false.
122
process_flag(trap_exit, false),
123
case init:get_plain_arguments() of
125
parse_and_run(File, Args, EscriptOptions);
127
io:format("escript: Missing filename\n", []),
132
io:format("escript: ~s\n", [Str]),
135
io:format("escript: Internal error: ~p\n", [Reason]),
136
io:format("~p\n", [erlang:get_stacktrace()]),
140
parse_and_run(File, Args, Options) ->
141
CheckOnly = lists:member("s", Options),
142
{Source, Module, FormsOrBin, Mode} = parse_file(File, CheckOnly),
144
case lists:member("d", Options) of
148
case lists:member("c", Options) of
152
case lists:member("i", Options) of
159
is_list(FormsOrBin) ->
162
interpret(FormsOrBin, File, Args);
164
case compile:forms(FormsOrBin, [report]) of
165
{ok, Module, BeamBin} ->
166
{module, Module} = code:load_binary(Module, File, BeamBin),
169
fatal("There were compilation errors.")
172
case compile:forms(FormsOrBin, [report, debug_info]) of
173
{ok,Module,BeamBin} ->
174
{module, Module} = code:load_binary(Module, File, BeamBin),
175
debug(Module, {Module, File, File, BeamBin}, Args);
177
fatal("There were compilation errors.")
180
is_binary(FormsOrBin) ->
183
case code:set_primary_archive(File, FormsOrBin) of
185
case code:load_file(Module) of
187
case erlang:function_exported(Module, main, 1) of
191
Text = lists:concat(["Function ", Module, ":main/1 is not exported"]),
195
Text = lists:concat(["Cannot load module ", Module, " from archive"]),
200
run -> run(Module, Args);
201
debug -> debug(Module, Module, Args)
204
fatal("Not an archive file");
211
{module, Module} = code:load_binary(Module, File, FormsOrBin),
214
[Base | Rest] = lists:reverse(filename:split(File)),
215
Base2 = filename:basename(Base, code:objfile_extension()),
218
["ebin" | Top] -> ["src" | Top];
221
SrcFile = filename:join(lists:reverse([Base2 ++ ".erl" | Rest2])),
222
debug(Module, {Module, SrcFile, File, FormsOrBin}, Args)
227
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
229
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
231
parse_file(File, CheckOnly) ->
232
S = #state{file = File,
235
exports_main = false,
236
has_records = false},
238
case file:open(File, [read]) of
242
fatal(lists:concat([file:format_error(R), ": '", File, "'"]))
244
{HeaderSz, StartLine, FirstBodyLine} = skip_header(Fd, 1),
248
forms_or_bin = FormsOrBin} =
249
case FirstBodyLine of
253
parse_archive(S, File, HeaderSz);
254
[$F, $O, $R, $1 | _] ->
257
parse_beam(S, File, HeaderSz, CheckOnly);
260
parse_source(S, File, Fd, StartLine, HeaderSz, CheckOnly)
262
{Source, Module, FormsOrBin, Mode}.
231
264
%% Skip header and return first body line
265
skip_header(P, LineNo) ->
233
266
%% Skip shebang on first line
235
{ok, HeaderSz1} = file:position(P, cur),
237
%% Look for special comment on second line
239
{ok, HeaderSz2} = file:position(P, cur),
241
[$\%, $\%, $\! | _] ->
242
%% Skip special comment on second line
244
{HeaderSz2, 3, Line3};
246
%% Look for special comment on third line
248
{ok, HeaderSz3} = file:position(P, cur),
250
[$\%, $\%, $\! | _] ->
251
%% Skip special comment on third line
253
{HeaderSz3, 4, Line4};
255
%% Just skip shebang on first line
256
{HeaderSz1, 2, Line2}
267
{ok, HeaderSz0} = file:position(P, cur),
272
{ok, HeaderSz1} = file:position(P, cur),
274
%% Look for special comment on second line
276
{ok, HeaderSz2} = file:position(P, cur),
278
[$\%, $\%, $\! | _] ->
279
%% Skip special comment on second line
281
{HeaderSz2, LineNo + 2, Line3};
283
%% Look for special comment on third line
285
{ok, HeaderSz3} = file:position(P, cur),
287
[$\%, $\%, $\! | _] ->
288
%% Skip special comment on third line
290
{HeaderSz3, LineNo + 3, Line4};
292
%% Just skip shebang on first line
293
{HeaderSz1, LineNo + 1, Line2}
297
%% No shebang. Assume that there is no header.
298
{HeaderSz0, LineNo, Line1}
261
302
case io:get_line(P, '') of
263
fatal("Premature end of file reached");
268
parse_include_lib(File, Nerrs, L0, Mode) ->
269
case open_lib_dir(File) of
271
L = [{attribute,1,file,{File,1}}|L0],
272
Ret = parse_loop(P, File, io:parse_erl_form(P, '', 1), Nerrs, L, Mode),
275
{error,bad_libdir} ->
276
io:format("Misformed -include_lib");
278
io:format("Failed to open ~s: ~s\n", [File,file:format_error(Reason)]),
282
open_lib_dir(File0) ->
284
[LibName|Rest] = filename:split(File0),
285
File = filename:join([code:lib_dir(list_to_atom(LibName))|Rest]),
286
file:open(File, [read])
292
parse_check_error(_File, {0,Module,Mode = run}) when is_atom(Module) ->
294
parse_check_error(File, {0,L0,Mode}) ->
295
L = lists:reverse(L0),
296
Code = [{attribute,0,file,{File,1}},
297
mk_mod()|case is_main_exported(L) of
299
[{attribute,0,export,[{main,1}]}|L];
304
parse_check_error(_, _) ->
305
fatal("There were compilation errors.").
307
maybe_expand_records(Code) ->
308
case erase(there_are_records) of
309
true -> erl_expand_records:module(Code, []);
313
parse_loop(_, _File, {eof,_}, Nerrs, L, Mode) ->
315
parse_loop(P, File, {ok, Form, Ln}, Nerrs0, L0, Mode0) ->
317
{attribute,_,mode,compile} ->
318
parse_loop(P, File, io:parse_erl_form(P,'',Ln), Nerrs0, L0, compile);
319
{attribute,_,include_lib,Include} ->
320
{Nerrs,L1,Mode} = parse_include_lib(Include, Nerrs0, L0, Mode0),
321
L2 = [{attribute,Ln+1,file,{File,Ln+1}}|L1],
322
parse_loop(P, File, io:parse_erl_form(P,'',Ln), Nerrs, L2, Mode);
323
{attribute,_,record,_} ->
324
put(there_are_records, true),
325
parse_loop(P, File, io:parse_erl_form(P,'',Ln), Nerrs0, [Form|L0], Mode0);
327
parse_loop(P, File, io:parse_erl_form(P,'',Ln), Nerrs0, [Form|L0], Mode0)
329
parse_loop(P, File, {error,{Ln,Mod,Args}, Ln1}, Nerrs, L, Mode) ->
330
io:format("~s:~w: ~s\n",
331
[File,Ln,Mod:format_error(Args)]),
332
parse_loop(P, File, io:parse_erl_form(P, '', Ln1), Nerrs+1, L, Mode).
334
code_handler(local, [file], _, File) ->
336
code_handler(Name, Args, Dict, File) ->
337
%%io:format("code handler=~p~n",[{Name, Args}]),
338
Arity = length(Args),
339
case dict:find({local,Name,Arity}, Dict) of
341
LF = {value,fun(I, J) ->
342
code_handler(I, J, Dict, File)
344
case erl_eval:match_clause(Cs, Args,erl_eval:new_bindings(),LF) of
346
{value, Val, _Bs1} = erl_eval:exprs(Body, Bs, LF),
349
erlang:error({function_clause,[{local,Name,Args}]})
304
fatal("Premature end of file reached");
309
parse_archive(S, File, HeaderSz) ->
310
case file:read_file(File) of
311
{ok, <<_FirstLine:HeaderSz/binary, Bin/binary>>} ->
313
case init:get_argument(escript) of
314
{ok, [["main", M]]} ->
315
%% Use explicit module name
318
%% Use escript name without extension as module name
319
RevBase = lists:reverse(filename:basename(File)),
321
case lists:dropwhile(fun(X) -> X =/= $. end, RevBase) of
325
list_to_atom(lists:reverse(RevBase2))
328
S#state{source = archive,
333
fatal("Illegal archive format");
335
fatal(file:format_error(Reason))
339
parse_beam(S, File, HeaderSz, CheckOnly) ->
340
{ok, <<_FirstLine:HeaderSz/binary, Bin/binary>>} =
341
file:read_file(File),
342
case beam_lib:chunks(Bin, [exports]) of
343
{ok, {Module, [{exports, Exports}]}} ->
346
case lists:member({main, 1}, Exports) of
350
Text = lists:concat(["Function ", Module, ":main/1 is not exported"]),
354
S#state{source = beam,
352
case dict:find({remote,{Name,Arity}}, Dict) of
354
%% io:format("Calling:~p~n",[{Mod,Name,Args}]),
355
apply(Mod, Name, Args);
359
{error, beam_lib, Reason} when is_tuple(Reason) ->
360
fatal(element(1, Reason));
361
{error, beam_lib, Reason} ->
365
parse_source(S, File, Fd, StartLine, HeaderSz, CheckOnly) ->
366
{PreDefMacros, Module} = pre_def_macros(File),
368
{ok, _} = file:position(Fd, {bof, HeaderSz}),
369
case epp:open(File, Fd, StartLine, IncludePath, PreDefMacros) of
371
{ok, FileForm} = epp:parse_erl_form(Epp),
372
OptModRes = epp:parse_erl_form(Epp),
373
S2 = S#state{source = text, module = Module},
376
{ok, {attribute,_, module, M} = Form} ->
377
epp_parse_file(Epp, S2#state{module = M}, [Form, FileForm]);
379
ModForm = {attribute,1,module, Module},
380
epp_parse_file2(Epp, S2, [ModForm, FileForm], OptModRes);
382
epp_parse_file2(Epp, S2, [FileForm], OptModRes);
384
S#state{forms_or_bin = [FileForm, {eof,LastLine}]}
388
check_source(S3, CheckOnly);
390
io:format("escript: ~p\n", [Reason]),
391
fatal("Preprocessor error")
394
check_source(S, CheckOnly) ->
396
#state{n_errors = Nerrs} when Nerrs =/= 0 ->
397
fatal("There were compilation errors.");
398
#state{exports_main = ExpMain,
399
has_records = HasRecs,
400
forms_or_bin = [FileForm2, ModForm2 | Forms]} ->
401
%% Optionally add export of main/1
404
false -> [{attribute,0,export, [{main,1}]} | Forms];
407
Forms3 = [FileForm2, ModForm2 | Forms2],
410
%% Optionally expand records
414
true -> erl_expand_records:module(Forms3, [])
416
%% Strong validation and halt
417
case compile:forms(Forms4, [report,strong_validation]) of
421
fatal("There were compilation errors.")
424
%% Basic validation before execution
425
case erl_lint:module(Forms3) of
431
fatal("There were compilation errors.")
433
%% Optionally expand records
437
true -> erl_expand_records:module(Forms3, [])
439
S#state{forms_or_bin = Forms4}
443
pre_def_macros(File) ->
444
{MegaSecs, Secs, MicroSecs} = erlang:now(),
447
filename:basename(File) ++ "__" ++
448
integer_to_list(MegaSecs) ++ "__" ++
449
integer_to_list(Secs) ++ "__" ++
450
integer_to_list(MicroSecs),
451
Module = list_to_atom(ModuleStr),
452
PreDefMacros = [{'MODULE', Module, redefine},
453
{'MODULE_STRING', ModuleStr, redefine}],
454
{PreDefMacros, Module}.
456
epp_parse_file(Epp, S, Forms) ->
457
Parsed = epp:parse_erl_form(Epp),
458
epp_parse_file2(Epp, S, Forms, Parsed).
460
epp_parse_file2(Epp, S, Forms, Parsed) ->
461
%% io:format("~p\n", [Parsed]),
465
{attribute,Ln,record,{Record,Fields}} ->
466
S2 = S#state{has_records = true},
467
case epp:normalize_typed_record_fields(Fields) of
468
{typed, NewFields} ->
469
epp_parse_file(Epp, S2,
470
[{attribute, Ln, record, {Record, NewFields}},
471
{attribute, Ln, type,
472
{{record, Record}, Fields, []}} | Forms]);
474
epp_parse_file(Epp, S2, [Form | Forms])
476
{attribute,Ln,mode,NewMode} ->
477
S2 = S#state{mode = NewMode},
479
NewMode =:= compile; NewMode =:= interpret; NewMode =:= debug ->
480
epp_parse_file(Epp, S2, [Form | Forms]);
482
Args = lists:flatten(io_lib:format("illegal mode attribute: ~p", [NewMode])),
483
io:format("~s:~w ~s\n", [S#state.file,Ln,Args]),
484
Error = {error,{Ln,erl_parse,Args}},
485
Nerrs= S#state.n_errors + 1,
486
epp_parse_file(Epp, S2#state{n_errors = Nerrs}, [Error | Forms])
488
{attribute,_,export,Fs} ->
489
case lists:member({main,1}, Fs) of
491
epp_parse_file(Epp, S, [Form | Forms]);
493
epp_parse_file(Epp, S#state{exports_main = true}, [Form | Forms])
496
epp_parse_file(Epp, S, [Form | Forms])
498
{error,{Ln,Mod,Args}} = Form ->
499
io:format("~s:~w: ~s\n",
500
[S#state.file,Ln,Mod:format_error(Args)]),
501
epp_parse_file(Epp, S#state{n_errors = S#state.n_errors + 1}, [Form | Forms]);
503
S#state{forms_or_bin = lists:reverse([{eof, LastLine} | Forms])}
506
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
508
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
510
debug(Module, AbsMod, Args) ->
511
case hidden_apply(debugger, debugger, start, []) of
513
case hidden_apply(debugger, int, i, [AbsMod]) of
515
hidden_apply(debugger, debugger, auto_attach, [[init]]),
357
io:format("Script does not export ~w/~w\n", [Name,Arity]),
362
is_main_exported([{attribute,_,export,Fs}|T]) ->
363
case lists:member({main,1}, Fs) of
364
false -> is_main_exported(T);
367
is_main_exported([_|T]) -> is_main_exported(T);
368
is_main_exported([]) -> false.
518
Text = lists:concat(["Cannot load the code for ", Module, " into the debugger"]),
522
fatal("Cannot start the debugger")
531
fatal(format_exception(Class, Reason))
534
interpret(Forms, File, Args) ->
535
Dict = parse_to_dict(Forms),
536
ArgsA = erl_parse:abstract(Args, 0),
537
Call = {call,0,{atom,0,main},[ArgsA]},
540
erl_eval:new_bindings(),
541
{value,fun(I, J) -> code_handler(I, J, Dict, File) end}),
545
fatal(format_exception(Class, Reason))
373
548
report_errors(Errors) ->
374
549
lists:foreach(fun ({{F,_L},Eds}) -> list_errors(F, Eds);
375
({F,Eds}) -> list_errors(F, Eds) end,
550
({F,Eds}) -> list_errors(F, Eds) end,
378
553
list_errors(F, [{Line,Mod,E}|Es]) ->
379
554
io:fwrite("~s:~w: ~s\n", [F,Line,Mod:format_error(E)]),