/*
* 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.
*/
/*
* DataConstructorCode_Test.java
* Creation date: Jul 13, 2005.
* By: Edward Lam
*/
package org.openquark.cal.compiler;
import java.util.Arrays;
import java.util.List;
import junit.extensions.TestSetup;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.openquark.cal.CALPlatformTestModuleNames;
import org.openquark.cal.compiler.SourceModel.TypeConstructorDefn.AlgebraicType.DataConsDefn;
import org.openquark.cal.module.Cal.Core.CAL_Prelude;
import org.openquark.cal.runtime.CALExecutorException;
import org.openquark.cal.runtime.MachineType;
import org.openquark.cal.services.BasicCALServices;
import org.openquark.cal.services.CALServicesTestUtilities;
import org.openquark.cal.services.GemCompilationException;
import org.openquark.cal.services.Status;
import org.openquark.cal.services.StringModuleSourceDefinition;
import org.openquark.cal.services.WorkspaceManager;
/**
* A set of JUnit test cases for verifying the static analysis of data constructors in .cal code.
* Note: these tests test for failure cases -- we can include cases which should succeed as part of actual module code (eg. M2.cal).
*
* @author Edward Lam
*/
public class DataConstructorCode_Test extends TestCase {
private static final ModuleName Prelude = CAL_Prelude.MODULE_NAME;
/**
* A copy of CAL services for use in the test cases.
*/
private static BasicCALServices leccCALServices;
private static final ModuleName DEFAULT_TEST_MODULE_NAME = ModuleName.make("DataConstructorCodeTestModule");
private static final String DEFAULT_TEST_FUNCTION_NAME = "dataConstructorCodeTestFunction";
private static final String DEFAULT_DATA_CONS_NAME = "DataConstructorCodeTestType";
private static final SourceModel.Name.DataCons DEFAULT_DATA_CONS_QUALIFIED_NAME =
SourceModel.Name.DataCons.make(QualifiedName.make(DEFAULT_TEST_MODULE_NAME, DEFAULT_DATA_CONS_NAME));
/**
* @return a test suite containing all the test cases for testing CAL source
* generation.
*/
public static Test suite() {
TestSuite suite = new TestSuite(DataConstructorCode_Test.class);
return new TestSetup(suite) {
protected void setUp() {
oneTimeSetUp();
}
protected void tearDown() {
oneTimeTearDown();
}
};
}
/**
* Performs the setup for the test suite.
*/
private static void oneTimeSetUp() {
leccCALServices = CALServicesTestUtilities.getCommonCALServices(MachineType.LECC, "cal.platform.test.cws");
}
/**
* Performs the tear down for the test suite.
*/
private static void oneTimeTearDown() {
leccCALServices = null;
}
/**
* Constructor for DataConstructorCode_Test.
*
* @param name
* the name of the test.
*/
public DataConstructorCode_Test(String name) {
super(name);
}
/**
* Tests that an argument name can't be used twice for a data constructor.
*/
public void testRepeatedDataConstructorArgumentNameFails() {
// Field names {foo, foo, bar} -- field name "foo" is repeated.
String[] textualFieldNames = new String[] {"foo", "foo", "bar"};
// Create the type constructor with the data cons definition.
SourceModel.TypeConstructorDefn typeConsDefn = getSingleDataConstructorTypeConstructorDefinition(textualFieldNames);
// Compile as a new module.
CompilerMessageLogger logger = compileAndRemoveModuleForTopLevelSourceElements(DEFAULT_TEST_MODULE_NAME, new SourceModel.TopLevelSourceElement[]{typeConsDefn});
// Check that we got an error message of the expected type.
CompilerMessage error = logger.getFirstError();
assertTrue("No errors logged.", error != null);
assertEquals(MessageKind.Error.RepeatedFieldNameInDataConstructorDeclaration.class, error.getMessageKind().getClass());
}
/**
* Tests that an error is given for unknown field names when using the matching notation for data constructor unpacking.
* eg. where SomeDataCons does not have an argument named "unknownDataConsArg":
* myFunction arg = case arg of SomeDataCons {unknownDataConsArg = patternVar} -> patternVar;;
*/
public void testMatchingUnknownDataConstructorArgument() {
// Create the type constructor definition..
String[] textualFieldNames = new String[] {"foo", "bar"};
SourceModel.TypeConstructorDefn typeConsDefn = getSingleDataConstructorTypeConstructorDefinition(textualFieldNames);
// Create a case alt for a data constructor using the matching notation, where a field name is unknown.
FieldName fieldName = FieldName.make("unknownFieldName");
SourceModel.Pattern pattern = SourceModel.Pattern.Var.make("unusedPatternVar");
SourceModel.FieldPattern fieldPattern = SourceModel.FieldPattern.make(SourceModel.Name.Field.make(fieldName), pattern);
SourceModel.FieldPattern[] fieldPatterns = new SourceModel.FieldPattern[] {fieldPattern};
SourceModel.Expr.Case.Alt caseAlt =
SourceModel.Expr.Case.Alt.UnpackDataCons.make(DEFAULT_DATA_CONS_QUALIFIED_NAME, fieldPatterns, SourceModel.Expr.makeBooleanValue(true));
// Put into a case expression (conditional upon "var"), wrap with a function.
SourceModel.Expr.Var varExpr = SourceModel.Expr.Var.makeUnqualified("var");
SourceModel.Expr.Case caseExpr = SourceModel.Expr.Case.make(varExpr, new SourceModel.Expr.Case.Alt[]{caseAlt});
SourceModel.Parameter[] parameters = new SourceModel.Parameter[] {SourceModel.Parameter.make("var", false)};
SourceModel.FunctionDefn functionDefn =
SourceModel.FunctionDefn.Algebraic.make(DEFAULT_TEST_FUNCTION_NAME, Scope.PRIVATE, parameters, caseExpr);
// Compile our elements to a new module.
SourceModel.TopLevelSourceElement[] topLevelSourceElements = new SourceModel.TopLevelSourceElement[]{typeConsDefn, functionDefn};
CompilerMessageLogger logger = compileAndRemoveModuleForTopLevelSourceElements(DEFAULT_TEST_MODULE_NAME, topLevelSourceElements);
// Check that we got an error message of the expected type.
CompilerMessage error = logger.getFirstError();
assertTrue("No errors logged.", error != null);
assertEquals(MessageKind.Error.UnknownDataConstructorField.class, error.getMessageKind().getClass());
}
/**
* Tests that an error is given for repeated field names when using the matching notation for data constructor unpacking.
* eg. myFunction arg = case arg of SomeDataCons {repeatedFieldName = patternVar1, repeatedFieldName = patternVar2} -> True;;
*/
public void testRepeatedFieldNameInFieldBinding() {
// Create the type constructor definition..
String[] textualFieldNames = new String[] {"foo", "bar"};
SourceModel.TypeConstructorDefn typeConsDefn = getSingleDataConstructorTypeConstructorDefinition(textualFieldNames);
// Create a case alt for a data constructor using the matching notation, with two field patterns where the field names are the same.
FieldName repeatedFieldName = FieldName.make("foo");
SourceModel.Pattern pattern1 = SourceModel.Pattern.Var.make("unusedPatternVar1");
SourceModel.Pattern pattern2 = SourceModel.Pattern.Var.make("unusedPatternVar2");
SourceModel.FieldPattern fieldPattern1 = SourceModel.FieldPattern.make(SourceModel.Name.Field.make(repeatedFieldName), pattern1);
SourceModel.FieldPattern fieldPattern2 = SourceModel.FieldPattern.make(SourceModel.Name.Field.make(repeatedFieldName), pattern2);
SourceModel.FieldPattern[] fieldPatterns = new SourceModel.FieldPattern[] {fieldPattern1, fieldPattern2};
SourceModel.Expr.Case.Alt caseAlt =
SourceModel.Expr.Case.Alt.UnpackDataCons.make(DEFAULT_DATA_CONS_QUALIFIED_NAME, fieldPatterns, SourceModel.Expr.makeBooleanValue(true));
// Put into a case expression (conditional upon "var")
SourceModel.Expr.Case caseExpr = SourceModel.Expr.Case.make(SourceModel.Expr.Var.makeUnqualified("var"),
new SourceModel.Expr.Case.Alt[]{caseAlt});
// wrap with a function.
SourceModel.Parameter[] parameters = new SourceModel.Parameter[] {SourceModel.Parameter.make("var", false)};
SourceModel.FunctionDefn functionDefn =
SourceModel.FunctionDefn.Algebraic.make(DEFAULT_TEST_FUNCTION_NAME, Scope.PRIVATE, parameters, caseExpr);
// Compile our elements to a new module.
SourceModel.TopLevelSourceElement[] topLevelSourceElements = new SourceModel.TopLevelSourceElement[]{typeConsDefn, functionDefn};
CompilerMessageLogger logger = compileAndRemoveModuleForTopLevelSourceElements(DEFAULT_TEST_MODULE_NAME, topLevelSourceElements);
// Check that we got a single error message of the expected type.
CompilerMessage error = logger.getFirstError();
assertTrue("No errors logged.", error != null);
assertEquals(MessageKind.Error.RepeatedFieldNameInFieldBindingPattern.class, error.getMessageKind().getClass());
}
// repeated pattern variable in field binding.
/**
* Tests that an error is given for repeated pattern variables when using the matching notation for data constructor unpacking.
* eg. myFunction arg = case arg of SomeDataCons {dataConsArg1 = repeatedPatternVar, dataConsArg2 = repeatedPatternVar} -> True;;
*/
public void testRepeatedPatternVarInFieldBinding() {
// Create the type constructor definition..
String[] textualFieldNames = new String[] {"foo", "bar"};
SourceModel.TypeConstructorDefn typeConsDefn = getSingleDataConstructorTypeConstructorDefinition(textualFieldNames);
// Create a case alt for a data constructor using the matching notation, with two field patterns where the field names are the same.
FieldName fieldName1 = FieldName.make("foo");
FieldName fieldName2 = FieldName.make("bar");
SourceModel.Pattern repeatedPattern = SourceModel.Pattern.Var.make("repeatedPatternVar");
SourceModel.FieldPattern fieldPattern1 = SourceModel.FieldPattern.make(SourceModel.Name.Field.make(fieldName1), repeatedPattern);
SourceModel.FieldPattern fieldPattern2 = SourceModel.FieldPattern.make(SourceModel.Name.Field.make(fieldName2), repeatedPattern);
SourceModel.FieldPattern[] fieldPatterns = new SourceModel.FieldPattern[] {fieldPattern1, fieldPattern2};
SourceModel.Expr.Case.Alt caseAlt =
SourceModel.Expr.Case.Alt.UnpackDataCons.make(DEFAULT_DATA_CONS_QUALIFIED_NAME, fieldPatterns, SourceModel.Expr.makeBooleanValue(true));
// Put into a case expression (conditional upon "var")
SourceModel.Expr.Case caseExpr = SourceModel.Expr.Case.make(SourceModel.Expr.Var.makeUnqualified("var"),
new SourceModel.Expr.Case.Alt[]{caseAlt});
// wrap with a function.
SourceModel.Parameter[] parameters = new SourceModel.Parameter[] {SourceModel.Parameter.make("var", false)};
SourceModel.FunctionDefn functionDefn =
SourceModel.FunctionDefn.Algebraic.make(DEFAULT_TEST_FUNCTION_NAME, Scope.PRIVATE, parameters, caseExpr);
// Compile our elements to a new module.
SourceModel.TopLevelSourceElement[] topLevelSourceElements = new SourceModel.TopLevelSourceElement[]{typeConsDefn, functionDefn};
CompilerMessageLogger logger = compileAndRemoveModuleForTopLevelSourceElements(DEFAULT_TEST_MODULE_NAME, topLevelSourceElements);
// Check that we got an error message of the expected type.
CompilerMessage error = logger.getFirstError();
assertTrue("No errors logged.", error != null);
assertEquals(MessageKind.Error.RepeatedPatternVariableInFieldBindingPattern.class, error.getMessageKind().getClass());
}
/**
* Helper function to get a source model for a type constructor consisting of a single data constructor with the given fields.
* Each of the fields will have the Unit type, so the type constructor will take a single parameter of type Unit.
*
* @param textualFieldNames the names of the fields. These must be valid textual field names.
* @return the source model for the corresponding type constructor.
*/
private static SourceModel.TypeConstructorDefn getSingleDataConstructorTypeConstructorDefinition(String[] textualFieldNames) {
// Create the field names.
FieldName[] fieldNames = new FieldName[textualFieldNames.length];
for (int i = 0; i < fieldNames.length; i++) {
fieldNames[i] = FieldName.make(textualFieldNames[i]);
}
// Create the type arguments.
DataConsDefn.TypeArgument[] typeArguments = new DataConsDefn.TypeArgument[fieldNames.length];
for (int i = 0; i < fieldNames.length; i++) {
typeArguments[i] = DataConsDefn.TypeArgument.make(SourceModel.Name.Field.make(fieldNames[i]), SourceModel.TypeExprDefn.Unit.make(), false);
}
// Create the data constructor definition.
DataConsDefn dataConsDefnWithRepeatedArgName = DataConsDefn.make(DEFAULT_DATA_CONS_NAME, Scope.PRIVATE, typeArguments);
// Create the type constructor with the data cons definition.
SourceModel.TypeConstructorDefn typeConsDefn =
SourceModel.TypeConstructorDefn.AlgebraicType.make(DEFAULT_DATA_CONS_NAME, Scope.PRIVATE, null,
new DataConsDefn[]{dataConsDefnWithRepeatedArgName},
SourceModel.TypeConstructorDefn.NO_DERIVING_CLAUSE);
return typeConsDefn;
}
/**
* Check that a given set of outer defns gives a compile error when compiled to a module.
* @param outerDefnTextLines the lines of text of the outer defns.
* @param expectedErrorClass the class of the expected error.
*/
private static void checkDefnForExpectedError(String[] outerDefnTextLines, Class<? extends MessageKind.Error> expectedErrorClass) {
CompilerTestUtilities.checkDefnForExpectedError(outerDefnTextLines, expectedErrorClass, leccCALServices);
}
/**
* Compile a new module containing only the provided top-level source elements, plus required imports, and remove it afterwards.
* @param moduleName the name of the module.
* @param topLevelSourceElements the top-level source elements to include.
* @return a logger which logged the results of the compile.
*/
private static CompilerMessageLogger compileAndRemoveModuleForTopLevelSourceElements(ModuleName moduleName, SourceModel.TopLevelSourceElement[] topLevelSourceElements) {
// Get the workspace manager and the logger.
WorkspaceManager workspaceManager = leccCALServices.getWorkspaceManager();
CompilerMessageLogger logger = new MessageLogger();
// Get the module defn.
SourceModel.ModuleDefn moduleDefnWithoutImports = SourceModel.ModuleDefn.make(moduleName, new SourceModel.Import[0], topLevelSourceElements);
SourceModel.ModuleDefn moduleDefn = SourceModelUtilities.ImportAugmenter.augmentWithImports(moduleDefnWithoutImports);
// Compile the module.
SourceModelModuleSource moduleSource = new SourceModelModuleSource(moduleDefn);
workspaceManager.makeModule(moduleSource, logger);
// Remove the module.
leccCALServices.getWorkspaceManager().removeModule(DEFAULT_TEST_MODULE_NAME, new Status("Remove module status."));
return logger;
}
/**
* Test that a data constructor argument without a field name gives an error.
*/
public void testUnnamedDCArgError() {
// Get the workspace manager and the logger.
WorkspaceManager workspaceManager = leccCALServices.getWorkspaceManager();
CompilerMessageLogger logger = new MessageLogger();
ModuleName moduleName = DEFAULT_TEST_MODULE_NAME;
final String moduleCode =
"module " + DEFAULT_TEST_MODULE_NAME + ";" +
"import " + Prelude + ";" +
"data Foo = Foo " + Prelude + ".Int;";
// Compile the module.
ModuleSourceDefinition moduleSourceDef = new StringModuleSourceDefinition(moduleName, moduleCode);
workspaceManager.makeModule(moduleSourceDef, logger);
// Remove the module.
leccCALServices.getWorkspaceManager().removeModule(DEFAULT_TEST_MODULE_NAME, new Status("Remove module status."));
// Check that we got an error message of the expected type.
// Note: this can only check for a syntax error. However, there are many ways in which a syntax error can occur.
CompilerMessage error = logger.getFirstError();
assertTrue("No errors logged.", error != null);
assertEquals(MessageKind.Error.SyntaxErrorWithParaphrase.class, error.getMessageKind().getClass());
}
/**
* Check that an error is given if, in a data constructor field selection expression, the dataCons-valued expression
* doesn't evaluate to the expected data constructor.
*
* ie. "[].Cons.head" should give a runtime error, since the data constructor for "[]" is "Nil".
*
*/
public void testUnexpectedDCForSelectDCFieldExpr() throws GemCompilationException {
try {
CALServicesTestUtilities.runNamedFunction(QualifiedName.make(CALPlatformTestModuleNames.M2, "selectDCFieldShouldFail"), leccCALServices);
fail("This should have failed");
} catch (CALExecutorException e){
// Can't check position - no position information because the call is evaluated lazily.
}
}
/**
* Check for an error when the field name is not valid for a selectDCField expression.
*/
public void testUnknownDCFieldNameInSelectDCFieldExpr() {
{
CompilerMessageLogger logger = compileSelectDCExprFromSingleElementDoubleList("hd");
// Check that we got an error message of the expected type.
CompilerMessage error = logger.getFirstError();
assertTrue("No errors logged.", error != null);
assertEquals(MessageKind.Error.UnknownDataConstructorField.class, error.getMessageKind().getClass());
}
{
CompilerMessageLogger logger = compileSelectDCExprFromSingleElementDoubleList("#1");
// Check that we got an error message of the expected type.
CompilerMessage error = logger.getFirstError();
assertTrue("No errors logged.", error != null);
assertEquals(MessageKind.Error.UnknownDataConstructorField.class, error.getMessageKind().getClass());
}
}
/**
* A helper method for tests of errors in field selection.
* Creates and compiles a function of the form:
* someFunctionName = [1.0].Cons.(calSourceFormFieldName);
*
* @param calSourceFormFieldName the cal source form of the field to select.
* @return the message logger resulting from the compile
*/
private CompilerMessageLogger compileSelectDCExprFromSingleElementDoubleList(String calSourceFormFieldName) {
SourceModel.Expr dataConsValuedExpr = SourceModel.Expr.List.make(new SourceModel.Expr[]{SourceModel.Expr.makeDoubleValue(1.0)});
SourceModel.Name.DataCons dataConsName = SourceModel.Name.DataCons.make(Prelude, CAL_Prelude.DataConstructors.Cons.getUnqualifiedName());
SourceModel.Expr selectDCExpr = SourceModel.Expr.SelectDataConsField.make(dataConsValuedExpr, dataConsName, SourceModel.Name.Field.make(FieldName.make(calSourceFormFieldName)));
SourceModel.FunctionDefn functionDefn =
SourceModel.FunctionDefn.Algebraic.make(DEFAULT_TEST_FUNCTION_NAME, Scope.PRIVATE, null, selectDCExpr);
// Compile our elements to a new module.
SourceModel.TopLevelSourceElement[] topLevelSourceElements = new SourceModel.TopLevelSourceElement[]{functionDefn};
CompilerMessageLogger logger = compileAndRemoveModuleForTopLevelSourceElements(DEFAULT_TEST_MODULE_NAME, topLevelSourceElements);
return logger;
}
/**
* Check for an error when an incorrect number of args appears in a case alt using pattern group syntax.
*/
public void testIncorrectNArgsWithPatternGroup() {
String[][] dcFieldNames = new String[][] {
{"foo", "bar"},
{"foo"},
{"qux"}
};
SourceModel.TypeConstructorDefn typeConsDefn = getTypeConstructorDefinition(dcFieldNames);
/*
* foo var =
* case var of
* ( (DEFAULT_DATA_CONS_NAME)0 | (DEFAULT_DATA_CONS_NAME)1 ) foo bar -> True;
* ;
*/
{
SourceModel.Name.DataCons[] dataConsNames = new SourceModel.Name.DataCons[] {
SourceModel.Name.DataCons.make(QualifiedName.make(DEFAULT_TEST_MODULE_NAME, DEFAULT_DATA_CONS_NAME + 0)),
SourceModel.Name.DataCons.make(QualifiedName.make(DEFAULT_TEST_MODULE_NAME, DEFAULT_DATA_CONS_NAME + 1))
};
// Create a case alt using positional notation, where the names are the same.
SourceModel.Pattern.Var[] patterns = {
SourceModel.Pattern.Var.make("foo"),
SourceModel.Pattern.Var.make("bar")
};
SourceModel.Expr.Case.Alt caseAlt =
SourceModel.Expr.Case.Alt.UnpackDataCons.make(dataConsNames, patterns, SourceModel.Expr.makeBooleanValue(true));
// Put into a case expression (conditional upon "var"), wrap with a function.
SourceModel.Expr.Var varExpr = SourceModel.Expr.Var.makeUnqualified("var");
SourceModel.Expr.Case caseExpr = SourceModel.Expr.Case.make(varExpr, new SourceModel.Expr.Case.Alt[]{caseAlt});
SourceModel.Parameter[] parameters = new SourceModel.Parameter[] {SourceModel.Parameter.make("var", false)};
SourceModel.FunctionDefn functionDefn =
SourceModel.FunctionDefn.Algebraic.make(DEFAULT_TEST_FUNCTION_NAME, Scope.PRIVATE, parameters, caseExpr);
// Compile our elements to a new module.
SourceModel.TopLevelSourceElement[] topLevelSourceElements = new SourceModel.TopLevelSourceElement[]{typeConsDefn, functionDefn};
CompilerMessageLogger logger = compileAndRemoveModuleForTopLevelSourceElements(DEFAULT_TEST_MODULE_NAME, topLevelSourceElements);
// Check that we got a single error message of the expected type.
CompilerMessage error = logger.getFirstError();
assertTrue("No errors logged.", error != null);
assertEquals(MessageKind.Error.ConstructorMustHaveExactlyNArgsInPattern.class, error.getMessageKind().getClass());
}
}
/**
* Check for an error when a repeated pattern appears in a case alt using pattern group syntax.
*/
public void testRepeatedPatternWithPatternGroup() {
String[][] dcFieldNames = new String[][] {
{"foo", "bar"},
{"baz"},
{"qux"}
};
SourceModel.TypeConstructorDefn typeConsDefn = getTypeConstructorDefinition(dcFieldNames);
/*
* Repeated within an individual group.
*
* foo var =
* case var of
* ( (DEFAULT_DATA_CONS_NAME)0 | (DEFAULT_DATA_CONS_NAME)0 ) {} -> True;
* ;
*/
{
SourceModel.Name.DataCons[] dataConsNames = {
SourceModel.Name.DataCons.make(QualifiedName.make(DEFAULT_TEST_MODULE_NAME, DEFAULT_DATA_CONS_NAME + 0)),
SourceModel.Name.DataCons.make(QualifiedName.make(DEFAULT_TEST_MODULE_NAME, DEFAULT_DATA_CONS_NAME + 0))
};
SourceModel.FieldPattern[] fieldPatterns = SourceModel.FieldPattern.NO_FIELD_PATTERNS;
SourceModel.Expr.Case.Alt caseAlt =
SourceModel.Expr.Case.Alt.UnpackDataCons.make(dataConsNames, fieldPatterns, SourceModel.Expr.makeBooleanValue(true));
// Put into a case expression (conditional upon "var"), wrap with a function.
SourceModel.Expr.Var varExpr = SourceModel.Expr.Var.makeUnqualified("var");
SourceModel.Expr.Case caseExpr = SourceModel.Expr.Case.make(varExpr, new SourceModel.Expr.Case.Alt[]{caseAlt});
SourceModel.Parameter[] parameters = new SourceModel.Parameter[] {SourceModel.Parameter.make("var", false)};
SourceModel.FunctionDefn functionDefn =
SourceModel.FunctionDefn.Algebraic.make(DEFAULT_TEST_FUNCTION_NAME, Scope.PRIVATE, parameters, caseExpr);
// Compile our elements to a new module.
SourceModel.TopLevelSourceElement[] topLevelSourceElements = new SourceModel.TopLevelSourceElement[]{typeConsDefn, functionDefn};
CompilerMessageLogger logger = compileAndRemoveModuleForTopLevelSourceElements(DEFAULT_TEST_MODULE_NAME, topLevelSourceElements);
// Check that we got a single error message of the expected type.
CompilerMessage error = logger.getFirstError();
assertTrue("No errors logged.", error != null);
assertEquals(MessageKind.Error.RepeatedPatternInCaseExpression.class, error.getMessageKind().getClass());
}
/*
* Repeated among separate groups.
*
* foo var =
* case var of
* ( (DEFAULT_DATA_CONS_NAME)0 | (DEFAULT_DATA_CONS_NAME)1 ) {} -> True;
* ( (DEFAULT_DATA_CONS_NAME)2 | (DEFAULT_DATA_CONS_NAME)1 ) {} -> False;
* ;
*/
{
SourceModel.Name.DataCons[] dataConsNames1 = {
SourceModel.Name.DataCons.make(QualifiedName.make(DEFAULT_TEST_MODULE_NAME, DEFAULT_DATA_CONS_NAME + 0)),
SourceModel.Name.DataCons.make(QualifiedName.make(DEFAULT_TEST_MODULE_NAME, DEFAULT_DATA_CONS_NAME + 1))
};
SourceModel.Name.DataCons[] dataConsNames2 = {
SourceModel.Name.DataCons.make(QualifiedName.make(DEFAULT_TEST_MODULE_NAME, DEFAULT_DATA_CONS_NAME + 2)),
SourceModel.Name.DataCons.make(QualifiedName.make(DEFAULT_TEST_MODULE_NAME, DEFAULT_DATA_CONS_NAME + 1))
};
SourceModel.FieldPattern[] fieldPatterns = SourceModel.FieldPattern.NO_FIELD_PATTERNS;
SourceModel.Expr.Case.Alt caseAlt1 =
SourceModel.Expr.Case.Alt.UnpackDataCons.make(dataConsNames1, fieldPatterns, SourceModel.Expr.makeBooleanValue(true));
SourceModel.Expr.Case.Alt caseAlt2 =
SourceModel.Expr.Case.Alt.UnpackDataCons.make(dataConsNames2, fieldPatterns, SourceModel.Expr.makeBooleanValue(false));
// Put into a case expression (conditional upon "var"), wrap with a function.
SourceModel.Expr.Var varExpr = SourceModel.Expr.Var.makeUnqualified("var");
SourceModel.Expr.Case caseExpr = SourceModel.Expr.Case.make(varExpr, new SourceModel.Expr.Case.Alt[]{caseAlt1, caseAlt2});
SourceModel.Parameter[] parameters = new SourceModel.Parameter[] {SourceModel.Parameter.make("var", false)};
SourceModel.FunctionDefn functionDefn =
SourceModel.FunctionDefn.Algebraic.make(DEFAULT_TEST_FUNCTION_NAME, Scope.PRIVATE, parameters, caseExpr);
// Compile our elements to a new module.
SourceModel.TopLevelSourceElement[] topLevelSourceElements = new SourceModel.TopLevelSourceElement[]{typeConsDefn, functionDefn};
CompilerMessageLogger logger = compileAndRemoveModuleForTopLevelSourceElements(DEFAULT_TEST_MODULE_NAME, topLevelSourceElements);
// Check that we got a single error message of the expected type.
List<CompilerMessage> errorList = logger.getCompilerMessages();
assertFalse("No errors logged.", errorList.isEmpty());
CompilerMessage error = errorList.get(0);
assertEquals(MessageKind.Error.RepeatedPatternInCaseExpression.class, error.getMessageKind().getClass());
}
}
/**
* Check for an error when a repeated var name appears in a case alt using pattern group syntax.
*/
public void testRepeatedVarNameWithPatternGroup() {
String[][] dcFieldNames = new String[][] {
{"foo", "bar"},
{"foo", "baz"},
{"qux"}
};
SourceModel.TypeConstructorDefn typeConsDefn = getTypeConstructorDefinition(dcFieldNames);
/*
* foo var =
* case var of
* ( (DEFAULT_DATA_CONS_NAME)0 | (DEFAULT_DATA_CONS_NAME)1 ) foo foo -> True;
* ;
*/
{
SourceModel.Name.DataCons[] dataConsNames = new SourceModel.Name.DataCons[] {
SourceModel.Name.DataCons.make(QualifiedName.make(DEFAULT_TEST_MODULE_NAME, DEFAULT_DATA_CONS_NAME + 0)),
SourceModel.Name.DataCons.make(QualifiedName.make(DEFAULT_TEST_MODULE_NAME, DEFAULT_DATA_CONS_NAME + 1))
};
// Create a case alt using positional notation, where the names are the same.
SourceModel.Pattern.Var[] patterns = {
SourceModel.Pattern.Var.make("foo"),
SourceModel.Pattern.Var.make("foo")
};
SourceModel.Expr.Case.Alt caseAlt =
SourceModel.Expr.Case.Alt.UnpackDataCons.make(dataConsNames, patterns, SourceModel.Expr.makeBooleanValue(true));
// Put into a case expression (conditional upon "var"), wrap with a function.
SourceModel.Expr.Var varExpr = SourceModel.Expr.Var.makeUnqualified("var");
SourceModel.Expr.Case caseExpr = SourceModel.Expr.Case.make(varExpr, new SourceModel.Expr.Case.Alt[]{caseAlt});
SourceModel.Parameter[] parameters = new SourceModel.Parameter[] {SourceModel.Parameter.make("var", false)};
SourceModel.FunctionDefn functionDefn =
SourceModel.FunctionDefn.Algebraic.make(DEFAULT_TEST_FUNCTION_NAME, Scope.PRIVATE, parameters, caseExpr);
// Compile our elements to a new module.
SourceModel.TopLevelSourceElement[] topLevelSourceElements = new SourceModel.TopLevelSourceElement[]{typeConsDefn, functionDefn};
CompilerMessageLogger logger = compileAndRemoveModuleForTopLevelSourceElements(DEFAULT_TEST_MODULE_NAME, topLevelSourceElements);
// Check that we got a single error message of the expected type.
CompilerMessage error = logger.getFirstError();
assertTrue("No errors logged.", error != null);
assertEquals(MessageKind.Error.RepeatedVariableUsedInBinding.class, error.getMessageKind().getClass());
}
/*
* foo var =
* case var of
* ( (DEFAULT_DATA_CONS_NAME)0 | (DEFAULT_DATA_CONS_NAME)1 ) {foo, foo} -> True;
* ;
*/
{
SourceModel.Name.DataCons[] dataConsNames = new SourceModel.Name.DataCons[] {
SourceModel.Name.DataCons.make(QualifiedName.make(DEFAULT_TEST_MODULE_NAME, DEFAULT_DATA_CONS_NAME + 0)),
SourceModel.Name.DataCons.make(QualifiedName.make(DEFAULT_TEST_MODULE_NAME, DEFAULT_DATA_CONS_NAME + 1))
};
// Create a case alt using matching notation, where the names are the same.
FieldName fooFieldName = FieldName.make("foo");
SourceModel.FieldPattern[] patterns = {
SourceModel.FieldPattern.make(SourceModel.Name.Field.make(fooFieldName), null),
SourceModel.FieldPattern.make(SourceModel.Name.Field.make(fooFieldName), null)
};
SourceModel.Expr.Case.Alt caseAlt =
SourceModel.Expr.Case.Alt.UnpackDataCons.make(dataConsNames, patterns, SourceModel.Expr.makeBooleanValue(true));
// Put into a case expression (conditional upon "var"), wrap with a function.
SourceModel.Expr.Var varExpr = SourceModel.Expr.Var.makeUnqualified("var");
SourceModel.Expr.Case caseExpr = SourceModel.Expr.Case.make(varExpr, new SourceModel.Expr.Case.Alt[]{caseAlt});
SourceModel.Parameter[] parameters = new SourceModel.Parameter[] {SourceModel.Parameter.make("var", false)};
SourceModel.FunctionDefn functionDefn =
SourceModel.FunctionDefn.Algebraic.make(DEFAULT_TEST_FUNCTION_NAME, Scope.PRIVATE, parameters, caseExpr);
// Compile our elements to a new module.
SourceModel.TopLevelSourceElement[] topLevelSourceElements = new SourceModel.TopLevelSourceElement[]{typeConsDefn, functionDefn};
CompilerMessageLogger logger = compileAndRemoveModuleForTopLevelSourceElements(DEFAULT_TEST_MODULE_NAME, topLevelSourceElements);
// Check that we got a single error message of the expected type.
List<CompilerMessage> errorList = logger.getCompilerMessages();
assertFalse("No errors logged.", errorList.isEmpty());
CompilerMessage error = errorList.get(0);
assertEquals(MessageKind.Error.RepeatedFieldNameInFieldBindingPattern.class, error.getMessageKind().getClass());
}
}
/**
* Check for an error when a non-existent var name appears in a case alt using pattern group syntax.
*/
public void testNonExistentVarWithPatternGroup() {
String[][] dcFieldNames = new String[][] {
{"foo", "bar"},
{"foo"},
{"qux"}
};
SourceModel.TypeConstructorDefn typeConsDefn = getTypeConstructorDefinition(dcFieldNames);
/*
* Exists - should be ok.
*
* foo var =
* case var of
* ( (DEFAULT_DATA_CONS_NAME)0 | (DEFAULT_DATA_CONS_NAME)1 ) {foo} -> foo;
* ;
*/
{
SourceModel.Name.DataCons[] dataConsNames = {
SourceModel.Name.DataCons.make(QualifiedName.make(DEFAULT_TEST_MODULE_NAME, DEFAULT_DATA_CONS_NAME + 0)),
SourceModel.Name.DataCons.make(QualifiedName.make(DEFAULT_TEST_MODULE_NAME, DEFAULT_DATA_CONS_NAME + 1))
};
FieldName fieldName = FieldName.make("foo");
SourceModel.FieldPattern[] fieldPatterns = {SourceModel.FieldPattern.make(SourceModel.Name.Field.make(fieldName), null)};
SourceModel.Expr.Case.Alt caseAlt =
SourceModel.Expr.Case.Alt.UnpackDataCons.make(dataConsNames, fieldPatterns, SourceModel.Expr.Var.makeUnqualified("foo"));
// Put into a case expression (conditional upon "var"), wrap with a function.
SourceModel.Expr.Var varExpr = SourceModel.Expr.Var.makeUnqualified("var");
SourceModel.Expr.Case caseExpr = SourceModel.Expr.Case.make(varExpr, new SourceModel.Expr.Case.Alt[]{caseAlt});
SourceModel.Parameter[] parameters = new SourceModel.Parameter[] {SourceModel.Parameter.make("var", false)};
SourceModel.FunctionDefn functionDefn =
SourceModel.FunctionDefn.Algebraic.make(DEFAULT_TEST_FUNCTION_NAME, Scope.PRIVATE, parameters, caseExpr);
// Compile our elements to a new module.
SourceModel.TopLevelSourceElement[] topLevelSourceElements = new SourceModel.TopLevelSourceElement[]{typeConsDefn, functionDefn};
CompilerMessageLogger logger = compileAndRemoveModuleForTopLevelSourceElements(DEFAULT_TEST_MODULE_NAME, topLevelSourceElements);
// Check that we got a single error message of the expected type.
List<CompilerMessage> errorList = logger.getCompilerMessages();
assertTrue("Errors logged.", errorList.isEmpty());
}
/*
* Doesn't exist..
*
* foo var =
* case var of
* ( (DEFAULT_DATA_CONS_NAME)0 | (DEFAULT_DATA_CONS_NAME)1 ) {bar} -> bar;
* ;
*/
{
SourceModel.Name.DataCons[] dataConsNames = {
SourceModel.Name.DataCons.make(QualifiedName.make(DEFAULT_TEST_MODULE_NAME, DEFAULT_DATA_CONS_NAME + 0)),
SourceModel.Name.DataCons.make(QualifiedName.make(DEFAULT_TEST_MODULE_NAME, DEFAULT_DATA_CONS_NAME + 1))
};
FieldName fieldName = FieldName.make("bar");
SourceModel.FieldPattern[] fieldPatterns = {SourceModel.FieldPattern.make(SourceModel.Name.Field.make(fieldName), null)};
SourceModel.Expr.Case.Alt caseAlt =
SourceModel.Expr.Case.Alt.UnpackDataCons.make(dataConsNames, fieldPatterns, SourceModel.Expr.Var.makeUnqualified("bar"));
// Put into a case expression (conditional upon "var"), wrap with a function.
SourceModel.Expr.Var varExpr = SourceModel.Expr.Var.makeUnqualified("var");
SourceModel.Expr.Case caseExpr = SourceModel.Expr.Case.make(varExpr, new SourceModel.Expr.Case.Alt[]{caseAlt});
SourceModel.Parameter[] parameters = new SourceModel.Parameter[] {SourceModel.Parameter.make("var", false)};
SourceModel.FunctionDefn functionDefn =
SourceModel.FunctionDefn.Algebraic.make(DEFAULT_TEST_FUNCTION_NAME, Scope.PRIVATE, parameters, caseExpr);
// Compile our elements to a new module.
SourceModel.TopLevelSourceElement[] topLevelSourceElements = new SourceModel.TopLevelSourceElement[]{typeConsDefn, functionDefn};
CompilerMessageLogger logger = compileAndRemoveModuleForTopLevelSourceElements(DEFAULT_TEST_MODULE_NAME, topLevelSourceElements);
// Check that we got a single error message of the expected type.
List<CompilerMessage> errorList = logger.getCompilerMessages();
assertFalse("No errors logged.", errorList.isEmpty());
CompilerMessage error = errorList.get(0);
assertEquals(MessageKind.Error.UnknownDataConstructorField.class, error.getMessageKind().getClass());
}
}
/**
* Check for an error when a case alt unpack pattern using pattern group syntax uses an argument which cannot
* be assigned a type.
*/
public void testDataConstructorPatternGroupArgumentNotTypeable() {
String[][] dcFieldNames = new String[][] {
{"arg"},
{"arg"}
};
SourceModel.TypeExprDefn[][] dcFieldTypes = new SourceModel.TypeExprDefn[][] {
{SourceModel.TypeExprDefn.TypeCons.make(Prelude, CAL_Prelude.TypeConstructors.Int.getUnqualifiedName())},
{SourceModel.TypeExprDefn.TypeCons.make(Prelude, CAL_Prelude.TypeConstructors.Double.getUnqualifiedName())}
};
SourceModel.TypeConstructorDefn typeConsDefn = getTypeConstructorDefinition(dcFieldNames, dcFieldTypes);
SourceModel.Name.DataCons[] dataConsNames = {
SourceModel.Name.DataCons.make(QualifiedName.make(DEFAULT_TEST_MODULE_NAME, DEFAULT_DATA_CONS_NAME + 0)),
SourceModel.Name.DataCons.make(QualifiedName.make(DEFAULT_TEST_MODULE_NAME, DEFAULT_DATA_CONS_NAME + 1))
};
SourceModel.Pattern argPattern = SourceModel.Pattern.Var.make("arg");
/*
* foo var =
* case var of
* ( (DEFAULT_DATA_CONS_NAME)0 | (DEFAULT_DATA_CONS_NAME)1 ) arg -> arg;
* ;
*/
{
SourceModel.Pattern[] argPatterns = {argPattern};
SourceModel.Expr altExpr = SourceModel.Expr.Var.makeUnqualified("arg");
SourceModel.Expr.Case.Alt caseAlt =
SourceModel.Expr.Case.Alt.UnpackDataCons.make(dataConsNames, argPatterns, altExpr);
// Put into a case expression (conditional upon "var"), wrap with a function.
SourceModel.Expr.Var varExpr = SourceModel.Expr.Var.makeUnqualified("var");
SourceModel.Expr.Case caseExpr = SourceModel.Expr.Case.make(varExpr, new SourceModel.Expr.Case.Alt[]{caseAlt});
SourceModel.Parameter[] parameters = new SourceModel.Parameter[] {SourceModel.Parameter.make("var", false)};
SourceModel.FunctionDefn functionDefn =
SourceModel.FunctionDefn.Algebraic.make(DEFAULT_TEST_FUNCTION_NAME, Scope.PRIVATE, parameters, caseExpr);
// Compile our elements to a new module.
SourceModel.TopLevelSourceElement[] topLevelSourceElements = new SourceModel.TopLevelSourceElement[]{typeConsDefn, functionDefn};
CompilerMessageLogger logger = compileAndRemoveModuleForTopLevelSourceElements(DEFAULT_TEST_MODULE_NAME, topLevelSourceElements);
// Check that we got a single error message of the expected type.
CompilerMessage error = logger.getFirstError();
assertTrue("No errors logged.", error != null);
assertEquals(MessageKind.Error.DataConstructorPatternGroupArgumentNotTypeable.class, error.getMessageKind().getClass());
}
/*
* foo var =
* case var of
* ( (DEFAULT_DATA_CONS_NAME)0 | (DEFAULT_DATA_CONS_NAME)1 ) arg -> True;
* ;
*
* arg is unused, but we still should check whether its type is unifiable for all dc's.
*/
{
SourceModel.Pattern[] argPatterns = {argPattern};
SourceModel.Expr.Case.Alt caseAlt =
SourceModel.Expr.Case.Alt.UnpackDataCons.make(dataConsNames, argPatterns, SourceModel.Expr.makeBooleanValue(true));
// Put into a case expression (conditional upon "var"), wrap with a function.
SourceModel.Expr.Var varExpr = SourceModel.Expr.Var.makeUnqualified("var");
SourceModel.Expr.Case caseExpr = SourceModel.Expr.Case.make(varExpr, new SourceModel.Expr.Case.Alt[]{caseAlt});
SourceModel.Parameter[] parameters = new SourceModel.Parameter[] {SourceModel.Parameter.make("var", false)};
SourceModel.FunctionDefn functionDefn =
SourceModel.FunctionDefn.Algebraic.make(DEFAULT_TEST_FUNCTION_NAME, Scope.PRIVATE, parameters, caseExpr);
// Compile our elements to a new module.
SourceModel.TopLevelSourceElement[] topLevelSourceElements = new SourceModel.TopLevelSourceElement[]{typeConsDefn, functionDefn};
CompilerMessageLogger logger = compileAndRemoveModuleForTopLevelSourceElements(DEFAULT_TEST_MODULE_NAME, topLevelSourceElements);
// Check that we got a single error message of the expected type.
List<CompilerMessage> errorList = logger.getCompilerMessages();
assertFalse("No errors logged.", errorList.isEmpty());
CompilerMessage error = errorList.get(0);
assertEquals(MessageKind.Error.DataConstructorPatternGroupArgumentNotTypeable.class, error.getMessageKind().getClass());
}
/*
* foo var =
* case var of
* ( (DEFAULT_DATA_CONS_NAME)0 | (DEFAULT_DATA_CONS_NAME)1 ) {arg} -> True;
* ;
*/
{
FieldName fieldName = FieldName.make("arg");
SourceModel.FieldPattern[] fieldPatterns = {SourceModel.FieldPattern.make(SourceModel.Name.Field.make(fieldName), argPattern)};
SourceModel.Expr.Case.Alt caseAlt =
SourceModel.Expr.Case.Alt.UnpackDataCons.make(dataConsNames, fieldPatterns, SourceModel.Expr.makeBooleanValue(true));
// Put into a case expression (conditional upon "var"), wrap with a function.
SourceModel.Expr.Var varExpr = SourceModel.Expr.Var.makeUnqualified("var");
SourceModel.Expr.Case caseExpr = SourceModel.Expr.Case.make(varExpr, new SourceModel.Expr.Case.Alt[]{caseAlt});
SourceModel.Parameter[] parameters = new SourceModel.Parameter[] {SourceModel.Parameter.make("var", false)};
SourceModel.FunctionDefn functionDefn =
SourceModel.FunctionDefn.Algebraic.make(DEFAULT_TEST_FUNCTION_NAME, Scope.PRIVATE, parameters, caseExpr);
// Compile our elements to a new module.
SourceModel.TopLevelSourceElement[] topLevelSourceElements = new SourceModel.TopLevelSourceElement[]{typeConsDefn, functionDefn};
CompilerMessageLogger logger = compileAndRemoveModuleForTopLevelSourceElements(DEFAULT_TEST_MODULE_NAME, topLevelSourceElements);
// Check that we got a single error message of the expected type.
List<CompilerMessage> errorList = logger.getCompilerMessages();
assertFalse("No errors logged.", errorList.isEmpty());
CompilerMessage error = errorList.get(0);
assertEquals(MessageKind.Error.DataConstructorPatternGroupArgumentNotTypeable.class, error.getMessageKind().getClass());
}
}
/**
* Helper function to get a source model for a type constructor consisting of a number of data constructors with given fields.
* Each of the fields will have the Unit type.
*
* The definition will be:
* data private (DEFAULT_DATA_CONS_NAME) =
* private (DEFAULT_DATA_CONS_NAME)0
* fieldNamesSourceFormArray[0][0] :: ()
* fieldNamesSourceFormArray[0][1] :: ()
* ...
* private (DEFAULT_DATA_CONS_NAME)1
* fieldNamesSourceFormArray[1][0] :: ()
* fieldNamesSourceFormArray[1][1] :: ()
* ...
* private (DEFAULT_DATA_CONS_NAME)2
* fieldNamesSourceFormArray[2][0] :: ()
* fieldNamesSourceFormArray[2][1] :: ()
* ...
* ...
*
* @param fieldNamesSourceFormArray the names of the fields. These must be valid cal source forms.
* The string array at index n will give the names of the fields for data constructor n.
* @return the source model for the corresponding type constructor.
*/
private static SourceModel.TypeConstructorDefn getTypeConstructorDefinition(String[][] fieldNamesSourceFormArray) {
// Create an array for corresponding type expr defns.
int nDCDefs = fieldNamesSourceFormArray.length;
SourceModel.TypeExprDefn[][] fieldTypesArray = new SourceModel.TypeExprDefn[nDCDefs][];
// Fill the arrays with the unit type.
for (int i = 0; i < nDCDefs; i++) {
String[] fieldNamesSourceForm = fieldNamesSourceFormArray[i];
SourceModel.TypeExprDefn[] typeExprDefnArray = new SourceModel.TypeExprDefn[fieldNamesSourceForm.length];
fieldTypesArray[i] = typeExprDefnArray;
Arrays.fill(typeExprDefnArray, SourceModel.TypeExprDefn.Unit.make());
}
// Defer to the more general method.
return getTypeConstructorDefinition(fieldNamesSourceFormArray, fieldTypesArray);
}
/**
* Helper function to get a source model for a type constructor consisting of a number of data constructors with given fields and types.
* The types should not be parametrized -- ie. the resulting data constructor should have no arrows in its type.
*
* The definition will be:
* data private (DEFAULT_DATA_CONS_NAME) =
* private (DEFAULT_DATA_CONS_NAME)0
* fieldNamesSourceFormArray[0][0] :: fieldTypesArray[0][0]
* fieldNamesSourceFormArray[0][1] :: fieldTypesArray[0][1]
* ...
* private (DEFAULT_DATA_CONS_NAME)1
* fieldNamesSourceFormArray[1][0] :: fieldTypesArray[1][0]
* fieldNamesSourceFormArray[1][1] :: fieldTypesArray[1][1]
* ...
* private (DEFAULT_DATA_CONS_NAME)2
* fieldNamesSourceFormArray[2][0] :: fieldTypesArray[2][0]
* fieldNamesSourceFormArray[2][1] :: fieldTypesArray[2][1]
* ...
* ...
*
* @param fieldNamesSourceFormArray the names of the fields. These must be valid cal source forms.
* The string array at index n will give the names of the fields for data constructor n.
* @param fieldTypesArray the types of the fields. This should have the same structure as fieldNamesSourceFormArray.
* The argument at fieldTypesArray[i][j] will be the type of the argument corresponding to fieldNamesSourceFormArray[i][j].
* @return the source model for the corresponding type constructor.
*/
private static SourceModel.TypeConstructorDefn getTypeConstructorDefinition(
String[][] fieldNamesSourceFormArray, SourceModel.TypeExprDefn[][] fieldTypesArray) {
int nDCDefs = fieldNamesSourceFormArray.length;
DataConsDefn[] dcDefs = new DataConsDefn[nDCDefs];
for (int i = 0; i < nDCDefs; i++) {
String[] fieldNamesSourceForm = fieldNamesSourceFormArray[i];
// Create the field names.
FieldName[] fieldNames = new FieldName[fieldNamesSourceForm.length];
for (int j = 0; j < fieldNames.length; j++) {
fieldNames[j] = FieldName.make(fieldNamesSourceForm[j]);
}
// Create the type arguments.
DataConsDefn.TypeArgument[] typeArguments = new DataConsDefn.TypeArgument[fieldNames.length];
for (int j = 0; j < fieldNames.length; j++) {
typeArguments[j] = DataConsDefn.TypeArgument.make(SourceModel.Name.Field.make(fieldNames[j]), fieldTypesArray[i][j], false);
}
// Create the data constructor definition.
String dcName = DEFAULT_DATA_CONS_NAME + i;
dcDefs[i] = DataConsDefn.make(dcName, Scope.PRIVATE, typeArguments);
}
// Create the type constructor with the data cons definition.
SourceModel.TypeConstructorDefn typeConsDefn =
SourceModel.TypeConstructorDefn.AlgebraicType.make(DEFAULT_DATA_CONS_NAME, Scope.PRIVATE, null,
dcDefs, SourceModel.TypeConstructorDefn.NO_DERIVING_CLAUSE);
return typeConsDefn;
}
/**
* Check for an error when a case alt unpack pattern on ints uses the same int.
*/
public void testIntCaseCollision() {
{
String[] outerDefnText = {
"testIntCase x = ",
" case x of ",
" (1 | 2) -> " + Prelude + ".True;",
" 1 -> " + Prelude + ".True;",
" ;"
};
checkDefnForExpectedError(outerDefnText, MessageKind.Error.RepeatedPatternValueInCaseExpression.class);
}
{
String[] outerDefnText = {
"testIntCase x = ",
" case x of ",
" (1 | 1) -> " + Prelude + ".True;",
" ;"
};
checkDefnForExpectedError(outerDefnText, MessageKind.Error.RepeatedPatternValueInCaseExpression.class);
}
{
String[] outerDefnText = {
"testIntCase x =",
" case x of",
" -0 -> " + Prelude + ".True;",
" 0 -> " + Prelude + ".True;",
" ;"
};
checkDefnForExpectedError(outerDefnText, MessageKind.Error.RepeatedPatternValueInCaseExpression.class);
}
}
/**
* Check for an error when a case alt unpack pattern on ints uses an integer literal out of range of the Int type.
*/
public void testIntLiteralOutOfRange() {
{
String[] outerDefnText = {
"testIntCase x =",
" case x of",
" - 1873468172648912649812764912837643 -> " + Prelude + ".True;",
" ;"
};
checkDefnForExpectedError(outerDefnText, MessageKind.Error.IntLiteralOutOfRange.class);
}
}
/**
* Check for an error when a case alt unpack pattern on chars uses the same char.
*/
public void testCharCaseCollision() {
{
String[] outerDefnText = {
"testCharCase x = ",
" case x of ",
" ('a' | 'b') -> " + Prelude + ".True;",
" 'a' -> " + Prelude + ".True;",
" ;"
};
checkDefnForExpectedError(outerDefnText, MessageKind.Error.RepeatedPatternValueInCaseExpression.class);
}
{
String[] outerDefnText = {
"testCharCase x = ",
" case x of ",
" ('a' | 'a') -> " + Prelude + ".True;",
" ; "
};
checkDefnForExpectedError(outerDefnText, MessageKind.Error.RepeatedPatternValueInCaseExpression.class);
}
{
String[] outerDefnText = {
"testCharCase x = ",
" case x of ",
" '\045' -> " + Prelude + ".True;",
" '%' -> " + Prelude + ".True;",
" ; "
};
checkDefnForExpectedError(outerDefnText, MessageKind.Error.RepeatedPatternValueInCaseExpression.class);
}
{
String[] outerDefnText = {
"testCharCase x = ",
" case x of ",
" '\u0025' -> " + Prelude + ".True;",
" '%' -> " + Prelude + ".True;",
" ; "
};
checkDefnForExpectedError(outerDefnText, MessageKind.Error.RepeatedPatternValueInCaseExpression.class);
}
{
String[] outerDefnText = {
"testCharCase x = ",
" case x of ",
" '\045' -> " + Prelude + ".True;",
" '\u0025' -> " + Prelude + ".True;",
" ; "
};
checkDefnForExpectedError(outerDefnText, MessageKind.Error.RepeatedPatternValueInCaseExpression.class);
}
}
}