Package wyvern.tools.tests.tagTests

Source Code of wyvern.tools.tests.tagTests.TagTests

package wyvern.tools.tests.tagTests;

import java.io.IOException;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import org.junit.Assert;
import org.junit.Test;

import edu.umn.cs.melt.copper.runtime.logging.CopperParserException;
import wyvern.stdlib.Globals;
import wyvern.tools.errors.ErrorMessage;
import wyvern.tools.errors.ToolError;
import wyvern.tools.parsing.Wyvern;
import wyvern.tools.typedAST.core.binding.TagBinding;
import wyvern.tools.typedAST.core.expressions.TaggedInfo;
import wyvern.tools.typedAST.interfaces.TypedAST;
import wyvern.tools.typedAST.interfaces.Value;

public class TagTests {
 
  @Test
  /**
   * Test the tagged keyword works with classes.
   */
  public void taggedClassParseTest1() throws CopperParserException, IOException {   
    String input =
        "tagged class X                 \n" +
        "    class def create() : X     \n" +
        "        new                    \n";
   
    getAST(input);
    //reaching here without a parse exception is a pass
  }
 
  @Test
  /**
   * Test the tagged keyword works with types.
   */
  public void taggedTypeParseTest1() throws CopperParserException, IOException {   
    String input =
        "tagged type IntWrapper    \n" +
        "  def getValue() : Int    \n";
   
    getAST(input);
    //reaching here without a parse exception is a pass
  }
 
  @Test
  /**
   * Test the tagged keyword works with multiple types.
   */
  public void taggedTypeParseTest2() throws CopperParserException, IOException {   
    String input =
        "tagged type Type1          \n" +
        "  def getValue1() : Int    \n" +
        "                           \n" +
        "tagged type Type2          \n" +
        "  def getValue2() : Int    \n";
   
    getAST(input);
    //reaching here without a parse exception is a pass
  }
 
  @Test
  public void matchParseTest1() throws CopperParserException, IOException {   
    String input =
        "tagged class X                 \n" +
        "    class def create() : X     \n" +
        "        new                    \n" +
        "                               \n" +
        "val x = X.create()             \n" +
        "                               \n" +
        "match(x):                      \n" +
        "  X => 15                     \n" +
        "  default => 15               \n";
   
    getAST(input);
    //reaching here without a parse exception is a pass
  }
 
  @Test
  public void matchParseTest2() throws CopperParserException, IOException {   
    String input =
        "tagged class X                 \n" +
        "    class def create() : X     \n" +
        "        new                    \n" +
        "                               \n" +
        "val x = X.create()             \n" +
        "                               \n" +
        "match(x):                      \n" +
        "  default => 15               \n";
       
    TypedAST ast = getAST(input);
    evaluateExpecting(ast, 15);
  }
 
  @Test
  public void matchParseTestMulti1() throws CopperParserException, IOException {   
    String input =  
        "tagged class X                 \n" +
        "    class def create() : X     \n" +
        "        new                    \n" +
        "                               \n" +
        "tagged class Y                 \n" +
        "    class def create() : Y     \n" +
        "        new                    \n" +
        "                               \n" +
        "val x = X.create()             \n" +
        "                               \n" +
        "match(x):                      \n" +
        "  X => 15                     \n" +
        "  Y => 23                     \n" +
        "  default => 50               \n";
       
    getAST(input);
    //reaching here without a parse exception is a pass
  }
 
  @Test
  public void matchParseTestMulti2() throws CopperParserException, IOException {   
    String input =
        "tagged class X                 \n" +
        "    class def create() : X     \n" +
        "        new                    \n" +
        "                               \n" +
        "tagged class Y                 \n" +
        "    class def create() : Y     \n" +
        "        new                    \n" +
        "                               \n" +
        "val x = X.create()             \n" +
        "                               \n" +
        "match(x):                      \n" +
        "  X => 15                     \n" +
        "  Y => 23                     \n" +
        "  default => 50               \n";
       
    getAST(input);
    //reaching here without a parse exception is a pass
  }
 
