Mercurial > urweb
comparison src/compiler.sml @ 274:e4baf03a3a64
Generating SQL files
author | Adam Chlipala <adamc@hcoop.net> |
---|---|
date | Tue, 02 Sep 2008 13:44:54 -0400 |
parents | 4d80d6122df1 |
children | fdd7a698be01 |
comparison
equal
deleted
inserted
replaced
273:09c66a30ef32 | 274:e4baf03a3a64 |
---|---|
35 structure Lex = Lex | 35 structure Lex = Lex |
36 structure LrParser = LrParser) | 36 structure LrParser = LrParser) |
37 | 37 |
38 type job = { | 38 type job = { |
39 database : string option, | 39 database : string option, |
40 sources : string list | 40 sources : string list, |
41 exe : string, | |
42 sql : string option, | |
43 debug : bool | |
41 } | 44 } |
42 | 45 |
43 type ('src, 'dst) phase = { | 46 type ('src, 'dst) phase = { |
44 func : 'src -> 'dst, | 47 func : 'src -> 'dst, |
45 print : 'dst -> Print.PD.pp_desc | 48 print : 'dst -> Print.PD.pp_desc |
188 | _ => absyn | 191 | _ => absyn |
189 end | 192 end |
190 handle LrParser.ParseError => [], | 193 handle LrParser.ParseError => [], |
191 print = SourcePrint.p_file} | 194 print = SourcePrint.p_file} |
192 | 195 |
193 fun p_job {database, sources} = | 196 fun p_job {database, exe, sql, sources, debug} = |
194 let | 197 let |
195 open Print.PD | 198 open Print.PD |
196 open Print | 199 open Print |
197 in | 200 in |
198 box [case database of | 201 box [if debug then |
202 box [string "DEBUG", newline] | |
203 else | |
204 box [], | |
205 case database of | |
199 NONE => string "No database." | 206 NONE => string "No database." |
200 | SOME db => string ("Database: " ^ db), | 207 | SOME db => string ("Database: " ^ db), |
201 newline, | 208 newline, |
209 string "Exe: ", | |
210 string exe, | |
211 newline, | |
212 case sql of | |
213 NONE => string "No SQL file." | |
214 | SOME sql => string ("SQL fle: " ^ sql), | |
202 string "Sources:", | 215 string "Sources:", |
203 p_list string sources, | 216 p_list string sources, |
204 newline] | 217 newline] |
205 end | 218 end |
206 | 219 |
215 val parseUrp = { | 228 val parseUrp = { |
216 func = fn filename => | 229 func = fn filename => |
217 let | 230 let |
218 val dir = OS.Path.dir filename | 231 val dir = OS.Path.dir filename |
219 val inf = TextIO.openIn (OS.Path.joinBaseExt {base = filename, ext = SOME "urp"}) | 232 val inf = TextIO.openIn (OS.Path.joinBaseExt {base = filename, ext = SOME "urp"}) |
233 | |
234 fun relify fname = | |
235 OS.Path.concat (dir, fname) | |
236 handle OS.Path.Path => fname | |
220 | 237 |
221 fun readSources acc = | 238 fun readSources acc = |
222 case TextIO.inputLine inf of | 239 case TextIO.inputLine inf of |
223 NONE => rev acc | 240 NONE => rev acc |
224 | SOME line => | 241 | SOME line => |
227 acc | 244 acc |
228 else | 245 else |
229 let | 246 let |
230 val fname = String.implode (List.filter (fn x => not (Char.isSpace x)) | 247 val fname = String.implode (List.filter (fn x => not (Char.isSpace x)) |
231 (String.explode line)) | 248 (String.explode line)) |
232 val fname = OS.Path.concat (dir, fname) | 249 val fname = relify fname |
233 handle OS.Path.Path => fname | |
234 in | 250 in |
235 fname :: acc | 251 fname :: acc |
236 end | 252 end |
237 in | 253 in |
238 readSources acc | 254 readSources acc |
239 end | 255 end |
240 | 256 |
241 fun read database = | 257 fun finish (database, exe, sql, debug, sources) = |
258 {database = database, | |
259 exe = Option.getOpt (exe, OS.Path.joinBaseExt {base = OS.Path.base filename, | |
260 ext = SOME "exe"}), | |
261 sql = sql, | |
262 debug = debug, | |
263 sources = sources} | |
264 | |
265 fun read (database, exe, sql, debug) = | |
242 case TextIO.inputLine inf of | 266 case TextIO.inputLine inf of |
243 NONE => {database = database, sources = []} | 267 NONE => finish (database, exe, sql, debug, []) |
244 | SOME "\n" => {database = database, sources = readSources []} | 268 | SOME "\n" => finish (database, exe, sql, debug, readSources []) |
245 | SOME line => | 269 | SOME line => |
246 let | 270 let |
247 val (cmd, arg) = Substring.splitl (fn x => not (Char.isSpace x)) (Substring.full line) | 271 val (cmd, arg) = Substring.splitl (fn x => not (Char.isSpace x)) (Substring.full line) |
248 val cmd = Substring.string (trim cmd) | 272 val cmd = Substring.string (trim cmd) |
249 val arg = Substring.string (trim arg) | 273 val arg = Substring.string (trim arg) |
251 case cmd of | 275 case cmd of |
252 "database" => | 276 "database" => |
253 (case database of | 277 (case database of |
254 NONE => () | 278 NONE => () |
255 | SOME _ => ErrorMsg.error "Duplicate 'database' directive"; | 279 | SOME _ => ErrorMsg.error "Duplicate 'database' directive"; |
256 read (SOME arg)) | 280 read (SOME arg, exe, sql, debug)) |
281 | "exe" => | |
282 (case exe of | |
283 NONE => () | |
284 | SOME _ => ErrorMsg.error "Duplicate 'exe' directive"; | |
285 read (database, SOME (relify arg), sql, debug)) | |
286 | "sql" => | |
287 (case sql of | |
288 NONE => () | |
289 | SOME _ => ErrorMsg.error "Duplicate 'sql' directive"; | |
290 read (database, exe, SOME (relify arg), debug)) | |
291 | "debug" => read (database, exe, sql, true) | |
257 | _ => (ErrorMsg.error ("Unrecognized command '" ^ cmd ^ "'"); | 292 | _ => (ErrorMsg.error ("Unrecognized command '" ^ cmd ^ "'"); |
258 read database) | 293 read (database, exe, sql, debug)) |
259 end | 294 end |
260 in | 295 in |
261 read NONE | 296 read (NONE, NONE, NONE, false) |
262 before TextIO.closeIn inf | 297 before TextIO.closeIn inf |
263 end, | 298 end, |
264 print = p_job | 299 print = p_job |
265 } | 300 } |
266 | 301 |
268 | 303 |
269 fun capitalize "" = "" | 304 fun capitalize "" = "" |
270 | capitalize s = str (Char.toUpper (String.sub (s, 0))) ^ String.extract (s, 1, NONE) | 305 | capitalize s = str (Char.toUpper (String.sub (s, 0))) ^ String.extract (s, 1, NONE) |
271 | 306 |
272 val parse = { | 307 val parse = { |
273 func = fn {database, sources = fnames} => | 308 func = fn {database, sources = fnames, ...} : job => |
274 let | 309 let |
275 fun nameOf fname = capitalize (OS.Path.file fname) | 310 fun nameOf fname = capitalize (OS.Path.file fname) |
276 | 311 |
277 fun parseOne fname = | 312 fun parseOne fname = |
278 let | 313 let |
411 func = Cjrize.cjrize, | 446 func = Cjrize.cjrize, |
412 print = CjrPrint.p_file CjrEnv.empty | 447 print = CjrPrint.p_file CjrEnv.empty |
413 } | 448 } |
414 | 449 |
415 val toCjrize = transform cjrize "cjrize" o toMono_opt2 | 450 val toCjrize = transform cjrize "cjrize" o toMono_opt2 |
451 | |
452 val sqlify = { | |
453 func = Cjrize.cjrize, | |
454 print = CjrPrint.p_sql CjrEnv.empty | |
455 } | |
456 | |
457 val toSqlify = transform sqlify "sqlify" o toMono_opt2 | |
416 | 458 |
417 fun compileC {cname, oname, ename} = | 459 fun compileC {cname, oname, ename} = |
418 let | 460 let |
419 val compile = "gcc -O3 -I include -c " ^ cname ^ " -o " ^ oname | 461 val compile = "gcc -O3 -I include -c " ^ cname ^ " -o " ^ oname |
420 val link = "gcc -O3 -pthread -lpq clib/urweb.o " ^ oname ^ " clib/driver.o -o " ^ ename | 462 val link = "gcc -O3 -pthread -lpq clib/urweb.o " ^ oname ^ " clib/driver.o -o " ^ ename |
430 fun compile job = | 472 fun compile job = |
431 case run toCjrize job of | 473 case run toCjrize job of |
432 NONE => print "Ur compilation failed\n" | 474 NONE => print "Ur compilation failed\n" |
433 | SOME file => | 475 | SOME file => |
434 let | 476 let |
435 val cname = "/tmp/urweb.c" | 477 val job = valOf (run (transform parseUrp "parseUrp") job) |
436 val oname = "/tmp/urweb.o" | 478 |
437 val ename = "/tmp/webapp" | 479 val (cname, oname, cleanup) = |
438 | 480 if #debug job then |
439 val outf = TextIO.openOut cname | 481 ("/tmp/urweb.c", "/tmp/urweb.o", fn () => ()) |
440 val s = TextIOPP.openOut {dst = outf, wid = 80} | 482 else |
483 let | |
484 val dir = OS.FileSys.tmpName () | |
485 val cname = OS.Path.joinDirFile {dir = dir, file = "urweb.c"} | |
486 val oname = OS.Path.joinDirFile {dir = dir, file = "urweb.o"} | |
487 in | |
488 OS.FileSys.mkDir dir; | |
489 (cname, oname, | |
490 fn () => (OS.FileSys.remove cname; | |
491 OS.FileSys.remove oname; | |
492 OS.FileSys.rmDir dir)) | |
493 end | |
494 val ename = #exe job | |
441 in | 495 in |
442 Print.fprint s (CjrPrint.p_file CjrEnv.empty file); | 496 let |
443 TextIO.closeOut outf; | 497 val outf = TextIO.openOut cname |
444 | 498 val s = TextIOPP.openOut {dst = outf, wid = 80} |
445 compileC {cname = cname, oname = oname, ename = ename} | 499 in |
500 Print.fprint s (CjrPrint.p_file CjrEnv.empty file); | |
501 TextIO.closeOut outf; | |
502 | |
503 case #sql job of | |
504 NONE => () | |
505 | SOME sql => | |
506 let | |
507 val outf = TextIO.openOut sql | |
508 val s = TextIOPP.openOut {dst = outf, wid = 80} | |
509 in | |
510 Print.fprint s (CjrPrint.p_sql CjrEnv.empty file); | |
511 TextIO.closeOut outf | |
512 end; | |
513 | |
514 compileC {cname = cname, oname = oname, ename = ename}; | |
515 | |
516 cleanup () | |
517 end | |
518 handle ex => (((cleanup ()) handle _ => ()); raise ex) | |
446 end | 519 end |
447 | 520 |
448 end | 521 end |