Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 359 lines (296 sloc) 9.808 kb
d69e4d8 @klacke ""
authored
1 %%%----------------------------------------------------------------------
2 %%% File : yaws_compile.erl
3 %%% Author : Claes Wikstrom <klacke@hyber.org>
4 %%% Purpose :
5 %%% Created : 20 Feb 2002 by Claes Wikstrom <klacke@hyber.org>
6 %%%----------------------------------------------------------------------
7
8 -module(yaws_compile).
9 -author('klacke@hyber.org').
10
11 -compile(export_all).
3c06a9e @klacke rearr of includefiles
authored
12
13
14
15 -include_lib("yaws/include/yaws.hrl").
16 -include_lib("yaws/include/yaws_api.hrl").
17 -include("yaws_debug.hrl").
d69e4d8 @klacke ""
authored
18
19
20
21 %% tada !!
22 %% returns a CodeSpec which is:
23 %% a list {data, NumChars} |
24 %% {mod, LineNo, YawsFile, NumSkipChars, Mod, Func} |
25 %% {error, NumSkipChars, E}}
26
27 % each erlang fragment inside <erl> .... </erl> is compiled into
28 % its own module
29
30
31 -record(comp, {
32 gc, %% global conf
33 sc, %% server conf
34 startline = 0,
35 modnum = 1,
36 infile,
37 infd,
38 outfile,
39 outfd}).
40
41
42 comp_opts(GC) ->
6c9c37f @klacke ""
authored
43 ?Debug("I=~p~n", [GC#gconf.include_dir]),
d69e4d8 @klacke ""
authored
44 I = lists:map(fun(Dir) -> {i, Dir} end, GC#gconf.include_dir),
9cd59a3 @klacke ""
authored
45 Opts = [binary, return_errors | I],
d69e4d8 @klacke ""
authored
46 ?Debug("Compile opts = ~p~n", [Opts]),
47 Opts.
48
49
50 compile_file(File, GC, SC) ->
567034e @klacke *** empty log message ***
authored
51 case file_open(File) of
d69e4d8 @klacke ""
authored
52 {ok, Fd} ->
53 Spec = compile_file(#comp{infile = File,
54 infd = Fd, gc = GC, sc = SC},
9cd59a3 @klacke ""
authored
55 1,
7c5307a @klacke don't log a crash when we get methods we don't support and also a fix in...
authored
56 get_line(Fd), init, 0, [], 0),
2129adc @klacke ""
authored
57 Spec;
58 _Err ->
d69e4d8 @klacke ""
authored
59 yaws:elog("can't open ~s~n", [File]),
60 exit(normal)
61 end.
62
9cd59a3 @klacke ""
authored
63 compile_file(C, _LineNo, eof, _Mode, NumChars, Ack, Errors) ->
368cfec @klacke *** empty log message ***
authored
64 file_close(C#comp.infd),
8722844 @klacke a file which has at least one compilation error shouldn't be cached in t...
authored
65 {ok, [{errors, Errors} |lists:reverse([{data, NumChars} |Ack])]};
d69e4d8 @klacke ""
authored
66
67
39c94ab @klacke ""
authored
68 %% skip initial space if first thing is <erl> otherwise not
8722844 @klacke a file which has at least one compilation error shouldn't be cached in t...
authored
69 compile_file(C, LineNo, Chars, init, NumChars, Ack, Errs) ->
d69e4d8 @klacke ""
authored
70 case Chars -- [$\s, $\t, $\n, $\r] of
71 [] ->
961926f @klacke ""
authored
72 ?Debug("SKIP ~p~n", [Chars]),
73 L=length(Chars),
8722844 @klacke a file which has at least one compilation error shouldn't be cached in t...
authored
74 compile_file(C, LineNo+1, line(C), init, NumChars-L, Ack, Errs);
39c94ab @klacke ""
authored
75 "<erl>" ++ _ -> %% first chunk is erl, skip whistespace
8722844 @klacke a file which has at least one compilation error shouldn't be cached in t...
authored
76 compile_file(C, LineNo, Chars, html, NumChars, Ack, Errs);
d69e4d8 @klacke ""
authored
77 _ ->
39c94ab @klacke ""
authored
78 %% first chunk is html, keep whitespace
79 Fd=C#comp.infd,
80 file:position(Fd, bof),
7c5307a @klacke don't log a crash when we get methods we don't support and also a fix in...
authored
81 compile_file(C,1,line(C),html,0,[], Errs)
d69e4d8 @klacke ""
authored
82 end;
83
8722844 @klacke a file which has at least one compilation error shouldn't be cached in t...
authored
84 compile_file(C, LineNo, Chars = "<erl>" ++ _Tail, html, NumChars, Ack,Es) ->
d69e4d8 @klacke ""
authored
85 ?Debug("start erl:~p",[LineNo]),
86 C2 = new_out_file(LineNo, C, C#comp.gc),
87 C3 = C2#comp{startline = LineNo},
88 L = length(Chars),
89 if
90 NumChars > 0 ->
91 compile_file(C3, LineNo+1, line(C) , erl,L,
8722844 @klacke a file which has at least one compilation error shouldn't be cached in t...
authored
92 [{data, NumChars} | Ack], Es);
d69e4d8 @klacke ""
authored
93 true -> %% just ignore zero byte data segments
8722844 @klacke a file which has at least one compilation error shouldn't be cached in t...
authored
94 compile_file(C3, LineNo+1, line(C) , erl, L + (-NumChars),
95 Ack, Es) %hack
d69e4d8 @klacke ""
authored
96 end;
97
8722844 @klacke a file which has at least one compilation error shouldn't be cached in t...
authored
98 compile_file(C, LineNo, Chars = "</erl>" ++ _Tail, erl, NumChars, Ack, Es) ->
d69e4d8 @klacke ""
authored
99 ?Debug("stop erl:~p",[LineNo]),
100 file:close(C#comp.outfd),
101 NumChars2 = NumChars + length(Chars),
102 case proc_compile_file(C#comp.outfile, comp_opts(C#comp.gc)) of
103 {ok, ModuleName, Binary} ->
104 case code:load_binary(ModuleName, C#comp.outfile, Binary) of
105 {module, ModuleName} ->
106 C2 = C#comp{modnum = C#comp.modnum+1},
107 L2 = check_exported(C, LineNo,NumChars2, ModuleName),
8722844 @klacke a file which has at least one compilation error shouldn't be cached in t...
authored
108 compile_file(C2, LineNo+1, line(C),html,0,L2++Ack, Es);
d69e4d8 @klacke ""
authored
109 Err ->
110 A2 = gen_err(C, LineNo, NumChars2,
111 ?F("Cannot load module ~p: ~p",
112 [ModuleName, Err])),
113 compile_file(C, LineNo+1, line(C),
8722844 @klacke a file which has at least one compilation error shouldn't be cached in t...
authored
114 html, 0, [A2|Ack], Es+1)
d69e4d8 @klacke ""
authored
115 end;
2129adc @klacke ""
authored
116 {error, Errors, _Warnings} ->
d69e4d8 @klacke ""
authored
117 %% FIXME remove outfile here ... keep while debuging
118 A2 = comp_err(C, LineNo, NumChars2, Errors),
8722844 @klacke a file which has at least one compilation error shouldn't be cached in t...
authored
119 compile_file(C, LineNo+1, line(C), html, 0, [A2|Ack], Es+1);
d69e4d8 @klacke ""
authored
120 {error, Str} ->
121 %% this is boring but does actually happen
122 %% in order to get proper user errors here we need to catch i/o
123 %% or hack compiler/parser
9cd59a3 @klacke ""
authored
124 yaws:elog("Dynamic compile error in file ~s, line ~w~n~s",
125 [C#comp.infile, LineNo, Str]),
d69e4d8 @klacke ""
authored
126 A2 = {error, NumChars2, ?F("<pre> Dynamic compile error in file "
127 " ~s line ~w~n~s </pre>",
128 [C#comp.infile, LineNo, Str])},
8722844 @klacke a file which has at least one compilation error shouldn't be cached in t...
authored
129 compile_file(C, LineNo+1, line(C), html, 0, [A2|Ack], Es+1)
d69e4d8 @klacke ""
authored
130 end;
131
8722844 @klacke a file which has at least one compilation error shouldn't be cached in t...
authored
132 compile_file(C, LineNo, Chars = "<pre>" ++ _Tail, html, NumChars, Ack, Es) ->
d69e4d8 @klacke ""
authored
133 ?Debug("start pre:~p",[LineNo]),
8722844 @klacke a file which has at least one compilation error shouldn't be cached in t...
authored
134 compile_file(C, LineNo+1, line(C) , pre, NumChars + length(Chars), Ack,Es);
d69e4d8 @klacke ""
authored
135
8722844 @klacke a file which has at least one compilation error shouldn't be cached in t...
authored
136 compile_file(C, LineNo, Chars = "</pre>" ++ _Tail, pre, NumChars, Ack,Es) ->
d69e4d8 @klacke ""
authored
137 ?Debug("stop pre:~p",[LineNo]),
8722844 @klacke a file which has at least one compilation error shouldn't be cached in t...
authored
138 compile_file(C, LineNo+1, line(C) , html, NumChars + length(Chars), Ack,Es);
d69e4d8 @klacke ""
authored
139
8722844 @klacke a file which has at least one compilation error shouldn't be cached in t...
authored
140 compile_file(C, LineNo, Chars, erl, NumChars, Ack,Es) ->
0d623c1 @klacke ""
authored
141 case has_tag(Chars, "</erl>") of
142 {ok, Skipped, Chars2} ->
8722844 @klacke a file which has at least one compilation error shouldn't be cached in t...
authored
143 compile_file(C, LineNo, Chars2, erl, NumChars + Skipped, Ack,Es);
0d623c1 @klacke ""
authored
144 false ->
567034e @klacke *** empty log message ***
authored
145 ?Debug("Gen: ~s", [Chars]),
0d623c1 @klacke ""
authored
146 io:format(C#comp.outfd, "~s", [Chars]),
147 compile_file(C, LineNo+1, line(C), erl, NumChars +
8722844 @klacke a file which has at least one compilation error shouldn't be cached in t...
authored
148 length(Chars), Ack,Es)
0d623c1 @klacke ""
authored
149 end;
150
d69e4d8 @klacke ""
authored
151
8722844 @klacke a file which has at least one compilation error shouldn't be cached in t...
authored
152 compile_file(C, LineNo, Chars, html, NumChars, Ack,Es) ->
0d623c1 @klacke ""
authored
153 case has_tag(Chars, "<erl>") of
154 {ok, Skipped, Chars2} ->
8722844 @klacke a file which has at least one compilation error shouldn't be cached in t...
authored
155 compile_file(C, LineNo, Chars2, html, NumChars+Skipped, Ack,Es);
0d623c1 @klacke ""
authored
156 false ->
157 compile_file(C, LineNo+1, line(C), html, NumChars +
8722844 @klacke a file which has at least one compilation error shouldn't be cached in t...
authored
158 length(Chars), Ack,Es)
0d623c1 @klacke ""
authored
159 end;
d69e4d8 @klacke ""
authored
160
8722844 @klacke a file which has at least one compilation error shouldn't be cached in t...
authored
161 compile_file(C, LineNo, Chars, pre, NumChars, Ack,Es) ->
162 compile_file(C, LineNo+1, line(C), pre, NumChars + length(Chars), Ack,Es).
d69e4d8 @klacke ""
authored
163
164
165
0d623c1 @klacke ""
authored
166 has_tag(L, Str) ->
167 has_tag(L, Str, 0).
168 has_tag([H|T], Tag, Num) ->
169 case yaws:is_space(H) of
170 true ->
171 has_tag(T, Tag, Num+1);
172 false ->
173 case lists:prefix(Tag, [H|T]) of
174 true ->
175 {ok, Num, [H|T]};
176 false ->
177 false
178 end
179 end;
180 has_tag(_,_,_) ->
181 false.
d69e4d8 @klacke ""
authored
182
183 check_exported(C, LineNo, NumChars, Mod) ->
184 case is_exported(out, 1, Mod) of
185 true ->
186 [{mod, C#comp.startline, C#comp.infile,
187 NumChars,Mod,out}];
188 false ->
189 ?Debug("XX ~p~n", [C]),
190 [gen_err(C, LineNo, NumChars,
191 "out/1 is not defined ")]
192 end.
193
194 line(C) ->
7c5307a @klacke don't log a crash when we get methods we don't support and also a fix in...
authored
195 get_line(C#comp.infd).
d69e4d8 @klacke ""
authored
196
197 is_exported(Fun, A, Mod) ->
198 case (catch Mod:module_info()) of
199 List when list(List) ->
200 case lists:keysearch(exports, 1, List) of
201 {value, {exports, Exp}} ->
202 lists:member({Fun, A}, Exp);
203 _ ->
204 false
205 end;
206 _ ->
207 false
208 end.
209
210
211 %% this will generate 9 lines
212 new_out_file(Line, C, GC) ->
2f51c68 @klacke -check arg
authored
213 Mnum = case catch gen_server:call(yaws_server, mnum) of
214 {'EXIT', _} ->
215 1;
216 Other ->
217 Other
218 end,
d69e4d8 @klacke ""
authored
219 Module = [$m | integer_to_list(Mnum)],
3dc56a7 @klacke javascript support in ehtml
authored
220 OutFile = lists:flatten(
221 io_lib:format(
222 "/tmp/yaws/~s/~s.erl",[GC#gconf.uid, Module])),
223
224 %% "/tmp/yaws/" ++ Module ++ ".erl",
225
d69e4d8 @klacke ""
authored
226 ?Debug("Writing outout file~s~n", [OutFile]),
227 {ok, Out} = file:open(OutFile, [write]),
228 ok = io:format(Out, "-module(~s).~n-compile(export_all).~n~n", [Module]),
229 io:format(Out, "%%~n%% code at line ~w from file ~s~n%%~n",
230 [Line, C#comp.infile]),
231
232 io:format(Out, "-import(yaws_api, [f/2, fl/1, parse_post_data/2]). ~n~n", []),
233 io:format(Out, '-include("~s/include/yaws_api.hrl").~n',
234 [GC#gconf.yaws_dir]),
235 C#comp{outfd = Out,
236 outfile = OutFile}.
237
238
2129adc @klacke ""
authored
239 gen_err(C, _LineNo, NumChars, Err) ->
d69e4d8 @klacke ""
authored
240 S = io_lib:format("<p> Error in File ~s Erlang code beginning "
241 "at line ~w~n"
242 "Error is: ~p~n", [C#comp.infile, C#comp.startline,
243 Err]),
244 yaws:elog("~s~n", [S]),
245 {error, NumChars, S}.
246
247
2129adc @klacke ""
authored
248 comp_err(C, _LineNo, NumChars, Err) ->
d69e4d8 @klacke ""
authored
249 case Err of
2129adc @klacke ""
authored
250 [{_FileName, [ErrInfo|_]} |_] ->
d69e4d8 @klacke ""
authored
251 {Line0, Mod, E}=ErrInfo,
252 Line = Line0 + C#comp.startline - 9,
2129adc @klacke ""
authored
253 ?Debug("XX ~p~n", [{_LineNo, Line0}]),
1986fbf @klacke ""
authored
254 Str = io_lib:format("~s:~w:~n ~s\n",
d69e4d8 @klacke ""
authored
255 [C#comp.infile, Line,
256 apply(Mod, format_error, [E])]),
257 HtmlStr = ?F("~n<pre>~nDynamic compile error: ~s~n</pre>~n",
258 [Str]),
259 yaws:elog("Dynamic compiler err ~s", [Str]),
260 {error, NumChars, HtmlStr};
2129adc @klacke ""
authored
261 _Other ->
d69e4d8 @klacke ""
authored
262 yaws:elog("Dynamic compile error", []),
263 {error, NumChars, ?F("<pre> Compile error - "
264 "Other err ~p</pre>~n", [Err])}
265 end.
266
267
268 %% due to compiler not producing proper error
269 %% we NEED to catch all io produced by the compiler
270
271 proc_compile_file(F, Opts) ->
272 G = group_leader(),
273 group_leader(self(), self()),
274 P = proc_lib:spawn(?MODULE, compiler_proc, [self(), F, Opts]),
275 Res = get_compiler_data(P, []),
276 group_leader(G, self()),
277 Res.
278
279 compiler_proc(Top, F, Opts) ->
280 R = (catch compile:file(F, Opts)),
281 Top ! {self(), result, R}.
282
283
284 get_compiler_data(P, Ack) ->
285 receive
286 {P, result, {ok, Mod, Bin}} ->
287 {ok, Mod, Bin};
288 {io_request, P1, P2, {put_chars, M, F, A}} ->
289 P1 ! {io_reply, P2, ok},
290 Str = apply(M, F, A),
291 get_compiler_data(P, [Str|Ack]);
292 {P, result, {error, Errors, Warnings}} ->
293 {error, Errors, Warnings};
294 {P, result, error} ->
295 S = lists:map(
296 fun(S) -> S ++ "\n" end, lists:reverse(Ack)),
297 {error, S}
298 end.
299
300
301
7c5307a @klacke don't log a crash when we get methods we don't support and also a fix in...
authored
302 %% This code is so that we get the \r in the line
303 %% when we're parsing msdos files.
304
567034e @klacke *** empty log message ***
authored
305 file_open(Fname) ->
306 case file:read_file(Fname) of
307 {ok, Bin} ->
308 put(yfile_data, binary_to_list(Bin)),
368cfec @klacke *** empty log message ***
authored
309 {ok, yfile_data};
567034e @klacke *** empty log message ***
authored
310 Err ->
311 Err
7c5307a @klacke don't log a crash when we get methods we don't support and also a fix in...
authored
312 end.
313
368cfec @klacke *** empty log message ***
authored
314 file_close(Key) ->
315 erase(Key).
567034e @klacke *** empty log message ***
authored
316
317
368cfec @klacke *** empty log message ***
authored
318 get_line(Fd) ->
567034e @klacke *** empty log message ***
authored
319 case get (yfile_data) of
7c5307a @klacke don't log a crash when we get methods we don't support and also a fix in...
authored
320 [] ->
567034e @klacke *** empty log message ***
authored
321 eof;
7c5307a @klacke don't log a crash when we get methods we don't support and also a fix in...
authored
322 Chars ->
323 case get_line_from_chars(Chars, []) of
324 {ok, Line, Tail} ->
567034e @klacke *** empty log message ***
authored
325 put (yfile_data, Tail),
7c5307a @klacke don't log a crash when we get methods we don't support and also a fix in...
authored
326 Line;
327 need_more ->
567034e @klacke *** empty log message ***
authored
328 put(yfile_data, []),
329 Chars
7c5307a @klacke don't log a crash when we get methods we don't support and also a fix in...
authored
330 end
331 end.
332
333 get_line_from_chars([$\r, $\n | Tail], Line) ->
334 {ok, lists:reverse([$\n, $\r|Line]), Tail};
335
336 get_line_from_chars([$\n | Tail], Line) ->
337 {ok, lists:reverse([$\n|Line]), Tail};
d69e4d8 @klacke ""
authored
338
567034e @klacke *** empty log message ***
authored
339 get_line_from_chars([], Line) ->
7c5307a @klacke don't log a crash when we get methods we don't support and also a fix in...
authored
340 need_more;
341 get_line_from_chars([H|T], Line) ->
342 get_line_from_chars(T, [H|Line]).
d69e4d8 @klacke ""
authored
343
344
345
346
567034e @klacke *** empty log message ***
authored
347 gg() ->
348 {ok, Fd} = file_open("arg.yaws"),
349 gg(Fd).
350
351 gg(Fd) ->
352 case get_line(Fd) of
353 eof ->
354 eof;
355 X ->
356 io:format("~s", [X]),
357 gg(Fd)
358 end.
Something went wrong with that request. Please try again.