summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Uko Kokņevičs2024-08-24 04:18:28 +0800
committerGravatar Uko Kokņevičs2024-08-24 04:18:28 +0800
commite897791330f0b36d61cd85ab5a1015d6194a35de (patch)
tree8faa8ea7f4c9bcadbccc5af9e6f19ab0b2b1621c
parentAdded fancier tuple argument specs. (diff)
downloadorang-e897791330f0b36d61cd85ab5a1015d6194a35de.tar.gz
orang-e897791330f0b36d61cd85ab5a1015d6194a35de.tar.xz
orang-e897791330f0b36d61cd85ab5a1015d6194a35de.zip
Added array access.
-rw-r--r--ast/src/main/java/lv/enes/orang/ast/ArrayAccessExpression.java10
-rw-r--r--ast/src/main/java/lv/enes/orang/ast/ExpressionVisitor.java1
-rw-r--r--checker/src/main/java/lv/enes/orang/checker/Checker.java7
-rw-r--r--evaluator/src/main/java/lv/enes/orang/evaluator/Array.java12
-rw-r--r--evaluator/src/main/java/lv/enes/orang/evaluator/Evaluator.java7
-rw-r--r--evaluator/src/main/java/lv/enes/orang/evaluator/Value.java5
-rw-r--r--grammar.bnf4
-rw-r--r--lexer/src/main/java/lv/enes/orang/lexer/Lexer.java8
-rw-r--r--lexer/src/main/java/lv/enes/orang/lexer/Token.java2
-rw-r--r--parser/src/main/java/lv/enes/orang/parser/Parser.java14
10 files changed, 67 insertions, 3 deletions
diff --git a/ast/src/main/java/lv/enes/orang/ast/ArrayAccessExpression.java b/ast/src/main/java/lv/enes/orang/ast/ArrayAccessExpression.java
new file mode 100644
index 0000000..784146c
--- /dev/null
+++ b/ast/src/main/java/lv/enes/orang/ast/ArrayAccessExpression.java
@@ -0,0 +1,10 @@
1package lv.enes.orang.ast;
2
3import lv.enes.orang.core.OrangException;
4
5public record ArrayAccessExpression(Expression array, Expression index) implements Expression {
6 @Override
7 public <R, E extends OrangException> R accept(ExpressionVisitor<R, E> visitor) throws E {
8 return visitor.visitArrayAccess(this);
9 }
10}
diff --git a/ast/src/main/java/lv/enes/orang/ast/ExpressionVisitor.java b/ast/src/main/java/lv/enes/orang/ast/ExpressionVisitor.java
index 226b340..60ec3c2 100644
--- a/ast/src/main/java/lv/enes/orang/ast/ExpressionVisitor.java
+++ b/ast/src/main/java/lv/enes/orang/ast/ExpressionVisitor.java
@@ -8,6 +8,7 @@ public interface ExpressionVisitor<R, E extends OrangException> {
8 } 8 }
9 9
10 R visitArray(ArrayExpression array) throws E; 10 R visitArray(ArrayExpression array) throws E;
11 R visitArrayAccess(ArrayAccessExpression arrayAccess) throws E;
11 R visitBoolean(BooleanLiteral expr) throws E; 12 R visitBoolean(BooleanLiteral expr) throws E;
12 R visitBinaryExpression(BinaryExpression expr) throws E; 13 R visitBinaryExpression(BinaryExpression expr) throws E;
13 R visitCallExpression(CallExpression expr) throws E; 14 R visitCallExpression(CallExpression expr) throws E;
diff --git a/checker/src/main/java/lv/enes/orang/checker/Checker.java b/checker/src/main/java/lv/enes/orang/checker/Checker.java
index f926f59..1c7303e 100644
--- a/checker/src/main/java/lv/enes/orang/checker/Checker.java
+++ b/checker/src/main/java/lv/enes/orang/checker/Checker.java
@@ -24,6 +24,13 @@ public class Checker implements ExpressionVisitor<Void, CheckerException>, State
24 } 24 }
25 25
26 @Override 26 @Override
27 public Void visitArrayAccess(ArrayAccessExpression arrayAccess) throws CheckerException {
28 visit(arrayAccess.array());
29 visit(arrayAccess.index());
30 return null;
31 }
32
33 @Override
27 public Void visitBoolean(BooleanLiteral expr) { 34 public Void visitBoolean(BooleanLiteral expr) {
28 // Always ok 35 // Always ok
29 return null; 36 return null;
diff --git a/evaluator/src/main/java/lv/enes/orang/evaluator/Array.java b/evaluator/src/main/java/lv/enes/orang/evaluator/Array.java
index 4c76eff..ab0d896 100644
--- a/evaluator/src/main/java/lv/enes/orang/evaluator/Array.java
+++ b/evaluator/src/main/java/lv/enes/orang/evaluator/Array.java
@@ -51,6 +51,18 @@ public record Array(List<Value> items) implements Value {
51 } 51 }
52 52
53 @Override 53 @Override
54 public Value arrayAccess(Value idx) throws OrangRuntimeException {
55 if (idx instanceof OrangInteger(var i)) {
56 if (i < 0 || i >= items.size()) {
57 throw new OrangRuntimeException(STR."Index out of bounds: \{i} not in [0;\{items.size()})");
58 }
59 return items.get(i);
60 } else {
61 throw new OrangRuntimeException(STR."array access not implemented for Array and \{idx.typeName()}");
62 }
63 }
64
65 @Override
54 public Value multiply(Value rhs) throws OrangRuntimeException { 66 public Value multiply(Value rhs) throws OrangRuntimeException {
55 if (rhs instanceof OrangInteger(var repeat)) { 67 if (rhs instanceof OrangInteger(var repeat)) {
56 var newItems = new ArrayList<Value>(items.size() * repeat); 68 var newItems = new ArrayList<Value>(items.size() * repeat);
diff --git a/evaluator/src/main/java/lv/enes/orang/evaluator/Evaluator.java b/evaluator/src/main/java/lv/enes/orang/evaluator/Evaluator.java
index 1f51b9d..69c03e8 100644
--- a/evaluator/src/main/java/lv/enes/orang/evaluator/Evaluator.java
+++ b/evaluator/src/main/java/lv/enes/orang/evaluator/Evaluator.java
@@ -24,6 +24,13 @@ public record Evaluator(Map<String, Value> scope, Value lastResult) implements E
24 } 24 }
25 25
26 @Override 26 @Override
27 public Value visitArrayAccess(ArrayAccessExpression arrayAccess) throws OrangRuntimeException {
28 var array = visit(arrayAccess.array());
29 var index = visit(arrayAccess.index());
30 return array.arrayAccess(index);
31 }
32
33 @Override
27 public Value visitBinaryExpression(BinaryExpression expr) throws OrangRuntimeException { 34 public Value visitBinaryExpression(BinaryExpression expr) throws OrangRuntimeException {
28 var lhs = visit(expr.lhs()); 35 var lhs = visit(expr.lhs());
29 var rhs = visit(expr.rhs()); 36 var rhs = visit(expr.rhs());
diff --git a/evaluator/src/main/java/lv/enes/orang/evaluator/Value.java b/evaluator/src/main/java/lv/enes/orang/evaluator/Value.java
index 1a1aad6..35af35b 100644
--- a/evaluator/src/main/java/lv/enes/orang/evaluator/Value.java
+++ b/evaluator/src/main/java/lv/enes/orang/evaluator/Value.java
@@ -13,6 +13,11 @@ public sealed interface Value
13 } 13 }
14 14
15 15
16 default Value arrayAccess(Value idx) throws OrangRuntimeException {
17 throw new OrangRuntimeException(STR."array access is not implemented for \{typeName()}");
18 }
19
20
16 default Value negate() throws OrangRuntimeException { 21 default Value negate() throws OrangRuntimeException {
17 throw new OrangRuntimeException(STR."negate is not implemented for \{typeName()}"); 22 throw new OrangRuntimeException(STR."negate is not implemented for \{typeName()}");
18 } 23 }
diff --git a/grammar.bnf b/grammar.bnf
index 30b48f6..3dcb1c6 100644
--- a/grammar.bnf
+++ b/grammar.bnf
@@ -10,9 +10,11 @@ arg-spec-tuple ::= '(' ')' | '(' arg-spec ',' arg-spec (',' arg-spec)* ','? ')';
10expression ::= binary-expression | unary-expression; 10expression ::= binary-expression | unary-expression;
11unary-expression ::= unop+ simple-expression; 11unary-expression ::= unop+ simple-expression;
12binary-expression ::= call-expression (binop call-expression)*; 12binary-expression ::= call-expression (binop call-expression)*;
13call-expression ::= simple-expression+; 13call-expression ::= member-access-expression+;
14binop ::= '*' | '/' | '+' | '-' | '?=' | '/=' | '>' | '>=' | '<' | '<='; 14binop ::= '*' | '/' | '+' | '-' | '?=' | '/=' | '>' | '>=' | '<' | '<=';
15unop ::= '+' | '-' | '!'; 15unop ::= '+' | '-' | '!';
16member-access-expression ::= simple-expression (member-access)*;
17member-access ::= '.[' expression ']';
16simple-expression ::= '(' expression ')' 18simple-expression ::= '(' expression ')'
17 | 'true' | 'false' 19 | 'true' | 'false'
18 | INTEGER 20 | INTEGER
diff --git a/lexer/src/main/java/lv/enes/orang/lexer/Lexer.java b/lexer/src/main/java/lv/enes/orang/lexer/Lexer.java
index ac336f4..5cea0a3 100644
--- a/lexer/src/main/java/lv/enes/orang/lexer/Lexer.java
+++ b/lexer/src/main/java/lv/enes/orang/lexer/Lexer.java
@@ -95,6 +95,14 @@ public class Lexer implements Iterator<Token> {
95 } 95 }
96 case '(' -> new Token(Token.Type.PAREN_LEFT, input.next()); 96 case '(' -> new Token(Token.Type.PAREN_LEFT, input.next());
97 case ')' -> new Token(Token.Type.PAREN_RIGHT, input.next()); 97 case ')' -> new Token(Token.Type.PAREN_RIGHT, input.next());
98 case '.' -> {
99 var first = input.next();
100 if (input.peek().cp() == '[') {
101 yield new Token(Token.Type.PERIOD_BRACKET_LEFT, first, input.next());
102 } else {
103 yield new Token(Token.Type.PERIOD, first);
104 }
105 }
98 case '+' -> new Token(Token.Type.PLUS, input.next()); 106 case '+' -> new Token(Token.Type.PLUS, input.next());
99 case '?' -> { 107 case '?' -> {
100 var first = input.next(); 108 var first = input.next();
diff --git a/lexer/src/main/java/lv/enes/orang/lexer/Token.java b/lexer/src/main/java/lv/enes/orang/lexer/Token.java
index 13236dd..65e0f1d 100644
--- a/lexer/src/main/java/lv/enes/orang/lexer/Token.java
+++ b/lexer/src/main/java/lv/enes/orang/lexer/Token.java
@@ -54,6 +54,8 @@ public record Token(Type type, String literal) {
54 MINUS_GREATER, 54 MINUS_GREATER,
55 PAREN_LEFT, 55 PAREN_LEFT,
56 PAREN_RIGHT, 56 PAREN_RIGHT,
57 PERIOD,
58 PERIOD_BRACKET_LEFT,
57 PLUS, 59 PLUS,
58 QUESTION_EQUAL, 60 QUESTION_EQUAL,
59 SEMICOLON, 61 SEMICOLON,
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 06183a3..3d1d42b 100644
--- a/parser/src/main/java/lv/enes/orang/parser/Parser.java
+++ b/parser/src/main/java/lv/enes/orang/parser/Parser.java
@@ -205,9 +205,9 @@ public class Parser {
205 } 205 }
206 206
207 private Expression parseCallExpression() throws ParserException { 207 private Expression parseCallExpression() throws ParserException {
208 var callee = parseSimpleExpression(); 208 var callee = parseMemberAccessExpression();
209 while (couldStartSimpleExpression(input.peek().type())) { 209 while (couldStartSimpleExpression(input.peek().type())) {
210 var arg = parseSimpleExpression(); 210 var arg = parseMemberAccessExpression();
211 callee = new CallExpression(callee, arg); 211 callee = new CallExpression(callee, arg);
212 } 212 }
213 return callee; 213 return callee;
@@ -298,6 +298,16 @@ public class Parser {
298 return new LetInExpression(Collections.unmodifiableList(bindings), body); 298 return new LetInExpression(Collections.unmodifiableList(bindings), body);
299 } 299 }
300 300
301 private Expression parseMemberAccessExpression() throws ParserException {
302 var expr = parseSimpleExpression();
303 while (maybeConsumeToken(Token.Type.PERIOD_BRACKET_LEFT)) {
304 var idx = parseExpression();
305 consumeToken(Token.Type.BRACKET_RIGHT);
306 expr = new ArrayAccessExpression(expr, idx);
307 }
308 return expr;
309 }
310
301 private Statement parseReplLine() throws ParserException { 311 private Statement parseReplLine() throws ParserException {
302 if (input.peek().type() == Token.Type.DEF) { 312 if (input.peek().type() == Token.Type.DEF) {
303 return parseStatement(); 313 return parseStatement();