  @Test
  public void matchInterpretTest1() throws CopperParserException, IOException {   
    String input =
        "tagged class X                 \n" +
        "    class def create() : X     \n" +
        "        new                    \n" +
        "                               \n" +
        "val x = X.create()             \n" +
        "                               \n" +
        "match(x):                      \n" +
        "  default => 15               \n";
       
   
    TypedAST ast = getAST(input);
    evaluateExpecting(ast, 15);
  }
 
  @Test
  public void matchInterpretTest2() throws CopperParserException, IOException {   
    String input =
        "tagged class Z                 \n" +
        "    class def create() : Z     \n" +
        "        new                    \n" +
        "                               \n" +
        "tagged class Y                 \n" +
        "    class def create() : Y     \n" +
        "        new                    \n" +
        "                               \n" +
        "tagged class W                 \n" +
        "    class def create() : W     \n" +
        "        new                    \n" +
        "                               \n" +
        "tagged class V                 \n" +
        "    class def create() : V     \n" +
        "        new                    \n" +
        "                               \n" +
        "tagged class U                 \n" +
        "    class def create() : U     \n" +
        "        new                    \n" +
        "                               \n" +
        "tagged class X                 \n" +
        "    class def create() : X     \n" +
        "        new                    \n" +
        "                               \n" +
        "val x = X.create()             \n" +
        "                               \n" +
        "match(x):                      \n" +
        "  X => 1                     \n" +
        "  Y => 2                     \n" +
        "  Z => 3                     \n" +
        "  W => 4                     \n" +
        "  U => 5                     \n" +
        "  V => 6                     \n" +
        "  default => 15               \n";
   
    TypedAST ast = getAST(input);
    evaluateExpecting(ast, 1);
  }
 
  @Test
  public void matchInterpretTest3() throws CopperParserException, IOException {
    String input =
        "tagged class X                 \n" +
        "    class def create() : X     \n" +
        "        new                    \n" +
        "                               \n" +
        "tagged class Y                 \n" +
        "    class def create() : Y     \n" +
        "        new                    \n" +
        "                               \n" +
        "val y = Y.create()             \n" +
        "                               \n" +
        "match(y):                      \n" +
        "  X => 15                     \n" +
        "  Y => 23                     \n" +
        "  default => 50               \n";
   
    TypedAST ast = getAST(input);
    evaluateExpecting(ast, 23);
  }
 
  @Test
  public void duplicateCaseTest() throws CopperParserException, IOException {
    String input =
        "tagged class X                 \n" +
        "    class def create() : X     \n" +
        "        new                    \n" +
        "                               \n" +
        "tagged class Y                 \n" +
        "    class def create() : Y     \n" +
        "        new                    \n" +
        "                               \n" +
        "val x = X.create()             \n" +
        "                               \n" +
        "match(x):                      \n" +
        "  X => 15                     \n" +
        "  Y => 23                     \n" +
        "  Y => 34                     \n" // Y given twice; error
        "  default => 50               \n";
       
    TypedAST res = getAST(input);
   
    typeCheckfailWith(res, ErrorMessage.DUPLICATE_TAG);
  }
 
  @Test
  public void unknownCaseTest() throws CopperParserException, IOException {
    String input =  
        "tagged class X                 \n" +
        "    class def create() : X     \n" +
        "        new                    \n" +
        "                               \n" +
        "tagged class Y                 \n" +
        "    class def create() : Y     \n" +
        "        new                    \n" +
        "                               \n" +
        "val x = X.create()             \n" +
        "                               \n" +
        "match(x):                      \n" +
        "  X => 15                     \n" +
        "  Y => 23                     \n" +
        "  Z => 34                     \n" // Z is not declared anywhere; error
        "  default => 50               \n";
       
    TypedAST res = getAST(input);
   
    typeCheckfailWith(res, ErrorMessage.UNKNOWN_TAG);
  }
 
