All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jaitools.jiffle.parser.AbstractSourceGenerator Maven / Gradle / Ivy

/* 
 *  Copyright (c) 2011, Michael Bedward. 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.   
 *   
 *  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 HOLDER 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. 
 */   

package org.jaitools.jiffle.parser;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.List;

import org.antlr.runtime.ANTLRStringStream;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.RecognizerSharedState;
import org.antlr.runtime.RuleReturnScope;
import org.antlr.runtime.Token;
import org.antlr.runtime.tree.TreeNodeStream;
import org.antlr.stringtemplate.StringTemplateGroup;

import org.jaitools.CollectionFactory;
import org.jaitools.jiffle.Jiffle;
import org.jaitools.jiffle.JiffleException;
import org.jaitools.jiffle.JiffleProperties;
import org.jaitools.jiffle.parser.CommentFinder;

/**
 * Base class for tree parsers that generate Jiffle runtime source.
 * 

* The runtime source generator is created from the ANTLR grammar * ({@code RuntimeSourceGenerator.g}. This class provides a small number * of common methods and fields. * * @author Michael Bedward * @since 0.1 * @version $Id$ */ public abstract class AbstractSourceGenerator extends ErrorHandlingTreeParser implements SourceGenerator { /** The runtime model to generate source for. */ protected Jiffle.RuntimeModel model; /** The package name to use for the runtime class. */ protected String pkgName; /** The imports to be included with the runtime class. */ protected List imports; /** The runtime class name. */ protected String className; /** The name of the base class for the runtime class. */ protected String baseClassName; /** A counter used in naming variables inserted into the runtime source. */ protected int varIndex = 0; /** * Constructor called by ANTLR. * * @param input AST node stream */ public AbstractSourceGenerator(TreeNodeStream input) { this(input, new RecognizerSharedState()); } /** * Constructor called by ANTLR. * * @param input AST node stream * @param state parser state (not used by Jiffle directly) */ protected AbstractSourceGenerator(TreeNodeStream input, RecognizerSharedState state) { super(input, state); this.pkgName = JiffleProperties.get(JiffleProperties.RUNTIME_PACKAGE_KEY); this.imports = CollectionFactory.list(); String value = JiffleProperties.get(JiffleProperties.IMPORTS_KEY); if (value != null && !(value.trim().length() == 0)) { this.imports.addAll( Arrays.asList( value.split(JiffleProperties.RUNTIME_IMPORTS_DELIM) ) ); } } /** * {@inheritDoc} */ public void setRuntimeModel(Jiffle.RuntimeModel model) { this.model = model; switch (model) { case DIRECT: className = JiffleProperties.get(JiffleProperties.DIRECT_CLASS_KEY); break; case INDIRECT: className = JiffleProperties.get(JiffleProperties.INDIRECT_CLASS_KEY); break; default: throw new IllegalArgumentException("Internal compiler error"); } } /** * {@inheritDoc} */ public void setBaseClassName(String baseClassName) { this.baseClassName = baseClassName; } /** * {@inheritDoc} */ public String getSource(String script) throws JiffleException { if (model == null) { throw new RuntimeException("Runtime model has not been set"); } if (baseClassName == null || baseClassName.trim().length() == 0) { throw new RuntimeException("Base class name has not been set"); } String commonTemplateFile = JiffleProperties.get(JiffleProperties.COMMON_SOURCE_TEMPLATES_KEY); String modelTemplateFile = null; switch (model) { case DIRECT: modelTemplateFile = JiffleProperties.get(JiffleProperties.DIRECT_SOURCE_TEMPLATES_KEY); break; case INDIRECT: modelTemplateFile = JiffleProperties.get(JiffleProperties.INDIRECT_SOURCE_TEMPLATES_KEY); break; } try { InputStream strm = AbstractSourceGenerator.class.getResourceAsStream(commonTemplateFile); InputStreamReader reader = new InputStreamReader(strm); StringTemplateGroup commonSTG = new StringTemplateGroup(reader); reader.close(); strm = AbstractSourceGenerator.class.getResourceAsStream(modelTemplateFile); reader = new InputStreamReader(strm); StringTemplateGroup modelSTG = new StringTemplateGroup(reader); setTemplateLib(modelSTG); reader.close(); } catch (Exception ex) { throw new RuntimeException(ex); } try { setErrorReporter(new DeferredErrorReporter()); return generate(script).getTemplate().toString(); } catch (RecognitionException ex) { if (errorReporter != null && errorReporter.getNumErrors() > 0) { throw new JiffleException(errorReporter.getErrors()); } else { throw new JiffleException( "Error creating runtime source. No details available."); } } } /** * Starts generating source code based on the abstract syntax tree * produced by the Jiffle compiler. * * @param script the Jiffle script to include in the class javadocs; * may be {@code null} or empty * * @return an ANTLR rule return object from which the results can be * retrieved * * @throws RecognitionException on errors processing the AST */ protected abstract RuleReturnScope generate(String script) throws RecognitionException; /** * Used internally to set the string templates for source generation. * Declared public to accord with the underlying ANTLR tree parser. * * @param templateLib source generation templates */ public abstract void setTemplateLib(StringTemplateGroup templateLib); /** * Looks up the runtime source for a Jiffle function. * * @param name function name * @param argTypes argument type names; null or empty for no-arg functions * * @return runtime source */ protected String getRuntimeExpr(String name, List argTypes) { try { return FunctionLookup.getRuntimeExpr(name, argTypes); } catch (UndefinedFunctionException ex) { throw new IllegalArgumentException(ex); } } /** * Looks up the runtime source for a Jiffle function. * * @param name function name * @param argTypes argument type names; null or empty for no-arg functions * * @return runtime source */ protected String getRuntimeExpr(String name, String ...argTypes) { return getRuntimeExpr(name, Arrays.asList(argTypes)); } /** * Gets the runtime source for a script option name:value pair. * * @param name option name * @param value option value * @return the runtime source */ protected String getOptionExpr(String name, String value) { try { return OptionLookup.getActiveRuntimExpr(name, value); } catch (UndefinedOptionException ex) { throw new IllegalArgumentException(ex); } } /** * Adds the given imports to those that will be included in the * runtime source. * * @param importNames fully qualified class names */ protected void addImport(String ...importNames) { for (String name : importNames) { boolean found = false; for (String imp : imports) { if (imp.equals(name)) { found = true; break; } } if (!found) { imports.add(name); } } } /** * Prepares the Jiffle source for inclusion in the run-time class javadocs. * Comments are stripped from the script and it is split into lines. * * @param script the Jiffle source * * @return prepared script as a list of lines */ protected List prepareScriptForComments(String script) { ANTLRStringStream stream = new ANTLRStringStream(script); CommentFinder finder = new CommentFinder(stream); Token tok = finder.nextToken(); while (tok.getType() != Token.EOF) { tok = finder.nextToken(); } List indices = finder.getStartEndIndices(); StringBuilder sb = new StringBuilder(); if (indices.isEmpty()) { sb.append(script); } else { int pos = 0; for (int i = 0; i < indices.size() && pos < script.length(); i += 2) { int start = indices.get(i); int end = indices.get(i+1); sb.append(script.substring(pos, start)); pos = end; } if (pos < script.length()) { sb.append(script.substring(pos, script.length())); } } String[] lines = sb.toString().split("[\n\r]+"); return Arrays.asList(lines); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy