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{graphicx}
|
||||
\usepackage{pdfpages}
|
||||
\usepackage[dutch]{babel}
|
||||
\usepackage[english]{babel}
|
||||
\usepackage{amsmath}
|
||||
\usepackage{amsfonts}
|
||||
\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 pp.iloc.model.Reg;
|
||||
import pp.s1184725.boppi.type.*;
|
||||
|
||||
/**
|
||||
* This class holds properties of all AST nodes during compilation.
|
||||
*
|
||||
* @author Frank Wibbelink
|
||||
*/
|
||||
public class Annotations {
|
||||
/**
|
||||
|
|
|
@ -7,14 +7,15 @@ import java.util.stream.Collectors;
|
|||
import org.antlr.v4.runtime.ParserRuleContext;
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
|
||||
import pp.s1184725.boppi.antlr.BoppiBaseVisitor;
|
||||
import pp.s1184725.boppi.antlr.BoppiLexer;
|
||||
import pp.s1184725.boppi.antlr.*;
|
||||
import pp.s1184725.boppi.antlr.BoppiParser.*;
|
||||
import pp.s1184725.boppi.type.*;
|
||||
|
||||
/**
|
||||
* This class performs type checking and variable assignment on a bare parse
|
||||
* tree.
|
||||
*
|
||||
* @author Frank Wibbelink
|
||||
*/
|
||||
public class BoppiChecker extends BoppiBaseVisitor<Type> {
|
||||
private Annotations an;
|
||||
|
@ -305,7 +306,7 @@ public class BoppiChecker extends BoppiBaseVisitor<Type> {
|
|||
|
||||
@Override
|
||||
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
|
||||
|
|
|
@ -10,12 +10,14 @@ import org.apache.commons.lang3.StringUtils;
|
|||
|
||||
import pp.iloc.eval.Machine;
|
||||
import pp.iloc.model.*;
|
||||
import pp.s1184725.boppi.antlr.BoppiBaseVisitor;
|
||||
import pp.s1184725.boppi.antlr.BoppiLexer;
|
||||
import pp.s1184725.boppi.antlr.*;
|
||||
import pp.s1184725.boppi.antlr.BoppiParser.*;
|
||||
import pp.s1184725.boppi.type.*;
|
||||
|
||||
/**
|
||||
* The generator stage of the Boppi toolchain.
|
||||
*
|
||||
* @author Frank Wibbelink
|
||||
*/
|
||||
public class BoppiGenerator extends BoppiBaseVisitor<Void> {
|
||||
private static final int ARBASESIZE = 16;
|
||||
|
|
|
@ -3,6 +3,8 @@ package pp.s1184725.boppi;
|
|||
import java.util.*;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import pp.s1184725.boppi.type.*;
|
||||
|
||||
/**
|
||||
* This class maps string identifiers to {@link Variable} instances. It takes
|
||||
* care of lexical scope, memory offsets and variable lifetime. This
|
||||
|
@ -12,6 +14,8 @@ import java.util.function.Supplier;
|
|||
*
|
||||
* @param <T>
|
||||
* the typing class
|
||||
*
|
||||
* @author Frank Wibbelink
|
||||
*/
|
||||
public class CachingSymbolTable<T extends Type> {
|
||||
protected Stack<Map<String, Variable<T>>> symbolMapStack;
|
||||
|
|
|
@ -2,12 +2,16 @@ package pp.s1184725.boppi;
|
|||
|
||||
import java.util.EmptyStackException;
|
||||
|
||||
import pp.s1184725.boppi.type.*;
|
||||
|
||||
/**
|
||||
* Same functionality as {@link CachingSymbolTable} except actions on the table
|
||||
* are logged to the console.
|
||||
*
|
||||
* @param <T>
|
||||
* the typing class
|
||||
*
|
||||
* @author Frank Wibbelink
|
||||
*/
|
||||
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.model.Program;
|
||||
import pp.s1184725.boppi.antlr.BoppiLexer;
|
||||
import pp.s1184725.boppi.antlr.BoppiParser;
|
||||
import pp.s1184725.boppi.antlr.*;
|
||||
|
||||
/**
|
||||
* This class provides methods for all steps in the Boppi tool chain.
|
||||
*
|
||||
* @author Frank Wibbelink
|
||||
*/
|
||||
public class ToolChain {
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@ package pp.s1184725.boppi;
|
|||
*
|
||||
* @param <T>
|
||||
* the typing class
|
||||
*
|
||||
* @author Frank Wibbelink
|
||||
*/
|
||||
public class Variable<T> {
|
||||
private final T type;
|
||||
|
|
|
@ -1,29 +1,55 @@
|
|||
package pp.s1184725.boppi.test;
|
||||
|
||||
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.runners.Suite;
|
||||
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)
|
||||
@SuiteClasses({ CheckerTest.class, GeneratorTest.class, ParserTest.class })
|
||||
@SuiteClasses({ ExpressionTest.class, SimpleVariableTest.class, ConditionalTest.class, SimpleFunctionTest.class })
|
||||
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/");
|
||||
|
||||
/**
|
||||
* 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
|
||||
* include finer tests.
|
||||
*/
|
||||
public static Level logLevel = Level.SEVERE;
|
||||
private static Level logLevel = DEFAULT_LOG_LEVEL;
|
||||
|
||||
/**
|
||||
* Runs a test with warnings enabled.
|
||||
|
@ -34,6 +60,132 @@ public class AllTests {
|
|||
public static void withWarnings(Runnable test) {
|
||||
logLevel = Level.WARNING;
|
||||
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;
|
||||
function int intDiadic(int a, int b) undefined;
|
||||
var (int,int)->int intBinOp; //unused variable for type aliasing
|
||||
|
||||
function intDiadic getMultiply() {
|
||||
function intBinOp getMultiply() {
|
||||
function int multiply(int a, int b)
|
||||
a*b;
|
||||
multiply
|
||||
|
@ -9,7 +8,7 @@ function intDiadic getMultiply() {
|
|||
|
||||
function int biasedMultiply(int a, int b) a*b+4;
|
||||
|
||||
var intDiadic myMultiply;
|
||||
var intBinOp myMultiply;
|
||||
myMultiply := getMultiply();
|
||||
print(myMultiply(5, 8));
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package pp.s1184725.boppi;
|
||||
package pp.s1184725.boppi.type;
|
||||
|
||||
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 {
|
||||
private Type argument, result;
|
|
@ -1,4 +1,4 @@
|
|||
package pp.s1184725.boppi;
|
||||
package pp.s1184725.boppi.type;
|
||||
|
||||
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>void (empty/unit type)</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Frank Wibbelink
|
||||
*/
|
||||
public enum SimpleType implements Type {
|
||||
|
|
@ -1,11 +1,13 @@
|
|||
package pp.s1184725.boppi;
|
||||
package pp.s1184725.boppi.type;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
/**
|
||||
|
@ -19,6 +21,7 @@ public class TupleType extends AbstractList<Type> implements Type {
|
|||
* Creates an n-tuple of the given types.
|
||||
*
|
||||
* @param parameterTypes
|
||||
* a list of types for this tuple
|
||||
*/
|
||||
public TupleType(List<Type> parameterTypes) {
|
||||
parameters = new ArrayList<>(parameterTypes);
|
||||
|
@ -59,7 +62,8 @@ public class TupleType extends AbstractList<Type> implements Type {
|
|||
|
||||
@Override
|
||||
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
|
|
@ -1,7 +1,9 @@
|
|||
package pp.s1184725.boppi;
|
||||
package pp.s1184725.boppi.type;
|
||||
|
||||
/**
|
||||
* Generic type interface. All types must have at least these properties.
|
||||
*
|
||||
* @author Frank Wibbelink
|
||||
*/
|
||||
public interface Type {
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<project default="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://hamcrest.org/JavaHamcrest/javadoc/1.3/"/>
|
||||
<link href="https://docs.oracle.com/javase/8/docs/api/"/>
|
Loading…
Reference in New Issue