  @Test
  public void untaggedCaseTest() throws CopperParserException, IOException {
    String input =  
        "tagged class X                 \n" +
        "    class def create() : X     \n" +
        "        new                    \n" +
        "                               \n" +
        "tagged class Y                 \n" +
        "    class def create() : Y     \n" +
        "        new                    \n" +
        "                               \n" +
        "class Z                        \n" +
        "    class def create() : Z     \n" +
        "        new                    \n" +
        "                               \n" +
        "val x = X.create()             \n" +
        "                               \n" +
        "match(x):                      \n" +
        "  X => 15                     \n" +
        "  Y => 23                     \n" +
        "  Z => 34                     \n" // Z is declared but not a tagged type; error
        "  default => 50               \n";
       
    TypedAST ast = getAST(input);
   
    typeCheckfailWith(ast, ErrorMessage.NOT_TAGGED);
  }
 
  @Test
  public void defaultNotLastTest() throws CopperParserException, IOException {
    String input =  
        "tagged class X                 \n" +
        "    class def create() : X     \n" +
        "        new                    \n" +
        "                               \n" +
        "tagged class Y                 \n" +
        "    class def create() : Y     \n" +
        "        new                    \n" +
        "                               \n" +
        "val x = X.create()             \n" +
        "                               \n" +
        "match(x):                      \n" +
        "  X => 15                     \n" +
        "  default => 23               \n" +
        "  Y => 50                     \n";
       
    TypedAST res = getAST(input);
   
    typeCheckfailWith(res, ErrorMessage.DEFAULT_NOT_LAST);
  }
 
  @Test
  public void multipleDefaultsTest() throws CopperParserException, IOException {
    String input =  
        "tagged class X                 \n" +
        "    class def create() : X     \n" +
        "        new                    \n" +
        "                               \n" +
        "tagged class Y                 \n" +
        "    class def create() : Y     \n" +
        "        new                    \n" +
        "                               \n" +
        "val x = X.create()             \n" +
        "                               \n" +
        "match(x):                      \n" +
        "  X => 15                     \n" +
        "  default => 23               \n" +
        "  Y => 50                     \n" +
        "  default => 23               \n";
       
    TypedAST res = getAST(input);
   
    typeCheckfailWith(res, ErrorMessage.MULTIPLE_DEFAULTS);
  }
 
  @Test
  public void nonExhaustiveErrorTest() throws CopperParserException, IOException {
    String input =
      "tagged class Dyn [comprises DynInt, DynChar, DynByte]       \n" +
      "    class def create() : Dyn                                \n" +
      "        new                                                 \n" +
      "                                                            \n" +
      "tagged class DynInt [case of Dyn]                           \n" +
      "    class def create() : DynInt                             \n" +
      "        new                                                 \n" +
      "                                                            \n" +
      "tagged class DynChar [case of Dyn]                          \n" +
      "    class def create() : DynChar                            \n" +
      "        new                                                 \n" +
      "                                                            \n" +
      "tagged class DynByte [case of Dyn]                          \n" +
      "    class def create() : DynByte                            \n" +
      "        new                                                 \n" +
      "                                                            \n" +
      "val i = Dyn.create()                                        \n" +
      "                                                            \n" +
      "match(i):                                                   \n" +
      "  DynInt => 10                                             \n" +
      "  DynChar => 15                                            \n";
    // DynByte not specified; error
   
    TypedAST res = getAST(input);
 
    typeCheckfailWith(res, ErrorMessage.DEFAULT_NOT_PRESENT);
  }
 
