| @@ -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; | |||
| } | |||
| @@ -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> program() { | |||
| Optional<Program> program() { | |||
| List<Program> statements = new ArrayList<>(); | |||
| boolean run = true; | |||
| int start = position; | |||
| @@ -53,7 +53,7 @@ public class Parser { | |||
| return program; | |||
| } | |||
| private Optional<Program> statement() { | |||
| Optional<Program> statement() { | |||
| int start = position; | |||
| Optional<Program> result = assignment(); | |||
| if (!result.isPresent()) { | |||
| @@ -67,7 +67,7 @@ public class Parser { | |||
| return result; | |||
| } | |||
| private Optional<Program> loop() { | |||
| Optional<Program> loop() { | |||
| if (token("while") && token("(")) { | |||
| Optional<Expression> condition = expression(); | |||
| return condition.flatMap(cond -> { | |||
| @@ -81,13 +81,13 @@ public class Parser { | |||
| return Optional.empty(); | |||
| } | |||
| private Optional<Program> conditional() { | |||
| Optional<Program> conditional() { | |||
| if (token("if") && token("(")) { | |||
| Optional<Expression> condition = expression(); | |||
| condition.flatMap(cond -> { | |||
| return condition.flatMap(cond -> { | |||
| if (token(")") && token("then") && token("{")) { | |||
| Optional<Program> thenCase = program(); | |||
| thenCase.flatMap(thenC -> { | |||
| return thenCase.flatMap(thenC -> { | |||
| if (token("}") && token("else") && token("{")) { | |||
| Optional<Program> 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<Program> assignment() { | |||
| Optional<Program> assignment() { | |||
| Optional<Identifier> 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> expression() { | |||
| Optional<Expression> expression() { | |||
| List<OperatorWithExpression> 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<Expression> atom() { | |||
| Optional<Expression> atom() { | |||
| int start = position; | |||
| Optional<Expression> 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<Expression> number() { | |||
| Optional<Expression> 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> identifier() { | |||
| Optional<Identifier> 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) { | |||
| @@ -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")); | |||
| } | |||
| } | |||