/*
* 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.
*/
/*
* TypeChecker.java
* Created: Mar 5, 2003Feb 19, 2003 at 12:15:01 PM
* By: Raymond Cypher
*/
package org.openquark.cal.compiler;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.openquark.cal.machine.Module;
import org.openquark.cal.machine.Program;
import org.openquark.util.Pair;
/**
* This is the TypeChecker class/interface. It is the public interface of
* an object that clients use to do type checking.
*
* Created: Mar 5, 2003
* @author rcypher (extracted an interface from an existing class)
*/
public interface TypeChecker {
/**
* Get the types of all free gem parts in a graph - free inputs, free outputs, and trees.
*
* This generates a let expression which generates all free input and output types simultaneously when evaluated.
* Evaluation produces a type expression with arguments to the expression function yielding the types of the roots
* and free arguments in the graph.
*
* @param rootNodes Set the set of rootNodes in the graph to evaluate
* @param moduleName the name of the module in which the graph exists
* @return A pair of two maps:
* (CompositionNode.CompositionArg -> TypeExpr) Map from argument to its type.
* (CompositionNode -> List (of TypeExpr)) map from rootNode to the derived types for its definition..
* The types in the List are: argument types first (in order), then output.
* @throws TypeException
*/
public Pair<Map<CompositionNode.CompositionArgument, TypeExpr>, Map<CompositionNode, List<TypeExpr>>> checkGraph(Set<? extends CompositionNode> rootNodes, ModuleName moduleName, CompilerMessageLogger logger) throws TypeException;
/**
* Assuming that the main module has already been type checked using the check method, this
* methods checks if a new function definition is well typed. It uses the environment
* already built up while checking the main module. This method is intended to be called by
* tools, and so exceptions are suppressed.
*
* @return TypeExpr type of the defined function, or null if it is not well-typed
* @param function the adjunct source defining the function e.g. "add2 x = x + 2;"
* @param functionModule the module in which the function should be considered to be defined
*/
public TypeExpr checkFunction(AdjunctSource function, ModuleName functionModule, CompilerMessageLogger logger);
/**
* Get a TypeExpr from its string representation.
*
* Note: any compiler messages held by the compiler will be lost.
*
* @param typeString the string representation.
* @param workingModule the module in which the type exists.
* @return TypeExpr a TypeExpr representation of the string, or null if the string does not represent a valid type.
*/
public TypeExpr getTypeFromString(String typeString, ModuleName workingModule, CompilerMessageLogger logger);
/**
* Return a TypeCheckInfo object that bundles information necessary for doing type checking
* in a given module.
* @param moduleName
* @return TypeCheckInfo
*/
public TypeCheckInfo getTypeCheckInfo (ModuleName moduleName);
/**
* Parse the code text and return the list of identifiers that occur within it.
* This method is used for the initial syntax checking and qualification of
* text within a code gem.
*
* The identifiers returned include free symbols i.e. the symbols in the expression that
* are not defined within the expression itself (e.g. by a let definition). The free symbols can
* be either qualified (Prelude.x, Prelude.Boolean) or unqualified (True, Eq, sin). Those that are
* variables which do not successfully resolve to a top-level symbol must be arguments of the code
* expression.
*
* The list is ordered by increasing source positions of identifiers.
*
* Example:
* " let x :: Boolean; x = and Prelude.True False;
* in and x y ;"
* Returns identifiers : Boolean, and, Prelude.True, False, and, y
*
* Note: Any compiler messages held by the logger will be lost
*
* @param codeGemBodyText the text of the body of the code gem i.e. what the user actually typed
* @param moduleName the name of the module in which the code gem is considered to exist.
* @param moduleNameResolver the module name resolver for the module in which the code gem is considered to exist.
* @param logger the logger to use to log error messages.
* @return List (SourceIdentifier) the name, type and position of identifiers encountered in
* the expression. Returns null if the expression does not parse.
*/
public List<SourceIdentifier> findIdentifiersInExpression(String codeGemBodyText, ModuleName moduleName, ModuleNameResolver moduleNameResolver, CompilerMessageLogger logger);
/**
* Parses the specified expression and returns a copy of the expression with any references to the renamed entity updated.
* The changes may include renamings for references to the renamed symbol, and renamings for local variables if any
* conflict with the new name.
*
* Example:
* Renaming "s" to "r" in the expression
*
* "let r = 1.0;
* r2 = if (s r) then 2.0 else 0.0;
* in
* case x of
* (r, r3) -> and (s r) (r2 < r3);
* ;"
*
* Will return the following string:
*
* "let r3 = 1.0;
* r2 = if (r r3) then 2.0 else 0.0;
* in
* case x of
* (r4, r3) -> and (r r4) (r2 < r3);
* ;"
*
* @param codeExpression The text of the expression to update
* @param moduleName The name of the module that this expression belongs to
* @param moduleNameResolver the module name resolver for the module to which this expression belongs.
* @param qualificationMap The qualificationMap associated with this expression, or null if no such thing exists.
* @param oldName old name of the identifier
* @param newName new name of the identifier
* @param category category of the identifier
* @param logger message logger to hold any errors encountered
* @return True if changes were made to the expression
*/
public String calculateUpdatedCodeExpression (String codeExpression, ModuleName moduleName, ModuleNameResolver moduleNameResolver, CodeQualificationMap qualificationMap, QualifiedName oldName, QualifiedName newName, SourceIdentifier.Category category, CompilerMessageLogger logger);
/**
* A simple wrapper class to encapsulate the information needed to type check the text of a function.
* @author Edward Lam
*/
public final class TypeCheckInfo {
private final ModuleName moduleName;
private final TypeChecker typeChecker;
private final Program program;
/**
* Constructor for a TypeCheckInfo
* @param typeChecker the type checker
* @param moduleName the module name
* @param program
*/
TypeCheckInfo(ModuleName moduleName, TypeChecker typeChecker, Program program) {
if (moduleName == null || typeChecker == null || program == null) {
throw new NullPointerException();
}
this.moduleName = moduleName;
this.typeChecker = typeChecker;
this.program = program;
}
/**
* Returns the moduleName.
* @return the module name
*/
public ModuleName getModuleName() {
return moduleName;
}
/**
* Returns the typeChecker.
* @return TypeChecker the type checker
*/
public TypeChecker getTypeChecker() {
return typeChecker;
}
/**
* Get the ModuleTypeInfo for the current module in this info object.
* @return ModuleTypeInfo
*/
public final ModuleTypeInfo getModuleTypeInfo() {
Module module = program.getModule(moduleName);
if (module == null) {
return null;
}
return module.getModuleTypeInfo();
}
}
}