  @Test
  public void exhaustiveWithDefaultTest() throws CopperParserException, IOException {
    String input =
        "tagged class Dyn [comprises DynInt, DynChar, DynByte]       \n" +
        "    class def create() : Dyn                                \n" +
        "        new                                                 \n" +
        "                                                            \n" +
        "tagged class DynInt [case of Dyn]                           \n" +
        "    class def create() : DynInt                             \n" +
        "        new                                                 \n" +
        "                                                            \n" +
        "tagged class DynChar [case of Dyn]                          \n" +
        "    class def create() : DynChar                            \n" +
        "        new                                                 \n" +
        "                                                            \n" +
        "tagged class DynByte [case of Dyn]                          \n" +
        "    class def create() : DynByte                            \n" +
        "        new                                                 \n" +
        "                                                            \n" +
        "val i = Dyn.create()                                        \n" +
        "                                                            \n" +
        "match(i):                                                   \n" +
        "  DynInt => 10                                             \n" +
        "  DynChar => 15                                            \n" +
        "  DynByte => 20                                            \n" +
        "   Dyn     => 25                                            \n" +
        "  default => 30                                            \n";
      // default specified with exhaustive search; error
       
      TypedAST ast = getAST(input);
      typeCheckfailWith(ast, ErrorMessage.DEFAULT_PRESENT);
  }
 
  @Test
  public void caseOfParseTest() throws CopperParserException, IOException {
    String input =
      "tagged class Dyn                            \n" +
      "    class def create() : X                  \n" +
      "        new                                 \n" +
      "                                            \n" +
      "tagged class DynInt [case of Dyn]           \n" +
      "    class def create() : DynInt             \n" +
      "        new                                 \n" +
      "                                            \n" +
      "tagged class DynChar [case of Dyn]          \n" +
      "    class def create() : DynChar            \n" +
      "        new                                 \n" +
      "                                            \n" +
      "val i = DynInt.create()                     \n" +
      "                                            \n" +
      "match(i):                                   \n" +
      "  DynInt => 10                             \n" +
      "  DynChar => 15                            \n" +
      "  default => 23                            \n";
   
    getAST(input);
    //reaching here without a parse exception is a pass
  }
 
  @Test
  public void comprisesParseTest() throws CopperParserException, IOException {
    String input =
      "tagged class Dyn [comprises DynInt, DynChar] \n" +
      "    class def create() : X                   \n" +
      "        new                                  \n" +
      "                                             \n" +
      "tagged class DynInt [case of Dyn]            \n" +
      "    class def create() : DynInt              \n" +
      "        new                                  \n" +
      "                                             \n" +
      "tagged class DynChar [case of Dyn]           \n" +
      "    class def create() : DynChar             \n" +
      "        new                                  \n" +
      "                                             \n" +
      "val i = DynInt.create()                      \n" +
      "                                             \n" +
      "match(i):                                    \n" +
      "  DynInt => 10                              \n" +
      "  DynChar => 15                             \n" +
      "  default => 15                             \n";
   
   
    getAST(input);
    //reaching here without a parse exception is a pass
  }
 
  @Test
  public void defaultPresentFullComprisesTest() throws CopperParserException, IOException {
    //Checks that an error is caught when a default is included but all comprises tags are included
   
    String input =
      "tagged class Dyn [comprises DynInt, DynChar] \n" +
      "    class def create() : Dyn                 \n" +
      "        new                                  \n" +
      "                                             \n" +
      "tagged class DynInt [case of Dyn]            \n" +
      "    class def create() : DynInt              \n" +
      "        new                                  \n" +
      "                                             \n" +
      "tagged class DynChar [case of Dyn]           \n" +
      "    class def create() : DynChar             \n" +
      "        new                                  \n" +
      "                                             \n" +
      "val i = Dyn.create()                         \n" +
      "                                             \n" +
      "match(i):                                    \n" +
      "  DynInt => 10                              \n" +
      "  DynChar => 15                             \n" +
      "  Dyn => 5                                  \n" +
      "  default => 20                             \n";
   
   
    TypedAST res = getAST(input);
   
    typeCheckfailWith(res, ErrorMessage.DEFAULT_PRESENT);
  }
 
