/* * Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED * 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 Business Objects 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. */ /* * Target.java * Creation date: (11/05/01 11:39:38 AM) * By: Edward Lam */ package org.openquark.cal.valuenode; import java.util.ArrayList; import java.util.List; import org.openquark.cal.compiler.AdjunctSource; import org.openquark.cal.compiler.ModuleTypeInfo; import org.openquark.cal.compiler.Scope; import org.openquark.cal.compiler.SourceModel; import org.openquark.cal.compiler.SourceModelUtilities; import org.openquark.cal.compiler.TypeExpr; /** * An interface to a target that can be run by a target runner. * @author Edward Lam */ public abstract class Target { /* * TODOEL: When we can handle running an adjunct which has the same name as an existing sc in the current module, * remove the name-disambiguation code. */ /** The default name to use for the code generated for the target sc. */ private final String defaultSCName; /** * A simple Target with no arguments. * @author Edward Lam */ public static class SimpleTarget extends Target { /** The default name of the sc to use. */ private static final String defaultSCName = CALRunner.TEST_SC_NAME; /** The body of the target definition. */ private final SourceModel.Expr scBody; /** * Constructor for a SimpleTarget * @param scBody the body of the target sc defn. */ public SimpleTarget(String scBody) { this(SourceModelUtilities.TextParsing.parseExprIntoSourceModel(scBody)); } /** * Constructor for a SimpleTarget * @param scBody the body of the target sc defn. */ public SimpleTarget(SourceModel.Expr scBody) { // Just use a default defaultName. super(defaultSCName); // SCDefn: name = body; this.scBody = scBody; } /** * {@inheritDoc} */ @Override protected SourceModel.FunctionDefn getSCDefn(String scName) { return SourceModel.FunctionDefn.Algebraic.make(scName, Scope.PRIVATE, null, scBody); } } /** * Constructor for a Target. * @param defaultName the default name to use for the generated target's definition. * This name will be used as the basis for the name passed to getSCDefn(). */ protected Target(String defaultName) { this.defaultSCName = defaultName; } /** * Get the name that will be used for the generated sc. * @return the name that will be used for the generated sc. */ protected String getTargetName(ModuleTypeInfo currentModuleTypeInfo) { // The default implementation attempts to disambiguate the name with respect to the current module. return getSCName(defaultSCName, currentModuleTypeInfo); } /** * Get the SCDefinition. * @param scName the name of the sc. * @return the SCDefinition. */ protected abstract SourceModel.FunctionDefn getSCDefn(String scName); /** * Return the target definition as specified by the Gem tree rooted at the Target. * This will include the sc declaration (if any) plus its definition. * @param declaredType the declared type, if any. If null, a type declaration will not be included. * @param currentModuleTypeInfo if null, the target's default name may be used (the name of the target will not be changed). * @return AdjunctSource the definition of the supercombinator */ public AdjunctSource.FromSourceModel getTargetDef(TypeExpr declaredType, ModuleTypeInfo currentModuleTypeInfo) { return new AdjunctSource.FromSourceModel( getTargetSource(declaredType, currentModuleTypeInfo).toArray(new SourceModel.TopLevelSourceElement[0])); } /** * Return the target definition as a list of top level source models * This will include the sc declaration (if any) plus its definition. * @param declaredType the declared type, if any. If null, a type declaration will not be included. * @param currentModuleTypeInfo if null, the target's default name may be used (the name of the target will not be changed). * @return list of source model elements */ public List<SourceModel.TopLevelSourceElement> getTargetSource(TypeExpr declaredType, ModuleTypeInfo currentModuleTypeInfo) { List<SourceModel.TopLevelSourceElement> scDef = new ArrayList<SourceModel.TopLevelSourceElement>(); // Append the declared type if any. String scName = getTargetName(currentModuleTypeInfo); if (declaredType != null) { scDef.add(SourceModel.FunctionTypeDeclaration.make(scName, declaredType.toSourceModel())); } // Append the body.. scDef.add(getSCDefn(scName)); return scDef; } /** * Get a non-conflicting sc name to use. * The generated name of the target will be based on defaultName, but disambiguated such that its name does not conflict with * other sc's in the current module. * @param defaultName the default name to use for the generated target's definition. * @param currentModuleTypeInfo the ModuleTypeInfo for the module in which the target will be defined. * If null, the target's default name may be used (the name of the target will not be changed). * @return a name to use for the sc. */ private static String getSCName(String defaultName, ModuleTypeInfo currentModuleTypeInfo) { if (currentModuleTypeInfo == null) { return defaultName; } // Generate a name for the sc which does not conflict with any of the sc's in the current module. String candidateSCName = defaultName; int nextIndex = 2; while (currentModuleTypeInfo.getFunctionalAgent(candidateSCName) != null) { candidateSCName = defaultName + "_" + nextIndex; nextIndex++; } return candidateSCName; } }