From 16a20ee8b08df919e93ea1b878013f9a2ad709fa Mon Sep 17 00:00:00 2001 From: Uko Kokņevičs Date: Sat, 24 Aug 2024 03:54:25 +0800 Subject: Added fancier tuple argument specs. Made ArgSpec use visitor pattern to avoid problems the best way. Merged empty tuple and non-empty tuple classes. --- .../src/main/java/lv/enes/orang/parser/Parser.java | 59 ++++++++++++++++------ 1 file changed, 44 insertions(+), 15 deletions(-) (limited to 'parser/src') diff --git a/parser/src/main/java/lv/enes/orang/parser/Parser.java b/parser/src/main/java/lv/enes/orang/parser/Parser.java index 0ff1f78..06183a3 100644 --- a/parser/src/main/java/lv/enes/orang/parser/Parser.java +++ b/parser/src/main/java/lv/enes/orang/parser/Parser.java @@ -131,23 +131,51 @@ public class Parser { private List parseArgSpecs() throws ParserException { var argSpecs = new ArrayList(); - while (true) { - if (input.peek().type() == Token.Type.IDENTIFIER) { - argSpecs.add(ArgSpec.named(input.next().literal())); - } else if (input.peek().type() == Token.Type.PAREN_LEFT) { - consumeToken(Token.Type.PAREN_LEFT); - consumeToken(Token.Type.PAREN_RIGHT); - argSpecs.add(ArgSpec.nothing()); - } else if (input.peek().type() == Token.Type.UNDERSCORE) { - consumeToken(Token.Type.UNDERSCORE); - argSpecs.add(ArgSpec.ignored()); - } else { - break; - } + while (couldStartArgSpec(input.peek().type())) { + argSpecs.add(parseArgSpec()); } + argSpecs.trimToSize(); return Collections.unmodifiableList(argSpecs); } + private boolean couldStartArgSpec(Token.Type type) { + return switch (type) { + case IDENTIFIER, PAREN_LEFT, UNDERSCORE -> true; + default -> false; + }; + } + + private ArgSpec parseArgSpec() throws ParserException { + var token = input.next(); + return switch (token.type()) { + case IDENTIFIER -> new ArgSpecNamed(token.literal()); + case PAREN_LEFT -> { + if (maybeConsumeToken(Token.Type.PAREN_RIGHT)) { + yield new ArgSpecTuple(List.of()); + } + var argspec = parseArgSpec(); + if (maybeConsumeToken(Token.Type.COMMA)) { + yield parseArgSpecTuple(argspec); + } + consumeToken(Token.Type.PAREN_RIGHT); + yield argspec; + } + case UNDERSCORE -> ArgSpecIgnored.INSTANCE; + default -> throw new ParserException(STR."Unexpected token when parsing argspecs: \{token}"); + }; + } + + private ArgSpec parseArgSpecTuple(ArgSpec first) throws ParserException { + var specs = new ArrayList(); + specs.add(first); + do { + specs.add(parseArgSpec()); + maybeConsumeToken(Token.Type.COMMA); + } while (!maybeConsumeToken(Token.Type.PAREN_RIGHT)); + specs.trimToSize(); + return new ArgSpecTuple(specs); + } + private Expression parseBinaryExpression() throws ParserException { var lhs = parseCallExpression(); if (isNotBinaryOp(input.peek())) { @@ -283,7 +311,7 @@ public class Parser { case PAREN_LEFT -> { consumeToken(Token.Type.PAREN_LEFT); if (maybeConsumeToken(Token.Type.PAREN_RIGHT)) { - yield EmptyTupleLiteral.INSTANCE; + yield new TupleExpression(List.of()); } var expr = parseExpression(); if (maybeConsumeToken(Token.Type.COMMA)) { @@ -346,7 +374,8 @@ public class Parser { exprs.add(parseExpression()); maybeConsumeToken(Token.Type.COMMA); } while (!maybeConsumeToken(Token.Type.PAREN_RIGHT)); - return new TupleExpression(new NonEmptyList<>(exprs)); + exprs.trimToSize(); + return new TupleExpression(exprs); } private Expression parseUnaryExpression() throws ParserException { -- cgit v1.2.3