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
=
28 val cgiMode
= Posix
.FileSys
.S
.flags
[Posix
.FileSys
.S
.irwxu
,
29 Posix
.FileSys
.S
.iroth
,
30 Posix
.FileSys
.S
.ixoth
]
32 val consumer
= {consumer
= TextIO.print
,
33 flush
= fn () => TextIO.flushOut
TextIO.stdOut
,
41 else if String.sub (path
, i
) = #
"/" then
42 String.extract (path
, i
+1, NONE
)
56 else if String.sub (path
, i
) = #
"." then
57 String.substring (path
, 0, i
)
71 else if String.sub (path
, i
) = #
"." then
72 String.extract (path
, i
+1, NONE
)
79 val upperOffset
= ord #
"A" - ord #
"a"
81 if Char.isLower ch
then
82 chr (ord ch
+ upperOffset
)
89 if size name
>= 1 then
90 str (toUpper (String.sub (name
, 0))) ^
String.extract (name
, 1, NONE
)
98 fun compileTemplate (config
, env
, templates
) path
=
100 val fname
= getFname path
101 val name
= removeExt fname
102 val name
= makeName name
104 (name
, Mlt
.trans (config
, env
, templates
, name
, Parse
.parse path
))
107 fun compileDirectory config
=
109 val path
= Config
.inPath config
110 val outPath
= Config
.outPath config
111 val sml
= Config
.sml config
113 val dir
= Posix
.FileSys
.opendir path
115 fun loop (smls
, mlts
) =
116 (case Posix
.FileSys
.readdir dir
of
119 (case getExt fname
of
120 "mlt" => loop (smls
, (path ^
"/" ^ fname
) :: mlts
)
123 val fname
= getFname fname
125 if String.sub (fname
, 0) = #
"_" then
128 loop ((path ^
"/" ^ fname
) :: smls
, mlts
)
130 | _
=> loop (smls
, mlts
)))
132 val (smls
, mlts
) = loop ([], [])
134 val outf
= TextIO.openOut (outPath ^
"/libs.cm")
135 val printNames
= app (fn name
=> TextIO.output (outf
, "\t" ^ name ^
"\n"))
136 val _
= TextIO.output (outf
, "Group is\n\t");
137 val _
= TextIO.output (outf
, Config
.lib config
)
138 val _
= TextIO.output (outf
, "\n")
139 val _
= TextIO.output (outf
, "\n\t(* Extra libraries and such *)\n\n")
140 val _
= printNames (Config
.cm config
)
141 val _
= TextIO.output (outf
, "\n\t(* Project SML sources *)\n\n")
142 val _
= printNames smls
143 val _
= TextIO.closeOut outf
145 val outf
= TextIO.openOut (outPath ^
"/.build.sml")
146 val _
= TextIO.output (outf
, "Control.quotation := true;\nControl.printWarnings := false;\n")
147 fun printMlts
[] = ()
149 (TextIO.output (outf
, "\"" ^ h ^
"\"");
150 List.app (fn n
=> TextIO.output (outf
, ", \"" ^ n ^
"\"")) t
)
152 val libList
= foldl (fn (l
, s
) => s ^
"if CM.make \"" ^ l ^
"\" then () else OS.Process.exit OS.Process.failure;\n") "" (Config
.cm config
)
154 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");
155 TextIO.output (outf
, libList
);
156 TextIO.output (outf
, "Compiler.compileTemplates (Config.read \"mlt.conf\" (Config.default ())) ([");
158 TextIO.output (outf
, "], [");
160 TextIO.output (outf
, "]);\n");
161 TextIO.closeOut outf
;
162 OS
.Process
.system ("cat " ^ outPath ^
"/.build.sml | " ^ sml ^
"/sml")
165 fun compileTemplates
config (mlts
, smls
) =
167 val err_flag
= ref
false
168 val _
= ErrorMsg
.reset ()
170 val path
= Config
.inPath config
171 val outPath
= Config
.outPath config
172 val pubPath
= Config
.pubPath config
173 val sml
= Config
.sml config
175 val loc
= Environment
.staticPart (#
get (EnvRef
.loc ()) ())
176 val base
= Environment
.staticPart (#
get (EnvRef
.base ()) ())
177 val env
= StaticEnv
.atop (base
, loc
)
179 (*fun penv env
= (print
"I know about these symbols:\n";
180 StaticEnv
.app (fn (sym
, _
) => print (Symbol
.describe sym ^
"\n")) env
)
185 val templates
= StringSet
.addList (StringSet
.empty
, map (getFname
o removeExt
) mlts
)
186 val _
= print
"Templates: "
187 val _
= StringSet
.app (fn s
=> print (s ^
"; ")) templates
190 fun ct (fname
, (exports
, outputs
, scripts
)) =
192 val _
= print ("Compiling " ^ fname ^
"....\n")
193 val (name
, output
) = compileTemplate (config
, env
, templates
) fname
194 val _
= err_flag
:= (!err_flag
orelse !ErrorMsg
.anyErrors
)
195 val scriptName
= removeExt (getFname fname
)
196 val outName
= "__" ^ scriptName ^
".sml"
197 val outf
= TextIO.openOut (outPath ^
"/" ^ outName
)
199 TextIO.output (outf
, output
);
200 TextIO.closeOut outf
;
201 (name
:: exports
, outName
:: outputs
, (pubPath ^
"/" ^ scriptName
) :: scripts
)
204 val _
= print
"Compiling templates....\n"
206 val (exports
, outputs
, scripts
) = foldl
ct ([], [], []) mlts
208 val outf
= TextIO.openOut (outPath ^
"/_main.sml")
214 if List.exists (fn y
=> x
= y
) exports
then
219 fun decide NONE
= "(fn () => ())"
221 (case isTemplate t
of
222 SOME t
=> t ^
".exec"
223 | _
=> (err_flag
:= true;
224 print ("Template " ^ t ^
" specified in mlt.conf does not exist!\n");
226 val beforeT
= decide (Config
.beforeT config
)
227 val afterT
= decide (Config
.afterT config
)
228 val exnT
= decide (Config
.exnT config
)
230 val _
= (TextIO.output (outf
, "structure Templates :> TEMPLATES =\nstruct\n\tval beforeFn =");
231 TextIO.output (outf
, beforeT
);
232 TextIO.output (outf
, "\n\tval afterFn = ");
233 TextIO.output (outf
, afterT
);
234 TextIO.output (outf
, "\n\tval exnFn = ");
235 TextIO.output (outf
, exnT
);
236 TextIO.output (outf
, "\n\n\tval templates = ["))
237 val _
= (case exports
of
239 |
(exp
::rest
) => (TextIO.output (outf
, "(\"" ^ exp ^
"\", " ^ exp ^
".exec)");
240 app (fn exp
=> TextIO.output (outf
, ",\n\t\t(\"" ^ exp ^
"\", " ^ exp ^
".exec)"))
242 val _
= TextIO.output (outf
, "]\nend\n\nstructure Main = MainFn(Templates)\n")
243 val _
= TextIO.closeOut outf
245 val outf
= TextIO.openOut (outPath ^
"/.build.sml")
246 val _
= TextIO.output (outf
, "Control.printWarnings := false;\nprint \"Here we go\"\n;\nCM.make \"sources.cm\";\nSMLofNJ.exportFn (\"" ^ outPath ^
"/heap\", Main.main);\n")
247 val _
= TextIO.closeOut outf
249 val outf
= TextIO.openOut (outPath ^
"/sources.cm")
250 val printNames
= app (fn name
=> TextIO.output (outf
, "\t" ^ name ^
"\n"))
252 fun makeScript (name
, str
) =
254 val outf
= TextIO.openOut name
256 TextIO.output (outf
, "#!/bin/sh\n\n");
257 TextIO.output (outf
, sml ^
"/sml @SMLload=" ^ outPath ^
"/heap." ^ arch ^
" " ^ str ^
" $*\n");
258 TextIO.closeOut outf
;
259 Posix
.FileSys
.chmod (name
, cgiMode
)
263 (TextIO.print
"Errors compiling templates.\n";
266 (TextIO.output (outf
, "(* Automatic generate web fun happyness *)\n\nLibrary\n\tstructure Main\nis\n\t(* Web library *)\n\t");
267 TextIO.output (outf
, Config
.lib config
);
268 TextIO.output (outf
, "\n\n\t(* Libraries *)\n\n");
269 printNames (Config
.cm config
);
270 TextIO.output (outf
, "\n\t(* SML sources *)\n\n");
272 TextIO.output (outf
, "\n\t(* Templates *)\n\n");
274 TextIO.output (outf
, "\n\t(* Driver *)\n\n\t_main.sml\n");
275 TextIO.closeOut outf
;
276 if OS
.Process
.system ("cd " ^ outPath ^
" ; cat .build.sml | " ^ sml ^
"/sml") = OS
.Process
.success
then
277 (ListPair.app
makeScript (scripts
, exports
);