Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 303 lines (245 sloc) 8.729 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
43 comp_opts(GC) ->
6c9c37f @klacke ""
authored
44 ?Debug("I=~p~n", [GC#gconf.include_dir]),
d69e4d8 @klacke ""
authored
45 I = lists:map(fun(Dir) -> {i, Dir} end, GC#gconf.include_dir),
9cd59a3 @klacke ""
authored
46 Opts = [binary, return_errors | I],
d69e4d8 @klacke ""
authored
47 ?Debug("Compile opts = ~p~n", [Opts]),
48 Opts.
49
50
51 compile_file(File, GC, SC) ->
52 case file:open(File, [read]) of
53 {ok, Fd} ->
54 Spec = compile_file(#comp{infile = File,
55 infd = Fd, gc = GC, sc = SC},
9cd59a3 @klacke ""
authored
56 1,
8722844 @klacke a file which has at least one compilation error shouldn't be cached i…
authored
57 io:get_line(Fd, ''), init, 0, [], 0),
2129adc @klacke ""
authored
58 Spec;
59 _Err ->
d69e4d8 @klacke ""
authored
60 yaws:elog("can't open ~s~n", [File]),
61 exit(normal)
62 end.
63
9cd59a3 @klacke ""
authored
64 compile_file(C, _LineNo, eof, _Mode, NumChars, Ack, Errors) ->
d69e4d8 @klacke ""
authored
65 file:close(C#comp.infd),
8722844 @klacke a file which has at least one compilation error shouldn't be cached i…
authored
66 {ok, [{errors, Errors} |lists:reverse([{data, NumChars} |Ack])]};
d69e4d8 @klacke ""
authored
67
68
39c94ab @klacke ""
authored
69 %% 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 i…
authored
70 compile_file(C, LineNo, Chars, init, NumChars, Ack, Errs) ->
d69e4d8 @klacke ""
authored
71 case Chars -- [$\s, $\t, $\n, $\r] of
72 [] ->
961926f @klacke ""
authored
73 ?Debug("SKIP ~p~n", [Chars]),
74 L=length(Chars),
8722844 @klacke a file which has at least one compilation error shouldn't be cached i…
authored
75 compile_file(C, LineNo+1, line(C), init, NumChars-L, Ack, Errs);
39c94ab @klacke ""
authored
76 "<erl>" ++ _ -> %% first chunk is erl, skip whistespace
8722844 @klacke a file which has at least one compilation error shouldn't be cached i…
authored
77 compile_file(C, LineNo, Chars, html, NumChars, Ack, Errs);
d69e4d8 @klacke ""
authored
78 _ ->
39c94ab @klacke ""
authored
79 %% first chunk is html, keep whitespace
80 Fd=C#comp.infd,
81 file:position(Fd, bof),
9cd59a3 @klacke ""
authored
82 compile_file(C,noline,io:get_line(Fd,''),html,0,[], Errs)
d69e4d8 @klacke ""
authored
83 end;
84
8722844 @klacke a file which has at least one compilation error shouldn't be cached i…
authored
85 compile_file(C, LineNo, Chars = "<erl>" ++ _Tail, html, NumChars, Ack,Es) ->
d69e4d8 @klacke ""
authored
86 ?Debug("start erl:~p",[LineNo]),
87 C2 = new_out_file(LineNo, C, C#comp.gc),
88 C3 = C2#comp{startline = LineNo},
89 L = length(Chars),
90 if
91 NumChars > 0 ->
92 compile_file(C3, LineNo+1, line(C) , erl,L,
8722844 @klacke a file which has at least one compilation error shouldn't be cached i…
authored
93 [{data, NumChars} | Ack], Es);
d69e4d8 @klacke ""
authored
94 true -> %% just ignore zero byte data segments
8722844 @klacke a file which has at least one compilation error shouldn't be cached i…
authored
95 compile_file(C3, LineNo+1, line(C) , erl, L + (-NumChars),
96 Ack, Es) %hack
d69e4d8 @klacke ""
authored
97 end;
98
8722844 @klacke a file which has at least one compilation error shouldn't be cached i…
authored
99 compile_file(C, LineNo, Chars = "</erl>" ++ _Tail, erl, NumChars, Ack, Es) ->
d69e4d8 @klacke ""
authored
100 ?Debug("stop erl:~p",[LineNo]),
101 file:close(C#comp.outfd),
102 NumChars2 = NumChars + length(Chars),
103 case proc_compile_file(C#comp.outfile, comp_opts(C#comp.gc)) of
104 {ok, ModuleName, Binary} ->
105 case code:load_binary(ModuleName, C#comp.outfile, Binary) of
106 {module, ModuleName} ->
107 C2 = C#comp{modnum = C#comp.modnum+1},
108 L2 = check_exported(C, LineNo,NumChars2, ModuleName),
8722844 @klacke a file which has at least one compilation error shouldn't be cached i…
authored
109 compile_file(C2, LineNo+1, line(C),html,0,L2++Ack, Es);
d69e4d8 @klacke ""
authored
110 Err ->
111 A2 = gen_err(C, LineNo, NumChars2,
112 ?F("Cannot load module ~p: ~p",
113 [ModuleName, Err])),
114 compile_file(C, LineNo+1, line(C),
8722844 @klacke a file which has at least one compilation error shouldn't be cached i…
authored
115 html, 0, [A2|Ack], Es+1)
d69e4d8 @klacke ""
authored
116 end;
2129adc @klacke ""
authored
117 {error, Errors, _Warnings} ->
d69e4d8 @klacke ""
authored
118 %% FIXME remove outfile here ... keep while debuging
119 A2 = comp_err(C, LineNo, NumChars2, Errors),
8722844 @klacke a file which has at least one compilation error shouldn't be cached i…
authored
120 compile_file(C, LineNo+1, line(C), html, 0, [A2|Ack], Es+1);
d69e4d8 @klacke ""
authored
121 {error, Str} ->
122 %% this is boring but does actually happen
123 %% in order to get proper user errors here we need to catch i/o
124 %% or hack compiler/parser
9cd59a3 @klacke ""
authored
125 yaws:elog("Dynamic compile error in file ~s, line ~w~n~s",
126 [C#comp.infile, LineNo, Str]),
d69e4d8 @klacke ""
authored
127 A2 = {error, NumChars2, ?F("<pre> Dynamic compile error in file "
128 " ~s line ~w~n~s </pre>",
129 [C#comp.infile, LineNo, Str])},
8722844 @klacke a file which has at least one compilation error shouldn't be cached i…
authored
130 compile_file(C, LineNo+1, line(C), html, 0, [A2|Ack], Es+1)
d69e4d8 @klacke ""
authored
131 end;
132
8722844 @klacke a file which has at least one compilation error shouldn't be cached i…
authored
133 compile_file(C, LineNo, Chars = "<pre>" ++ _Tail, html, NumChars, Ack, Es) ->
d69e4d8 @klacke ""
authored
134 ?Debug("start pre:~p",[LineNo]),
8722844 @klacke a file which has at least one compilation error shouldn't be cached i…
authored
135 compile_file(C, LineNo+1, line(C) , pre, NumChars + length(Chars), Ack,Es);
d69e4d8 @klacke ""
authored
136
8722844 @klacke a file which has at least one compilation error shouldn't be cached i…
authored
137 compile_file(C, LineNo, Chars = "</pre>" ++ _Tail, pre, NumChars, Ack,Es) ->
d69e4d8 @klacke ""
authored
138 ?Debug("stop pre:~p",[LineNo]),
8722844 @klacke a file which has at least one compilation error shouldn't be cached i…
authored
139 compile_file(C, LineNo+1, line(C) , html, NumChars + length(Chars), Ack,Es);
d69e4d8 @klacke ""
authored
140
8722844 @klacke a file which has at least one compilation error shouldn't be cached i…
authored
141 compile_file(C, LineNo, Chars, erl, NumChars, Ack,Es) ->
0d623c1 @klacke ""
authored
142 case has_tag(Chars, "</erl>") of
143 {ok, Skipped, Chars2} ->
8722844 @klacke a file which has at least one compilation error shouldn't be cached i…
authored
144 compile_file(C, LineNo, Chars2, erl, NumChars + Skipped, Ack,Es);
0d623c1 @klacke ""
authored
145 false ->
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 i…
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 i…
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 i…
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 i…
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 i…
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) ->
195 io:get_line(C#comp.infd, '').
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) ->
213 Mnum = gen_server:call(yaws_server, mnum),
214 Module = [$m | integer_to_list(Mnum)],
3dc56a7 @klacke javascript support in ehtml
authored
215 OutFile = lists:flatten(
216 io_lib:format(
217 "/tmp/yaws/~s/~s.erl",[GC#gconf.uid, Module])),
218
219 %% "/tmp/yaws/" ++ Module ++ ".erl",
220
d69e4d8 @klacke ""
authored
221 ?Debug("Writing outout file~s~n", [OutFile]),
222 {ok, Out} = file:open(OutFile, [write]),
223 ok = io:format(Out, "-module(~s).~n-compile(export_all).~n~n", [Module]),
224 io:format(Out, "%%~n%% code at line ~w from file ~s~n%%~n",
225 [Line, C#comp.infile]),
226
227 io:format(Out, "-import(yaws_api, [f/2, fl/1, parse_post_data/2]). ~n~n", []),
228 io:format(Out, '-include("~s/include/yaws_api.hrl").~n',
229 [GC#gconf.yaws_dir]),
230 C#comp{outfd = Out,
231 outfile = OutFile}.
232
233
2129adc @klacke ""
authored
234 gen_err(C, _LineNo, NumChars, Err) ->
d69e4d8 @klacke ""
authored
235 S = io_lib:format("<p> Error in File ~s Erlang code beginning "
236 "at line ~w~n"
237 "Error is: ~p~n", [C#comp.infile, C#comp.startline,
238 Err]),
239 yaws:elog("~s~n", [S]),
240 {error, NumChars, S}.
241
242
2129adc @klacke ""
authored
243 comp_err(C, _LineNo, NumChars, Err) ->
d69e4d8 @klacke ""
authored
244 case Err of
2129adc @klacke ""
authored
245 [{_FileName, [ErrInfo|_]} |_] ->
d69e4d8 @klacke ""
authored
246 {Line0, Mod, E}=ErrInfo,
247 Line = Line0 + C#comp.startline - 9,
2129adc @klacke ""
authored
248 ?Debug("XX ~p~n", [{_LineNo, Line0}]),
d69e4d8 @klacke ""
authored
249 Str = io_lib:format("~s:~w: ~s\n",
250 [C#comp.infile, Line,
251 apply(Mod, format_error, [E])]),
252 HtmlStr = ?F("~n<pre>~nDynamic compile error: ~s~n</pre>~n",
253 [Str]),
254 yaws:elog("Dynamic compiler err ~s", [Str]),
255 {error, NumChars, HtmlStr};
2129adc @klacke ""
authored
256 _Other ->
d69e4d8 @klacke ""
authored
257 yaws:elog("Dynamic compile error", []),
258 {error, NumChars, ?F("<pre> Compile error - "
259 "Other err ~p</pre>~n", [Err])}
260 end.
261
262
263 %% due to compiler not producing proper error
264 %% we NEED to catch all io produced by the compiler
265
266 proc_compile_file(F, Opts) ->
267 G = group_leader(),
268 group_leader(self(), self()),
269 P = proc_lib:spawn(?MODULE, compiler_proc, [self(), F, Opts]),
270 Res = get_compiler_data(P, []),
271 group_leader(G, self()),
272 Res.
273
274 compiler_proc(Top, F, Opts) ->
275 R = (catch compile:file(F, Opts)),
276 Top ! {self(), result, R}.
277
278
279 get_compiler_data(P, Ack) ->
280 receive
281 {P, result, {ok, Mod, Bin}} ->
282 {ok, Mod, Bin};
283 {io_request, P1, P2, {put_chars, M, F, A}} ->
284 P1 ! {io_reply, P2, ok},
285 Str = apply(M, F, A),
286 get_compiler_data(P, [Str|Ack]);
287 {P, result, {error, Errors, Warnings}} ->
288 {error, Errors, Warnings};
289 {P, result, error} ->
290 S = lists:map(
291 fun(S) -> S ++ "\n" end, lists:reverse(Ack)),
292 {error, S}
293 end.
294
295
296
297
298
299
300
301
302
Something went wrong with that request. Please try again.