  @Test
  public void comprisesExecTest() throws CopperParserException, IOException {
    String input =
      "tagged class Dyn [comprises DynInt, DynChar] \n" +
      "    class def create() : Dyn                 \n" +
      "        new                                  \n" +
      "                                             \n" +
      "tagged class DynInt [case of Dyn]            \n" +
      "    class def create() : DynInt              \n" +
      "        new                                  \n" +
      "                                             \n" +
      "tagged class DynChar [case of Dyn]           \n" +
      "    class def create() : DynChar             \n" +
      "        new                                  \n" +
      "                                             \n" +
      "val i  = Dyn.create()                         \n" +
      "                                             \n" +
      "match(i):                                    \n" +
      "  DynInt => 10                              \n" +
      "  DynChar => 15                             \n" +
      "  default => 15                             \n";
   
    TypedAST ast = getAST(input);
   
    // Should be 15 because D is a subclass of B and will match that
    evaluateExpecting(ast, 15);
  }
 
  @Test
  public void subtagAfterSupertagTest1() throws CopperParserException, IOException {
    String input =
      "tagged class A                               \n" +
      "    class def create() : A                   \n" +
      "        new                                  \n" +
      "                                             \n" +
      "tagged class B [case of A]                   \n" +
      "    class def create() : B                   \n" +
      "        new                                  \n" +
      "                                             \n" +
      "tagged class C [case of A]                   \n" +
      "    class def create() : C                   \n" +
      "        new                                  \n" +
      "                                             \n" +
      "tagged class D [case of B]                   \n" +
      "    class def create() : D                   \n" +
      "        new                                  \n" +
     
      "val d = D.create()                           \n" +
      "                                             \n" +
      "match(d):                                    \n" +
      "  A => 15                                   \n" //Error, this will catch everything
      "  B => 15                                   \n" + //So anything after is pointless
      "  C => 25                                   \n" +
      "  default => 35                             \n";
   
    TypedAST ast = getAST(input);
   
    typeCheckfailWith(ast, ErrorMessage.SUPERTAG_PRECEEDS_SUBTAG);
  }
 
  @Test
  public void subtagAfterSupertagTest2() throws CopperParserException, IOException {
    String input =
      "tagged class A [comprises B, C]              \n" +
      "    class def create() : A                   \n" +
      "        new                                  \n" +
      "                                             \n" +
      "tagged class B [case of A]                   \n" +
      "    class def create() : B                   \n" +
      "        new                                  \n" +
      "                                             \n" +
      "tagged class C [case of A]                   \n" +
      "    class def create() : C                   \n" +
      "        new                                  \n" +
      "                                             \n" +
      "tagged class D [case of B]                   \n" +
      "    class def create() : D                   \n" +
      "        new                                  \n" +
     
      "val d = A.create()                           \n" +
      "                                             \n" +
      "match(d):                                    \n" +
      "  C => 15                                   \n"
      "  B => 15                                   \n" + //Error, this will catch the D just below
      "  D => 25                                   \n" +
      "  A => 25                                   \n";
   
    TypedAST ast = getAST(input);
   
    typeCheckfailWith(ast, ErrorMessage.SUPERTAG_PRECEEDS_SUBTAG);
  }
 
  @Test
  public void simpleHierarchicalExecTest() throws CopperParserException, IOException {
    String input =
      "tagged class A                               \n" +
      "    class def create() : A                   \n" +
      "        new                                  \n" +
      "                                             \n" +
      "tagged class B [case of A]                   \n" +
      "    class def create() : B                   \n" +
      "        new                                  \n" +
      "                                             \n" +
      "tagged class C [case of A]                   \n" +
      "    class def create() : C                   \n" +
      "        new                                  \n" +
      "                                             \n" +
      "tagged class D [case of B]                   \n" +
      "    class def create() : D                   \n" +
      "        new                                  \n" +
     
      "val d = D.create()                           \n" +
      "                                             \n" +
      "match(d):                                    \n" +
      "  B => 15                                   \n" +    //matches B since D is a subtag of B
      "  C => 25                                   \n" +
      "  default => 35                             \n";
   
    TypedAST ast = getAST(input);
   
    // Should be 15 because D is a subclass of B and will match that
    evaluateExpecting(ast, 15);
  }
 
