diff --git a/src/expression/Number.java b/src/expression/Int.java similarity index 73% rename from src/expression/Number.java rename to src/expression/Int.java index eb491fb..6932c75 100644 --- a/src/expression/Number.java +++ b/src/expression/Int.java @@ -1,9 +1,9 @@ package expression; -public class Number extends Expression { +public class Int extends Expression { public final int value; - public Number(int value) { + public Int(int value) { this.value = value; } @@ -12,9 +12,9 @@ public class Number extends Expression { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; - Number number = (Number) o; + Int integer = (Int) o; - return value == number.value; + return value == integer.value; } diff --git a/src/parser/Parser.java b/src/parser/Parser.java index 7f2e338..1972b7b 100644 --- a/src/parser/Parser.java +++ b/src/parser/Parser.java @@ -1,7 +1,7 @@ package parser; import expression.*; -import expression.Number; +import expression.Int; import program.*; import java.util.ArrayList; @@ -10,8 +10,8 @@ import java.util.Optional; public class Parser { - private int position = 0; - private String input; + int position = 0; + String input; public Parser(String input) { this.input = input; @@ -27,7 +27,7 @@ public class Parser { return program; } - private Optional program() { + Optional program() { List statements = new ArrayList<>(); boolean run = true; int start = position; @@ -53,7 +53,7 @@ public class Parser { return program; } - private Optional statement() { + Optional statement() { int start = position; Optional result = assignment(); if (!result.isPresent()) { @@ -67,7 +67,7 @@ public class Parser { return result; } - private Optional loop() { + Optional loop() { if (token("while") && token("(")) { Optional condition = expression(); return condition.flatMap(cond -> { @@ -81,13 +81,13 @@ public class Parser { return Optional.empty(); } - private Optional conditional() { + Optional conditional() { if (token("if") && token("(")) { Optional condition = expression(); - condition.flatMap(cond -> { + return condition.flatMap(cond -> { if (token(")") && token("then") && token("{")) { Optional thenCase = program(); - thenCase.flatMap(thenC -> { + return thenCase.flatMap(thenC -> { if (token("}") && token("else") && token("{")) { Optional elseCase = program(); return elseCase.filter(elseC -> token("}")).map(elseC -> new Conditional(cond, thenC, elseC)); @@ -101,7 +101,7 @@ public class Parser { return Optional.empty(); } - private Optional assignment() { + Optional assignment() { Optional identifier = identifier(); return identifier.flatMap(id -> { if (token(":=")) { @@ -112,17 +112,17 @@ public class Parser { }); } - private static class OperatorWithExpression { + static class OperatorWithExpression { private final Operator operator; private final Expression expression; - private OperatorWithExpression(Operator operator, Expression expression) { + OperatorWithExpression(Operator operator, Expression expression) { this.operator = operator; this.expression = expression; } } - private enum Operator { + enum Operator { PLUS, MINUS, NONE; Expression toOperation(Expression leftHandSide, Expression rightHandSide) { @@ -136,7 +136,7 @@ public class Parser { } } - private Optional expression() { + Optional expression() { List atoms = new ArrayList<>(); Operator operator = Operator.PLUS; int start = position; @@ -163,7 +163,7 @@ public class Parser { return expression; } - private Operator operator() { + Operator operator() { if (token("+")) { return Operator.PLUS; } else if (token("-")) { @@ -173,7 +173,7 @@ public class Parser { } } - private Optional atom() { + Optional atom() { int start = position; Optional result; if (token("(")) { @@ -181,7 +181,7 @@ public class Parser { result = expression.filter(exp -> token(")")); } else { position = start; - result = number(); + result = integer(); if (!result.isPresent()) { position = start; result = identifier().map(id -> id); @@ -190,11 +190,11 @@ public class Parser { return result; } - private boolean isLowerLetter(char ch) { + boolean isLowerLetter(char ch) { return ch >= 'a' && ch <= 'z'; } - private Optional number() { + Optional integer() { whitespace(); int start = position; boolean minus = position < input.length() && input.charAt(position) == '-'; @@ -207,13 +207,13 @@ public class Parser { digitsFound = true; } if (digitsFound) { - return Optional.of(new Number(Integer.parseInt(input.substring(start, position)))); + return Optional.of(new Int(Integer.parseInt(input.substring(start, position)))); } else { return Optional.empty(); } } - private Optional identifier() { + Optional identifier() { whitespace(); int start = position; while (position < input.length() && isLowerLetter(input.charAt(position))) { @@ -226,13 +226,13 @@ public class Parser { return Optional.empty(); } - private void whitespace() { + void whitespace() { while(position < input.length() && Character.isWhitespace(input.charAt(position))) { position += 1; } } - private boolean token(String token) { + boolean token(String token) { whitespace(); boolean success = position + token.length() <= input.length() && input.substring(position, position + token.length()).equals(token); if (success) { diff --git a/test/parser/ParserTest.java b/test/parser/ParserTest.java index 68d7c7e..5daec11 100644 --- a/test/parser/ParserTest.java +++ b/test/parser/ParserTest.java @@ -1,25 +1,140 @@ package parser; -import expression.Addition; -import expression.Identifier; -import expression.Number; -import expression.Subtraction; -import org.junit.Assert; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import org.junit.Test; -import program.Assignment; -import program.Composition; -import program.Loop; -import program.Program; +import expression.*; +import parser.Parser.Operator; +import program.*; + +import java.util.Optional; public class ParserTest { + final String loopCode = "while (a) { r := r + b ; a := a - 1 }"; + final Loop loop = new Loop(new Identifier("a"), new Composition(new Assignment(new Identifier("r"), new Addition(new Identifier("r"), new Identifier("b"))), new Assignment(new Identifier("a"), new Subtraction(new Identifier("a"), new Int(1))))); + + final String assignmentCode = "a := 2"; + final Assignment assignment = new Assignment(new Identifier("a"), new Int(2)); + + final String compositionCode = assignmentCode + " ; b := bar"; + final Composition composition = new Composition(assignment, new Assignment(new Identifier("b"), new Identifier("bar"))); + + final String conditionalCode = "if (foo - bar) then { x := 5 } else { x := x }"; + final Conditional conditional = new Conditional(new Subtraction(new Identifier("foo"), new Identifier("bar")), new Assignment(new Identifier("x"), new Int(5)), new Assignment(new Identifier("x"), new Identifier("x"))); + + final String programCode = compositionCode + " ; " + loopCode + " ; " + conditionalCode; + final Program program = new Composition(new Composition(composition, loop), conditional); + @Test public void testParse() { - String program = "a := 2 ; b := 4 ; r := 0 ; while (a) { r := r + b ; a := a - 1 }"; - Parser parser = new Parser(program); - Program initialization = new Composition(new Composition(new Assignment(new Identifier("a"), new Number(2)), new Assignment(new Identifier("b"), new Number(4))), new Assignment(new Identifier("r"), new Number(0))); - Program loop = new Loop(new Identifier("a"), new Composition(new Assignment(new Identifier("r"), new Addition(new Identifier("r"), new Identifier("b"))), new Assignment(new Identifier("a"), new Subtraction(new Identifier("a"), new Number(1))))); - Program expected = new Composition(initialization, loop); - Program actual = parser.parse(); - Assert.assertEquals(expected, actual); + Parser parser = new Parser(programCode); + assertEquals(program, parser.parse()); + } + + @Test + public void testProgram() { + Parser parser = new Parser(programCode); + assertEquals(Optional.of(program), parser.program()); + } + + @Test + public void testStatementAssignment() { + Parser parser = new Parser(assignmentCode); + assertEquals(Optional.of(assignment), parser.statement()); + } + + @Test + public void testStatementConditional() { + Parser parser = new Parser(conditionalCode); + assertEquals(Optional.of(conditional), parser.statement()); + } + + @Test + public void testStatementLoop() { + Parser parser = new Parser(loopCode); + assertEquals(Optional.of(loop), parser.statement()); + } + + @Test + public void testAssignment() { + Parser parser = new Parser(assignmentCode); + assertEquals(Optional.of(assignment), parser.assignment()); + } + + @Test + public void testConditional() { + Parser parser = new Parser(conditionalCode); + assertEquals(Optional.of(conditional), parser.conditional()); + } + + @Test + public void testLoop() { + Parser parser = new Parser(loopCode); + assertEquals(Optional.of(loop), parser.loop()); + } + + final String expressionCode = "a+b - (c - 56) + -47"; + final Expression expression = new Addition(new Subtraction(new Addition(new Identifier("a"), new Identifier("b")), new Subtraction(new Identifier("c"), new Int(56))), new Int(-47)); + + @Test + public void testExpression() { + Parser parser = new Parser(expressionCode); + assertEquals(Optional.of(expression), parser.expression()); + } + + @Test + public void testOperatorMinus() { + Parser parser = new Parser("-"); + assertEquals(Operator.MINUS, parser.operator()); + } + + @Test + public void testOperatorPlus() { + Parser parser = new Parser("+"); + assertEquals(Operator.PLUS, parser.operator()); + } + + @Test + public void testAtomExpression() { + Parser parser = new Parser("(" + expressionCode + ")"); + assertEquals(Optional.of(expression), parser.atom()); + } + + @Test + public void testAtomNumber() { + Parser parser = new Parser("37658"); + assertEquals(Optional.of(new Int(37658)), parser.atom()); + } + + @Test + public void testAtomIdentifier() { + Parser parser = new Parser("egjfd"); + assertEquals(Optional.of(new Identifier("egjfd")), parser.atom()); + } + + @Test + public void testNumber() { + Parser parser = new Parser("37658"); + assertEquals(Optional.of(new Int(37658)), parser.integer()); + } + + @Test + public void testIdentifier() { + Parser parser = new Parser("egjfd"); + assertEquals(Optional.of(new Identifier("egjfd")), parser.identifier()); + } + + @Test + public void testWhitespace() { + Parser parser = new Parser(" \n\t x"); + parser.whitespace(); + assertEquals('x', parser.input.charAt(parser.position)); + } + + @Test + public void testToken() { + Parser parser = new Parser("gehjfwdk"); + assertTrue(parser.token("gehjfwdk")); } }