su4sml/src/codegen/gcg_core.sml

162 lines
6.1 KiB
Standard ML

(*****************************************************************************
* su4sml --- an SML repository for managing (Secure)UML/OCL models
* http://projects.brucker.ch/su4sml/
*
* gcg_core.sml --- implements functor GCG_Core
* transcribes a su4sml model according to a template tree
* into code specific to a target language cartridge
* This file is part of su4sml.
*
* Copyright (c) 2005-2007, ETH Zurich, Switzerland
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* * Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************)
(* $Id$ *)
(** A Code generator *)
signature GCG =
sig
val writeLine : string -> unit
val generate : Rep.Model -> string -> unit
end
(** builds a code generator from a cartridge chain. *)
functor GCG_Core (C: CARTRIDGE): GCG =
struct
val curFile = ref ""
val out = ref TextIO.stdOut
fun closeFile () = if (!curFile = "")
then ()
else (TextIO.closeOut (!out);
(* info ("closing "^(!curFile));*)
curFile := "")
(* FIXME: set out to a real NullStream *)
fun openNull file = (closeFile ();
Logger.info ("skipping "^file);
out := (TextIO.openOut "/dev/null");
curFile := "/dev/null"
)
fun openFile file = (closeFile ();
Logger.info ("opening "^file);
Gcg_Helper.assureDir file;
out := (TextIO.openOut file);
curFile := file
)
fun openFileIfNotExists file = (closeFile ();
(if ((OS.FileSys.fileSize file) > 0)
then openNull file
else openFile file
) handle SysErr => ( openFile file ))
fun initOut () = (out := TextIO.stdOut;
curFile := "")
fun writeLine s = TextIO.output (!out,s)
fun eval s = (Logger.info "<eval>"; CompilerExt.eval true s)
(** applies f to every other element in l starting with the second
*)
fun map2EveryOther f [] = []
| map2EveryOther f [a] = [a]
| map2EveryOther f (a::b::z) = a::(f b)::(map2EveryOther f z)
fun substituteVars e s =
let val tkl = Gcg_Helper.joinEscapeSplitted "$" (Gcg_Helper.fieldSplit #"$" s)
in
String.concat (map2EveryOther (C.lookup e) tkl)
handle ex => (Logger.error ("in GCG_Core.substituteVars: \
\variable lookup failure in string \""^s^"\".");
s)
end
(** traverses a templateParseTree and executes the given instructions *)
fun write env (Tpl_Parser.RootNode(l)) = List.app (write env) l
| write env (Tpl_Parser.OpenFileLeaf(file)) = openFile (substituteVars env file)
| write env (Tpl_Parser.OpenFileIfNotExistsLeaf(file)) =
openFileIfNotExists (substituteVars env file)
| write env (Tpl_Parser.EvalLeaf(l)) =
let fun collectEval [] = ""
| collectEval ((Tpl_Parser.TextLeaf(expr))::t) = expr^"\n"^(collectEval t)
| collectEval _ =
Logger.error "in GCG_Core.write: No TextLeaf in EvalLeaf"
in
eval (substituteVars env (collectEval l))
end
| write env (Tpl_Parser.TextLeaf(s)) = writeLine (substituteVars env s)
| write env (Tpl_Parser.IfNode(cond,l)) =
let fun writeThen _ [] = ()
| writeThen _ [Tpl_Parser.ElseNode(_)] = ()
| writeThen e (h::t) = (write e h ;writeThen e t)
in
(if (C.test env cond)
then writeThen env l
else case (List.last l) of nd as (Tpl_Parser.ElseNode(_)) => write env nd
| _ => ())
handle ex => Logger.error ("in GCG_Core.write: problem in IfNode "^cond)
end
| write env (Tpl_Parser.ElseNode(l)) = List.app (write env) l
| write env (Tpl_Parser.ForEachNode(listType,children))=
let val list_of_environments = C.foreach listType env
fun write_children e = List.app (fn tree => write e tree) children
in
List.app (fn e => write_children e) list_of_environments
handle ex => (Logger.error ("in GCG_Core.write: error in foreach node "^listType^
": "^General.exnMessage ex);
())
end
(** generate code according to the given template file for the given model *)
fun generate model template
= let val env = C.initEnv model
val tree = Tpl_Parser.parse template
in
(initOut();
(*printTTree tree;*)
write env tree;
closeFile ();
Logger.info "codegen finished successfully"
)
handle ex => (closeFile(); raise ex)
end
end