diff --git a/Triangle.Compiler/build.gradle b/Triangle.Compiler/build.gradle index 62c56de..9733b3f 100644 --- a/Triangle.Compiler/build.gradle +++ b/Triangle.Compiler/build.gradle @@ -9,10 +9,13 @@ repositories { dependencies { - implementation project(':Solutions.Triangle.AbstractMachine') + implementation project(':Triangle.AbstractMachine') testImplementation group: 'junit', name: 'junit', version: '4.13.2' } application { mainClass = 'Triangle.Compiler' } + +// allow access to programs for unit tests +sourceSets.test.resources.srcDir file("$rootDir/programs") \ No newline at end of file diff --git a/Triangle.Compiler/src/main/java/triangle/Compiler.java b/Triangle.Compiler/src/main/java/triangle/Compiler.java index 65020a8..9b5cbe4 100644 --- a/Triangle.Compiler/src/main/java/triangle/Compiler.java +++ b/Triangle.Compiler/src/main/java/triangle/Compiler.java @@ -71,7 +71,7 @@ public class Compiler { } scanner = new Scanner(source); - reporter = new ErrorReporter(); + reporter = new ErrorReporter(false); parser = new Parser(scanner, reporter); checker = new Checker(reporter); emitter = new Emitter(reporter); @@ -80,7 +80,7 @@ public class Compiler { // scanner.enableDebugging(); theAST = parser.parseProgram(); // 1st pass - if (reporter.numErrors == 0) { + if (reporter.getNumErrors() == 0) { // if (showingAST) { // drawer.draw(theAST); // } @@ -89,13 +89,13 @@ public class Compiler { if (showingAST) { drawer.draw(theAST); } - if (reporter.numErrors == 0) { + if (reporter.getNumErrors() == 0) { System.out.println("Code Generation ..."); encoder.encodeRun(theAST, showingTable); // 3rd pass } } - boolean successful = (reporter.numErrors == 0); + boolean successful = (reporter.getNumErrors() == 0); if (successful) { emitter.saveObjectProgram(objectName); System.out.println("Compilation was successful."); diff --git a/Triangle.Compiler/src/main/java/triangle/ErrorReporter.java b/Triangle.Compiler/src/main/java/triangle/ErrorReporter.java index ee458bd..cfcc753 100644 --- a/Triangle.Compiler/src/main/java/triangle/ErrorReporter.java +++ b/Triangle.Compiler/src/main/java/triangle/ErrorReporter.java @@ -18,25 +18,44 @@ import triangle.syntacticAnalyzer.SourcePosition; public class ErrorReporter { - int numErrors; - - ErrorReporter() { + private int numErrors; + + private boolean throwExceptions; + + /** + * @param throwExceptions if true, throw exceptions (good for unit tests) otherwise write to stdout + */ + public ErrorReporter(boolean throwExceptions) { numErrors = 0; + this.throwExceptions = throwExceptions; } public void reportError(String message, String tokenName, SourcePosition pos) { - System.out.print("ERROR: "); + + numErrors++; + + String s = ("ERROR: "); for (int p = 0; p < message.length(); p++) if (message.charAt(p) == '%') - System.out.print(tokenName); + s += tokenName; else - System.out.print(message.charAt(p)); - System.out.println(" " + pos.start + ".." + pos.finish); - numErrors++; + s += message.charAt(p); + s += (" " + pos.start + ".." + pos.finish); + + if (throwExceptions) { + throw new RuntimeException(s); + } else { + System.out.println(s); + } + } public void reportRestriction(String message) { System.out.println("RESTRICTION: " + message); } + + public int getNumErrors() { + return numErrors; + } } diff --git a/Triangle.Compiler/src/test/java/triangle/syntacticAnalyser/TestScanner.java b/Triangle.Compiler/src/test/java/triangle/syntacticAnalyser/TestScanner.java index 6b02c62..599f8be 100644 --- a/Triangle.Compiler/src/test/java/triangle/syntacticAnalyser/TestScanner.java +++ b/Triangle.Compiler/src/test/java/triangle/syntacticAnalyser/TestScanner.java @@ -1,14 +1,58 @@ package triangle.syntacticAnalyser; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; import org.junit.Test; +import org.junit.function.ThrowingRunnable; + +import triangle.ErrorReporter; +import triangle.abstractSyntaxTrees.AbstractSyntaxTree; +import triangle.syntacticAnalyzer.Parser; +import triangle.syntacticAnalyzer.Scanner; +import triangle.syntacticAnalyzer.SourceFile; public class TestScanner { @Test - public void test() { - fail("Not yet implemented"); + public void testHi() { + // build.gradle has a line sourceSets.test.resources.srcDir file("$rootDir/programs") + // which adds the programs directory to the list of places Java can easily find files + // getResource() below searches for a file, which is in /programs + SourceFile source = SourceFile.ofPath(this.getClass().getResource("/hi.tri").getFile().toString()); + + Scanner scanner = new Scanner(source); + ErrorReporter reporter = new ErrorReporter(true); + Parser parser = new Parser(scanner, reporter); + + parser.parseProgram(); + + // we should get to here with no exceptions + + assertEquals("Problem compiling hi.tri", 0, reporter.getNumErrors()); + } + + + @Test + public void testHiNewComment() { + SourceFile source = SourceFile.ofPath(this.getClass().getResource("/hi-newcomment.tri").getFile().toString()); + + Scanner scanner = new Scanner(source); + ErrorReporter reporter = new ErrorReporter(true); + Parser parser = new Parser(scanner, reporter); + + // we expect an exception here as the program has invalid syntax + assertThrows(RuntimeException.class, new ThrowingRunnable() { + public void run(){ + parser.parseProgram(); + } + }); + + // currently this program will fail + assertNotEquals("Problem compiling hi-newcomment.tri", 0, reporter.getNumErrors()); } }