diff options
Diffstat (limited to '')
| -rw-r--r-- | parser/src/main/java/lv/enes/orang/parser/Parser.java (renamed from orang/src/main/java/lv/enes/orang/Parser.java) | 129 | ||||
| -rw-r--r-- | parser/src/main/java/lv/enes/orang/parser/ParserException.java (renamed from orang/src/main/java/lv/enes/orang/ParserException.java) | 2 | ||||
| -rw-r--r-- | parser/src/main/java/module-info.java | 8 |
3 files changed, 95 insertions, 44 deletions
diff --git a/orang/src/main/java/lv/enes/orang/Parser.java b/parser/src/main/java/lv/enes/orang/parser/Parser.java index 77abe24..6c86e85 100644 --- a/orang/src/main/java/lv/enes/orang/Parser.java +++ b/parser/src/main/java/lv/enes/orang/parser/Parser.java | |||
| @@ -1,9 +1,12 @@ | |||
| 1 | package lv.enes.orang; | 1 | package lv.enes.orang.parser; |
| 2 | 2 | ||
| 3 | import lv.enes.orang.ast.*; | 3 | import lv.enes.orang.ast.*; |
| 4 | import lv.enes.orang.ast.IfElseExpression; | 4 | import lv.enes.orang.ast.IfElseExpression; |
| 5 | import lv.enes.orang.ast.Statement; | 5 | import lv.enes.orang.ast.Statement; |
| 6 | import lv.enes.orang.lexer.Lexer; | ||
| 7 | import lv.enes.orang.lexer.Token; | ||
| 6 | import lv.enes.orang.utils.NonEmptyList; | 8 | import lv.enes.orang.utils.NonEmptyList; |
| 9 | import lv.enes.orang.utils.PeekableStream; | ||
| 7 | 10 | ||
| 8 | import java.io.InputStream; | 11 | import java.io.InputStream; |
| 9 | import java.io.Reader; | 12 | import java.io.Reader; |
| @@ -49,13 +52,53 @@ public class Parser { | |||
| 49 | 52 | ||
| 50 | public Program parseProgram() throws ParserException { | 53 | public Program parseProgram() throws ParserException { |
| 51 | var statements = new ArrayList<Statement>(); | 54 | var statements = new ArrayList<Statement>(); |
| 52 | while (!maybeConsumeToken(TokenType.EOF)) { | 55 | while (!maybeConsumeToken(Token.Type.EOF)) { |
| 53 | statements.add(parseStatement()); | 56 | statements.add(parseStatement()); |
| 54 | maybeConsumeToken(TokenType.SEMICOLON); | 57 | maybeConsumeToken(Token.Type.SEMICOLON); |
| 55 | } | 58 | } |
| 56 | return new Program(Collections.unmodifiableList(statements)); | 59 | return new Program(Collections.unmodifiableList(statements)); |
| 57 | } | 60 | } |
| 58 | 61 | ||
| 62 | private static boolean isBinaryOp(Token token) { | ||
| 63 | return switch (token.type()) { | ||
| 64 | case ASTERISK, SLASH, PLUS, MINUS, QUESTION_EQUAL, SLASH_EQUAL, GREATER, GREATER_EQUAL, LESS, LESS_EQUAL | ||
| 65 | -> true; | ||
| 66 | default -> false; | ||
| 67 | }; | ||
| 68 | } | ||
| 69 | |||
| 70 | private static BinaryExpression.Operator toBinaryOp(Token token) { | ||
| 71 | return switch (token.type()) { | ||
| 72 | case ASTERISK -> BinaryExpression.Operator.MULTIPLY; | ||
| 73 | case SLASH -> BinaryExpression.Operator.DIVIDE; | ||
| 74 | case PLUS -> BinaryExpression.Operator.ADD; | ||
| 75 | case MINUS -> BinaryExpression.Operator.SUBTRACT; | ||
| 76 | case QUESTION_EQUAL -> BinaryExpression.Operator.EQUALS; | ||
| 77 | case SLASH_EQUAL -> BinaryExpression.Operator.NOT_EQUALS; | ||
| 78 | case GREATER -> BinaryExpression.Operator.GT; | ||
| 79 | case GREATER_EQUAL -> BinaryExpression.Operator.GTE; | ||
| 80 | case LESS -> BinaryExpression.Operator.LT; | ||
| 81 | case LESS_EQUAL -> BinaryExpression.Operator.LTE; | ||
| 82 | default -> throw new IllegalStateException(STR."Token \{token.type()} is not a binary operator"); | ||
| 83 | }; | ||
| 84 | } | ||
| 85 | |||
| 86 | public static boolean isUnaryOp(Token token) { | ||
| 87 | return switch (token.type()) { | ||
| 88 | case PLUS, MINUS, BANG -> true; | ||
| 89 | default -> false; | ||
| 90 | }; | ||
| 91 | } | ||
| 92 | |||
| 93 | public static UnaryExpression.Operator toUnaryOp(Token token) { | ||
| 94 | return switch (token.type()) { | ||
| 95 | case PLUS -> UnaryExpression.Operator.PLUS; | ||
| 96 | case MINUS -> UnaryExpression.Operator.NEGATE; | ||
| 97 | case BANG -> UnaryExpression.Operator.NOT; | ||
| 98 | default -> throw new IllegalStateException(STR."Token \{token.type()} is not a unary operator"); | ||
| 99 | }; | ||
| 100 | } | ||
| 101 | |||
| 59 | private Token consume(Predicate<Token> pred, String msg) throws ParserException { | 102 | private Token consume(Predicate<Token> pred, String msg) throws ParserException { |
| 60 | var tok = input.next(); | 103 | var tok = input.next(); |
| 61 | if (!pred.test(tok)) { | 104 | if (!pred.test(tok)) { |
| @@ -64,11 +107,11 @@ public class Parser { | |||
| 64 | return tok; | 107 | return tok; |
| 65 | } | 108 | } |
| 66 | 109 | ||
| 67 | private Token consumeToken(TokenType type) throws ParserException { | 110 | private Token consumeToken(Token.Type type) throws ParserException { |
| 68 | return consume(tok -> tok.type() == type, STR."Expected \{type}"); | 111 | return consume(tok -> tok.type() == type, STR."Expected \{type}"); |
| 69 | } | 112 | } |
| 70 | 113 | ||
| 71 | private boolean maybeConsumeToken(TokenType type) { | 114 | private boolean maybeConsumeToken(Token.Type type) { |
| 72 | if (input.peek().type() == type) { | 115 | if (input.peek().type() == type) { |
| 73 | input.next(); | 116 | input.next(); |
| 74 | return true; | 117 | return true; |
| @@ -77,16 +120,16 @@ public class Parser { | |||
| 77 | } | 120 | } |
| 78 | 121 | ||
| 79 | private ArrayExpression parseArray() throws ParserException { | 122 | private ArrayExpression parseArray() throws ParserException { |
| 80 | consumeToken(TokenType.BRACKET_LEFT); | 123 | consumeToken(Token.Type.BRACKET_LEFT); |
| 81 | if (maybeConsumeToken(TokenType.BRACKET_RIGHT)) { | 124 | if (maybeConsumeToken(Token.Type.BRACKET_RIGHT)) { |
| 82 | return new ArrayExpression(List.of()); | 125 | return new ArrayExpression(List.of()); |
| 83 | } | 126 | } |
| 84 | 127 | ||
| 85 | var items = new ArrayList<Expression>(); | 128 | var items = new ArrayList<Expression>(); |
| 86 | do { | 129 | do { |
| 87 | items.add(parseExpression()); | 130 | items.add(parseExpression()); |
| 88 | } while (maybeConsumeToken(TokenType.COMMA)); | 131 | } while (maybeConsumeToken(Token.Type.COMMA)); |
| 89 | consumeToken(TokenType.BRACKET_RIGHT); | 132 | consumeToken(Token.Type.BRACKET_RIGHT); |
| 90 | 133 | ||
| 91 | return new ArrayExpression(Collections.unmodifiableList(items)); | 134 | return new ArrayExpression(Collections.unmodifiableList(items)); |
| 92 | } | 135 | } |
| @@ -94,11 +137,11 @@ public class Parser { | |||
| 94 | private List<ArgSpec> parseArgSpecs() throws ParserException { | 137 | private List<ArgSpec> parseArgSpecs() throws ParserException { |
| 95 | var argSpecs = new ArrayList<ArgSpec>(); | 138 | var argSpecs = new ArrayList<ArgSpec>(); |
| 96 | while (true) { | 139 | while (true) { |
| 97 | if (input.peek().type() == TokenType.IDENTIFIER) { | 140 | if (input.peek().type() == Token.Type.IDENTIFIER) { |
| 98 | argSpecs.add(ArgSpec.named(input.next().literal())); | 141 | argSpecs.add(ArgSpec.named(input.next().literal())); |
| 99 | } else if (input.peek().type() == TokenType.PAREN_LEFT) { | 142 | } else if (input.peek().type() == Token.Type.PAREN_LEFT) { |
| 100 | consumeToken(TokenType.PAREN_LEFT); | 143 | consumeToken(Token.Type.PAREN_LEFT); |
| 101 | consumeToken(TokenType.PAREN_RIGHT); | 144 | consumeToken(Token.Type.PAREN_RIGHT); |
| 102 | argSpecs.add(ArgSpec.nothing()); | 145 | argSpecs.add(ArgSpec.nothing()); |
| 103 | } else { | 146 | } else { |
| 104 | break; | 147 | break; |
| @@ -109,20 +152,20 @@ public class Parser { | |||
| 109 | 152 | ||
| 110 | private Expression parseBinaryExpression() throws ParserException { | 153 | private Expression parseBinaryExpression() throws ParserException { |
| 111 | var lhs = parseCallExpression(); | 154 | var lhs = parseCallExpression(); |
| 112 | if (!input.peek().type().isBinaryOp()) { | 155 | if (!isBinaryOp(input.peek())) { |
| 113 | return lhs; | 156 | return lhs; |
| 114 | } | 157 | } |
| 115 | 158 | ||
| 116 | return parseBinaryExpressionRhs(lhs, input.next().type().toBinaryOp()); | 159 | return parseBinaryExpressionRhs(lhs, toBinaryOp(input.next())); |
| 117 | } | 160 | } |
| 118 | 161 | ||
| 119 | private Expression parseBinaryExpressionRhs(Expression lhs, BinaryExpression.Operator op) throws ParserException { | 162 | private Expression parseBinaryExpressionRhs(Expression lhs, BinaryExpression.Operator op) throws ParserException { |
| 120 | var rhs = parseCallExpression(); | 163 | var rhs = parseCallExpression(); |
| 121 | if (!input.peek().type().isBinaryOp()) { | 164 | if (!isBinaryOp(input.peek())) { |
| 122 | return new BinaryExpression(op, lhs, rhs); | 165 | return new BinaryExpression(op, lhs, rhs); |
| 123 | } | 166 | } |
| 124 | 167 | ||
| 125 | var op2 = input.next().type().toBinaryOp(); | 168 | var op2 = toBinaryOp(input.next()); |
| 126 | if (op2.bindsStrongerThan(op)) { | 169 | if (op2.bindsStrongerThan(op)) { |
| 127 | return new BinaryExpression(op, lhs, parseBinaryExpressionRhs(rhs, op2)); | 170 | return new BinaryExpression(op, lhs, parseBinaryExpressionRhs(rhs, op2)); |
| 128 | } else { | 171 | } else { |
| @@ -131,8 +174,8 @@ public class Parser { | |||
| 131 | } | 174 | } |
| 132 | 175 | ||
| 133 | private BooleanLiteral parseBoolean() throws ParserException { | 176 | private BooleanLiteral parseBoolean() throws ParserException { |
| 134 | var t = consume(tok -> tok.type() == TokenType.FALSE || tok.type() == TokenType.TRUE, "Expected TRUE or FALSE"); | 177 | var t = consume(tok -> tok.type() == Token.Type.FALSE || tok.type() == Token.Type.TRUE, "Expected TRUE or FALSE"); |
| 135 | return new BooleanLiteral(t.type() == TokenType.TRUE); | 178 | return new BooleanLiteral(t.type() == Token.Type.TRUE); |
| 136 | } | 179 | } |
| 137 | 180 | ||
| 138 | private Expression parseCallExpression() throws ParserException { | 181 | private Expression parseCallExpression() throws ParserException { |
| @@ -145,9 +188,9 @@ public class Parser { | |||
| 145 | } | 188 | } |
| 146 | 189 | ||
| 147 | private Definition parseDefinition() throws ParserException { | 190 | private Definition parseDefinition() throws ParserException { |
| 148 | consumeToken(TokenType.DEF); | 191 | consumeToken(Token.Type.DEF); |
| 149 | var defSpec = parseDefSpec(); | 192 | var defSpec = parseDefSpec(); |
| 150 | consumeToken(TokenType.EQUAL); | 193 | consumeToken(Token.Type.EQUAL); |
| 151 | var value = parseExpression(); | 194 | var value = parseExpression(); |
| 152 | if (defSpec.args().isEmpty()) { | 195 | if (defSpec.args().isEmpty()) { |
| 153 | return new Definition(defSpec.name(), value); | 196 | return new Definition(defSpec.name(), value); |
| @@ -157,59 +200,59 @@ public class Parser { | |||
| 157 | } | 200 | } |
| 158 | 201 | ||
| 159 | private DefSpec parseDefSpec() throws ParserException { | 202 | private DefSpec parseDefSpec() throws ParserException { |
| 160 | var name = consumeToken(TokenType.IDENTIFIER).literal(); | 203 | var name = consumeToken(Token.Type.IDENTIFIER).literal(); |
| 161 | var argSpecs = parseArgSpecs(); | 204 | var argSpecs = parseArgSpecs(); |
| 162 | return new DefSpec(name, argSpecs); | 205 | return new DefSpec(name, argSpecs); |
| 163 | } | 206 | } |
| 164 | 207 | ||
| 165 | private DoExpression parseDoExpression() throws ParserException { | 208 | private DoExpression parseDoExpression() throws ParserException { |
| 166 | consumeToken(TokenType.DO); | 209 | consumeToken(Token.Type.DO); |
| 167 | var exprs = new ArrayList<Expression>(); | 210 | var exprs = new ArrayList<Expression>(); |
| 168 | do { | 211 | do { |
| 169 | exprs.add(parseExpression()); | 212 | exprs.add(parseExpression()); |
| 170 | } while (maybeConsumeToken(TokenType.SEMICOLON)); | 213 | } while (maybeConsumeToken(Token.Type.SEMICOLON)); |
| 171 | consumeToken(TokenType.END); | 214 | consumeToken(Token.Type.END); |
| 172 | return new DoExpression(Collections.unmodifiableList(exprs)); | 215 | return new DoExpression(Collections.unmodifiableList(exprs)); |
| 173 | } | 216 | } |
| 174 | 217 | ||
| 175 | private Expression parseExpression() throws ParserException { | 218 | private Expression parseExpression() throws ParserException { |
| 176 | if (input.peek().type().isUnaryOp()) { | 219 | if (isUnaryOp(input.peek())) { |
| 177 | return parseUnaryExpression(); | 220 | return parseUnaryExpression(); |
| 178 | } | 221 | } |
| 179 | return parseBinaryExpression(); | 222 | return parseBinaryExpression(); |
| 180 | } | 223 | } |
| 181 | 224 | ||
| 182 | private FnExpression parseFnExpression() throws ParserException { | 225 | private FnExpression parseFnExpression() throws ParserException { |
| 183 | consumeToken(TokenType.FN); | 226 | consumeToken(Token.Type.FN); |
| 184 | var argSpecs = parseArgSpecs(); | 227 | var argSpecs = parseArgSpecs(); |
| 185 | if (argSpecs.isEmpty()) { | 228 | if (argSpecs.isEmpty()) { |
| 186 | throw new ParserException("Function definition with no arguments"); | 229 | throw new ParserException("Function definition with no arguments"); |
| 187 | } | 230 | } |
| 188 | var body = maybeConsumeToken(TokenType.MINUS_GREATER) ? parseExpression() : parseDoExpression(); | 231 | var body = maybeConsumeToken(Token.Type.MINUS_GREATER) ? parseExpression() : parseDoExpression(); |
| 189 | return new FnExpression(new NonEmptyList<>(argSpecs), body); | 232 | return new FnExpression(new NonEmptyList<>(argSpecs), body); |
| 190 | } | 233 | } |
| 191 | 234 | ||
| 192 | private IfElseExpression parseIfElseExpression() throws ParserException { | 235 | private IfElseExpression parseIfElseExpression() throws ParserException { |
| 193 | consumeToken(TokenType.IF); | 236 | consumeToken(Token.Type.IF); |
| 194 | var cond = parseExpression(); | 237 | var cond = parseExpression(); |
| 195 | consumeToken(TokenType.THEN); | 238 | consumeToken(Token.Type.THEN); |
| 196 | var trueBranch = parseExpression(); | 239 | var trueBranch = parseExpression(); |
| 197 | consumeToken(TokenType.ELSE); | 240 | consumeToken(Token.Type.ELSE); |
| 198 | var falseBranch = parseExpression(); | 241 | var falseBranch = parseExpression(); |
| 199 | return new IfElseExpression(cond, trueBranch, falseBranch); | 242 | return new IfElseExpression(cond, trueBranch, falseBranch); |
| 200 | } | 243 | } |
| 201 | 244 | ||
| 202 | private IntLiteral parseInteger() throws ParserException { | 245 | private IntLiteral parseInteger() throws ParserException { |
| 203 | var tok = consumeToken(TokenType.INTEGER); | 246 | var tok = consumeToken(Token.Type.INTEGER); |
| 204 | return new IntLiteral(Integer.parseInt(tok.literal())); | 247 | return new IntLiteral(Integer.parseInt(tok.literal())); |
| 205 | } | 248 | } |
| 206 | 249 | ||
| 207 | private LetInExpression parseLetInExpression() throws ParserException { | 250 | private LetInExpression parseLetInExpression() throws ParserException { |
| 208 | consumeToken(TokenType.LET); | 251 | consumeToken(Token.Type.LET); |
| 209 | var bindings = new ArrayList<LetInExpression.Binding>(); | 252 | var bindings = new ArrayList<LetInExpression.Binding>(); |
| 210 | do { | 253 | do { |
| 211 | var defSpec = parseDefSpec(); | 254 | var defSpec = parseDefSpec(); |
| 212 | consumeToken(TokenType.EQUAL); | 255 | consumeToken(Token.Type.EQUAL); |
| 213 | var value = parseExpression(); | 256 | var value = parseExpression(); |
| 214 | if (defSpec.args().isEmpty()) { | 257 | if (defSpec.args().isEmpty()) { |
| 215 | bindings.add(new LetInExpression.Binding(defSpec.name(), value)); | 258 | bindings.add(new LetInExpression.Binding(defSpec.name(), value)); |
| @@ -217,8 +260,8 @@ public class Parser { | |||
| 217 | var fn = new FnExpression(new NonEmptyList<>(defSpec.args()), value); | 260 | var fn = new FnExpression(new NonEmptyList<>(defSpec.args()), value); |
| 218 | bindings.add(new LetInExpression.Binding(defSpec.name(), fn)); | 261 | bindings.add(new LetInExpression.Binding(defSpec.name(), fn)); |
| 219 | } | 262 | } |
| 220 | } while (maybeConsumeToken(TokenType.AND)); | 263 | } while (maybeConsumeToken(Token.Type.AND)); |
| 221 | consumeToken(TokenType.IN); | 264 | consumeToken(Token.Type.IN); |
| 222 | var body = parseExpression(); | 265 | var body = parseExpression(); |
| 223 | return new LetInExpression(Collections.unmodifiableList(bindings), body); | 266 | return new LetInExpression(Collections.unmodifiableList(bindings), body); |
| 224 | } | 267 | } |
| @@ -226,12 +269,12 @@ public class Parser { | |||
| 226 | private Expression parseSimpleExpression() throws ParserException { | 269 | private Expression parseSimpleExpression() throws ParserException { |
| 227 | return switch (input.peek().type()) { | 270 | return switch (input.peek().type()) { |
| 228 | case PAREN_LEFT -> { | 271 | case PAREN_LEFT -> { |
| 229 | consumeToken(TokenType.PAREN_LEFT); | 272 | consumeToken(Token.Type.PAREN_LEFT); |
| 230 | if (maybeConsumeToken(TokenType.PAREN_RIGHT)) { | 273 | if (maybeConsumeToken(Token.Type.PAREN_RIGHT)) { |
| 231 | yield VoidExpression.INSTANCE; | 274 | yield VoidExpression.INSTANCE; |
| 232 | } | 275 | } |
| 233 | var expr = parseExpression(); | 276 | var expr = parseExpression(); |
| 234 | consumeToken(TokenType.PAREN_RIGHT); | 277 | consumeToken(Token.Type.PAREN_RIGHT); |
| 235 | yield expr; | 278 | yield expr; |
| 236 | } | 279 | } |
| 237 | case TRUE, FALSE -> parseBoolean(); | 280 | case TRUE, FALSE -> parseBoolean(); |
| @@ -247,7 +290,7 @@ public class Parser { | |||
| 247 | }; | 290 | }; |
| 248 | } | 291 | } |
| 249 | 292 | ||
| 250 | private boolean couldStartSimpleExpression(TokenType type) { | 293 | private boolean couldStartSimpleExpression(Token.Type type) { |
| 251 | return switch (type) { | 294 | return switch (type) { |
| 252 | case PAREN_LEFT, TRUE, FALSE, INTEGER, IDENTIFIER, STRING, BRACKET_LEFT, IF, LET, FN, DO -> true; | 295 | case PAREN_LEFT, TRUE, FALSE, INTEGER, IDENTIFIER, STRING, BRACKET_LEFT, IF, LET, FN, DO -> true; |
| 253 | default -> false; | 296 | default -> false; |
| @@ -255,7 +298,7 @@ public class Parser { | |||
| 255 | } | 298 | } |
| 256 | 299 | ||
| 257 | private Statement parseStatement() throws ParserException { | 300 | private Statement parseStatement() throws ParserException { |
| 258 | if (input.peek().type() == TokenType.DEF) { | 301 | if (input.peek().type() == Token.Type.DEF) { |
| 259 | return parseDefinition(); | 302 | return parseDefinition(); |
| 260 | } else { | 303 | } else { |
| 261 | return new ExpressionStatement(parseExpression()); | 304 | return new ExpressionStatement(parseExpression()); |
| @@ -286,8 +329,8 @@ public class Parser { | |||
| 286 | } | 329 | } |
| 287 | 330 | ||
| 288 | private Expression parseUnaryExpression() throws ParserException { | 331 | private Expression parseUnaryExpression() throws ParserException { |
| 289 | if (input.peek().type().isUnaryOp()) { | 332 | if (isUnaryOp(input.peek())) { |
| 290 | var op = input.next().type().toUnaryOp(); | 333 | var op = toUnaryOp(input.next()); |
| 291 | return new UnaryExpression(op, parseUnaryExpression()); | 334 | return new UnaryExpression(op, parseUnaryExpression()); |
| 292 | } else { | 335 | } else { |
| 293 | return parseSimpleExpression(); | 336 | return parseSimpleExpression(); |
diff --git a/orang/src/main/java/lv/enes/orang/ParserException.java b/parser/src/main/java/lv/enes/orang/parser/ParserException.java index bd65e7a..632ce15 100644 --- a/orang/src/main/java/lv/enes/orang/ParserException.java +++ b/parser/src/main/java/lv/enes/orang/parser/ParserException.java | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | package lv.enes.orang; | 1 | package lv.enes.orang.parser; |
| 2 | 2 | ||
| 3 | import lv.enes.orang.core.OrangException; | 3 | import lv.enes.orang.core.OrangException; |
| 4 | 4 | ||
diff --git a/parser/src/main/java/module-info.java b/parser/src/main/java/module-info.java new file mode 100644 index 0000000..43c2dc5 --- /dev/null +++ b/parser/src/main/java/module-info.java | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | module lv.enes.orang.parser { | ||
| 2 | exports lv.enes.orang.parser; | ||
| 3 | |||
| 4 | requires lv.enes.orang.ast; | ||
| 5 | requires lv.enes.orang.core; | ||
| 6 | requires lv.enes.orang.lexer; | ||
| 7 | requires lv.enes.orang.utils; | ||
| 8 | } \ No newline at end of file | ||