2 * Dynamic web page generation
with Standard ML
3 * Copyright (C
) 2003 Adam Chlipala
5 * This library is free software
; you can redistribute it
and/or
6 * modify it under the terms
of the GNU Lesser General Public
7 * License
as published by the Free Software Foundation
; either
8 * version
2.1 of the License
, or (at your option
) any later version
.
10 * This library is distributed
in the hope that it will be useful
,
11 * but WITHOUT ANY WARRANTY
; without even the implied warranty
of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE
. See the GNU
13 * Lesser General Public License for more details
.
15 * You should have received a copy
of the GNU Lesser General Public
16 * License along
with this library
; if not
, write to the Free Software
17 * Foundation
, Inc
., 59 Temple Place
, Suite
330, Boston
, MA
02111-1307 USA
20 (* Template compiler interface
*)
22 structure Compiler
:> COMPILER
=
26 val cgiMode
= Posix
.FileSys
.S
.flags
[Posix
.FileSys
.S
.irwxu
,
27 Posix
.FileSys
.S
.iroth
,
28 Posix
.FileSys
.S
.ixoth
]
30 val consumer
= {consumer
= TextIO.print
,
31 flush
= fn () => TextIO.flushOut
TextIO.stdOut
,
39 else if String.sub (path
, i
) = #
"/" then
40 String.extract (path
, i
+1, NONE
)
54 else if String.sub (path
, i
) = #
"." then
55 String.substring (path
, 0, i
)
69 else if String.sub (path
, i
) = #
"." then
70 String.extract (path
, i
+1, NONE
)
77 val upperOffset
= ord #
"A" - ord #
"a"
79 if Char.isLower ch
then
80 chr (ord ch
+ upperOffset
)
84 fun compileTemplate (config
, env
, templates
) path
=
86 val fname
= getFname path
87 val name
= removeExt fname
89 if size name
>= 1 then
90 str (toUpper (String.sub (name
, 0))) ^
String.extract (name
, 1, NONE
)
95 (name
, Mlt
.trans (config
, env
, templates
, name
, Parse
.parse path
))
98 fun compileDirectory config
=
100 val path
= Config
.inPath config
101 val outPath
= Config
.outPath config
102 val sml
= Config
.sml config
104 val dir
= Posix
.FileSys
.opendir path
106 fun loop (smls
, mlts
) =
107 (case Posix
.FileSys
.readdir dir
of
110 (case getExt fname
of
111 "mlt" => loop (smls
, (path ^
"/" ^ fname
) :: mlts
)
114 val fname
= getFname fname
116 if String.sub (fname
, 0) = #
"_" then
119 loop ((path ^
"/" ^ fname
) :: smls
, mlts
)
121 | _
=> loop (smls
, mlts
)))
123 val (smls
, mlts
) = loop ([], [])
125 val outf
= TextIO.openOut (outPath ^
"/libs.cm")
126 val printNames
= app (fn name
=> TextIO.output (outf
, "\t" ^ name ^
"\n"))
127 val _
= TextIO.output (outf
, "Group is\n\t");
128 val _
= TextIO.output (outf
, Config
.lib config
)
129 val _
= TextIO.output (outf
, "\n")
130 val _
= TextIO.output (outf
, "\n\t(* Extra libraries and such *)\n\n")
131 val _
= printNames (Config
.cm config
)
132 val _
= TextIO.output (outf
, "\n\t(* Project SML sources *)\n\n")
133 val _
= printNames smls
134 val _
= TextIO.closeOut outf
136 val outf
= TextIO.openOut (outPath ^
"/.build.sml")
137 val _
= TextIO.output (outf
, "Control.quotation := true;\n")
138 fun printMlts
[] = ()
140 (TextIO.output (outf
, "\"" ^ h ^
"\"");
141 List.app (fn n
=> TextIO.output (outf
, ", \"" ^ n ^
"\"")) t
)
143 val libList
= foldl (fn (l
, s
) => s ^
"if CM.make \"" ^ l ^
"\" then () else OS.Process.exit OS.Process.failure;\n") "" (Config
.cm config
)
145 TextIO.output (outf
, "if CM.make \"" ^ outPath ^
"/libs.cm\" then () else OS.Process.exit OS.Process.failure;\nif CM.make \"" ^ Config
.compiler config ^
"\" then () else OS.Process.exit OS.Process.failure;\nif CM.make \"" ^ Config
.lib config ^
"\" then () else OS.Process.exit OS.Process.failure;\n");
146 TextIO.output (outf
, libList
);
147 TextIO.output (outf
, "Compiler.compileTemplates (Config.read \"mlt.conf\" (Config.default ())) ([");
149 TextIO.output (outf
, "], [");
151 TextIO.output (outf
, "]);\n");
152 TextIO.closeOut outf
;
153 OS
.Process
.system ("cat " ^ outPath ^
"/.build.sml | " ^ sml ^
"/sml")
156 fun compileTemplates
config (mlts
, smls
) =
158 val err_flag
= ref
false
159 val _
= ErrorMsg
.reset ()
161 val path
= Config
.inPath config
162 val outPath
= Config
.outPath config
163 val pubPath
= Config
.pubPath config
164 val sml
= Config
.sml config
165 val arch
= "x86-linux"
167 val loc
= Environment
.staticPart (#
get (EnvRef
.loc ()) ())
168 val base
= Environment
.staticPart (#
get (EnvRef
.base ()) ())
169 val env
= StaticEnv
.atop (base
, loc
)
171 (*fun penv env
= (print
"I know about these symbols:\n";
172 StaticEnv
.app (fn (sym
, _
) => print (Symbol
.describe sym ^
"\n")) env
)
177 val templates
= StringSet
.addList (StringSet
.empty
, map (getFname
o removeExt
) mlts
)
178 val _
= print
"Templates: "
179 val _
= StringSet
.app (fn s
=> print (s ^
"; ")) templates
182 fun ct (fname
, (exports
, outputs
, scripts
)) =
184 val _
= print ("Compiling " ^ fname ^
"....\n")
185 val (name
, output
) = compileTemplate (config
, env
, templates
) fname
186 val _
= err_flag
:= (!err_flag
orelse !ErrorMsg
.anyErrors
)
187 val scriptName
= removeExt (getFname fname
)
188 val outName
= "__" ^ scriptName ^
".sml"
189 val outf
= TextIO.openOut (outPath ^
"/" ^ outName
)
191 TextIO.output (outf
, output
);
192 TextIO.closeOut outf
;
193 (name
:: exports
, outName
:: outputs
, (pubPath ^
"/" ^ scriptName
) :: scripts
)
196 val _
= print
"Compiling templates....\n"
198 val (exports
, outputs
, scripts
) = foldl
ct ([], [], []) mlts
200 val outf
= TextIO.openOut (outPath ^
"/_main.sml")
202 val _
= TextIO.output (outf
, "structure Templates :> TEMPLATES =\nstruct\n\tval templates = [")
203 val _
= (case exports
of
205 |
(exp
::rest
) => (TextIO.output (outf
, "(\"" ^ exp ^
"\", " ^ exp ^
".exec)");
206 app (fn exp
=> TextIO.output (outf
, ",\n\t\t(\"" ^ exp ^
"\", " ^ exp ^
".exec)"))
208 val _
= TextIO.output (outf
, "]\nend\n\nstructure Main = MainFn(Templates)\n")
209 val _
= TextIO.closeOut outf
211 val outf
= TextIO.openOut (outPath ^
"/sources.cm")
212 val printNames
= app (fn name
=> TextIO.output (outf
, "\t" ^ name ^
"\n"))
214 fun makeScript (name
, str
) =
216 val outf
= TextIO.openOut name
218 TextIO.output (outf
, "#!/bin/sh\n\n");
219 TextIO.output (outf
, sml ^
"/sml @SMLload=" ^ outPath ^
"/heap." ^ arch ^
" " ^ str ^
" $*\n");
220 TextIO.closeOut outf
;
221 Posix
.FileSys
.chmod (name
, cgiMode
)
225 (TextIO.print
"Errors compiling templates.\n";
228 (TextIO.output (outf
, "(* Automatic generate web fun happyness *)\n\nLibrary\n\tstructure Main\nis\n\t(* Web library *)\n\t");
229 TextIO.output (outf
, Config
.lib config
);
230 TextIO.output (outf
, "\n\n\t(* Libraries *)\n\n");
231 printNames (Config
.cm config
);
232 TextIO.output (outf
, "\n\t(* SML sources *)\n\n");
234 TextIO.output (outf
, "\n\t(* Templates *)\n\n");
236 TextIO.output (outf
, "\n\t(* Driver *)\n\n\t_main.sml\n");
237 TextIO.closeOut outf
;
238 if OS
.Process
.system (sml ^
"/ml-build " ^ outPath ^
"/sources.cm Main.main " ^ outPath ^
"/heap") = OS
.Process
.success
then
239 (ListPair.app
makeScript (scripts
, exports
);