  @Test
  public void jsonTest() throws CopperParserException, IOException {
    //TODO, make this test do something useful!
   
    String input =
        "tagged class JSON                            \n" +
        "    class def create() : JSON                \n" +
        "        new                                  \n" +
        "                                             \n" +
        "tagged class ValueJSON [case of JSON]        \n" +
        "    class def create() : ValueJSON           \n" +
        "        new                                  \n" +
        "                                             \n" +
        "tagged class ObjJSON [case of JSON]          \n" +
        "    class def create() : ObjJSON             \n" +
        "        new                                  \n" +
        "                                             \n" +
        "tagged class StrJSON [case of JSON]          \n" +
        "    class def create() : StrJSON             \n" +
        "        new                                  \n" +
        "                                             \n" +
        "tagged class NumJSON [case of JSON]          \n" +
        "    class def create() : NumJSON             \n" +
        "        new                                  \n" +
        "                                             \n" +
        "tagged class IntJSON [case of NumJSON]       \n" +
        "    class def create() : IntJSON             \n" +
        "        new                                  \n" +
        "                                             \n" +
        "tagged class DoubleJSON [case of NumJSON]    \n" +
        "    class def create() : DoubleJSON          \n" +
        "        new                                  \n" +
        "                                             \n" +
        "val json = IntJSON.create()                  \n" +
        "                                             \n" +
        "match(json):                                 \n" +
        "  IntJSON => 25                             \n" +
        "  NumJSON => 10                             \n" +
        "  ObjJSON => 15                             \n" +
        "  StrJSON => 20                             \n" +
        "  default => 30                             \n";
     
      TypedAST ast = getAST(input);
     
      evaluateExpecting(ast, 25);
  }
 
  /**
   * Attempts to typecheck the given AST and catch the given ErrorMessage.
   * This error being thrown indicates the test passed.
   *
   * If the error isn't thrown, the test fails.
   *
   * @param ast
   * @param errorMessage
   */
  public static void typeCheckfailWith(TypedAST ast, ErrorMessage errorMessage) {
    try {
      ast.typecheck(Globals.getStandardEnv(), Optional.empty());
    } catch (ToolError toolError) {
      Assert.assertEquals(errorMessage, toolError.getTypecheckingErrorMessage());
     
      return;
    }
   
    Assert.fail("Should have failed with error: " + errorMessage);
  }
 
  /**
   * First typechecks the AST, then executes it.
   *
   * Any returned value is discarded, but anything printed to stdout will be visible.
   *
   * @param ast
   */
  public static void evaluate(TypedAST ast) {
    ast.typecheck(Globals.getStandardEnv(), Optional.empty());
    ast.evaluate(Globals.getStandardEnv());
  }
 
  /**
   * Completely evaluates the given AST, and compares it to the given value.
   * Does typechecking first, then evaluation.
   *
   * @param ast
   * @param value
   */
  public static void evaluateExpecting(TypedAST ast, int value) {
    ast.typecheck(Globals.getStandardEnv(), Optional.empty());
    Value v = ast.evaluate(Globals.getStandardEnv());
   
    String expecting = "IntegerConstant(" + value + ")";

    Assert.assertEquals(expecting, v.toString());
  }
 
  /**
   * Converts the given program into the AST representation.
   *
   * @param program
   * @return
   * @throws IOException
   * @throws CopperParserException
   */
  public static TypedAST getAST(String program) throws CopperParserException, IOException {
    TagBinding.resetHACK();
    return (TypedAST)new Wyvern().parse(new StringReader(program), "test input");
  }
}
TOP

Related Classes of wyvern.tools.tests.tagTests.TagTests

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.