From 0aeff1a757908bdc8972bca20330752858cbb903 Mon Sep 17 00:00:00 2001 From: Uko Kokņevičs Date: Fri, 16 Aug 2024 23:29:12 +0300 Subject: Big Refactoring, added support for comments --- src/main/java/lv/enes/orang/Builtins.java | 95 ------- src/main/java/lv/enes/orang/Codepoint.java | 24 -- src/main/java/lv/enes/orang/Lexer.java | 168 ------------ src/main/java/lv/enes/orang/Main.java | 77 ------ src/main/java/lv/enes/orang/NonEmptyList.java | 28 -- src/main/java/lv/enes/orang/OrangException.java | 11 - .../java/lv/enes/orang/OrangRuntimeException.java | 11 - src/main/java/lv/enes/orang/Parser.java | 291 --------------------- src/main/java/lv/enes/orang/ParserException.java | 7 - src/main/java/lv/enes/orang/PeekableStream.java | 38 --- src/main/java/lv/enes/orang/Scope.java | 54 ---- src/main/java/lv/enes/orang/State.java | 12 - src/main/java/lv/enes/orang/Token.java | 15 -- src/main/java/lv/enes/orang/TokenType.java | 91 ------- .../java/lv/enes/orang/ast/ArrayExpression.java | 21 -- .../java/lv/enes/orang/ast/BinaryExpression.java | 53 ---- .../java/lv/enes/orang/ast/BooleanLiteral.java | 12 - .../java/lv/enes/orang/ast/CallExpression.java | 12 - src/main/java/lv/enes/orang/ast/DefSpec.java | 6 - src/main/java/lv/enes/orang/ast/Definition.java | 15 -- src/main/java/lv/enes/orang/ast/DoExpression.java | 19 -- src/main/java/lv/enes/orang/ast/Expression.java | 14 - src/main/java/lv/enes/orang/ast/FnExpression.java | 14 - .../java/lv/enes/orang/ast/IfElseExpression.java | 22 -- src/main/java/lv/enes/orang/ast/IntLiteral.java | 12 - .../java/lv/enes/orang/ast/LetInExpression.java | 27 -- src/main/java/lv/enes/orang/ast/Program.java | 17 -- src/main/java/lv/enes/orang/ast/Statement.java | 8 - src/main/java/lv/enes/orang/ast/StringLiteral.java | 13 - .../java/lv/enes/orang/ast/UnaryExpression.java | 23 -- .../java/lv/enes/orang/ast/VariableExpression.java | 12 - src/main/java/lv/enes/orang/value/Array.java | 65 ----- .../java/lv/enes/orang/value/BuiltinFunction.java | 31 --- src/main/java/lv/enes/orang/value/Function.java | 28 -- .../java/lv/enes/orang/value/OrangBoolean.java | 55 ---- .../java/lv/enes/orang/value/OrangInteger.java | 70 ----- src/main/java/lv/enes/orang/value/OrangString.java | 49 ---- .../enes/orang/value/PartialBuiltinFunction.java | 32 --- .../java/lv/enes/orang/value/PartialFunction.java | 37 --- src/main/java/lv/enes/orang/value/Undefined.java | 21 -- src/main/java/lv/enes/orang/value/Value.java | 77 ------ 41 files changed, 1687 deletions(-) delete mode 100644 src/main/java/lv/enes/orang/Builtins.java delete mode 100644 src/main/java/lv/enes/orang/Codepoint.java delete mode 100644 src/main/java/lv/enes/orang/Lexer.java delete mode 100644 src/main/java/lv/enes/orang/Main.java delete mode 100644 src/main/java/lv/enes/orang/NonEmptyList.java delete mode 100644 src/main/java/lv/enes/orang/OrangException.java delete mode 100644 src/main/java/lv/enes/orang/OrangRuntimeException.java delete mode 100644 src/main/java/lv/enes/orang/Parser.java delete mode 100644 src/main/java/lv/enes/orang/ParserException.java delete mode 100644 src/main/java/lv/enes/orang/PeekableStream.java delete mode 100644 src/main/java/lv/enes/orang/Scope.java delete mode 100644 src/main/java/lv/enes/orang/State.java delete mode 100644 src/main/java/lv/enes/orang/Token.java delete mode 100644 src/main/java/lv/enes/orang/TokenType.java delete mode 100644 src/main/java/lv/enes/orang/ast/ArrayExpression.java delete mode 100644 src/main/java/lv/enes/orang/ast/BinaryExpression.java delete mode 100644 src/main/java/lv/enes/orang/ast/BooleanLiteral.java delete mode 100644 src/main/java/lv/enes/orang/ast/CallExpression.java delete mode 100644 src/main/java/lv/enes/orang/ast/DefSpec.java delete mode 100644 src/main/java/lv/enes/orang/ast/Definition.java delete mode 100644 src/main/java/lv/enes/orang/ast/DoExpression.java delete mode 100644 src/main/java/lv/enes/orang/ast/Expression.java delete mode 100644 src/main/java/lv/enes/orang/ast/FnExpression.java delete mode 100644 src/main/java/lv/enes/orang/ast/IfElseExpression.java delete mode 100644 src/main/java/lv/enes/orang/ast/IntLiteral.java delete mode 100644 src/main/java/lv/enes/orang/ast/LetInExpression.java delete mode 100644 src/main/java/lv/enes/orang/ast/Program.java delete mode 100644 src/main/java/lv/enes/orang/ast/Statement.java delete mode 100644 src/main/java/lv/enes/orang/ast/StringLiteral.java delete mode 100644 src/main/java/lv/enes/orang/ast/UnaryExpression.java delete mode 100644 src/main/java/lv/enes/orang/ast/VariableExpression.java delete mode 100644 src/main/java/lv/enes/orang/value/Array.java delete mode 100644 src/main/java/lv/enes/orang/value/BuiltinFunction.java delete mode 100644 src/main/java/lv/enes/orang/value/Function.java delete mode 100644 src/main/java/lv/enes/orang/value/OrangBoolean.java delete mode 100644 src/main/java/lv/enes/orang/value/OrangInteger.java delete mode 100644 src/main/java/lv/enes/orang/value/OrangString.java delete mode 100644 src/main/java/lv/enes/orang/value/PartialBuiltinFunction.java delete mode 100644 src/main/java/lv/enes/orang/value/PartialFunction.java delete mode 100644 src/main/java/lv/enes/orang/value/Undefined.java delete mode 100644 src/main/java/lv/enes/orang/value/Value.java (limited to 'src/main/java/lv') diff --git a/src/main/java/lv/enes/orang/Builtins.java b/src/main/java/lv/enes/orang/Builtins.java deleted file mode 100644 index 0a76387..0000000 --- a/src/main/java/lv/enes/orang/Builtins.java +++ /dev/null @@ -1,95 +0,0 @@ -package lv.enes.orang; - -import lombok.extern.slf4j.Slf4j; -import lv.enes.orang.value.*; - -import java.io.IOException; -import java.util.List; -import java.util.Map; -import java.util.Random; - -import static lv.enes.orang.State.STDIN; -import static lv.enes.orang.State.STDOUT; - -@Slf4j -public final class Builtins { - public static final Map BUILTINS = Map.ofEntries( - Map.entry("__builtin_isRepl", new BuiltinFunction(1, Builtins::isRepl)), - Map.entry("__builtin_len", new BuiltinFunction(1, Builtins::len)), - Map.entry("__builtin_parseInt", new BuiltinFunction(1, Builtins::parseInt)), - Map.entry("__builtin_print", new BuiltinFunction(1, Builtins::print)), - Map.entry("__builtin_randInt", new BuiltinFunction(2, Builtins::randInt)), - Map.entry("__builtin_readLn", new BuiltinFunction(1, Builtins::readLn)) - ); - - private Builtins() {} - - private static Value isRepl(List args) { - return OrangBoolean.TRUE; - } - - private static Value len(List args) throws OrangRuntimeException { - assert args.size() == 1; - var arg = args.getFirst(); - - if (arg instanceof OrangString(var value)) { - return new OrangInteger(value.length()); - } else if (arg instanceof Array(var items)) { - return new OrangInteger(items.size()); - } else { - throw new OrangRuntimeException(STR."len \{arg.typeName()} is not implemented"); - } - } - - private static Value parseInt(List args) throws OrangRuntimeException { - assert args.size() == 1; - - var arg = args.getFirst(); - if (arg instanceof OrangInteger) { - log.warn("Attempted to parseInt an Integer!"); - return arg; - } else if (arg instanceof OrangString(var value)) { - try { - return new OrangInteger(Integer.parseInt(value.trim())); - } catch (NumberFormatException ex) { - throw new OrangRuntimeException(ex); - } - } else { - throw new OrangRuntimeException(STR."parseInt \{arg.typeName()} is not implemented"); - } - } - - private static Value print(List args) { - assert args.size() == 1; - STDOUT.print(args.getFirst().display()); - STDOUT.flush(); - return args.getFirst(); - } - - private static Value randInt(List args) throws OrangRuntimeException { - assert args.size() == 2; - - var minv = args.getFirst(); - var maxv = args.get(1); - if (minv instanceof OrangInteger(var min) && maxv instanceof OrangInteger(var max)) { - return new OrangInteger(new Random().nextInt(min, max)); - } else { - throw new OrangRuntimeException(STR."randInt \{minv.typeName()} \{maxv.typeName()} is not implemented"); - } - } - - private static Value readLn(List args) throws OrangRuntimeException { - assert args.size() == 1; - - var arg = args.getFirst(); - if (!(arg instanceof Array) || !((Array) arg).items().isEmpty()) { - log.warn("You should call readLn with an empty tuple like `readLn ()`"); - } - - try { - return new OrangString(STDIN.readLine()); - } catch (IOException e) { - throw new OrangRuntimeException(e); - } - } -} diff --git a/src/main/java/lv/enes/orang/Codepoint.java b/src/main/java/lv/enes/orang/Codepoint.java deleted file mode 100644 index 0dfaa2b..0000000 --- a/src/main/java/lv/enes/orang/Codepoint.java +++ /dev/null @@ -1,24 +0,0 @@ -package lv.enes.orang; - -public record Codepoint(int cp) { - @Override - public String toString() { - return Character.toString(cp); - } - - public boolean isIdentInitial() { - return Character.isLetter(cp) || cp == '_'; - } - - public boolean isIdentFinal() { - return isIdentInitial() || Character.isDigit(cp); - } - - public boolean isNumeral() { - return Character.isDigit(cp); - } - - public boolean isWhitespace() { - return Character.isWhitespace(cp); - } -} diff --git a/src/main/java/lv/enes/orang/Lexer.java b/src/main/java/lv/enes/orang/Lexer.java deleted file mode 100644 index 0ee2503..0000000 --- a/src/main/java/lv/enes/orang/Lexer.java +++ /dev/null @@ -1,168 +0,0 @@ -package lv.enes.orang; - -import java.io.*; -import java.util.Iterator; -import java.util.function.BiFunction; -import java.util.function.Predicate; -import java.util.stream.IntStream; -import java.util.stream.Stream; - -public class Lexer implements Iterator { - private final PeekableStream input; - - public Lexer(InputStream input) { - this(new InputStreamReader(input)); - } - - public Lexer(Reader input) { - var cpStream = new BufferedReader(input) - .lines() - .flatMapToInt(str -> IntStream.concat(str.codePoints(), IntStream.of('\n'))) - .mapToObj(Codepoint::new); - var theEof = Stream.of(new Codepoint(-1)); - this.input = new PeekableStream<>(Stream.concat(cpStream, theEof).iterator()); - } - - public Lexer(String input) { - this(new StringReader(input)); - } - - private boolean hasNext = true; - - @Override - public Token next() { - var tok = nextToken(); - if (tok.type() == TokenType.EOF) { - hasNext = false; - } - return tok; - } - - @Override - public boolean hasNext() { - return hasNext; - } - - private Token nextToken() { - skipWhitespace(); - return switch (input.peek().cp()) { - case -1 -> new Token(TokenType.EOF, ""); - - case '*' -> new Token(TokenType.ASTERISK, input.next()); - case '!' -> new Token(TokenType.BANG, input.next()); - case '[' -> new Token(TokenType.BRACKET_LEFT, input.next()); - case ']' -> new Token(TokenType.BRACKET_RIGHT, input.next()); - case ',' -> new Token(TokenType.COMMA, input.next()); - case '=' -> new Token(TokenType.EQUAL, input.next()); - case '>' -> { - var first = input.next(); - if (input.peek().cp() == '=') { - yield new Token(TokenType.GREATER_EQUAL, first, input.next()); - } else { - yield new Token(TokenType.GREATER, first); - } - } - case '<' -> { - var first = input.next(); - if (input.peek().cp() == '=') { - yield new Token(TokenType.LESS_EQUAL, first, input.next()); - } else { - yield new Token(TokenType.LESS, first); - } - } - case '-' -> { - var first = input.next(); - if (input.peek().cp() == '>') { - yield new Token(TokenType.MINUS_GREATER, first, input.next()); - } else { - yield new Token(TokenType.MINUS, first); - } - } - case '(' -> new Token(TokenType.PAREN_LEFT, input.next()); - case ')' -> new Token(TokenType.PAREN_RIGHT, input.next()); - case '+' -> new Token(TokenType.PLUS, input.next()); - case '?' -> { - var first = input.next(); - if (input.peek().cp() == '=') { - yield new Token(TokenType.QUESTION_EQUAL, first, input.next()); - } else { - yield new Token(TokenType.ILLEGAL, first, input.next()); - } - } - case ';' -> new Token(TokenType.SEMICOLON, input.next()); - case '/' -> { - var first = input.next(); - if (input.peek().cp() == '=') { - yield new Token(TokenType.SLASH_EQUAL, first, input.next()); - } else { - yield new Token(TokenType.SLASH, first); - } - } - - case '"' -> new Token(TokenType.STRING, readString()); - - default -> { - if (input.peek().isIdentInitial()) { - var ident = readIdentifier(); - var type = switch (ident) { - case "and" -> TokenType.AND; - case "def" -> TokenType.DEF; - case "do" -> TokenType.DO; - case "else" -> TokenType.ELSE; - case "end" -> TokenType.END; - case "false" -> TokenType.FALSE; - case "fn" -> TokenType.FN; - case "if" -> TokenType.IF; - case "in" -> TokenType.IN; - case "let" -> TokenType.LET; - case "then" -> TokenType.THEN; - case "true" -> TokenType.TRUE; - default -> TokenType.IDENTIFIER; - }; - yield new Token(type, ident); - } else if (input.peek().isNumeral()) { - yield new Token(TokenType.INTEGER, readInteger()); - } else { - yield new Token(TokenType.ILLEGAL, input.next()); - } - } - }; - } - - private T foldWhile(Predicate pred, T initial, BiFunction combine) { - var res = initial; - var ch = input.peek(); - while (pred.test(ch)) { - res = combine.apply(res, input.next()); - ch = input.peek(); - } - return res; - } - - private String readWhile(Predicate pred) { - return foldWhile(pred, new StringBuilder(), StringBuilder::append).toString(); - } - - private void skipWhile(Predicate pred) { - foldWhile(pred, Object.class, (x, _) -> x); - } - - private String readIdentifier() { - return readWhile(Codepoint::isIdentFinal); - } - - private String readInteger() { - return readWhile(Codepoint::isNumeral); - } - - private String readString() { - input.next(); - var literal = readWhile(cp -> cp.cp() != '"'); - input.next(); - return literal; - } - - private void skipWhitespace() { - skipWhile(Codepoint::isWhitespace); - } -} diff --git a/src/main/java/lv/enes/orang/Main.java b/src/main/java/lv/enes/orang/Main.java deleted file mode 100644 index 9a607ed..0000000 --- a/src/main/java/lv/enes/orang/Main.java +++ /dev/null @@ -1,77 +0,0 @@ -package lv.enes.orang; - -import java.io.FileReader; -import java.io.IOException; - -import static lv.enes.orang.State.STDIN; -import static lv.enes.orang.State.STDOUT; - -public class Main { - public static final String PROMPT = ">> "; - - public static void main() throws IOException { - repl(); - } - - private static void repl() throws IOException { - var scope = new Scope(); - - try (var stream = Main.class.getResourceAsStream("prelude.orang")) { - var prog = Parser.parseProgram(stream); - scope = prog.runStatement(scope); - } catch (OrangException ex) { - STDOUT.println(STR."While evaluating prelude: \{ex}"); - throw new RuntimeException(ex); - } - - boolean running = true; - while (running) { - STDOUT.print(PROMPT); - STDOUT.flush(); - - var line = STDIN.readLine(); - if (line == null) { - return; - } - - if (line.isEmpty()) { - continue; - } - - if (line.charAt(0) == ':') { - if (line.length() == 1) { - continue; - } - - switch (line.charAt(1)) { - case 'l': - var filename = line.substring(2).trim(); - try (var reader = new FileReader((filename))) { - var prog = Parser.parseProgram(reader); - scope = prog.runStatement(scope); - } catch (IOException | OrangException ex) { - STDOUT.println(ex); - } - break; - case 'q': - running = false; - break; - default: - STDOUT.println("Unrecognised REPL command"); - } - continue; - } - - try { - var prog = Parser.parseProgram(line); - scope = prog.runStatement(scope); - if (scope.getLastResult() != null) { - STDOUT.print("-> "); - STDOUT.println(scope.getLastResult().stringify()); - } - } catch (OrangException ex) { - STDOUT.println(ex); - } - } - } -} diff --git a/src/main/java/lv/enes/orang/NonEmptyList.java b/src/main/java/lv/enes/orang/NonEmptyList.java deleted file mode 100644 index 860db28..0000000 --- a/src/main/java/lv/enes/orang/NonEmptyList.java +++ /dev/null @@ -1,28 +0,0 @@ -package lv.enes.orang; - -import lombok.EqualsAndHashCode; - -import java.util.AbstractList; -import java.util.List; - -@EqualsAndHashCode(callSuper = true) -public class NonEmptyList extends AbstractList { - private final List delegate; - - public NonEmptyList(List delegate) { - if (delegate.isEmpty()) { - throw new IllegalArgumentException("Empty list"); - } - this.delegate = List.copyOf(delegate); - } - - @Override - public E get(int index) { - return delegate.get(index); - } - - @Override - public int size() { - return delegate.size(); - } -} diff --git a/src/main/java/lv/enes/orang/OrangException.java b/src/main/java/lv/enes/orang/OrangException.java deleted file mode 100644 index 9308643..0000000 --- a/src/main/java/lv/enes/orang/OrangException.java +++ /dev/null @@ -1,11 +0,0 @@ -package lv.enes.orang; - -public abstract class OrangException extends Exception { - protected OrangException(String message) { - super(message); - } - - protected OrangException(Throwable cause) { - super(cause); - } -} diff --git a/src/main/java/lv/enes/orang/OrangRuntimeException.java b/src/main/java/lv/enes/orang/OrangRuntimeException.java deleted file mode 100644 index 9648c30..0000000 --- a/src/main/java/lv/enes/orang/OrangRuntimeException.java +++ /dev/null @@ -1,11 +0,0 @@ -package lv.enes.orang; - -public class OrangRuntimeException extends OrangException { - public OrangRuntimeException(String message) { - super(message); - } - - public OrangRuntimeException(Throwable cause) { - super(cause); - } -} diff --git a/src/main/java/lv/enes/orang/Parser.java b/src/main/java/lv/enes/orang/Parser.java deleted file mode 100644 index fd4b9bb..0000000 --- a/src/main/java/lv/enes/orang/Parser.java +++ /dev/null @@ -1,291 +0,0 @@ -package lv.enes.orang; - -import lv.enes.orang.ast.*; -import lv.enes.orang.ast.IfElseExpression; -import lv.enes.orang.ast.Statement; - -import java.io.InputStream; -import java.io.Reader; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.function.Predicate; - -public class Parser { - public static Program parseProgram(InputStream in) throws ParserException { - var parser = new Parser(in); - return parser.parseProgram(); - } - - public static Program parseProgram(Reader in) throws ParserException { - var parser = new Parser(in); - return parser.parseProgram(); - } - - public static Program parseProgram(String in) throws ParserException { - var parser = new Parser(in); - return parser.parseProgram(); - } - - private final PeekableStream input; - - public Parser(InputStream in) { - this(new Lexer(in)); - } - - public Parser(Reader in) { - this(new Lexer(in)); - } - - public Parser(String in) { - this(new Lexer(in)); - } - - public Parser(Iterator input) { - this.input = new PeekableStream<>(input); - } - - public Program parseProgram() throws ParserException { - var statements = new ArrayList(); - while (!maybeConsumeToken(TokenType.EOF)) { - statements.add(parseStatement()); - maybeConsumeToken(TokenType.SEMICOLON); - } - return new Program(Collections.unmodifiableList(statements)); - } - - private Token consume(Predicate pred, String msg) throws ParserException { - var tok = input.next(); - if (!pred.test(tok)) { - throw new ParserException(STR."\{msg}, got \{tok}"); - } - return tok; - } - - private Token consumeToken(TokenType type) throws ParserException { - return consume(tok -> tok.type() == type, STR."Expected \{type}"); - } - - private boolean maybeConsumeToken(TokenType type) { - if (input.peek().type() == type) { - input.next(); - return true; - } - return false; - } - - private ArrayExpression parseArray() throws ParserException { - consumeToken(TokenType.BRACKET_LEFT); - if (maybeConsumeToken(TokenType.BRACKET_RIGHT)) { - return new ArrayExpression(List.of()); - } - - var items = new ArrayList(); - do { - items.add(parseExpression()); - } while (maybeConsumeToken(TokenType.COMMA)); - consumeToken(TokenType.BRACKET_RIGHT); - - return new ArrayExpression(Collections.unmodifiableList(items)); - } - - private List parseArgSpecs() { - var argSpecs = new ArrayList(); - while (true) { - if (input.peek().type() == TokenType.IDENTIFIER) { - argSpecs.add(input.next().literal()); - } else { - break; - } - } - return Collections.unmodifiableList(argSpecs); - } - - private Expression parseBinaryExpression() throws ParserException { - var lhs = parseCallExpression(); - if (!input.peek().type().isBinaryOp()) { - return lhs; - } - - return parseBinaryExpressionRhs(lhs, input.next().type().toBinaryOp()); - } - - private Expression parseBinaryExpressionRhs(Expression lhs, BinaryExpression.Operator op) throws ParserException { - var rhs = parseCallExpression(); - if (!input.peek().type().isBinaryOp()) { - return new BinaryExpression(op, lhs, rhs); - } - - var op2 = input.next().type().toBinaryOp(); - if (op2.bindsStrongerThan(op)) { - return new BinaryExpression(op, lhs, parseBinaryExpressionRhs(rhs, op2)); - } else { - return parseBinaryExpressionRhs(new BinaryExpression(op, lhs, rhs), op2); - } - } - - private BooleanLiteral parseBoolean() throws ParserException { - var t = consume(tok -> tok.type() == TokenType.FALSE || tok.type() == TokenType.TRUE, "Expected TRUE or FALSE"); - return new BooleanLiteral(t.type() == TokenType.TRUE); - } - - private Expression parseCallExpression() throws ParserException { - var callee = parseSimpleExpression(); - while (couldStartSimpleExpression(input.peek().type())) { - var arg = parseSimpleExpression(); - callee = new CallExpression(callee, arg); - } - return callee; - } - - private Definition parseDefinition() throws ParserException { - consumeToken(TokenType.DEF); - var defSpec = parseDefSpec(); - consumeToken(TokenType.EQUAL); - var value = parseExpression(); - if (defSpec.args().isEmpty()) { - return new Definition(defSpec.name(), value); - } else { - return new Definition(defSpec.name(), new FnExpression(new NonEmptyList<>(defSpec.args()), value)); - } - } - - private DefSpec parseDefSpec() throws ParserException { - var name = consumeToken(TokenType.IDENTIFIER).literal(); - var argSpecs = parseArgSpecs(); - return new DefSpec(name, argSpecs); - } - - private DoExpression parseDoExpression() throws ParserException { - consumeToken(TokenType.DO); - var exprs = new ArrayList(); - do { - exprs.add(parseExpression()); - } while (maybeConsumeToken(TokenType.SEMICOLON)); - consumeToken(TokenType.END); - return new DoExpression(Collections.unmodifiableList(exprs)); - } - - private Expression parseExpression() throws ParserException { - if (input.peek().type().isUnaryOp()) { - return parseUnaryExpression(); - } - return parseBinaryExpression(); - } - - private FnExpression parseFnExpression() throws ParserException { - consumeToken(TokenType.FN); - var argSpecs = parseArgSpecs(); - if (argSpecs.isEmpty()) { - throw new ParserException("Function definition with no arguments"); - } - var body = maybeConsumeToken(TokenType.MINUS_GREATER) ? parseExpression() : parseDoExpression(); - return new FnExpression(new NonEmptyList<>(argSpecs), body); - } - - private IfElseExpression parseIfElseExpression() throws ParserException { - consumeToken(TokenType.IF); - var cond = parseExpression(); - consumeToken(TokenType.THEN); - var trueBranch = parseExpression(); - consumeToken(TokenType.ELSE); - var falseBranch = parseExpression(); - return new IfElseExpression(cond, trueBranch, falseBranch); - } - - private IntLiteral parseInteger() throws ParserException { - var tok = consumeToken(TokenType.INTEGER); - return new IntLiteral(Integer.parseInt(tok.literal())); - } - - private LetInExpression parseLetInExpression() throws ParserException { - consumeToken(TokenType.LET); - var bindings = new ArrayList(); - do { - var defSpec = parseDefSpec(); - consumeToken(TokenType.EQUAL); - var value = parseExpression(); - if (defSpec.args().isEmpty()) { - bindings.add(new LetInExpression.Binding(defSpec.name(), value)); - } else { - var fn = new FnExpression(new NonEmptyList<>(defSpec.args()), value); - bindings.add(new LetInExpression.Binding(defSpec.name(), fn)); - } - } while (maybeConsumeToken(TokenType.AND)); - consumeToken(TokenType.IN); - var body = parseExpression(); - return new LetInExpression(Collections.unmodifiableList(bindings), body); - } - - private Expression parseSimpleExpression() throws ParserException { - return switch (input.peek().type()) { - case PAREN_LEFT -> { - consumeToken(TokenType.PAREN_LEFT); - if (maybeConsumeToken(TokenType.PAREN_RIGHT)) { - yield new ArrayExpression(List.of()); - } - var expr = parseExpression(); - consumeToken(TokenType.PAREN_RIGHT); - yield expr; - } - case TRUE, FALSE -> parseBoolean(); - case INTEGER -> parseInteger(); - case IDENTIFIER -> new VariableExpression(input.next().literal()); - case STRING -> parseString(); - case BRACKET_LEFT -> parseArray(); - case IF -> parseIfElseExpression(); - case LET -> parseLetInExpression(); - case FN -> parseFnExpression(); - case DO -> parseDoExpression(); - default -> throw new ParserException(STR."Unexpected token \{input.peek()}"); - }; - } - - private boolean couldStartSimpleExpression(TokenType type) { - return switch (type) { - case PAREN_LEFT, TRUE, FALSE, INTEGER, IDENTIFIER, STRING, BRACKET_LEFT, IF, LET, FN, DO -> true; - default -> false; - }; - } - - private Statement parseStatement() throws ParserException { - if (input.peek().type() == TokenType.DEF) { - return parseDefinition(); - } else { - return parseExpression(); - } - } - - private Expression parseString() throws ParserException { - var sb = new StringBuilder(); - var cps = input.next().literal().codePoints().iterator(); - while (cps.hasNext()) { - var cp = cps.next(); - if (cp == '\\') { - var escapeChar = cps.next(); - //noinspection UnnecessaryUnboxing - sb.append(switch (escapeChar.intValue()) { - case '\'' -> '\''; - case '"' -> '"'; - case 'r' -> '\r'; - case 'n' -> '\n'; - case 't' -> '\t'; - default -> throw new ParserException(STR."Unknown string escape '\\\{escapeChar}'"); - }); - } else { - sb.appendCodePoint(cp); - } - } - return new StringLiteral(sb.toString()); - } - - private Expression parseUnaryExpression() throws ParserException { - if (input.peek().type().isUnaryOp()) { - var op = input.next().type().toUnaryOp(); - return new UnaryExpression(op, parseUnaryExpression()); - } else { - return parseSimpleExpression(); - } - } -} diff --git a/src/main/java/lv/enes/orang/ParserException.java b/src/main/java/lv/enes/orang/ParserException.java deleted file mode 100644 index 9000a93..0000000 --- a/src/main/java/lv/enes/orang/ParserException.java +++ /dev/null @@ -1,7 +0,0 @@ -package lv.enes.orang; - -public class ParserException extends OrangException { - public ParserException(String message) { - super(message); - } -} diff --git a/src/main/java/lv/enes/orang/PeekableStream.java b/src/main/java/lv/enes/orang/PeekableStream.java deleted file mode 100644 index b77bab1..0000000 --- a/src/main/java/lv/enes/orang/PeekableStream.java +++ /dev/null @@ -1,38 +0,0 @@ -package lv.enes.orang; - -import java.util.ArrayDeque; -import java.util.Deque; -import java.util.Iterator; - -public class PeekableStream implements Iterator { - private final Iterator input; - private final Deque buffer = new ArrayDeque<>(); - - public PeekableStream(Iterator input) { - this.input = input; - } - - @Override - public boolean hasNext() { - return !buffer.isEmpty() || input.hasNext(); - } - - @Override - public T next() { - if (!buffer.isEmpty()) { - return buffer.pop(); - } else { - return input.next(); - } - } - - public T peek() { - var value = next(); - putBack(value); - return value; - } - - public void putBack(T value) { - buffer.push(value); - } -} diff --git a/src/main/java/lv/enes/orang/Scope.java b/src/main/java/lv/enes/orang/Scope.java deleted file mode 100644 index 3625c69..0000000 --- a/src/main/java/lv/enes/orang/Scope.java +++ /dev/null @@ -1,54 +0,0 @@ -package lv.enes.orang; - -import jakarta.annotation.Nullable; -import lv.enes.orang.value.Value; - -import java.util.HashMap; -import java.util.Map; - -public class Scope { - private final Map definitions; - - private final Value lastResult; - - public Scope() { - this(new HashMap<>(Builtins.BUILTINS), null); - } - - private Scope(Map definitions, Value lastResult) { - this.definitions = definitions; - this.lastResult = lastResult; - } - - public Value getDefinition(String name) throws OrangRuntimeException { - if (definitions.containsKey(name)) { - return definitions.get(name); - } - throw new OrangRuntimeException(STR."Value named \{name} is not defined!"); - } - - @Nullable - public Value getLastResult() { - return lastResult; - } - - public Scope withDefinition(String key, Value value) { - var newDefs = new HashMap<>(definitions); - newDefs.put(key, value); - return new Scope(newDefs, null); - } - - public Scope withDefinitions(Map definitions) { - var newDefs = new HashMap<>(this.definitions); - newDefs.putAll(definitions); - return new Scope(newDefs, null); - } - - public void setDefinition(String key, Value value) { - definitions.put(key, value); - } - - public Scope withLastResult(Value value) { - return new Scope(definitions, value); - } -} diff --git a/src/main/java/lv/enes/orang/State.java b/src/main/java/lv/enes/orang/State.java deleted file mode 100644 index 46b115b..0000000 --- a/src/main/java/lv/enes/orang/State.java +++ /dev/null @@ -1,12 +0,0 @@ -package lv.enes.orang; - -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.io.PrintWriter; - -public final class State { - public static final BufferedReader STDIN = new BufferedReader(new InputStreamReader(System.in)); - public static final PrintWriter STDOUT = new PrintWriter(System.out); - - private State() {} -} diff --git a/src/main/java/lv/enes/orang/Token.java b/src/main/java/lv/enes/orang/Token.java deleted file mode 100644 index 4456b8f..0000000 --- a/src/main/java/lv/enes/orang/Token.java +++ /dev/null @@ -1,15 +0,0 @@ -package lv.enes.orang; - -public record Token(TokenType type, String literal) { - public Token(TokenType type, Codepoint... cps) { - this(type, codepointsToString(cps)); - } - - private static String codepointsToString(Codepoint... cps) { - var sb = new StringBuilder(cps.length); - for (var cp : cps) { - sb.append(cp); - } - return sb.toString(); - } -} diff --git a/src/main/java/lv/enes/orang/TokenType.java b/src/main/java/lv/enes/orang/TokenType.java deleted file mode 100644 index 960435e..0000000 --- a/src/main/java/lv/enes/orang/TokenType.java +++ /dev/null @@ -1,91 +0,0 @@ -package lv.enes.orang; - -import lv.enes.orang.ast.BinaryExpression; -import lv.enes.orang.ast.UnaryExpression; - -public enum TokenType { - ILLEGAL, - EOF, - - // Literals - IDENTIFIER, - INTEGER, - STRING, - - // Keywords - AND, - DEF, - DO, - ELSE, - END, - FALSE, - FN, - IF, - IN, - LET, - THEN, - TRUE, - - // Special chars - ASTERISK, - BANG, - BRACKET_LEFT, - BRACKET_RIGHT, - COMMA, - EQUAL, - GREATER, - GREATER_EQUAL, - LESS, - LESS_EQUAL, - MINUS, - MINUS_GREATER, - PAREN_LEFT, - PAREN_RIGHT, - PLUS, - QUESTION_EQUAL, - SEMICOLON, - SLASH, - SLASH_EQUAL, - - ; - - public boolean isBinaryOp() { - return switch (this) { - case ASTERISK, SLASH, PLUS, MINUS, QUESTION_EQUAL, SLASH_EQUAL, GREATER, GREATER_EQUAL, LESS, LESS_EQUAL - -> true; - default -> false; - }; - } - - public BinaryExpression.Operator toBinaryOp() { - return switch (this) { - case ASTERISK -> BinaryExpression.Operator.MULTIPLY; - case SLASH -> BinaryExpression.Operator.DIVIDE; - case PLUS -> BinaryExpression.Operator.ADD; - case MINUS -> BinaryExpression.Operator.SUBTRACT; - case QUESTION_EQUAL -> BinaryExpression.Operator.EQUALS; - case SLASH_EQUAL -> BinaryExpression.Operator.NOT_EQUALS; - case GREATER -> BinaryExpression.Operator.GT; - case GREATER_EQUAL -> BinaryExpression.Operator.GTE; - case LESS -> BinaryExpression.Operator.LT; - case LESS_EQUAL -> BinaryExpression.Operator.LTE; - default -> throw new IllegalStateException("Token " + this + " is not a binary operator"); - }; - } - - public boolean isUnaryOp() { - return switch (this) { - case PLUS, MINUS, BANG -> true; - default -> false; - }; - } - - public UnaryExpression.Operator toUnaryOp() { - return switch (this) { - case PLUS -> UnaryExpression.Operator.PLUS; - case MINUS -> UnaryExpression.Operator.NEGATE; - case BANG -> UnaryExpression.Operator.NOT; - default -> throw new IllegalStateException("Token " + this + " is not a unary operator"); - }; - } -} diff --git a/src/main/java/lv/enes/orang/ast/ArrayExpression.java b/src/main/java/lv/enes/orang/ast/ArrayExpression.java deleted file mode 100644 index d2437cf..0000000 --- a/src/main/java/lv/enes/orang/ast/ArrayExpression.java +++ /dev/null @@ -1,21 +0,0 @@ -package lv.enes.orang.ast; - -import lv.enes.orang.OrangRuntimeException; -import lv.enes.orang.Scope; -import lv.enes.orang.value.Array; -import lv.enes.orang.value.Value; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -public record ArrayExpression(List items) implements Expression { - @Override - public Value evaluateExpression(Scope scope) throws OrangRuntimeException { - var values = new ArrayList(); - for (var item : items) { - values.add(item.evaluateExpression(scope)); - } - return new Array(Collections.unmodifiableList(values)); - } -} diff --git a/src/main/java/lv/enes/orang/ast/BinaryExpression.java b/src/main/java/lv/enes/orang/ast/BinaryExpression.java deleted file mode 100644 index c0b988c..0000000 --- a/src/main/java/lv/enes/orang/ast/BinaryExpression.java +++ /dev/null @@ -1,53 +0,0 @@ -package lv.enes.orang.ast; - -import lv.enes.orang.OrangRuntimeException; -import lv.enes.orang.Scope; -import lv.enes.orang.value.Value; - -public record BinaryExpression(Operator operator, Expression lhs, Expression rhs) implements Expression { - public enum Operator { - EQUALS, - NOT_EQUALS, - GT, - GTE, - LT, - LTE, - ADD, - SUBTRACT, - MULTIPLY, - DIVIDE, - ; - - public boolean bindsStrongerThan(Operator other) { - return switch (this) { - case EQUALS, NOT_EQUALS, GT, GTE, LT, LTE -> false; - case ADD, SUBTRACT -> switch (other) { - case EQUALS, NOT_EQUALS, GT, GTE, LTE -> true; - default -> false; - }; - case MULTIPLY, DIVIDE -> switch (other) { - case EQUALS, NOT_EQUALS, GT, GTE, LT, LTE, ADD, SUBTRACT -> true; - default -> false; - }; - }; - } - } - - @Override - public Value evaluateExpression(Scope scope) throws OrangRuntimeException { - var lhs = lhs().evaluateExpression(scope); - var rhs = rhs().evaluateExpression(scope); - return switch (operator) { - case EQUALS -> lhs.orangEquals(rhs); - case NOT_EQUALS -> lhs.notEquals(rhs); - case GT -> lhs.greaterThan(rhs); - case GTE -> lhs.greaterThanOrEqual(rhs); - case LT -> lhs.lessThan(rhs); - case LTE -> lhs.lessThanOrEqual(rhs); - case ADD -> lhs.add(rhs); - case SUBTRACT -> lhs.subtract(rhs); - case MULTIPLY -> lhs.multiply(rhs); - case DIVIDE -> lhs.divide(rhs); - }; - } -} diff --git a/src/main/java/lv/enes/orang/ast/BooleanLiteral.java b/src/main/java/lv/enes/orang/ast/BooleanLiteral.java deleted file mode 100644 index 9110f67..0000000 --- a/src/main/java/lv/enes/orang/ast/BooleanLiteral.java +++ /dev/null @@ -1,12 +0,0 @@ -package lv.enes.orang.ast; - -import lv.enes.orang.Scope; -import lv.enes.orang.value.OrangBoolean; -import lv.enes.orang.value.Value; - -public record BooleanLiteral(boolean value) implements Expression { - @Override - public Value evaluateExpression(Scope scope) { - return OrangBoolean.of(value); - } -} diff --git a/src/main/java/lv/enes/orang/ast/CallExpression.java b/src/main/java/lv/enes/orang/ast/CallExpression.java deleted file mode 100644 index 8f05496..0000000 --- a/src/main/java/lv/enes/orang/ast/CallExpression.java +++ /dev/null @@ -1,12 +0,0 @@ -package lv.enes.orang.ast; - -import lv.enes.orang.OrangRuntimeException; -import lv.enes.orang.Scope; -import lv.enes.orang.value.Value; - -public record CallExpression(Expression callee, Expression arg) implements Expression { - @Override - public Value evaluateExpression(Scope scope) throws OrangRuntimeException { - return callee.evaluateExpression(scope).call(arg.evaluateExpression(scope)); - } -} diff --git a/src/main/java/lv/enes/orang/ast/DefSpec.java b/src/main/java/lv/enes/orang/ast/DefSpec.java deleted file mode 100644 index 2233d3f..0000000 --- a/src/main/java/lv/enes/orang/ast/DefSpec.java +++ /dev/null @@ -1,6 +0,0 @@ -package lv.enes.orang.ast; - -import java.util.List; - -public record DefSpec(String name, List args) { -} diff --git a/src/main/java/lv/enes/orang/ast/Definition.java b/src/main/java/lv/enes/orang/ast/Definition.java deleted file mode 100644 index 715daae..0000000 --- a/src/main/java/lv/enes/orang/ast/Definition.java +++ /dev/null @@ -1,15 +0,0 @@ -package lv.enes.orang.ast; - -import lv.enes.orang.OrangRuntimeException; -import lv.enes.orang.Scope; -import lv.enes.orang.value.Undefined; - -public record Definition(String name, Expression body) implements Statement { - @Override - public Scope runStatement(Scope scope) throws OrangRuntimeException { - scope.setDefinition(name, Undefined.INSTANCE); - var value = body.evaluateExpression(scope); - scope.setDefinition(name, value); - return scope; - } -} diff --git a/src/main/java/lv/enes/orang/ast/DoExpression.java b/src/main/java/lv/enes/orang/ast/DoExpression.java deleted file mode 100644 index 9d69a3e..0000000 --- a/src/main/java/lv/enes/orang/ast/DoExpression.java +++ /dev/null @@ -1,19 +0,0 @@ -package lv.enes.orang.ast; - -import lv.enes.orang.OrangRuntimeException; -import lv.enes.orang.Scope; -import lv.enes.orang.value.Value; - -import java.util.List; - -public record DoExpression(List body) implements Expression { - // assert body.!isEmpty() - - @Override - public Value evaluateExpression(Scope scope) throws OrangRuntimeException { - for (var i = 0; i < body.size() - 1; i++) { - body.get(i).evaluateExpression(scope); - } - return body.getLast().evaluateExpression(scope); - } -} diff --git a/src/main/java/lv/enes/orang/ast/Expression.java b/src/main/java/lv/enes/orang/ast/Expression.java deleted file mode 100644 index a0fc3af..0000000 --- a/src/main/java/lv/enes/orang/ast/Expression.java +++ /dev/null @@ -1,14 +0,0 @@ -package lv.enes.orang.ast; - -import lv.enes.orang.OrangRuntimeException; -import lv.enes.orang.Scope; -import lv.enes.orang.value.Value; - -public interface Expression extends Statement { - Value evaluateExpression(Scope scope) throws OrangRuntimeException; - - @Override - default Scope runStatement(Scope scope) throws OrangRuntimeException { - return scope.withLastResult(evaluateExpression(scope)); - } -} diff --git a/src/main/java/lv/enes/orang/ast/FnExpression.java b/src/main/java/lv/enes/orang/ast/FnExpression.java deleted file mode 100644 index 3c3522f..0000000 --- a/src/main/java/lv/enes/orang/ast/FnExpression.java +++ /dev/null @@ -1,14 +0,0 @@ -package lv.enes.orang.ast; - -import lv.enes.orang.NonEmptyList; -import lv.enes.orang.OrangRuntimeException; -import lv.enes.orang.Scope; -import lv.enes.orang.value.Function; -import lv.enes.orang.value.Value; - -public record FnExpression(NonEmptyList args, Expression body) implements Expression { - @Override - public Value evaluateExpression(Scope scope) throws OrangRuntimeException { - return new Function(scope, args, body); - } -} diff --git a/src/main/java/lv/enes/orang/ast/IfElseExpression.java b/src/main/java/lv/enes/orang/ast/IfElseExpression.java deleted file mode 100644 index 9b52cc5..0000000 --- a/src/main/java/lv/enes/orang/ast/IfElseExpression.java +++ /dev/null @@ -1,22 +0,0 @@ -package lv.enes.orang.ast; - -import lv.enes.orang.OrangRuntimeException; -import lv.enes.orang.Scope; -import lv.enes.orang.value.OrangBoolean; -import lv.enes.orang.value.Value; - -public record IfElseExpression(Expression condition, Expression trueBranch, Expression falseBranch) implements Expression { - @Override - public Value evaluateExpression(Scope scope) throws OrangRuntimeException { - var condValue = condition.evaluateExpression(scope); - if (condValue instanceof OrangBoolean value) { - if (value.value()) { - return trueBranch.evaluateExpression(scope); - } else { - return falseBranch.evaluateExpression(scope); - } - } else { - throw new OrangRuntimeException(STR."Condition in an if should be a Boolean not a \{condValue.typeName()}"); - } - } -} diff --git a/src/main/java/lv/enes/orang/ast/IntLiteral.java b/src/main/java/lv/enes/orang/ast/IntLiteral.java deleted file mode 100644 index 339ba3b..0000000 --- a/src/main/java/lv/enes/orang/ast/IntLiteral.java +++ /dev/null @@ -1,12 +0,0 @@ -package lv.enes.orang.ast; - -import lv.enes.orang.Scope; -import lv.enes.orang.value.OrangInteger; -import lv.enes.orang.value.Value; - -public record IntLiteral(int value) implements Expression { - @Override - public Value evaluateExpression(Scope scope) { - return new OrangInteger(value); - } -} diff --git a/src/main/java/lv/enes/orang/ast/LetInExpression.java b/src/main/java/lv/enes/orang/ast/LetInExpression.java deleted file mode 100644 index 2379902..0000000 --- a/src/main/java/lv/enes/orang/ast/LetInExpression.java +++ /dev/null @@ -1,27 +0,0 @@ -package lv.enes.orang.ast; - -import lv.enes.orang.OrangRuntimeException; -import lv.enes.orang.Scope; -import lv.enes.orang.value.Undefined; -import lv.enes.orang.value.Value; - -import java.util.HashMap; -import java.util.List; - -public record LetInExpression(List bindings, Expression body) implements Expression { - @Override - public Value evaluateExpression(Scope scope) throws OrangRuntimeException { - var newDefs = new HashMap(); - for (var binding : bindings) { - newDefs.put(binding.name, Undefined.INSTANCE); - } - var newState = scope.withDefinitions(newDefs); - for (var binding : bindings) { - var value = binding.value.evaluateExpression(newState); - newState.setDefinition(binding.name, value); - } - return body.evaluateExpression(newState); - } - - public record Binding(String name, Expression value) {} -} diff --git a/src/main/java/lv/enes/orang/ast/Program.java b/src/main/java/lv/enes/orang/ast/Program.java deleted file mode 100644 index ae5d31e..0000000 --- a/src/main/java/lv/enes/orang/ast/Program.java +++ /dev/null @@ -1,17 +0,0 @@ -package lv.enes.orang.ast; - -import lv.enes.orang.OrangRuntimeException; -import lv.enes.orang.Scope; - -import java.util.List; - -public record Program(List statements) implements Statement { - @Override - public Scope runStatement(Scope inScope) throws OrangRuntimeException { - var state = inScope; - for (var statement : statements) { - state = statement.runStatement(state); - } - return state; - } -} diff --git a/src/main/java/lv/enes/orang/ast/Statement.java b/src/main/java/lv/enes/orang/ast/Statement.java deleted file mode 100644 index 0f52fc3..0000000 --- a/src/main/java/lv/enes/orang/ast/Statement.java +++ /dev/null @@ -1,8 +0,0 @@ -package lv.enes.orang.ast; - -import lv.enes.orang.OrangRuntimeException; -import lv.enes.orang.Scope; - -public interface Statement { - Scope runStatement(Scope scope) throws OrangRuntimeException; -} diff --git a/src/main/java/lv/enes/orang/ast/StringLiteral.java b/src/main/java/lv/enes/orang/ast/StringLiteral.java deleted file mode 100644 index 367dff5..0000000 --- a/src/main/java/lv/enes/orang/ast/StringLiteral.java +++ /dev/null @@ -1,13 +0,0 @@ -package lv.enes.orang.ast; - -import lv.enes.orang.OrangRuntimeException; -import lv.enes.orang.Scope; -import lv.enes.orang.value.OrangString; -import lv.enes.orang.value.Value; - -public record StringLiteral(String value) implements Expression { - @Override - public Value evaluateExpression(Scope scope) throws OrangRuntimeException { - return new OrangString(value); - } -} diff --git a/src/main/java/lv/enes/orang/ast/UnaryExpression.java b/src/main/java/lv/enes/orang/ast/UnaryExpression.java deleted file mode 100644 index a0f565b..0000000 --- a/src/main/java/lv/enes/orang/ast/UnaryExpression.java +++ /dev/null @@ -1,23 +0,0 @@ -package lv.enes.orang.ast; - -import lv.enes.orang.OrangRuntimeException; -import lv.enes.orang.Scope; -import lv.enes.orang.value.Value; - -public record UnaryExpression(Operator operator, Expression child) implements Expression { - public enum Operator { - PLUS, - NEGATE, - NOT, - } - - @Override - public Value evaluateExpression(Scope scope) throws OrangRuntimeException { - var child = child().evaluateExpression(scope); - return switch (operator) { - case PLUS -> child.plus(); - case NEGATE -> child.negate(); - case NOT -> child.not(); - }; - } -} diff --git a/src/main/java/lv/enes/orang/ast/VariableExpression.java b/src/main/java/lv/enes/orang/ast/VariableExpression.java deleted file mode 100644 index 1f5334d..0000000 --- a/src/main/java/lv/enes/orang/ast/VariableExpression.java +++ /dev/null @@ -1,12 +0,0 @@ -package lv.enes.orang.ast; - -import lv.enes.orang.OrangRuntimeException; -import lv.enes.orang.Scope; -import lv.enes.orang.value.Value; - -public record VariableExpression(String name) implements Expression { - @Override - public Value evaluateExpression(Scope scope) throws OrangRuntimeException { - return scope.getDefinition(name); - } -} diff --git a/src/main/java/lv/enes/orang/value/Array.java b/src/main/java/lv/enes/orang/value/Array.java deleted file mode 100644 index c3b645d..0000000 --- a/src/main/java/lv/enes/orang/value/Array.java +++ /dev/null @@ -1,65 +0,0 @@ -package lv.enes.orang.value; - -import lv.enes.orang.OrangRuntimeException; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -public record Array(List items) implements Value { - @Override - public String typeName() { - return "Array"; - } - - @Override - public String stringify() { - if (items.isEmpty()) { - return "[]"; - } - var sb = new StringBuilder("["); - sb.append(items.getFirst().stringify()); - for (int i = 1; i < items.size(); i++) { - sb.append(", ").append(items.get(i).stringify()); - } - sb.append("]"); - return sb.toString(); - } - - @Override - public String display() { - if (items.isEmpty()) { - return ""; - } - var sb = new StringBuilder(); - sb.append(items.getFirst().display()); - for (var i = 1; i < items.size(); i++) { - sb.append(" ").append(items.get(i).display()); - } - return sb.toString(); - } - - @Override - public Value add(Value rhs) throws OrangRuntimeException { - if (rhs instanceof Array(var rhsi)) { - var newItems = new ArrayList<>(this.items); - newItems.addAll(rhsi); - return new Array(Collections.unmodifiableList(newItems)); - } else { - throw new OrangRuntimeException(STR."add not implemented for Array and \{rhs.typeName()}"); - } - } - - @Override - public Value multiply(Value rhs) throws OrangRuntimeException { - if (rhs instanceof OrangInteger(var repeat)) { - var newItems = new ArrayList(items.size() * repeat); - for (var i = 0; i < repeat; i++) { - newItems.addAll(items); - } - return new Array(Collections.unmodifiableList(newItems)); - } else { - throw new OrangRuntimeException(STR."multiply not implemented for Array and \{rhs.typeName()}"); - } - } -} diff --git a/src/main/java/lv/enes/orang/value/BuiltinFunction.java b/src/main/java/lv/enes/orang/value/BuiltinFunction.java deleted file mode 100644 index 92ccc2e..0000000 --- a/src/main/java/lv/enes/orang/value/BuiltinFunction.java +++ /dev/null @@ -1,31 +0,0 @@ -package lv.enes.orang.value; - -import lv.enes.orang.OrangRuntimeException; - -import java.util.List; - -public record BuiltinFunction(int argCount, Impl impl) implements Value { - @FunctionalInterface - public interface Impl { - Value apply(List args) throws OrangRuntimeException; - } - - @Override - public String typeName() { - return "BuiltinFunction"; - } - - @Override - public String stringify() { - return "#builtinFunction"; - } - - @Override - public Value call(Value param) throws OrangRuntimeException { - if (argCount == 1) { - return impl.apply(List.of(param)); - } else { - return new PartialBuiltinFunction(argCount, List.of(param), impl); - } - } -} diff --git a/src/main/java/lv/enes/orang/value/Function.java b/src/main/java/lv/enes/orang/value/Function.java deleted file mode 100644 index 1f288c6..0000000 --- a/src/main/java/lv/enes/orang/value/Function.java +++ /dev/null @@ -1,28 +0,0 @@ -package lv.enes.orang.value; - -import lv.enes.orang.OrangRuntimeException; -import lv.enes.orang.Scope; -import lv.enes.orang.ast.Expression; - -import java.util.List; - -public record Function(Scope scope, List args, Expression body) implements Value { - @Override - public String typeName() { - return "Function"; - } - - @Override - public String stringify() { - return "#function"; - } - - @Override - public Value call(Value param) throws OrangRuntimeException { - if (args.size() == 1) { - return body.evaluateExpression(scope.withDefinition(args.getFirst(), param)); - } else { - return new PartialFunction(scope, args, List.of(param), body); - } - } -} diff --git a/src/main/java/lv/enes/orang/value/OrangBoolean.java b/src/main/java/lv/enes/orang/value/OrangBoolean.java deleted file mode 100644 index 8a4776c..0000000 --- a/src/main/java/lv/enes/orang/value/OrangBoolean.java +++ /dev/null @@ -1,55 +0,0 @@ -package lv.enes.orang.value; - -import lombok.EqualsAndHashCode; -import lv.enes.orang.OrangRuntimeException; - -@EqualsAndHashCode -public final class OrangBoolean implements Value { - public final static OrangBoolean TRUE = new OrangBoolean(true); - public final static OrangBoolean FALSE = new OrangBoolean(false); - - private final boolean value; - - private OrangBoolean(boolean value) { - this.value = value; - } - - public static OrangBoolean of(boolean value) { - if (value) { - return TRUE; - } - return FALSE; - } - - public boolean value() { - return value; - } - - @Override - public String typeName() { - return "Boolean"; - } - - @Override - public String stringify() { - if (value) { - return "true"; - } else { - return "false"; - } - } - - @Override - public OrangBoolean not() { - return new OrangBoolean(!value); - } - - @Override - public OrangBoolean or(Value rhs) throws OrangRuntimeException { - if (rhs instanceof OrangBoolean rhsb) { - return new OrangBoolean(value || rhsb.value); - } else { - throw new OrangRuntimeException(STR."or is not implemented for Boolean and \{rhs.typeName()}"); - } - } -} diff --git a/src/main/java/lv/enes/orang/value/OrangInteger.java b/src/main/java/lv/enes/orang/value/OrangInteger.java deleted file mode 100644 index 9b8d505..0000000 --- a/src/main/java/lv/enes/orang/value/OrangInteger.java +++ /dev/null @@ -1,70 +0,0 @@ -package lv.enes.orang.value; - -import lv.enes.orang.OrangRuntimeException; - -public record OrangInteger(int value) implements Value { - @Override - public String typeName() { - return "Integer"; - } - - @Override - public String stringify() { - return Integer.toString(value); - } - - @Override - public OrangInteger negate() { - return new OrangInteger(-value); - } - - @Override - public OrangInteger plus() { - return this; - } - - @Override - public OrangInteger add(Value rhs) throws OrangRuntimeException { - if (rhs instanceof OrangInteger(int rhsi)) { - return new OrangInteger(value + rhsi); - } else { - throw new OrangRuntimeException(STR."add is not implemented for Integer and \{rhs.typeName()}"); - } - } - - @Override - public OrangInteger divide(Value rhs) throws OrangRuntimeException { - if (rhs instanceof OrangInteger(int rhsi)) { - return new OrangInteger(value / rhsi); - } else { - throw new OrangRuntimeException(STR."divide is not implemented for Integer and \{rhs.typeName()}"); - } - } - - @Override - public OrangInteger multiply(Value rhs) throws OrangRuntimeException { - if (rhs instanceof OrangInteger(int rhsi)) { - return new OrangInteger(value * rhsi); - } else { - throw new OrangRuntimeException(STR."multiply is not implemented for Integer and \{rhs.typeName()}"); - } - } - - @Override - public OrangInteger subtract(Value rhs) throws OrangRuntimeException { - if (rhs instanceof OrangInteger(int rhsi)) { - return new OrangInteger(value - rhsi); - } else { - throw new OrangRuntimeException(STR."subtract is not implemented for Integer and \{rhs.typeName()}"); - } - } - - @Override - public OrangBoolean greaterThan(Value rhs) throws OrangRuntimeException { - if (rhs instanceof OrangInteger(int rhsi)) { - return OrangBoolean.of(value > rhsi); - } else { - throw new OrangRuntimeException(STR."greaterThan is not implemented for Integer and \{rhs.typeName()}"); - } - } -} diff --git a/src/main/java/lv/enes/orang/value/OrangString.java b/src/main/java/lv/enes/orang/value/OrangString.java deleted file mode 100644 index c03f7ac..0000000 --- a/src/main/java/lv/enes/orang/value/OrangString.java +++ /dev/null @@ -1,49 +0,0 @@ -package lv.enes.orang.value; - -import lv.enes.orang.OrangRuntimeException; - -public record OrangString(String value) implements Value { - @Override - public String typeName() { - return "String"; - } - - @Override - public String stringify() { - var sb = new StringBuilder("\""); - var cps = value.codePoints().iterator(); - while (cps.hasNext()) { - var cp = cps.next(); - if (cp == '"') { - sb.append("\\\""); - } else { - sb.appendCodePoint(cp); - } - } - sb.append('"'); - return sb.toString(); - } - - @Override - public String display() { - return value; - } - - @Override - public OrangString add(Value rhs) throws OrangRuntimeException { - if (rhs instanceof OrangString(String rhss)) { - return new OrangString(value + rhss); - } else { - throw new OrangRuntimeException(STR."add is not implemented for Integer and \{rhs.typeName()}"); - } - } - - @Override - public Value multiply(Value rhs) throws OrangRuntimeException { - if (rhs instanceof OrangInteger(var repeat)) { - return new OrangString(value.repeat(Math.max(0, repeat))); - } else { - throw new OrangRuntimeException(STR."multiply not implemented for Array and \{rhs.typeName()}"); - } - } -} diff --git a/src/main/java/lv/enes/orang/value/PartialBuiltinFunction.java b/src/main/java/lv/enes/orang/value/PartialBuiltinFunction.java deleted file mode 100644 index 37278a4..0000000 --- a/src/main/java/lv/enes/orang/value/PartialBuiltinFunction.java +++ /dev/null @@ -1,32 +0,0 @@ -package lv.enes.orang.value; - -import lv.enes.orang.OrangRuntimeException; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -public record PartialBuiltinFunction(int argCount, List params, BuiltinFunction.Impl impl) implements Value { - @Override - public String typeName() { - return "BuiltinFunction"; - } - - @Override - public String stringify() { - return "#builtinFunction"; - } - - @Override - public Value call(Value param) throws OrangRuntimeException { - List newParams = new ArrayList<>(params); - newParams.add(param); - newParams = Collections.unmodifiableList(newParams); - - if (newParams.size() == argCount) { - return impl.apply(newParams); - } else { - return new PartialBuiltinFunction(argCount, newParams, impl); - } - } -} diff --git a/src/main/java/lv/enes/orang/value/PartialFunction.java b/src/main/java/lv/enes/orang/value/PartialFunction.java deleted file mode 100644 index 59e1466..0000000 --- a/src/main/java/lv/enes/orang/value/PartialFunction.java +++ /dev/null @@ -1,37 +0,0 @@ -package lv.enes.orang.value; - -import lv.enes.orang.OrangRuntimeException; -import lv.enes.orang.Scope; -import lv.enes.orang.ast.Expression; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; - -public record PartialFunction(Scope scope, List args, List params, Expression body) implements Value { - @Override - public String typeName() { - return "Function"; - } - - @Override - public String stringify() { - return "#function"; - } - - @Override - public Value call(Value param) throws OrangRuntimeException { - var newParams = new ArrayList<>(params); - newParams.add(param); - if (newParams.size() == args.size()) { - var newDefs = new HashMap(); - for (var i = 0; i < args.size(); i++) { - newDefs.put(args.get(i), newParams.get(i)); - } - return body.evaluateExpression(scope.withDefinitions(newDefs)); - } - - return new PartialFunction(scope, args, Collections.unmodifiableList(newParams), body); - } -} diff --git a/src/main/java/lv/enes/orang/value/Undefined.java b/src/main/java/lv/enes/orang/value/Undefined.java deleted file mode 100644 index a341ee8..0000000 --- a/src/main/java/lv/enes/orang/value/Undefined.java +++ /dev/null @@ -1,21 +0,0 @@ -package lv.enes.orang.value; - -import lombok.EqualsAndHashCode; - -@EqualsAndHashCode -public final class Undefined implements Value { - public static final Undefined INSTANCE = new Undefined(); - - private Undefined() { - } - - @Override - public String typeName() { - return "Undefined"; - } - - @Override - public String stringify() { - return "#undefined"; - } -} diff --git a/src/main/java/lv/enes/orang/value/Value.java b/src/main/java/lv/enes/orang/value/Value.java deleted file mode 100644 index fa8275c..0000000 --- a/src/main/java/lv/enes/orang/value/Value.java +++ /dev/null @@ -1,77 +0,0 @@ -package lv.enes.orang.value; - -import lv.enes.orang.OrangRuntimeException; - -public sealed interface Value - permits Array, BuiltinFunction, Function, OrangBoolean, OrangInteger, OrangString, PartialBuiltinFunction, - PartialFunction, Undefined { - String typeName(); - String stringify(); - - default String display() { - return stringify(); - } - - - default Value negate() throws OrangRuntimeException { - throw new OrangRuntimeException(STR."negate is not implemented for \{typeName()}"); - } - - default Value not() throws OrangRuntimeException { - throw new OrangRuntimeException(STR."not is not implemented for \{typeName()}"); - } - - default Value plus() throws OrangRuntimeException { - throw new OrangRuntimeException(STR."plus is not implemented for \{typeName()}"); - } - - - default Value add(Value rhs) throws OrangRuntimeException { - throw new OrangRuntimeException(STR."add is not implemented for \{typeName()} and \{rhs.typeName()}"); - } - - default Value call(Value rhs) throws OrangRuntimeException { - throw new OrangRuntimeException(STR."call is not implemented for \{typeName()} and \{rhs.typeName()}"); - } - - default Value divide(Value rhs) throws OrangRuntimeException { - throw new OrangRuntimeException(STR."divide is not implemented for \{typeName()} and \{rhs.typeName()}"); - } - - default Value multiply(Value rhs) throws OrangRuntimeException { - throw new OrangRuntimeException(STR."multiply is not implemented for \{typeName()} and \{rhs.typeName()}"); - } - - default Value or(Value rhs) throws OrangRuntimeException { - throw new OrangRuntimeException(STR."or is not implemented for \{typeName()} and \{rhs.typeName()}"); - } - - default Value subtract(Value rhs) throws OrangRuntimeException { - throw new OrangRuntimeException(STR."subtract is not implemented for \{typeName()} and \{rhs.typeName()}"); - } - - - default OrangBoolean greaterThan(Value rhs) throws OrangRuntimeException { - throw new OrangRuntimeException(STR."greater than is not implemented for \{typeName()} and \{rhs.typeName()}"); - } - - default OrangBoolean greaterThanOrEqual(Value rhs) throws OrangRuntimeException { - return greaterThan(rhs).or(orangEquals(rhs)); - } - - default OrangBoolean lessThan(Value rhs) throws OrangRuntimeException { - return greaterThanOrEqual(rhs).not(); - } - - default OrangBoolean lessThanOrEqual(Value rhs) throws OrangRuntimeException { - return greaterThan(rhs).not(); - } - - default OrangBoolean orangEquals(Value rhs) { - return OrangBoolean.of(this.equals(rhs)); - } - - default OrangBoolean notEquals(Value rhs) { - return orangEquals(rhs).not(); - } -} -- cgit v1.2.3