|
|
Generic Template Language (GTL)GTL is a very simple but powerful template language. The source code for the GTL processor is only about 300 lines long. The downside to the power and simplicity is that the processor doesn't and can't do much checking to make sure that a template is well formed. It is therefore quite easy to write templates that produce junk output, or even that fail to terminate when evaluated. GTL relies on the GNU regular expression library implementation, which is licenced under the LGPL. A GTL input file is a text file with the following syntax: Input_file ::= Replacement_rules "endPatterns" <TEXT> <EOF> Replacement_rules ::= ( Replace | Replace_within )* Replace ::= "replace" <DOUBLE_QUOTE> <RE> <DOUBLE_QUOTE> <DOUBLE_QUOTE> <REPLACEMENT> <DOUBLE_QUOTE> Replace_within ::= "replaceWithin" <DOUBLE_QUOTE> <RE> <DOUBLE_QUOTE> <DOUBLE_QUOTE> <RE> <DOUBLE_QUOTE> <DOUBLE_QUOTE> <RE> <DOUBLE_QUOTE> <DOUBLE_QUOTE> <REPLACEMENT> <DOUBLE_QUOTE> The lexemes in this grammar follow the following rules:
A GTL input file is interpreted as follows:
The effect of processing a GTL file is therefore simply to apply a standard sequence of find and replace rules to the text of the file, until applying them has no further effect. Two outcomes are possible: either the file will always compile to the same output, or interpretation will fail to terminate. Neither of these outcomes seem particularly useful for a template language. Shouldn't a template language allow a variety of outputs from a single template? The reason GTL was designed like this is because most template languages make assumptions about the data structures forming the 'context' or the part that varies the output. GTL doesn't do that, and in fact eliminates the notion of context. To get it back, you use GTL files to generate generators in the programming language of your choice that work with the type of context that you want to use. You get the advantage of a flexible template syntax in the GTL file, combined with the ability to use any data structures (in any language!) as the context. There follows an example from the EMOFOCL project of a GTL file that generates a Java generator for a visitor for JMI data structures. The context used is JMI code for the UML metamodel. The example is initially confusing because it generates a program in Java for generating Java. This can be disentangled if you realise that the parts between the <?javaand ?>will eventually form part of the generator, with other Java code being what is generated. The example is intended to show that GTL can be used to produce templates that look a bit like JSP or velocity templates. replace "#\\*.*?\\*#" "" replace "##[^\\n]*\\n" "" replaceWithin "\\?>" "\\r\\n" "<\\?" "\\n" replaceWithin "\\?>" "\\n" "<\\?" "\\n" replaceWithin "\\?>" "\\t" "<\\?" "\\t" replace "\\?>\"" "?>\\\"" replaceWithin "\\?>" "([^\\\\])\"" "<\\?" "$1\\\"" replace "<\\?java([^?]*)\\?>" "<?$1?>" replace "<\\?=(([^?]|\\?[^>])*)\\?>" "<? out.print($1);?>" replace "\\?>(([^<]|<[^?])*)<\\?" " out.print(\"$1\");" replace "\\A.*?<\\?(.*)\\?>.*\\Z" "$1" endPatterns /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the template Factory.gtl, for generating a factory * for creating JMI repositories, generated from an EMOF meta-model. * * The Initial Developer of the Original Code is * James Skene. * Portions created by the Initial Developer are Copyright (C) 2005 * University College London. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ******/ #* $Header: /cs/research/sse/home0/green/jwskene/cvs/private/ uclmda.sourceforge.net/gtl.html,v 1.1 2005/10/03 16:55:41 jwskene Exp $ $Log: gtl.html,v $ Revision 1.3 2006/05/18 17:53:24 jwskene Ready to rock. Revision 1.2 2006/05/17 15:15:54 jwskene Update of UCLMDA website with UCL corporate identity. Revision 1.1 2005/10/03 16:55:41 jwskene First version of project documentation. *# <?java package uk.ac.ucl.cs.emofocl.jmigen.extended; import java.io.PrintStream; import uk.ac.ucl.cs.emofocl.jmi.extensions.Specification; public class FactoryGenerator { public static void generate(JMIContext context, Specification specification, PrintStream out) { String modelName = JMIContext.capitalise(specification.getName()); String modelType = context.getInterfacePackage(specification) + "." + JMIContext.capitalise(specification.getName()) + "Package"; String modelImplType = context.getImplementationPackage(specification) + "." + JMIContext.capitalise(specification.getName()) + "_PackageImpl"; ?> package <?= context.getInterfacePrefix() ?>; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.Collection; import java.util.Iterator; import java.util.logging.Logger; import javax.jmi.reflect.RefPackage; import javax.jmi.xmi.MalformedXMIException; import uk.ac.ucl.cs.emofocl.jmi.extensions.Specification; import uk.ac.ucl.cs.emofocl.jmi.extensions.SpecificationClass; /** * @author jwskene */ public class <?= modelName ?>Factory { private static Logger LOGGER = Logger.getLogger(<?= modelName ?>Factory.class.getCanonicalName()) ; // meta-meta-model classes private static uk.ac.ucl.cs.emofocl.jmi.EMOFOCLModelPackage m3Classes = null; // meta-model private static Specification m2 = null; private static boolean metaLoaded = false; private static void loadMeta() { metaLoaded = true; try { LOGGER.info("Instantiate meta-meta-model"); <?java if(specification.getName().equals("EMOFOCLModel")) { ?>## m3Classes = (uk.ac.ucl.cs.emofocl.jmi.EMOFOCLModelPackage) uk.ac.ucl.cs.emofocl.jmi.EMOFOCLModelFactory.getModel(false); <?java } else { ?>## m3Classes = (uk.ac.ucl.cs.emofocl.jmi.EMOFOCLModelPackage) uk.ac.ucl.cs.emofocl.jmi.EMOFOCLModelFactory.getModel(true); <?java } ?>## LOGGER.info("Open meta-model"); URL uRL = <?= modelName ?>Factory.class.getResource( "<?= modelName ?>.xmi"); InputStream input = uRL.openStream(); LOGGER.info("Read meta-model"); uk.ac.ucl.cs.emofocl.jmi.EMOFOCLModelXMIReader reader = new uk.ac.ucl.cs.emofocl.jmi.EMOFOCLModelXMIReader(); reader.read(input, null, m3Classes); LOGGER.info("Find Model package element"); SpecificationClass specificationProxy = m3Classes.getExtensions().getSpecification(); Collection specifications = specificationProxy.refAllOfType(); Iterator it = specifications.iterator(); m2 = null; while(it.hasNext() && m2 == null) { Specification s = (Specification)it.next(); if(s.getName().equals("<?= specification.getName() ?>")) m2 = s; } if(m2 == null) System.err.println("Specification not found"); } catch(IOException iOE) { iOE.printStackTrace(); } catch(MalformedXMIException mXMIE) { mXMIE.printStackTrace(); } } public static Specification getMetaModel() { if(!metaLoaded) loadMeta(); return m2; } /** * @see uk.ac.ucl.cs.jmi.JMIFactory#getModel() */ public static RefPackage getModel(boolean meta) { if(meta) { if(!metaLoaded) loadMeta(); return new <?= modelImplType ?>(m2); } else return new <?= modelImplType ?>(null); } } <?java } } ?> |