(feat) Parse array
diff --git a/src/main/java/com/googlecode/aviator/code/ConstantsCollector.java b/src/main/java/com/googlecode/aviator/code/ConstantsCollector.java new file mode 100644 index 0000000..916c2cd --- /dev/null +++ b/src/main/java/com/googlecode/aviator/code/ConstantsCollector.java
@@ -0,0 +1,263 @@ +package com.googlecode.aviator.code; + +import java.util.ArrayList; +import java.util.List; + +import com.googlecode.aviator.Expression; +import com.googlecode.aviator.LiteralExpression; +import com.googlecode.aviator.lexer.token.Token; + + +public class ConstantsCollector implements CodeGenerator { + + public List<Token<?>> getConstants() { + return constants; + } + + private List<Token<?>> constants = new ArrayList<Token<?>>(); + + + @Override + public void onShiftRight(Token<?> lookhead) { + throw new UnsupportedOperationException(); + } + + + @Override + public void onShiftLeft(Token<?> lookhead) { + throw new UnsupportedOperationException(); + } + + + @Override + public void onUnsignedShiftRight(Token<?> lookhead) { + throw new UnsupportedOperationException(); + + } + + + @Override + public void onBitOr(Token<?> lookhead) { + throw new UnsupportedOperationException(); + + } + + + @Override + public void onBitAnd(Token<?> lookhead) { + throw new UnsupportedOperationException(); + + } + + + @Override + public void onBitXor(Token<?> lookhead) { + throw new UnsupportedOperationException(); + + } + + + @Override + public void onBitNot(Token<?> lookhead) { + throw new UnsupportedOperationException(); + + } + + + @Override + public void onAdd(Token<?> lookhead) { + throw new UnsupportedOperationException(); + + } + + + @Override + public void onSub(Token<?> lookhead) { + throw new UnsupportedOperationException(); + + } + + + @Override + public void onMult(Token<?> lookhead) { + throw new UnsupportedOperationException(); + + } + + + @Override + public void onDiv(Token<?> lookhead) { + throw new UnsupportedOperationException(); + + } + + + @Override + public void onAndLeft(Token<?> lookhead) { + throw new UnsupportedOperationException(); + + } + + + @Override + public void onAndRight(Token<?> lookhead) { + throw new UnsupportedOperationException(); + + } + + + @Override + public void onTernaryBoolean(Token<?> lookhead) { + throw new UnsupportedOperationException(); + + } + + + @Override + public void onTernaryLeft(Token<?> lookhead) { + throw new UnsupportedOperationException(); + + } + + + @Override + public void onTernaryRight(Token<?> lookhead) { + throw new UnsupportedOperationException(); + + } + + + @Override + public void onJoinLeft(Token<?> lookhead) { + throw new UnsupportedOperationException(); + + } + + + @Override + public void onJoinRight(Token<?> lookhead) { + throw new UnsupportedOperationException(); + + } + + + @Override + public void onEq(Token<?> lookhead) { + throw new UnsupportedOperationException(); + + } + + + @Override + public void onMatch(Token<?> lookhead) { + throw new UnsupportedOperationException(); + + } + + + @Override + public void onNeq(Token<?> lookhead) { + throw new UnsupportedOperationException(); + + } + + + @Override + public void onLt(Token<?> lookhead) { + throw new UnsupportedOperationException(); + + } + + + @Override + public void onLe(Token<?> lookhead) { + throw new UnsupportedOperationException(); + + } + + + @Override + public void onGt(Token<?> lookhead) { + throw new UnsupportedOperationException(); + + } + + + @Override + public void onGe(Token<?> lookhead) { + throw new UnsupportedOperationException(); + + } + + + @Override + public void onMod(Token<?> lookhead) { + throw new UnsupportedOperationException(); + + } + + + @Override + public void onNot(Token<?> lookhead) { + throw new UnsupportedOperationException(); + + } + + + @Override + public void onNeg(Token<?> lookhead) { + throw new UnsupportedOperationException(); + + } + + + @Override + public Expression getResult() { + return new LiteralExpression(this.constants, null); + } + + + @Override + public void onConstant(Token<?> lookhead) { + this.constants.add(lookhead); + } + + + @Override + public void onMethodName(Token<?> lookhead) { + throw new UnsupportedOperationException(); + + } + + + @Override + public void onMethodParameter(Token<?> lookhead) { + throw new UnsupportedOperationException(); + + } + + + @Override + public void onMethodInvoke(Token<?> lookhead) { + throw new UnsupportedOperationException(); + + } + + + @Override + public void onArray(Token<?> lookhead) { + throw new UnsupportedOperationException(); + } + + + @Override + public void onArrayIndexStart(Token<?> token) { + throw new UnsupportedOperationException(); + } + + + @Override + public void onArrayIndexEnd(Token<?> lookhead) { + throw new UnsupportedOperationException(); + } +}
diff --git a/src/main/java/com/googlecode/aviator/lexer/token/ArrayToken.java b/src/main/java/com/googlecode/aviator/lexer/token/ArrayToken.java new file mode 100644 index 0000000..a32c18f --- /dev/null +++ b/src/main/java/com/googlecode/aviator/lexer/token/ArrayToken.java
@@ -0,0 +1,77 @@ +package com.googlecode.aviator.lexer.token; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + + +/** + * Array token, only created by parser. + * + * @author dennis + * + */ +public class ArrayToken implements Token<List<Object>> { + private List<Token<?>> values; + + private List<Object> result; + + private int index; + + + public ArrayToken(List<Token<?>> values, int index) { + super(); + this.values = values; + this.index = index; + } + + + @Override + public List<Object> getValue(Map<String, Object> env) { + if (result == null) { + result = new ArrayList<Object>(); + for (Token<?> t : this.values) { + result.add(t.getValue(env)); + } + } + return result; + } + + @Override + public com.googlecode.aviator.lexer.token.Token.TokenType getType() { + return TokenType.Array; + } + + + @Override + public String getLexeme() { + StringBuilder sb = new StringBuilder("["); + boolean wasFirst = true; + for (Object o : this.values) { + String literal = "nil"; + if (o != null) { + if (o instanceof String) { + literal = "\"" + o.toString() + "\""; + } + else { + literal = o.toString(); + } + } + if (wasFirst) { + sb.append(literal); + wasFirst = false; + } + else { + sb.append(", ").append(literal); + } + } + return sb.toString(); + } + + + @Override + public int getStartIndex() { + return this.index; + } + +}
diff --git a/src/main/java/com/googlecode/aviator/lexer/token/Token.java b/src/main/java/com/googlecode/aviator/lexer/token/Token.java index d4adfce..c47102f 100644 --- a/src/main/java/com/googlecode/aviator/lexer/token/Token.java +++ b/src/main/java/com/googlecode/aviator/lexer/token/Token.java
@@ -33,6 +33,7 @@ String, Variable, Number, + Array, Char, Operator, Pattern,
diff --git a/src/main/java/com/googlecode/aviator/parser/ExpressionParser.java b/src/main/java/com/googlecode/aviator/parser/ExpressionParser.java index 014d4e6..a68144a 100644 --- a/src/main/java/com/googlecode/aviator/parser/ExpressionParser.java +++ b/src/main/java/com/googlecode/aviator/parser/ExpressionParser.java
@@ -18,14 +18,20 @@ **/ package com.googlecode.aviator.parser; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; import java.util.HashSet; +import java.util.List; import java.util.Set; import com.googlecode.aviator.AviatorEvaluator; import com.googlecode.aviator.Expression; import com.googlecode.aviator.code.CodeGenerator; +import com.googlecode.aviator.code.ConstantsCollector; import com.googlecode.aviator.exception.ExpressionSyntaxErrorException; import com.googlecode.aviator.lexer.ExpressionLexer; +import com.googlecode.aviator.lexer.token.ArrayToken; import com.googlecode.aviator.lexer.token.CharToken; import com.googlecode.aviator.lexer.token.PatternToken; import com.googlecode.aviator.lexer.token.Token; @@ -55,7 +61,9 @@ private Token<?> prevToken; - private final CodeGenerator codeGenerator; + private CodeGenerator codeGenerator; + + private Deque<CodeGenerator> cgStack = new ArrayDeque<CodeGenerator>(); // Paren depth private int parenDepth = 0; @@ -470,6 +478,20 @@ } + public void array() { + while (true) { + this.factor(); + if (this.expectLexeme(",")) { + this.move(true); + continue; + } + else { + break; + } + } + } + + public void factor() { if (this.lookhead == null) { this.reportSyntaxError("invalid value"); @@ -486,6 +508,25 @@ } this.parenDepth--; } + else if (this.expectLexeme("[")) { + this.bracketDepth++; + int index = this.lookhead.getStartIndex(); + this.move(true); + this.cgStack.push(this.codeGenerator); + ConstantsCollector collector = new ConstantsCollector(); + this.codeGenerator = collector; + this.array(); + if (!expectLexeme("]")) { + this.reportSyntaxError("insert ']' to complete array."); + } + else { + this.move(true); + } + this.codeGenerator = this.cgStack.pop(); + this.prevToken = new ArrayToken(collector.getConstants(), index); + this.bracketDepth--; + this.codeGenerator.onConstant(this.prevToken); + } else if (this.lookhead.getType() == TokenType.Number || this.lookhead.getType() == TokenType.String || this.lookhead.getType() == TokenType.Variable || this.lookhead == Variable.TRUE || this.lookhead == Variable.FALSE || this.isOPVariable(this.lookhead)) { @@ -517,7 +558,7 @@ this.move(true); } this.codeGenerator.onArrayIndexStart(this.prevToken); - array(); + arrayIndex(); } if (!hasArray) this.codeGenerator.onConstant(this.prevToken); @@ -536,7 +577,7 @@ } - private void array() { + private void arrayIndex() { this.bracketDepth++; if (RESERVED_WORDS.contains(this.prevToken.getLexeme())) { throw new ExpressionSyntaxErrorException(this.prevToken.getLexeme() + " could not use [] operator");
diff --git a/src/test/java/com/googlecode/aviator/example/SimpleExample.java b/src/test/java/com/googlecode/aviator/example/SimpleExample.java index b174e56..3b5a48e 100644 --- a/src/test/java/com/googlecode/aviator/example/SimpleExample.java +++ b/src/test/java/com/googlecode/aviator/example/SimpleExample.java
@@ -5,7 +5,7 @@ public class SimpleExample { public static void main(String[] args) { - Long result = (Long) AviatorEvaluator.execute("1+2+3"); + Long result = (Long) AviatorEvaluator.execute("[1,2,3]"); System.out.println(result); } }