package com.javadude.annotation.processors.template; public class ConditionParser { private enum TokenType {NOT, LEFT_PAREN, RIGHT_PAREN, AND, OR, VARIABLE, EOF}; private static final String DELIMITERS = "!()&|"; private int parsePosition; private int parseLine; private String parseExpression; private Token lookahead; private static class Token { private TokenType type; private String text; public Token(TokenType type, String text) { this.type = type; this.text = text; } public TokenType getType() { return type; } public String getText() { return text; } } // condition = term (& term)* // term (| term)* // term = !term // (condition) // variableName public Condition parse(String expression, int line) { // System.out.println("parsing condition:" + expression + ':'); parsePosition = 0; parseExpression = expression; parseLine = line; lookahead = null; return condition(); } private void unexpected(String expected) { throw new ExpressionException("Expected " + expected + "; found '" + la().getText() + "' in expression '" + parseExpression + "' on line " + parseLine); } private Condition condition() { if (la().getType() == TokenType.EOF) { throw new ExpressionException("Missing expression on line " + parseLine); } Condition condition = term(); loop: while (true) { switch(la().getType()) { case EOF: case RIGHT_PAREN: break loop; case AND: match(TokenType.AND, "&"); condition = new And(condition, term()); break; case OR: match(TokenType.OR, "|"); condition = new Or(condition, term()); break; default: unexpected("'&', '|' or end-of-expression"); } } return condition; } private Condition term() { Condition condition = null; switch (la().getType()) { case NOT: match(TokenType.NOT, "!"); condition = new Not(term()); break; case LEFT_PAREN: match(TokenType.LEFT_PAREN, "("); condition = condition(); match(TokenType.RIGHT_PAREN, ")"); break; case VARIABLE: condition = new VariableTest(la().getText()); match(TokenType.VARIABLE, "<variable name>"); break; default: unexpected("'!', '(' or variable"); } return condition; } private Token la() { if (lookahead == null) lookahead = nextToken(); return lookahead; } private void match(TokenType type, String text) { if (la().getType() == TokenType.EOF) throw new ExpressionException("End-of-expression found when expecting '" + text + "' in expression '" + parseExpression + "' on line " + parseLine); if (la().getType() != type) unexpected(text); lookahead = null; } private Token nextToken() { int len = parseExpression.length(); while (parsePosition < len && Character.isWhitespace(parseExpression.charAt(parsePosition))) parsePosition++; if (parsePosition >= len) return new Token(TokenType.EOF, null); char c = parseExpression.charAt(parsePosition); int i = ConditionParser.DELIMITERS.indexOf(c); if (i != -1) { parsePosition++; return new Token(TokenType.values()[i], "" + c); } int start = parsePosition; while (parsePosition < len && Character.isLetter(parseExpression.charAt(parsePosition))) { parsePosition++; } return new Token(TokenType.VARIABLE, parseExpression.substring(start, parsePosition)); } }