/*
* 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.
*/
/*
* Optimizer_Test.java
* Creation date: (August 4th 2005 7:32:25 PM)
* By: Greg McClement
*/
package org.openquark.cal.compiler;
import java.util.TreeMap;
import junit.extensions.TestSetup;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.openquark.cal.compiler.Expression.RecordSelection;
import org.openquark.cal.compiler.io.EntryPoint;
import org.openquark.cal.compiler.io.EntryPointSpec;
import org.openquark.cal.internal.machine.lecc.JavaPackager.LECCMachineFunction;
import org.openquark.cal.internal.module.Cal.Core.CAL_Prelude_internal;
import org.openquark.cal.internal.module.Cal.Internal.CAL_Optimizer;
import org.openquark.cal.machine.CALExecutor;
import org.openquark.cal.machine.MachineFunction;
import org.openquark.cal.module.Cal.Collections.CAL_List;
import org.openquark.cal.module.Cal.Core.CAL_Prelude;
import org.openquark.cal.runtime.CALExecutorException;
import org.openquark.cal.runtime.ExecutionContext;
import org.openquark.cal.services.BasicCALServices;
import org.openquark.cal.services.CALServicesTestUtilities;
import org.openquark.cal.services.WorkspaceManager;
/**
* @author Greg McClement
*
* This code tests the optimizer related code paths in the compiler. There are two main
* areas.
*
* 1. The Java based optimizer code. This is tested by the function testJavaOptimizer.
* 2. The CAL based optimizer code. This is tested by the function testCALOptimizer. Currently this
* test is turned off because the data structure keep changing a little and I was tired of updating
* the code. Once the data strucures are stable I will fix the test up and enabled it.
*/
public class Optimizer_Test extends TestCase {
private final static Expression.Var prelude_id = new Expression.Var(CAL_Prelude.Functions.id);
private final static Expression.Var prelude_compose = new Expression.Var(CAL_Prelude.Functions.compose);
/**
* The CAL optimizer.
*/
private static CALExecutor optimizer_executor = null;
private static EntryPoint optimizer_entryPoint = null;
private static WorkspaceManager workspaceManager = null;
/**
* This will only be initialized if the optimizer is enabled.
*/
private static PreludeTypeConstants preludeTypeConstants = null;
private static DataConstructor nilDataCons = null;
private static DataConstructor consDataCons = null;
private static ModuleTypeInfo currentModuleTypeInfo = null;
/**
* @return a test suite containing all the test cases for testing CAL source
* generation.
*/
public static Test suite() {
TestSuite suite = new TestSuite(Optimizer_Test.class);
return new TestSetup(suite) {
@Override
protected void setUp() {
oneTimeSetUp();
}
@Override
protected void tearDown() {
oneTimeTearDown();
}
};
}
/**
* Performs the setup for the test suite.
*/
private static void oneTimeSetUp() {
initOptimizer();
}
/**
* Performs the tear down for the test suite.
*/
private static void oneTimeTearDown() {
optimizer_executor = null;
optimizer_entryPoint = null;
workspaceManager = null;
nilDataCons = null;
consDataCons = null;
currentModuleTypeInfo = null;
}
private Expression makeIdCall(Expression e){
return new Expression.Appl( prelude_id, e );
}
private Expression makeComposeCall(Expression g, Expression f, Expression x){
return new Expression.Appl(new Expression.Appl(new Expression.Appl(prelude_compose, g), f), x);
}
/**
* Load the CAL optimizer so I can run some expression through it for checking
* the effectiveness
*/
public static void initOptimizer(){
final ModuleName targetModule = CAL_Optimizer.MODULE_NAME;
final String defaultWorkspaceFile = "cal.optimizer.cws";
BasicCALServices calServices = CALServicesTestUtilities.makeUnsharedUnitTestCALServices(null, defaultWorkspaceFile, null, false);
calServices.getWorkspaceManager().useOptimizer(false);
CompilerMessageLogger messageLogger = new MessageLogger();
if (!calServices.compileWorkspace(null, messageLogger)) {
System.err.println(messageLogger.toString());
}
final ExecutionContext executionContext = calServices.getWorkspaceManager().makeExecutionContextWithDefaultProperties();
workspaceManager = calServices.getWorkspaceManager();
Compiler compiler = calServices.getCompiler();
optimizer_entryPoint = compiler.getEntryPoint(
EntryPointSpec.make(QualifiedName.make(ModuleName.make("Cal.Test.Internal.Optimizer_Test"), "unitTests")),
ModuleName.make("Cal.Test.Internal.Optimizer_Test"), messageLogger);
if (messageLogger.getNMessages() > 0) {
System.err.println(messageLogger.toString());
}
optimizer_executor = workspaceManager.makeExecutor(executionContext);
{
ModuleTypeInfo moduleTypeInfo = workspaceManager.getModuleTypeInfo(CAL_Prelude.MODULE_NAME);
preludeTypeConstants = new PreludeTypeConstants(moduleTypeInfo);
}
currentModuleTypeInfo = calServices.getCALWorkspace().getMetaModule(targetModule).getTypeInfo();
nilDataCons = currentModuleTypeInfo.getVisibleDataConstructor(CAL_Prelude.DataConstructors.Nil);
consDataCons = currentModuleTypeInfo.getVisibleDataConstructor(CAL_Prelude.DataConstructors.Cons);
}
Expression makeCall( Expression arg1, Expression arg2 ){
return new Expression.Appl(arg1, arg2);
}
Expression makeCall( Expression arg1, Expression arg2, Expression arg3 ){
return makeCall(makeCall(arg1, arg2), arg3);
}
Expression makeCall( Expression arg1, Expression arg2, Expression arg3, Expression arg4 ){
return makeCall(makeCall(makeCall(arg1, arg2), arg3), arg4);
}
Expression makeVar(ModuleName module, String function){
return new Expression.Var(QualifiedName.make(module, function));
}
Expression makeVar(FunctionalAgent entity){
return new Expression.Var(entity);
}
Expression makeInt(int value){
return new Expression.Literal( new Integer(value) );
}
/**
* Run the tests for the CAL transformation optimizer
*/
public void testCALOptimizer(){
try {
Object result = optimizer_executor.exec(optimizer_entryPoint, new Object[] { workspaceManager, preludeTypeConstants });
assertTrue(((Boolean) result).booleanValue());
} catch (CALExecutorException e) {
fail(e.toString());
}
}
/**
* Run the tests for the Java transformation optimizer.
*/
public void testJavaOptimizer() throws UnableToResolveForeignEntityException{
// test compose and id optimizations
{
Expression.Literal literal_dogdogdog = new Expression.Literal("dogdogdog");
Expression.Appl appl_compose_id = new Expression.Appl( prelude_compose, prelude_id );
Expression tuple_1_2;
{
TreeMap<FieldName, Expression> fieldMap1 = new TreeMap<FieldName, Expression>();
fieldMap1.put(FieldName.makeOrdinalField(1), new Expression.Literal(new Integer(1)));
fieldMap1.put(FieldName.makeOrdinalField(2), new Expression.Literal(new Integer(2)));
tuple_1_2 = new Expression.RecordExtension(null, fieldMap1);
}
Expression exprs[] = {
// 0. id id id "dogdogdog"
new Expression.Appl(
new Expression.Appl(
new Expression.Appl(prelude_id, prelude_id),
prelude_id
),
literal_dogdogdog
),
// 1. ((compose id) id id) "dogdogdog";
new Expression.Appl(
new Expression.Appl( new Expression.Appl( appl_compose_id, prelude_id ), prelude_id ),
literal_dogdogdog
),
// 2. ((compose id) id ((compose id) id id)) ((compose id) id "dogdogdog");
new Expression.Appl(
new Expression.Appl(new Expression.Appl( prelude_compose, prelude_id ), new Expression.Appl( new Expression.Appl( appl_compose_id, prelude_id ), prelude_id )),
new Expression.Appl(new Expression.Appl( appl_compose_id, prelude_id ), literal_dogdogdog)
),
// 3. emptyList => []
new Expression.Var(CAL_Prelude_internal.Functions.emptyList),
// 4. emptyString => ""
new Expression.Var(CAL_Prelude_internal.Functions.emptyString),
// 5. list0 => []
new Expression.Var(CAL_List.Functions.list0),
// 6. fst (1::Int, 2::Int) => (1::Int, 2::Int).#1
new Expression.Appl(
new Expression.Var(CAL_Prelude.Functions.fst),
tuple_1_2
),
// 7. asTypeOf 2 1::Int => 2
new Expression.Appl(
new Expression.Appl(
new Expression.Var(CAL_Prelude.Functions.asTypeOf),
new Expression.Literal( new Integer(2) ) ),
new Expression.Literal( new Integer(1) ) ),
// 8. const 2 1::Int => 2
new Expression.Appl(
new Expression.Appl(
new Expression.Var(CAL_Prelude.Functions.const_),
new Expression.Literal( new Integer(2) ) ),
new Expression.Literal( new Integer(1) ) ),
// 9. flip Cons Nil 1::Int => Cons 1::Int Nil
new Expression.Appl(
new Expression.Appl(
new Expression.Appl(
new Expression.Var(CAL_Prelude.Functions.flip),
new Expression.Var(consDataCons)),
new Expression.Var(nilDataCons)),
new Expression.Literal( new Integer(1) ) ),
// 10. flip (flip Cons) 1::Int Nil => Cons 1::Int Nil
new Expression.Appl(
new Expression.Appl(
new Expression.Appl(
new Expression.Var(CAL_Prelude.Functions.flip),
new Expression.Appl(new Expression.Var(CAL_Prelude.Functions.flip),new Expression.Var(consDataCons))),
new Expression.Literal( new Integer(1) )),
new Expression.Var(nilDataCons) ),
// 11. id( (id flip) (id ((id flip) (id Cons))) (id 1::Int) (id Nil)) => Cons 1::Int Nil
makeIdCall(new Expression.Appl(
makeIdCall(new Expression.Appl(
makeIdCall(new Expression.Appl(
makeIdCall(new Expression.Var(CAL_Prelude.Functions.flip)),
makeIdCall(new Expression.Appl(new Expression.Var(CAL_Prelude.Functions.flip),new Expression.Var(consDataCons))))),
makeIdCall(new Expression.Literal( new Integer(1) )))),
makeIdCall(new Expression.Var(nilDataCons) ))),
// 12. (compose id id flip) (compose id flip Cons) 1::Int Nil => Cons 1::Int Nil
new Expression.Appl(
new Expression.Appl(
new Expression.Appl(
makeComposeCall(prelude_id, prelude_id, new Expression.Var(CAL_Prelude.Functions.flip)),
makeComposeCall(prelude_id, new Expression.Var(CAL_Prelude.Functions.flip),new Expression.Var(consDataCons))),
new Expression.Literal( new Integer(1) )),
new Expression.Var(nilDataCons) ),
// 13. snd (1::Int, 2::Int) => (1::Int, 2::Int).#2
new Expression.Appl(
new Expression.Var(CAL_Prelude.Functions.snd ),
tuple_1_2),
// 14. field1 (1::Int, 2::Int) => (1::Int, 2::Int).#1
new Expression.Appl(
new Expression.Var( CAL_Prelude.Functions.field1 ),
tuple_1_2),
// 15. field2 (1::Int, 2::Int) => (1::Int, 2::Int).#2
new Expression.Appl(
new Expression.Var( CAL_Prelude.Functions.field2 ),
tuple_1_2),
};
for(int i = 0; i < exprs.length; ++i){
String[] formalParameters = {};
boolean[] parameterStrictness = {};
TypeExpr[] parameterTypes = {};
CoreFunction cf = CoreFunction.makeCALCoreFunction(
QualifiedName.make(CAL_Prelude.MODULE_NAME, "dogdogdog1"),
formalParameters,
parameterStrictness,
parameterTypes,
new TypeVar(),
1123191938810L
);
MachineFunction mf = new LECCMachineFunction(cf);
ExpressionAnalyzer analyzer = new ExpressionAnalyzer(currentModuleTypeInfo, mf);
Expression exprOptimized = analyzer.transformExpression(exprs[i]);
switch(i){
case 0:
case 1:
case 2:
assertTrue( literal_dogdogdog.equals(exprOptimized) );
break;
case 3:
case 5:
assertTrue( exprOptimized.asVar() != null );
assertTrue( exprOptimized.asVar().getFunctionalAgent() == nilDataCons);
break;
case 4:
assertTrue( exprOptimized.asLiteral() != null );
assertTrue( exprOptimized.asLiteral().getLiteral().equals(""));
break;
case 6:
case 14:
{
RecordSelection rs = exprOptimized.asRecordSelection();
assertTrue( rs != null );
FieldName.Ordinal ordinal = (FieldName.Ordinal) rs.getFieldName();
assertTrue(ordinal.getOrdinal() == 1);
assertTrue(rs.getRecordExpr() == tuple_1_2);
}
break;
case 7:
case 8:
assertTrue( exprOptimized.asLiteral() != null );
assertTrue(((Integer) exprOptimized.asLiteral().getLiteral()).intValue() == 2);
break;
case 9:
case 10:
case 11:
case 12:
{
Expression.Appl a = exprOptimized.asAppl();
assertTrue( a != null );
Expression.Appl a_1 = a.getE1().asAppl();
assertTrue( a_1 != null );
Expression.Var v_1_1 = a_1.getE1().asVar();
assertTrue( v_1_1 != null );
assertTrue( v_1_1.getFunctionalAgent() == consDataCons);
Expression.Literal v_1_2 = a_1.getE2().asLiteral();
assertTrue( v_1_2 != null );
assertTrue(((Integer) v_1_2.getLiteral()).intValue() == 1);
Expression.Var v_2 = a.getE2().asVar();
assertTrue( v_2 != null );
assertTrue( v_2.getFunctionalAgent() == nilDataCons);
}
break;
case 13:
case 15:
{
RecordSelection rs = exprOptimized.asRecordSelection();
assertTrue( rs != null );
FieldName.Ordinal ordinal = (FieldName.Ordinal) rs.getFieldName();
assertTrue(ordinal.getOrdinal() == 2);
assertTrue(rs.getRecordExpr() == tuple_1_2);
}
break;
}
}
}
}
}