From 5b2b9c587ab621be01205c6d080d34f7551666c4 Mon Sep 17 00:00:00 2001 From: Mads Ravn Date: Thu, 26 Oct 2023 19:58:44 +0200 Subject: [PATCH] We did it --- .../interpreter/ast/CallExpression.java | 2 +- .../interpreter/ast/FunctionLiteral.java | 2 +- .../interpreter/ast/LetStatement.java | 4 ++- .../interpreter/ast/ReturnStatement.java | 3 +- .../madsravn/interpreter/parser/Parser.java | 29 +++++++++++++++---- .../dk/madsravn/interpreter/repl/Repl.java | 16 ++++++++-- .../interpreter/parser/ParserTest.java | 11 ++++--- 7 files changed, 51 insertions(+), 16 deletions(-) diff --git a/src/main/java/dk/madsravn/interpreter/ast/CallExpression.java b/src/main/java/dk/madsravn/interpreter/ast/CallExpression.java index 91bf457..84a9c9a 100644 --- a/src/main/java/dk/madsravn/interpreter/ast/CallExpression.java +++ b/src/main/java/dk/madsravn/interpreter/ast/CallExpression.java @@ -28,7 +28,7 @@ public void expressionNode() {} public String string() { StringBuilder sb = new StringBuilder(); - String argumentString = arguments.stream().map(p -> p.string()).collect(Collectors.joining(",")); + String argumentString = arguments.stream().map(p -> p.string()).collect(Collectors.joining(", ")); sb.append(function.string()); sb.append("("); sb.append(argumentString); diff --git a/src/main/java/dk/madsravn/interpreter/ast/FunctionLiteral.java b/src/main/java/dk/madsravn/interpreter/ast/FunctionLiteral.java index 25fa0c4..62899cb 100644 --- a/src/main/java/dk/madsravn/interpreter/ast/FunctionLiteral.java +++ b/src/main/java/dk/madsravn/interpreter/ast/FunctionLiteral.java @@ -33,7 +33,7 @@ public void expressionNode() {} @Override public String string() { StringBuilder sb = new StringBuilder(); - String paramString = parameters.stream().map(p -> p.string()).collect(Collectors.joining(",")); + String paramString = parameters.stream().map(p -> p.string()).collect(Collectors.joining(", ")); sb.append(token.getLiteral()); sb.append("("); diff --git a/src/main/java/dk/madsravn/interpreter/ast/LetStatement.java b/src/main/java/dk/madsravn/interpreter/ast/LetStatement.java index 2ed4609..20c2941 100644 --- a/src/main/java/dk/madsravn/interpreter/ast/LetStatement.java +++ b/src/main/java/dk/madsravn/interpreter/ast/LetStatement.java @@ -8,8 +8,10 @@ public class LetStatement implements IStatement { Identifier name; IExpression value; - public LetStatement(Token token) { + public LetStatement(Token token, Identifier name, IExpression value) { this.token = token; + this.name = name; + this.value = value; } @Override public void statementNode() {} diff --git a/src/main/java/dk/madsravn/interpreter/ast/ReturnStatement.java b/src/main/java/dk/madsravn/interpreter/ast/ReturnStatement.java index 33845f1..1ba8171 100644 --- a/src/main/java/dk/madsravn/interpreter/ast/ReturnStatement.java +++ b/src/main/java/dk/madsravn/interpreter/ast/ReturnStatement.java @@ -6,8 +6,9 @@ public class ReturnStatement implements IStatement{ private Token token; private IExpression expression; - public ReturnStatement(Token token) { + public ReturnStatement(Token token, IExpression expression) { this.token = token; + this.expression = expression; } @Override diff --git a/src/main/java/dk/madsravn/interpreter/parser/Parser.java b/src/main/java/dk/madsravn/interpreter/parser/Parser.java index 0cf4deb..04d47bb 100644 --- a/src/main/java/dk/madsravn/interpreter/parser/Parser.java +++ b/src/main/java/dk/madsravn/interpreter/parser/Parser.java @@ -63,7 +63,7 @@ private IStatement parseStatement() { private boolean getInfixExpression(TokenType type) { switch(type) { - case PLUS, MINUS, SLASH, ASTERISK, EQ, NOT_EQ, LT, GT: + case PLUS, MINUS, SLASH, ASTERISK, EQ, NOT_EQ, LT, GT, LPAREN: return true; default: return false; @@ -222,6 +222,7 @@ private BlockStatement parseBlockStatement() { private IExpression parseExpression(PrecedenceEnum precedence) { IExpression left = getPrefixExpression(); if (left == null) { + noPrefixParseFunctionError(currentToken.getType()); return null; } @@ -230,10 +231,16 @@ private IExpression parseExpression(PrecedenceEnum precedence) { if (infix == false) { return null; } + // TODO: This needs to be prettier!!! + if(peekToken.getType() == LPAREN) { + nextToken(); + left = parseCallExpression(left); - nextToken(); + } else { - left = parseInfixExpression(left); + nextToken(); + left = parseInfixExpression(left); + } } return left; @@ -312,34 +319,44 @@ private ExpressionStatement parseExpressionStatement() { } private ReturnStatement parseReturnStatement() { - ReturnStatement statement = new ReturnStatement(currentToken); + Token token = currentToken; nextToken(); + IExpression value = parseExpression(LOWEST); + while(!currentTokenType(TokenType.SEMICOLON)) { nextToken(); } + + ReturnStatement statement = new ReturnStatement(token, value); return statement; } private LetStatement parseLetStatement() { - LetStatement statement = new LetStatement(currentToken); + Token token = currentToken; if (!expectPeekType(TokenType.IDENT)) { // TODO: This is ugly return null; } - statement.setName(new Identifier(currentToken, currentToken.getLiteral())); + // TODO: Remove method and replace with constructor call to LetStatement + Identifier name = new Identifier(currentToken, currentToken.getLiteral()); if (!expectPeekType(TokenType.ASSIGN)) { // TODO: This is ugly return null; } + nextToken(); + IExpression value = parseExpression(LOWEST); + + while (!currentTokenType(TokenType.SEMICOLON)) { nextToken(); } + LetStatement statement = new LetStatement(token, name, value); return statement; } diff --git a/src/main/java/dk/madsravn/interpreter/repl/Repl.java b/src/main/java/dk/madsravn/interpreter/repl/Repl.java index 056f217..be13b73 100644 --- a/src/main/java/dk/madsravn/interpreter/repl/Repl.java +++ b/src/main/java/dk/madsravn/interpreter/repl/Repl.java @@ -1,6 +1,8 @@ package dk.madsravn.interpreter.repl; +import dk.madsravn.interpreter.ast.Program; import dk.madsravn.interpreter.lexer.Lexer; +import dk.madsravn.interpreter.parser.Parser; import dk.madsravn.interpreter.tokens.Token; import java.io.BufferedReader; @@ -17,12 +19,22 @@ public void start() { try { String input = br.readLine(); Lexer lexer = new Lexer(input); - List tokens = lexer.readAllTokens(); - tokens.stream().forEach(System.out::println); + Parser parser = new Parser(lexer); + Program program = parser.parseProgram(); + if (parser.getErrors().size() > 0) { + printParserErrors(parser.getErrors()); + continue; + } + System.out.println(program.string()); + System.out.println(""); } catch (Exception e) { } } } + + private void printParserErrors(List errors) { + errors.stream().map(s -> "\t" + s).forEach(System.out::println); + } } diff --git a/src/test/java/dk/madsravn/interpreter/parser/ParserTest.java b/src/test/java/dk/madsravn/interpreter/parser/ParserTest.java index 05e4435..bfc093c 100644 --- a/src/test/java/dk/madsravn/interpreter/parser/ParserTest.java +++ b/src/test/java/dk/madsravn/interpreter/parser/ParserTest.java @@ -71,7 +71,7 @@ public void TestLetStatementWithErrors() { // TODO: Should the errors be on the program or on the parser? Program program = parser.parseProgram(); - assertEquals(parser.getErrors().size(), 4); + assertEquals(parser.getErrors().size(), 5); } @Test @@ -82,8 +82,7 @@ public void testStringMethods() { Program program = parser.parseProgram(); assertEquals(parser.getErrors().size(), 0); - // TODO: THIS DOESNT COMPLETELY WORK YET - assertEquals(program.string(), "let myVar = ;"); + assertEquals(program.string(), "let myVar = 5;"); } @Test @@ -348,7 +347,11 @@ public void testOperatorPrecedenceParsing() { new OperatorPrecedenceParsing("(5 + 5) * 2", "((5 + 5) * 2)"), new OperatorPrecedenceParsing("2 / (5 + 5)", "(2 / (5 + 5))"), new OperatorPrecedenceParsing("-(5 + 5)", "(-(5 + 5))"), - new OperatorPrecedenceParsing("!(true == true)", "(!(true == true))") + new OperatorPrecedenceParsing("!(true == true)", "(!(true == true))"), + new OperatorPrecedenceParsing("a + add(b * c) + d", "((a + add((b * c))) + d)"), + new OperatorPrecedenceParsing("add(a, b, 1, 2 * 3, 4 + 5, add(6, 7 * 8))", "add(a, b, 1, (2 * 3), (4 + 5), add(6, (7 * 8)))"), + new OperatorPrecedenceParsing("add(a + b + c * d / f + g)", "add((((a + b) + ((c * d) / f)) + g))") + );