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