refactored types, split tests into features instead of stages, added author
This commit is contained in:
parent
610611e212
commit
b617136564
|
@ -2,7 +2,7 @@
|
||||||
\usepackage[margin=1in]{geometry}
|
\usepackage[margin=1in]{geometry}
|
||||||
\usepackage{graphicx}
|
\usepackage{graphicx}
|
||||||
\usepackage{pdfpages}
|
\usepackage{pdfpages}
|
||||||
\usepackage[dutch]{babel}
|
\usepackage[english]{babel}
|
||||||
\usepackage{amsmath}
|
\usepackage{amsmath}
|
||||||
\usepackage{amsfonts}
|
\usepackage{amsfonts}
|
||||||
\usepackage[scientific-notation=true,round-precision=5,round-mode=figures]{siunitx}
|
\usepackage[scientific-notation=true,round-precision=5,round-mode=figures]{siunitx}
|
||||||
|
|
|
@ -5,10 +5,12 @@ import java.util.Stack;
|
||||||
import org.antlr.v4.runtime.tree.ParseTreeProperty;
|
import org.antlr.v4.runtime.tree.ParseTreeProperty;
|
||||||
|
|
||||||
import pp.iloc.model.Reg;
|
import pp.iloc.model.Reg;
|
||||||
|
import pp.s1184725.boppi.type.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class holds properties of all AST nodes during compilation.
|
* This class holds properties of all AST nodes during compilation.
|
||||||
*
|
*
|
||||||
|
* @author Frank Wibbelink
|
||||||
*/
|
*/
|
||||||
public class Annotations {
|
public class Annotations {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -7,14 +7,15 @@ import java.util.stream.Collectors;
|
||||||
import org.antlr.v4.runtime.ParserRuleContext;
|
import org.antlr.v4.runtime.ParserRuleContext;
|
||||||
import org.antlr.v4.runtime.tree.ParseTree;
|
import org.antlr.v4.runtime.tree.ParseTree;
|
||||||
|
|
||||||
import pp.s1184725.boppi.antlr.BoppiBaseVisitor;
|
import pp.s1184725.boppi.antlr.*;
|
||||||
import pp.s1184725.boppi.antlr.BoppiLexer;
|
|
||||||
import pp.s1184725.boppi.antlr.BoppiParser.*;
|
import pp.s1184725.boppi.antlr.BoppiParser.*;
|
||||||
|
import pp.s1184725.boppi.type.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class performs type checking and variable assignment on a bare parse
|
* This class performs type checking and variable assignment on a bare parse
|
||||||
* tree.
|
* tree.
|
||||||
*
|
*
|
||||||
|
* @author Frank Wibbelink
|
||||||
*/
|
*/
|
||||||
public class BoppiChecker extends BoppiBaseVisitor<Type> {
|
public class BoppiChecker extends BoppiBaseVisitor<Type> {
|
||||||
private Annotations an;
|
private Annotations an;
|
||||||
|
@ -305,7 +306,7 @@ public class BoppiChecker extends BoppiBaseVisitor<Type> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Type visitTypeTuple(TypeTupleContext ctx) {
|
public Type visitTypeTuple(TypeTupleContext ctx) {
|
||||||
return new TupleType(ctx.children.stream().map(this::visit).collect(Collectors.toList()));
|
return new TupleType(ctx.type().stream().map(this::visit).collect(Collectors.toList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -10,12 +10,14 @@ import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import pp.iloc.eval.Machine;
|
import pp.iloc.eval.Machine;
|
||||||
import pp.iloc.model.*;
|
import pp.iloc.model.*;
|
||||||
import pp.s1184725.boppi.antlr.BoppiBaseVisitor;
|
import pp.s1184725.boppi.antlr.*;
|
||||||
import pp.s1184725.boppi.antlr.BoppiLexer;
|
|
||||||
import pp.s1184725.boppi.antlr.BoppiParser.*;
|
import pp.s1184725.boppi.antlr.BoppiParser.*;
|
||||||
|
import pp.s1184725.boppi.type.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The generator stage of the Boppi toolchain.
|
* The generator stage of the Boppi toolchain.
|
||||||
|
*
|
||||||
|
* @author Frank Wibbelink
|
||||||
*/
|
*/
|
||||||
public class BoppiGenerator extends BoppiBaseVisitor<Void> {
|
public class BoppiGenerator extends BoppiBaseVisitor<Void> {
|
||||||
private static final int ARBASESIZE = 16;
|
private static final int ARBASESIZE = 16;
|
||||||
|
|
|
@ -3,6 +3,8 @@ package pp.s1184725.boppi;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import pp.s1184725.boppi.type.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class maps string identifiers to {@link Variable} instances. It takes
|
* This class maps string identifiers to {@link Variable} instances. It takes
|
||||||
* care of lexical scope, memory offsets and variable lifetime. This
|
* care of lexical scope, memory offsets and variable lifetime. This
|
||||||
|
@ -12,6 +14,8 @@ import java.util.function.Supplier;
|
||||||
*
|
*
|
||||||
* @param <T>
|
* @param <T>
|
||||||
* the typing class
|
* the typing class
|
||||||
|
*
|
||||||
|
* @author Frank Wibbelink
|
||||||
*/
|
*/
|
||||||
public class CachingSymbolTable<T extends Type> {
|
public class CachingSymbolTable<T extends Type> {
|
||||||
protected Stack<Map<String, Variable<T>>> symbolMapStack;
|
protected Stack<Map<String, Variable<T>>> symbolMapStack;
|
||||||
|
|
|
@ -2,12 +2,16 @@ package pp.s1184725.boppi;
|
||||||
|
|
||||||
import java.util.EmptyStackException;
|
import java.util.EmptyStackException;
|
||||||
|
|
||||||
|
import pp.s1184725.boppi.type.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Same functionality as {@link CachingSymbolTable} except actions on the table
|
* Same functionality as {@link CachingSymbolTable} except actions on the table
|
||||||
* are logged to the console.
|
* are logged to the console.
|
||||||
*
|
*
|
||||||
* @param <T>
|
* @param <T>
|
||||||
* the typing class
|
* the typing class
|
||||||
|
*
|
||||||
|
* @author Frank Wibbelink
|
||||||
*/
|
*/
|
||||||
public class DebugCachingSymbolTable<T extends Type> extends CachingSymbolTable<T> {
|
public class DebugCachingSymbolTable<T extends Type> extends CachingSymbolTable<T> {
|
||||||
|
|
||||||
|
|
|
@ -12,12 +12,12 @@ import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
import pp.iloc.Simulator;
|
import pp.iloc.Simulator;
|
||||||
import pp.iloc.model.Program;
|
import pp.iloc.model.Program;
|
||||||
import pp.s1184725.boppi.antlr.BoppiLexer;
|
import pp.s1184725.boppi.antlr.*;
|
||||||
import pp.s1184725.boppi.antlr.BoppiParser;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class provides methods for all steps in the Boppi tool chain.
|
* This class provides methods for all steps in the Boppi tool chain.
|
||||||
*
|
*
|
||||||
|
* @author Frank Wibbelink
|
||||||
*/
|
*/
|
||||||
public class ToolChain {
|
public class ToolChain {
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@ package pp.s1184725.boppi;
|
||||||
*
|
*
|
||||||
* @param <T>
|
* @param <T>
|
||||||
* the typing class
|
* the typing class
|
||||||
|
*
|
||||||
|
* @author Frank Wibbelink
|
||||||
*/
|
*/
|
||||||
public class Variable<T> {
|
public class Variable<T> {
|
||||||
private final T type;
|
private final T type;
|
||||||
|
|
|
@ -1,29 +1,55 @@
|
||||||
package pp.s1184725.boppi.test;
|
package pp.s1184725.boppi.test;
|
||||||
|
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
import java.util.logging.Level;
|
import java.util.List;
|
||||||
|
import java.util.logging.*;
|
||||||
|
|
||||||
|
import org.antlr.v4.runtime.CharStream;
|
||||||
|
import org.antlr.v4.runtime.tree.ParseTree;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.junit.runners.Suite;
|
import org.junit.runners.Suite;
|
||||||
import org.junit.runners.Suite.SuiteClasses;
|
import org.junit.runners.Suite.SuiteClasses;
|
||||||
|
|
||||||
|
import pp.iloc.Simulator;
|
||||||
|
import pp.iloc.model.Program;
|
||||||
|
import pp.s1184725.boppi.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test suite for all Boppi compiler stages and language features
|
* Test suite for all Boppi language features. This suite contains helper
|
||||||
|
* functions and attributes to assist test cases. Each test case should consider
|
||||||
|
* a single language feature across all compiler stages.
|
||||||
|
*
|
||||||
|
* @author Frank Wibbelink
|
||||||
*/
|
*/
|
||||||
@RunWith(Suite.class)
|
@RunWith(Suite.class)
|
||||||
@SuiteClasses({ CheckerTest.class, GeneratorTest.class, ParserTest.class })
|
@SuiteClasses({ ExpressionTest.class, SimpleVariableTest.class, ConditionalTest.class, SimpleFunctionTest.class })
|
||||||
public class AllTests {
|
public class AllTests {
|
||||||
/**
|
/**
|
||||||
* The location of test programs
|
* The path for test programs
|
||||||
*/
|
*/
|
||||||
public static final Path directory = Paths
|
public static final Path TEST_PROGRAM_LOCATION = Paths
|
||||||
.get("src/" + AllTests.class.getPackage().getName().replaceAll("\\.", "/") + "/programs/");
|
.get("src/" + AllTests.class.getPackage().getName().replaceAll("\\.", "/") + "/programs/");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default logging level
|
||||||
|
*/
|
||||||
|
public static final Level DEFAULT_LOG_LEVEL = Level.SEVERE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log records of last test
|
||||||
|
*/
|
||||||
|
public static List<LogRecord> log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Output of last program split by line breaks
|
||||||
|
*/
|
||||||
|
public static String[] out;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The level of error reporting to use for the tests. Can be changed to
|
* The level of error reporting to use for the tests. Can be changed to
|
||||||
* include finer tests.
|
* include finer tests.
|
||||||
*/
|
*/
|
||||||
public static Level logLevel = Level.SEVERE;
|
private static Level logLevel = DEFAULT_LOG_LEVEL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs a test with warnings enabled.
|
* Runs a test with warnings enabled.
|
||||||
|
@ -34,6 +60,132 @@ public class AllTests {
|
||||||
public static void withWarnings(Runnable test) {
|
public static void withWarnings(Runnable test) {
|
||||||
logLevel = Level.WARNING;
|
logLevel = Level.WARNING;
|
||||||
test.run();
|
test.run();
|
||||||
logLevel = Level.SEVERE;
|
logLevel = DEFAULT_LOG_LEVEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a string of code, logging to {@link #log}.
|
||||||
|
*
|
||||||
|
* @param code
|
||||||
|
* the code to parse
|
||||||
|
*/
|
||||||
|
public static void parseString(String code) {
|
||||||
|
parse(ToolChain.getCharStream(code));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses code from a file, logging to {@link #log}.
|
||||||
|
*
|
||||||
|
* @param file
|
||||||
|
* the file name
|
||||||
|
*/
|
||||||
|
public static void parseFile(String file) {
|
||||||
|
parse(ToolChain.getCharStream(TEST_PROGRAM_LOCATION.resolve(file)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void parse(CharStream stream) {
|
||||||
|
Logger logger = Logger.getAnonymousLogger();
|
||||||
|
log = ToolChain.makeListLog(logger);
|
||||||
|
logger.setLevel(logLevel);
|
||||||
|
|
||||||
|
ToolChain.getParser(ToolChain.getLexer(stream, logger), logger).program();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses and type checks a string of code, logging to {@link #log}.
|
||||||
|
*
|
||||||
|
* @param code
|
||||||
|
* the code to type check
|
||||||
|
*/
|
||||||
|
public static void checkString(String code) {
|
||||||
|
check(ToolChain.getCharStream(code));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses and type checks code from a file, logging to {@link #log}.
|
||||||
|
*
|
||||||
|
* @param file
|
||||||
|
* the file name
|
||||||
|
*/
|
||||||
|
public static void checkFile(String file) {
|
||||||
|
check(ToolChain.getCharStream(TEST_PROGRAM_LOCATION.resolve(file)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void check(CharStream stream) {
|
||||||
|
Logger logger = Logger.getAnonymousLogger();
|
||||||
|
log = ToolChain.makeListLog(logger);
|
||||||
|
logger.setLevel(logLevel);
|
||||||
|
|
||||||
|
ToolChain.getAnnotations(ToolChain.getParser(ToolChain.getLexer(stream, logger), logger).program(), logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compiles and runs a program from a string, logging to {@link #log} and
|
||||||
|
* writing lines of output to {@link #out}.
|
||||||
|
*
|
||||||
|
* @param code
|
||||||
|
* the code to type check
|
||||||
|
* @param input
|
||||||
|
* lines of input for the program
|
||||||
|
*/
|
||||||
|
public static void compileAndRunString(String code, String... input) {
|
||||||
|
compileAndRun(ToolChain.getCharStream(code), String.join("\n", input) + "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compiles and runs a program from a file, logging to {@link #log} and
|
||||||
|
* writing lines of output to {@link #out}.
|
||||||
|
*
|
||||||
|
* @param file
|
||||||
|
* the file name
|
||||||
|
* @param input
|
||||||
|
* lines of input for the program
|
||||||
|
*/
|
||||||
|
public static void compileAndRunFile(String file, String... input) {
|
||||||
|
compileAndRun(ToolChain.getCharStream(TEST_PROGRAM_LOCATION.resolve(file)), String.join("\n", input) + "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void compileAndRun(CharStream stream, String input) {
|
||||||
|
Logger logger = Logger.getAnonymousLogger();
|
||||||
|
log = ToolChain.makeListLog(logger);
|
||||||
|
logger.setLevel(logLevel);
|
||||||
|
|
||||||
|
ParseTree ast = ToolChain.getParser(ToolChain.getLexer(stream, logger), logger).program();
|
||||||
|
Annotations annotations = ToolChain.getAnnotations(ast, logger);
|
||||||
|
Program program = ToolChain.getILOC(ast, logger, annotations);
|
||||||
|
|
||||||
|
if (Simulator.DEBUG)
|
||||||
|
System.out.println(program.prettyPrint());
|
||||||
|
|
||||||
|
out = ToolChain.execute(program, logger, input).split("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compiles and runs a program in debug mode, printing the generated
|
||||||
|
* program, a simulation of the program and all log messages.
|
||||||
|
*
|
||||||
|
* @param stream
|
||||||
|
* a character stream with the program code
|
||||||
|
* @param input
|
||||||
|
* lines of input for the program
|
||||||
|
*/
|
||||||
|
public static void debugRun(CharStream stream, String... input) {
|
||||||
|
Simulator.DEBUG = true;
|
||||||
|
String in = String.join("\n", input) + "\n";
|
||||||
|
Logger logger = Logger.getAnonymousLogger();
|
||||||
|
log = ToolChain.makeListLog(logger);
|
||||||
|
logger.setLevel(Level.FINEST);
|
||||||
|
|
||||||
|
ParseTree ast = ToolChain.getParser(ToolChain.getLexer(stream, logger), logger).program();
|
||||||
|
Annotations annotations = ToolChain.getAnnotations(ast, logger);
|
||||||
|
Program program = ToolChain.getILOC(ast, logger, annotations);
|
||||||
|
|
||||||
|
System.out.println(program.prettyPrint());
|
||||||
|
|
||||||
|
out = ToolChain.execute(program, logger, in).split("\n");
|
||||||
|
|
||||||
|
log.forEach((entry) -> System.out.println(entry.getMessage()));
|
||||||
|
Simulator.DEBUG = false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,170 +0,0 @@
|
||||||
package pp.s1184725.boppi.test;
|
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
|
||||||
import static org.hamcrest.Matchers.*;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.logging.*;
|
|
||||||
|
|
||||||
import org.antlr.v4.runtime.CharStream;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import pp.s1184725.boppi.ToolChain;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test cases for the semantic checking stage for all language features.
|
|
||||||
*/
|
|
||||||
public class CheckerTest {
|
|
||||||
private List<LogRecord> log;
|
|
||||||
|
|
||||||
private void checkString(String code) {
|
|
||||||
check(ToolChain.getCharStream(code));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkFile(String file) {
|
|
||||||
check(ToolChain.getCharStream(AllTests.directory.resolve(file)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void check(CharStream stream) {
|
|
||||||
Logger logger = Logger.getAnonymousLogger();
|
|
||||||
log = ToolChain.makeListLog(logger);
|
|
||||||
logger.setLevel(AllTests.logLevel);
|
|
||||||
|
|
||||||
ToolChain.getAnnotations(ToolChain.getParser(ToolChain.getLexer(stream, logger), logger).program(), logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Correct basic expressions
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void correctExpressionTest() {
|
|
||||||
checkFile("simpleExpression.boppi");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Basic expressions with type errors
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void wrongExpressionTest() {
|
|
||||||
checkString("+true");
|
|
||||||
assertThat(log, hasSize(1));
|
|
||||||
|
|
||||||
checkString("5 || true");
|
|
||||||
assertThat(log, hasSize(1));
|
|
||||||
|
|
||||||
checkString("6 + 'c'");
|
|
||||||
assertThat(log, hasSize(1));
|
|
||||||
|
|
||||||
checkString("4 + print(5, 6)");
|
|
||||||
assertThat(log, hasSize(1));
|
|
||||||
|
|
||||||
checkString("print(print(3, 5))");
|
|
||||||
assertThat(log, hasSize(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Correct variable use
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void correctVariableTest() {
|
|
||||||
checkFile("simpleVariable.boppi");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Variable use with type errors
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void wrongVariableTest() {
|
|
||||||
checkString("var bool name; name := 5");
|
|
||||||
assertThat(log, hasSize(1));
|
|
||||||
|
|
||||||
checkString("undefinedName");
|
|
||||||
assertThat(log, hasSize(1));
|
|
||||||
|
|
||||||
checkString("var undefinedType name; 1");
|
|
||||||
assertThat(log, hasSize(1));
|
|
||||||
|
|
||||||
checkString("var bool endsWithDeclaration;");
|
|
||||||
assertThat(log, hasSize(1));
|
|
||||||
|
|
||||||
checkString("var bool var1; var var1 var2; var2 := 'c' ");
|
|
||||||
assertThat(log, hasSize(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Correct variable scoping
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void correctScopeTest() {
|
|
||||||
checkFile("simpleScope.boppi");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Variable redeclaring and out-of-scope errors
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void wrongScopeTest() {
|
|
||||||
checkString("var bool var1; var bool var1; 1");
|
|
||||||
assertThat(log, hasSize(1));
|
|
||||||
|
|
||||||
checkString("var bool var1; var char var1; 1");
|
|
||||||
assertThat(log, hasSize(1));
|
|
||||||
|
|
||||||
checkString("{ var int var1; var1 := 4}; var int var2; var1");
|
|
||||||
assertThat(log, hasSize(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Correct if-else and loop use
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void correctConditionalTest() {
|
|
||||||
checkFile("if.boppi");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
|
|
||||||
checkFile("while.boppi");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Correct function declaration and calls
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void correctFunctionTest() {
|
|
||||||
checkString("function int id(int a) a; 1");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
|
|
||||||
checkString("function int id(int a) a; id(1); 1");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
|
|
||||||
checkString("var int a; function int const() a; 1");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
|
|
||||||
checkString("function int add(int a, int b) a+b; print(add(4, 5)+1)");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
|
|
||||||
checkString("function char const(char a, char b) a; print(const('A', 'T'))");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
|
|
||||||
checkString("function int factorial(int n) {if (n > 1) then n*factorial(n-1) else 1 fi}");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function use with type errors
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void wrongFunctionTest() {
|
|
||||||
checkString("function int add(int a, char b) a+b; print(add(4, 'T')+1)");
|
|
||||||
assertThat(log, hasSize(1));
|
|
||||||
|
|
||||||
checkString("function char add(int a, int b) a+b; print(add(4, 5))");
|
|
||||||
assertThat(log, hasSize(1));
|
|
||||||
|
|
||||||
checkString("function int add(int a, int b) a+b; print(add(4, 'T')+1)");
|
|
||||||
assertThat(log, hasSize(1));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
package pp.s1184725.boppi.test;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for conditionals, i.e. if, if-else branching and while loops.
|
||||||
|
*
|
||||||
|
* @author Frank Wibbelink
|
||||||
|
*/
|
||||||
|
public class ConditionalTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct if-else and loop use
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void correctConditionalParsing() {
|
||||||
|
AllTests.parseFile("if.boppi");
|
||||||
|
assertThat(AllTests.log, empty());
|
||||||
|
|
||||||
|
AllTests.parseFile("while.boppi");
|
||||||
|
assertThat(AllTests.log, empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct if-else and loop use
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void correctConditionalChecking() {
|
||||||
|
AllTests.checkFile("if.boppi");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
|
||||||
|
AllTests.checkFile("while.boppi");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct evaluation of basic programs
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void basicPrograms() {
|
||||||
|
AllTests.compileAndRunString("print(5*3)");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
assertThat(AllTests.out, is(arrayContaining("15")));
|
||||||
|
|
||||||
|
AllTests.compileAndRunString("print({var int x; x := 8; print(x)})");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
assertThat(AllTests.out, is(arrayContaining("8", "8")));
|
||||||
|
|
||||||
|
AllTests.compileAndRunString("print('T', 'e', 's', 't', '!')");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
assertThat(AllTests.out, is(arrayContaining("T", "e", "s", "t", "!")));
|
||||||
|
|
||||||
|
AllTests.compileAndRunString("var int x; var int y; x := 3*(y := 4); print(x,y)");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
assertThat(AllTests.out, is(arrayContaining("12", "4")));
|
||||||
|
|
||||||
|
AllTests.compileAndRunFile("basicProgram1.boppi", "1", "T");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
assertThat(AllTests.out, is(arrayContaining("T", "T")));
|
||||||
|
|
||||||
|
AllTests.compileAndRunFile("fibonacciIterative.boppi", "6");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
assertThat(AllTests.out, is(arrayContaining("13")));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
package pp.s1184725.boppi.test;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test cases for the basic expression language.
|
||||||
|
*
|
||||||
|
* @author Frank Wibbelink
|
||||||
|
*/
|
||||||
|
public class ExpressionTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct basic expressions
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void correctExpressionParsing() {
|
||||||
|
AllTests.parseFile("simpleExpression.boppi");
|
||||||
|
assertThat(AllTests.log, empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic expressions with syntax errors
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void wrongExpressionParsing() {
|
||||||
|
AllTests.parseString("");
|
||||||
|
assertThat(AllTests.log, not(empty()));
|
||||||
|
|
||||||
|
AllTests.parseString("~");
|
||||||
|
assertThat(AllTests.log, not(empty()));
|
||||||
|
|
||||||
|
AllTests.parseString("0A");
|
||||||
|
assertThat(AllTests.log, hasSize(1));
|
||||||
|
|
||||||
|
AllTests.parseString("do");
|
||||||
|
assertThat(AllTests.log, hasSize(1));
|
||||||
|
|
||||||
|
AllTests.parseString("true true");
|
||||||
|
assertThat(AllTests.log, hasSize(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct basic expressions
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void correctExpressionChecking() {
|
||||||
|
AllTests.checkFile("simpleExpression.boppi");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic expressions with type errors
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void wrongExpressionChecking() {
|
||||||
|
AllTests.checkString("+true");
|
||||||
|
assertThat(AllTests.log, hasSize(1));
|
||||||
|
|
||||||
|
AllTests.checkString("5 || true");
|
||||||
|
assertThat(AllTests.log, hasSize(1));
|
||||||
|
|
||||||
|
AllTests.checkString("6 + 'c'");
|
||||||
|
assertThat(AllTests.log, hasSize(1));
|
||||||
|
|
||||||
|
AllTests.checkString("4 + print(5, 6)");
|
||||||
|
assertThat(AllTests.log, hasSize(1));
|
||||||
|
|
||||||
|
AllTests.checkString("print(print(3, 5))");
|
||||||
|
assertThat(AllTests.log, hasSize(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct basic expressions
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void correctExpressionGeneration() {
|
||||||
|
AllTests.compileAndRunFile("simpleExpression.boppi");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
|
||||||
|
int n = 12;
|
||||||
|
String expression = StringUtils.repeat("1+(", n) + "1" + StringUtils.repeat(")", n);
|
||||||
|
|
||||||
|
AllTests.withWarnings(() -> {
|
||||||
|
AllTests.compileAndRunString("print(" + expression + ")", "" + n);
|
||||||
|
assertThat(AllTests.log, hasSize(1));
|
||||||
|
assertThat(AllTests.log.get(0).getLevel(), is(Level.WARNING));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic expression with run-time error
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void wrongExpressionGeneration() {
|
||||||
|
AllTests.compileAndRunString("1/0");
|
||||||
|
assertThat(AllTests.log, hasSize(1));
|
||||||
|
assertThat(AllTests.log.get(0).getMessage(), containsString("zero"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,178 +0,0 @@
|
||||||
package pp.s1184725.boppi.test;
|
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
|
||||||
import static org.hamcrest.Matchers.*;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.logging.*;
|
|
||||||
|
|
||||||
import org.antlr.v4.runtime.CharStream;
|
|
||||||
import org.antlr.v4.runtime.tree.ParseTree;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import pp.iloc.Simulator;
|
|
||||||
import pp.iloc.model.Program;
|
|
||||||
import pp.s1184725.boppi.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test cases for the code generating stage for all language features.
|
|
||||||
*/
|
|
||||||
public class GeneratorTest {
|
|
||||||
private List<LogRecord> log;
|
|
||||||
private String[] out;
|
|
||||||
|
|
||||||
private void compileAndRunString(String code, String... input) {
|
|
||||||
compileAndRun(ToolChain.getCharStream(code), String.join("\n", input) + "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void compileAndRunFile(String file, String... input) {
|
|
||||||
compileAndRun(ToolChain.getCharStream(AllTests.directory.resolve(file)), String.join("\n", input) + "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void compileAndRun(CharStream stream, String input) {
|
|
||||||
Logger logger = Logger.getAnonymousLogger();
|
|
||||||
log = ToolChain.makeListLog(logger);
|
|
||||||
logger.setLevel(AllTests.logLevel);
|
|
||||||
|
|
||||||
ParseTree ast = ToolChain.getParser(ToolChain.getLexer(stream, logger), logger).program();
|
|
||||||
Annotations annotations = ToolChain.getAnnotations(ast, logger);
|
|
||||||
Program program = ToolChain.getILOC(ast, logger, annotations);
|
|
||||||
|
|
||||||
if (Simulator.DEBUG)
|
|
||||||
System.out.println(program.prettyPrint());
|
|
||||||
|
|
||||||
out = ToolChain.execute(program, logger, input).split("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private void debugRun(CharStream stream, String... input) {
|
|
||||||
Simulator.DEBUG = true;
|
|
||||||
String in = String.join("\n", input) + "\n";
|
|
||||||
Logger logger = Logger.getAnonymousLogger();
|
|
||||||
log = ToolChain.makeListLog(logger);
|
|
||||||
logger.setLevel(Level.FINEST);
|
|
||||||
|
|
||||||
ParseTree ast = ToolChain.getParser(ToolChain.getLexer(stream, logger), logger).program();
|
|
||||||
Annotations annotations = ToolChain.getAnnotations(ast, logger);
|
|
||||||
Program program = ToolChain.getILOC(ast, logger, annotations);
|
|
||||||
|
|
||||||
System.out.println(program.prettyPrint());
|
|
||||||
|
|
||||||
out = ToolChain.execute(program, logger, in).split("\n");
|
|
||||||
|
|
||||||
log.forEach((entry) -> System.out.println(entry.getMessage()));
|
|
||||||
Simulator.DEBUG = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Correct basic expressions
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void correctExpressionTest() {
|
|
||||||
compileAndRunFile("simpleExpression.boppi");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
|
|
||||||
int n = 12;
|
|
||||||
String expression = StringUtils.repeat("1+(", n) + "1" + StringUtils.repeat(")", n);
|
|
||||||
AllTests.withWarnings(() -> {
|
|
||||||
compileAndRunString("print(" + expression + ")", "" + n);
|
|
||||||
assertThat(log, hasSize(1));
|
|
||||||
assertThat(log.get(0).getLevel(), is(Level.WARNING));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Basic expression with run-time error
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void wrongExpressionTest() {
|
|
||||||
compileAndRunString("1/0");
|
|
||||||
assertThat(log, hasSize(1));
|
|
||||||
assertThat(log.get(0).getMessage(), containsString("zero"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Correct variable use
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void correctVariableTest() {
|
|
||||||
compileAndRunFile("simpleVariable.boppi");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Correct evaluation of basic programs
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void basicPrograms() {
|
|
||||||
compileAndRunString("print(5*3)");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
assertThat(out, is(arrayContaining("15")));
|
|
||||||
|
|
||||||
compileAndRunString("print({var int x; x := 8; print(x)})");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
assertThat(out, is(arrayContaining("8", "8")));
|
|
||||||
|
|
||||||
compileAndRunString("print('T', 'e', 's', 't', '!')");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
assertThat(out, is(arrayContaining("T", "e", "s", "t", "!")));
|
|
||||||
|
|
||||||
compileAndRunString("var int x; var int y; x := 3*(y := 4); print(x,y)");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
assertThat(out, is(arrayContaining("12", "4")));
|
|
||||||
|
|
||||||
compileAndRunFile("basicProgram1.boppi", "1", "T");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
assertThat(out, is(arrayContaining("T", "T")));
|
|
||||||
|
|
||||||
compileAndRunFile("fibonacciIterative.boppi", "6");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
assertThat(out, is(arrayContaining("13")));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Correct evaluation of basic functions
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void correctSimpleFunctionTest() {
|
|
||||||
compileAndRunString("function int id(int a) a; 1");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
|
|
||||||
compileAndRunString("function int id(int a) a; id(1); 1");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
|
|
||||||
compileAndRunString("var int a; function int const(int b) a; 1");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
|
|
||||||
compileAndRunString("var int a; a := 1; function int const(int b) a; print(const(4))");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
assertThat(out, is(arrayContaining("1")));
|
|
||||||
|
|
||||||
compileAndRunString("function int add(int a, int b) a+b; print(add(4, 5)+1)");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
assertThat(out, is(arrayContaining("10")));
|
|
||||||
|
|
||||||
compileAndRunString("function char const(char a, char b) a; print(const('A', 'T'))");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
assertThat(out, is(arrayContaining("A")));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Correct evaluation of recursive functions, nested functions and function
|
|
||||||
* passing
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void correctComplexFunctionTest() {
|
|
||||||
compileAndRunString("function int factorial(int n) {if (n > 1) then n*factorial(n-1) else 1 fi}");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
|
|
||||||
compileAndRunFile("recursiveFactorial.boppi", "5");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
assertThat(out, is(arrayContaining("120")));
|
|
||||||
|
|
||||||
compileAndRunFile("simpleFunctionPassing.boppi");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
assertThat(out, is(arrayContaining("40", "104", "1", "2", "8")));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,150 +0,0 @@
|
||||||
package pp.s1184725.boppi.test;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.logging.*;
|
|
||||||
|
|
||||||
import org.antlr.v4.runtime.CharStream;
|
|
||||||
import org.junit.Test;
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
|
||||||
import static org.hamcrest.Matchers.*;
|
|
||||||
import pp.s1184725.boppi.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test cases for the parsing stage for all language features.
|
|
||||||
*/
|
|
||||||
public class ParserTest {
|
|
||||||
private List<LogRecord> log;
|
|
||||||
|
|
||||||
private void parseString(String code) {
|
|
||||||
parse(ToolChain.getCharStream(code));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void parseFile(String file) {
|
|
||||||
parse(ToolChain.getCharStream(AllTests.directory.resolve(file)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void parse(CharStream stream) {
|
|
||||||
Logger logger = Logger.getAnonymousLogger();
|
|
||||||
log = ToolChain.makeListLog(logger);
|
|
||||||
logger.setLevel(AllTests.logLevel);
|
|
||||||
|
|
||||||
ToolChain.getParser(ToolChain.getLexer(stream, logger), logger).program();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Correct basic expressions
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void correctExpressionTest() {
|
|
||||||
parseFile("simpleExpression.boppi");
|
|
||||||
assertThat(log, empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Basic expressions with syntax errors
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void wrongExpressionTest() {
|
|
||||||
parseString("");
|
|
||||||
assertThat(log, not(empty()));
|
|
||||||
|
|
||||||
parseString("~");
|
|
||||||
assertThat(log, not(empty()));
|
|
||||||
|
|
||||||
parseString("0A");
|
|
||||||
assertThat(log, hasSize(1));
|
|
||||||
|
|
||||||
parseString("do");
|
|
||||||
assertThat(log, hasSize(1));
|
|
||||||
|
|
||||||
parseString("true true");
|
|
||||||
assertThat(log, hasSize(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Correct variable use
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void correctVariableTest() {
|
|
||||||
parseFile("simpleVariable.boppi");
|
|
||||||
assertThat(log, empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Variable use with syntax errors
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void wrongVariableTest() {
|
|
||||||
parseString("var");
|
|
||||||
assertThat(log, hasSize(1));
|
|
||||||
|
|
||||||
parseString("var bool 5");
|
|
||||||
assertThat(log, hasSize(1));
|
|
||||||
|
|
||||||
parseString("var 'c' varname");
|
|
||||||
assertThat(log, not(empty()));
|
|
||||||
|
|
||||||
parseString("var bool; true true;");
|
|
||||||
assertThat(log, hasSize(2));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Correct variable scoping
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void correctScopeTest() {
|
|
||||||
parseFile("simpleScope.boppi");
|
|
||||||
assertThat(log, empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Correct if-else and loop use
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void correctConditionalTest() {
|
|
||||||
parseFile("if.boppi");
|
|
||||||
assertThat(log, empty());
|
|
||||||
|
|
||||||
parseFile("while.boppi");
|
|
||||||
assertThat(log, empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Correct function declaration and calls
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void correctFunctionTest() {
|
|
||||||
parseString("function int id(int a) a; 1");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
|
|
||||||
parseString("function int id(int a) a; id(1)");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
|
|
||||||
parseString("var int a; a := 1; function int const() a; const()");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
|
|
||||||
parseString("function int add(int a, int b) a+b; print(add(4, 5)+1)");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
|
|
||||||
parseString("function char const(char a, char b) a; print(const('A', 'T'))");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
|
|
||||||
parseString("function int factorial(int n) {if (n > 1) then n*factorial(n-1) else 1 fi}");
|
|
||||||
assertThat(log, is(empty()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function use with syntax errors
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void wrongFunctionTest() {
|
|
||||||
parseString("function doNothing(int a, char b) a+b; print(add(4, 'T')+1)");
|
|
||||||
assertThat(log, hasSize(1));
|
|
||||||
|
|
||||||
parseString("function char add(int a, int b);");
|
|
||||||
assertThat(log, hasSize(1));
|
|
||||||
|
|
||||||
parseString("function int add(int a, int b) a+b; add(4,)");
|
|
||||||
assertThat(log, hasSize(1));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,137 @@
|
||||||
|
package pp.s1184725.boppi.test;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for function use and simple function passing (i.e. no closures required).
|
||||||
|
*
|
||||||
|
* @author Frank Wibbelink
|
||||||
|
*/
|
||||||
|
public class SimpleFunctionTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct function declaration and calls
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void correctFunctionParsing() {
|
||||||
|
AllTests.parseString("function int id(int a) a; 1");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
|
||||||
|
AllTests.parseString("function int id(int a) a; id(1)");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
|
||||||
|
AllTests.parseString("var int a; a := 1; function int const() a; const()");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
|
||||||
|
AllTests.parseString("function int add(int a, int b) a+b; print(add(4, 5)+1)");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
|
||||||
|
AllTests.parseString("function char const(char a, char b) a; print(const('A', 'T'))");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
|
||||||
|
AllTests.parseString("function int factorial(int n) {if (n > 1) then n*factorial(n-1) else 1 fi}");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function use with syntax errors
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void wrongFunctionParsing() {
|
||||||
|
AllTests.parseString("function doNothing(int a, char b) a+b; print(add(4, 'T')+1)");
|
||||||
|
assertThat(AllTests.log, hasSize(1));
|
||||||
|
|
||||||
|
AllTests.parseString("function char add(int a, int b);");
|
||||||
|
assertThat(AllTests.log, hasSize(1));
|
||||||
|
|
||||||
|
AllTests.parseString("function int add(int a, int b) a+b; add(4,)");
|
||||||
|
assertThat(AllTests.log, hasSize(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct function declaration and calls
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void correctFunctionChecking() {
|
||||||
|
AllTests.checkString("function int id(int a) a; 1");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
|
||||||
|
AllTests.checkString("function int id(int a) a; id(1); 1");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
|
||||||
|
AllTests.checkString("var int a; function int const() a; 1");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
|
||||||
|
AllTests.checkString("function int add(int a, int b) a+b; print(add(4, 5)+1)");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
|
||||||
|
AllTests.checkString("function char const(char a, char b) a; print(const('A', 'T'))");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
|
||||||
|
AllTests.checkString("function int factorial(int n) {if (n > 1) then n*factorial(n-1) else 1 fi}");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function use with type errors
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void wrongFunctionChecking() {
|
||||||
|
AllTests.checkString("function int add(int a, char b) a+b; print(add(4, 'T')+1)");
|
||||||
|
assertThat(AllTests.log, hasSize(1));
|
||||||
|
|
||||||
|
AllTests.checkString("function char add(int a, int b) a+b; print(add(4, 5))");
|
||||||
|
assertThat(AllTests.log, hasSize(1));
|
||||||
|
|
||||||
|
AllTests.checkString("function int add(int a, int b) a+b; print(add(4, 'T')+1)");
|
||||||
|
assertThat(AllTests.log, hasSize(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct evaluation of basic functions
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void correctSimpleFunctionGeneration() {
|
||||||
|
AllTests.compileAndRunString("function int id(int a) a; 1");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
|
||||||
|
AllTests.compileAndRunString("function int id(int a) a; id(1); 1");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
|
||||||
|
AllTests.compileAndRunString("var int a; function int const(int b) a; 1");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
|
||||||
|
AllTests.compileAndRunString("var int a; a := 1; function int const(int b) a; print(const(4))");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
assertThat(AllTests.out, is(arrayContaining("1")));
|
||||||
|
|
||||||
|
AllTests.compileAndRunString("function int add(int a, int b) a+b; print(add(4, 5)+1)");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
assertThat(AllTests.out, is(arrayContaining("10")));
|
||||||
|
|
||||||
|
AllTests.compileAndRunString("function char const(char a, char b) a; print(const('A', 'T'))");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
assertThat(AllTests.out, is(arrayContaining("A")));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct evaluation of recursive functions, nested functions and function
|
||||||
|
* passing
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void correctComplexFunctionGeneration() {
|
||||||
|
AllTests.compileAndRunString("function int factorial(int n) {if (n > 1) then n*factorial(n-1) else 1 fi}");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
|
||||||
|
AllTests.compileAndRunFile("recursiveFactorial.boppi", "5");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
assertThat(AllTests.out, is(arrayContaining("120")));
|
||||||
|
|
||||||
|
AllTests.compileAndRunFile("simpleFunctionPassing.boppi");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
assertThat(AllTests.out, is(arrayContaining("40", "104", "1", "2", "8")));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,113 @@
|
||||||
|
package pp.s1184725.boppi.test;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for simple (i.e. no functions involved) variable use.
|
||||||
|
*
|
||||||
|
* @author Frank Wibbelink
|
||||||
|
*/
|
||||||
|
public class SimpleVariableTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct variable use
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void correctVariableParsing() {
|
||||||
|
AllTests.parseFile("simpleVariable.boppi");
|
||||||
|
assertThat(AllTests.log, empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variable use with syntax errors
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void wrongVariableParsing() {
|
||||||
|
AllTests.parseString("var");
|
||||||
|
assertThat(AllTests.log, hasSize(1));
|
||||||
|
|
||||||
|
AllTests.parseString("var bool 5");
|
||||||
|
assertThat(AllTests.log, hasSize(1));
|
||||||
|
|
||||||
|
AllTests.parseString("var 'c' varname");
|
||||||
|
assertThat(AllTests.log, not(empty()));
|
||||||
|
|
||||||
|
AllTests.parseString("var bool; true true;");
|
||||||
|
assertThat(AllTests.log, hasSize(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct variable scoping
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void correctScopeParsing() {
|
||||||
|
AllTests.parseFile("simpleScope.boppi");
|
||||||
|
assertThat(AllTests.log, empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct variable use
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void correctVariableChecking() {
|
||||||
|
AllTests.checkFile("simpleVariable.boppi");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variable use with type errors
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void wrongVariableChecking() {
|
||||||
|
AllTests.checkString("var bool name; name := 5");
|
||||||
|
assertThat(AllTests.log, hasSize(1));
|
||||||
|
|
||||||
|
AllTests.checkString("undefinedName");
|
||||||
|
assertThat(AllTests.log, hasSize(1));
|
||||||
|
|
||||||
|
AllTests.checkString("var undefinedType name; 1");
|
||||||
|
assertThat(AllTests.log, hasSize(1));
|
||||||
|
|
||||||
|
AllTests.checkString("var bool endsWithDeclaration;");
|
||||||
|
assertThat(AllTests.log, hasSize(1));
|
||||||
|
|
||||||
|
AllTests.checkString("var bool var1; var var1 var2; var2 := 'c' ");
|
||||||
|
assertThat(AllTests.log, hasSize(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct variable scoping
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void correctScopeChecking() {
|
||||||
|
AllTests.checkFile("simpleScope.boppi");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variable redeclaring and out-of-scope errors
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void wrongScopeChecking() {
|
||||||
|
AllTests.checkString("var bool var1; var bool var1; 1");
|
||||||
|
assertThat(AllTests.log, hasSize(1));
|
||||||
|
|
||||||
|
AllTests.checkString("var bool var1; var char var1; 1");
|
||||||
|
assertThat(AllTests.log, hasSize(1));
|
||||||
|
|
||||||
|
AllTests.checkString("{ var int var1; var1 := 4}; var int var2; var1");
|
||||||
|
assertThat(AllTests.log, hasSize(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct variable use
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void correctVariableGeneration() {
|
||||||
|
AllTests.compileAndRunFile("simpleVariable.boppi");
|
||||||
|
assertThat(AllTests.log, is(empty()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
var int undefined;
|
var (int,int)->int intBinOp; //unused variable for type aliasing
|
||||||
function int intDiadic(int a, int b) undefined;
|
|
||||||
|
|
||||||
function intDiadic getMultiply() {
|
function intBinOp getMultiply() {
|
||||||
function int multiply(int a, int b)
|
function int multiply(int a, int b)
|
||||||
a*b;
|
a*b;
|
||||||
multiply
|
multiply
|
||||||
|
@ -9,7 +8,7 @@ function intDiadic getMultiply() {
|
||||||
|
|
||||||
function int biasedMultiply(int a, int b) a*b+4;
|
function int biasedMultiply(int a, int b) a*b+4;
|
||||||
|
|
||||||
var intDiadic myMultiply;
|
var intBinOp myMultiply;
|
||||||
myMultiply := getMultiply();
|
myMultiply := getMultiply();
|
||||||
print(myMultiply(5, 8));
|
print(myMultiply(5, 8));
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package pp.s1184725.boppi;
|
package pp.s1184725.boppi.type;
|
||||||
|
|
||||||
import pp.iloc.eval.Machine;
|
import pp.iloc.eval.Machine;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The (->) type. Takes exactly two types as arguments.
|
* The (->) type. Takes exactly two types as arguments.
|
||||||
|
*
|
||||||
|
* @author Frank Wibbelink
|
||||||
*/
|
*/
|
||||||
public class FunctionType implements Type {
|
public class FunctionType implements Type {
|
||||||
private Type argument, result;
|
private Type argument, result;
|
|
@ -1,4 +1,4 @@
|
||||||
package pp.s1184725.boppi;
|
package pp.s1184725.boppi.type;
|
||||||
|
|
||||||
import static pp.s1184725.boppi.antlr.BoppiLexer.*;
|
import static pp.s1184725.boppi.antlr.BoppiLexer.*;
|
||||||
|
|
||||||
|
@ -13,6 +13,8 @@ import pp.s1184725.boppi.antlr.BoppiLexer;
|
||||||
* <li>boolean (sized {@link Machine#INT_SIZE})</li>
|
* <li>boolean (sized {@link Machine#INT_SIZE})</li>
|
||||||
* <li>void (empty/unit type)</li>
|
* <li>void (empty/unit type)</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
|
*
|
||||||
|
* @author Frank Wibbelink
|
||||||
*/
|
*/
|
||||||
public enum SimpleType implements Type {
|
public enum SimpleType implements Type {
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
package pp.s1184725.boppi;
|
package pp.s1184725.boppi.type;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The n-tuple type. Takes exactly {@link #size()} types. The element indices in
|
* The n-tuple type. Takes exactly {@link #size()} types. The element indices in
|
||||||
* the tuple are 0-based.
|
* the tuple are zero-based.
|
||||||
|
*
|
||||||
|
* @author Frank Wibbelink
|
||||||
*/
|
*/
|
||||||
public class TupleType extends AbstractList<Type> implements Type {
|
public class TupleType extends AbstractList<Type> implements Type {
|
||||||
/**
|
/**
|
||||||
|
@ -19,6 +21,7 @@ public class TupleType extends AbstractList<Type> implements Type {
|
||||||
* Creates an n-tuple of the given types.
|
* Creates an n-tuple of the given types.
|
||||||
*
|
*
|
||||||
* @param parameterTypes
|
* @param parameterTypes
|
||||||
|
* a list of types for this tuple
|
||||||
*/
|
*/
|
||||||
public TupleType(List<Type> parameterTypes) {
|
public TupleType(List<Type> parameterTypes) {
|
||||||
parameters = new ArrayList<>(parameterTypes);
|
parameters = new ArrayList<>(parameterTypes);
|
||||||
|
@ -59,7 +62,8 @@ public class TupleType extends AbstractList<Type> implements Type {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return parameters.stream().map(Type::toString).collect(Collectors.joining(",", "(", ")"));
|
return parameters.stream().map((type) -> type == null ? "TYPE = NULL" : type.toString())
|
||||||
|
.collect(Collectors.joining(",", "(", ")"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
|
@ -1,7 +1,9 @@
|
||||||
package pp.s1184725.boppi;
|
package pp.s1184725.boppi.type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic type interface. All types must have at least these properties.
|
* Generic type interface. All types must have at least these properties.
|
||||||
|
*
|
||||||
|
* @author Frank Wibbelink
|
||||||
*/
|
*/
|
||||||
public interface Type {
|
public interface Type {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<project default="javadoc">
|
<project default="javadoc">
|
||||||
<target name="javadoc">
|
<target name="javadoc">
|
||||||
<javadoc access="public" author="true" classpath="lib/commons-lang3-3.5.jar;lib/antlr-4.7-complete.jar;lib/junit-4.12.jar;lib/hamcrest-all-1.3.jar" destdir="doc/javadoc" nodeprecated="false" nodeprecatedlist="false" noindex="false" nonavbar="false" notree="false" packagenames="pp.s1184725.boppi,pp.s1184725.boppi.test" source="1.8" sourcepath="src" splitindex="false" use="true" version="true">
|
<javadoc access="public" author="true" classpath="../lib/commons-lang3-3.5.jar;../lib/antlr-4.7-complete.jar;../lib/junit-4.12.jar;../lib/hamcrest-all-1.3.jar" destdir="../doc/javadoc" nodeprecated="false" nodeprecatedlist="false" noindex="false" nonavbar="false" notree="false" packagenames="pp.*" source="1.8" sourcepath="../src" splitindex="false" use="true" version="true">
|
||||||
<link href="http://www.antlr.org/api/Java/"/>
|
<link href="http://www.antlr.org/api/Java/"/>
|
||||||
<link href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/"/>
|
<link href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/"/>
|
||||||
<link href="https://docs.oracle.com/javase/8/docs/api/"/>
|
<link href="https://docs.oracle.com/javase/8/docs/api/"/>
|
Loading…
Reference in New Issue