refactor BoppiTests class, add object-oriented PoC

This commit is contained in:
User 2019-02-07 02:16:09 +01:00
parent ec8617354e
commit 1558ddac71
2 changed files with 203 additions and 41 deletions

View File

@ -3,11 +3,14 @@ package pp.s1184725.boppi.test;
import java.util.List; import java.util.List;
import java.util.logging.*; import java.util.logging.*;
import org.antlr.v4.runtime.CharStream; import java.io.*;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.ParseTree; 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 org.apache.commons.lang3.StringUtils;
import pp.iloc.Simulator; import pp.iloc.Simulator;
import pp.iloc.eval.Machine; import pp.iloc.eval.Machine;
@ -83,7 +86,7 @@ public class BoppiTests {
* the code to parse * the code to parse
*/ */
public static void parseString(String code) { public static void parseString(String code) {
parse(ToolChain.getCharStream(code)); parse(codeFromString(code));
} }
/** /**
@ -93,15 +96,7 @@ public class BoppiTests {
* the file name * the file name
*/ */
public static void parseFile(String file) { public static void parseFile(String file) {
parse(ToolChain.getCharStream(BoppiTests.class, file)); parse(codeFromFile(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();
} }
/** /**
@ -111,7 +106,7 @@ public class BoppiTests {
* the code to type check * the code to type check
*/ */
public static void checkString(String code) { public static void checkString(String code) {
check(ToolChain.getCharStream(code)); check(parse(codeFromString(code)));
} }
/** /**
@ -121,15 +116,7 @@ public class BoppiTests {
* the file name * the file name
*/ */
public static void checkFile(String file) { public static void checkFile(String file) {
check(ToolChain.getCharStream(BoppiTests.class, file)); check(parse(codeFromFile(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);
} }
/** /**
@ -142,7 +129,8 @@ public class BoppiTests {
* lines of input for the program * lines of input for the program
*/ */
public static void compileAndRunString(String code, String... input) { public static void compileAndRunString(String code, String... input) {
compileAndRun(ToolChain.getCharStream(code), String.join("\n", input) + "\n"); ParseTree ast = parse(codeFromString(code));
run(generate(ast, check(ast)), input);
} }
/** /**
@ -155,22 +143,84 @@ public class BoppiTests {
* lines of input for the program * lines of input for the program
*/ */
public static void compileAndRunFile(String file, String... input) { public static void compileAndRunFile(String file, String... input) {
compileAndRun(ToolChain.getCharStream(BoppiTests.class, file), String.join("\n", input) + "\n"); ParseTree ast = parse(codeFromFile(file));
run(generate(ast, check(ast)), input);
} }
private static void compileAndRun(CharStream stream, String input) {
private static CharStream codeFromString(String code) {
printCode(new StringReader(code));
return ToolChain.getCharStream(code);
}
private static CharStream codeFromFile(String file) {
printCode(new InputStreamReader(BoppiTests.class.getResourceAsStream(file)));
return ToolChain.getCharStream(BoppiTests.class, file);
}
private static ParseTree parse(CharStream stream) {
Logger logger = Logger.getAnonymousLogger(); Logger logger = Logger.getAnonymousLogger();
log = ToolChain.makeListLog(logger); log = ToolChain.makeListLog(logger);
logger.setLevel(logLevel); logger.setLevel(logLevel);
ParseTree ast = ToolChain.getParser(ToolChain.getLexer(stream, logger), logger).program(); printHeader("uncaught parse errors");
Annotations annotations = ToolChain.getAnnotations(ast, logger); ParseTree tree = ToolChain.getParser(ToolChain.getLexer(stream, logger), logger).program();
Program program = ToolChain.getILOC(ast, logger, annotations); printHeader("parse log");
printLog(log);
if (Simulator.DEBUG) return tree;
System.out.println(program.prettyPrint()); }
out = ToolChain.execute(program, logger, input).split("\n"); private static Annotations check(ParseTree tree) {
Logger logger = Logger.getAnonymousLogger();
List<LogRecord> tempLog = ToolChain.makeListLog(logger);
logger.setLevel(logLevel);
printHeader("uncaught checker errors");
Annotations an = ToolChain.getAnnotations(tree, logger);
printHeader("checker log");
printLog(tempLog);
log.addAll(tempLog);
return an;
}
private static Program generate(ParseTree ast, Annotations an) {
Logger logger = Logger.getAnonymousLogger();
List<LogRecord> tempLog = ToolChain.makeListLog(logger);
logger.setLevel(logLevel);
printHeader("uncaught generation errors");
Program program = ToolChain.getILOC(ast, logger, an);
printHeader("generation log");
printLog(tempLog);
log.addAll(tempLog);
return program;
}
private static void run(Program program, String[] in) {
Logger logger = Logger.getAnonymousLogger();
List<LogRecord> tempLog = ToolChain.makeListLog(logger);
logger.setLevel(logLevel);
printHeader("iloc code");
String iloc = program.prettyPrint();
System.out.println("...");
System.out.println(iloc.substring(iloc.indexOf("end of stdlib")));
printHeader("execution errors");
String input = String.join("\n", in) + "\n";
String output = ToolChain.execute(program, logger, input);
printHeader("execution log");
printLog(tempLog);
printHeader("input");
System.out.print(input);
printHeader("output");
System.out.println(output);
log.addAll(tempLog);
out = output.split("\n");
vm = ToolChain.machine; vm = ToolChain.machine;
} }
@ -240,4 +290,31 @@ public class BoppiTests {
Simulator.DEBUG = false; Simulator.DEBUG = false;
} }
private static void printHeader(String header) {
printHeader(header, '-');
}
private static void printHeader(String header, char separator) {
System.out.println(StringUtils.center(" "+header.toUpperCase()+" ", 150, separator));
}
private static void printCode(Reader r) {
System.out.println("\n\n\n"+StringUtils.repeat("=", 150));
BufferedReader bufReader = new BufferedReader(r);
printHeader("boppi code");
try {
for (String line = bufReader.readLine(); line != null; line = bufReader.readLine())
System.out.println("> " + line);
}
catch (IOException e) {}
}
private static void printLog(List<LogRecord> logs) {
logs.forEach((entry) -> System.out.println(entry.getMessage()));
}
} }

View File

@ -0,0 +1,85 @@
/**
* Proof of concept for Object-Oriented Programming in Boppi.
* Note that this is a very basic notion of OO that only includes private
* members. It does not support type checking, inheritance or public members.
* It requires a tremendous amount of boilerplate to work without proper
* tuples, parametrization or OO class syntax.
*/
//Declaring dummy functions for type aliases because Boppi disallows
//the use of Void directly in a type.
function intToVoid(int a) 0;
function int voidToInt() 0;
function class() 0;
//Class declaration whose sole purpose is to make the code look better.
//`Rectangle` type checks with every other `()->Void` type.
var class Rectangle;
//Helpers for making methods available outside their closure (the function
//references should be passed via a return value if tuples were supported)
//Assigning them immediately to suppress warnings.
var voidToInt _getWidth; _getWidth := voidToInt;
var intToVoid _setWidth; _setWidth := intToVoid;
var voidToInt _getHeight; _getHeight := voidToInt;
var intToVoid _setHeight; _setHeight := intToVoid;
var voidToInt _getArea; _getArea := voidToInt;
//Wrappers to make a `getWidth()` call less of an eyesore and allow you
//to nest these calls without overriding the target closure in between
function int getWidth (Rectangle rect) { rect();_getWidth() };
function setWidth (Rectangle rect, int width) { rect();_setWidth(width) };
function int getHeight(Rectangle rect) { rect();_getHeight() };
function setHeight(Rectangle rect, int height) { rect();_setHeight(height) };
function int getArea (Rectangle rect) { rect();_getArea() };
//A class definition looks decent apart from the bind function to expose
//the class methods. You can even add constructor arguments to your liking.
function Rectangle newRectangle() {
var int width;
var int height;
function int getWidth()
width;
function setWidth(int newWidth) {
width := newWidth;
};
function int getHeight()
height;
function setHeight(int newHeight) {
height := newHeight;
};
function int getArea()
width*height;
function bind() {
_getWidth := getWidth;
_setWidth := setWidth;
_getHeight := getHeight;
_setHeight := setHeight;
_getArea := getArea;
};
bind
};
//Time to use the class
var Rectangle a; a := newRectangle();
var Rectangle b; b := newRectangle();
setWidth(a, 4);
setWidth(b, getWidth(a)+2);
setHeight(b, 3);
print(getArea(b));