/** * Boilerplate method for {@code current().isEnd()} * * @return <tt>true</tt> if the current token is an "end of input" token, <tt>false</tt> otherwise. */ public boolean atEnd() { return current().isEnd(); }
/** * Boilerplate method for {@code current().isNotEnd()} * * @return <tt>true</tt> if the current token is not an "end of input" token, <tt>false</tt> otherwise. */ public boolean more() { return current().isNotEnd(); }
/** * Boilerplate method for {@code current().isEnd()} * * @return <tt>true</tt> if the current token is an "end of input" token, <tt>false</tt> otherwise. */ public boolean atEnd() { return current().isEnd(); }
/** * Boilerplate method for {@code current().isNotEnd()} * * @return <tt>true</tt> if the current token is not an "end of input" token, <tt>false</tt> otherwise. */ public boolean more() { return current().isNotEnd(); }
@Override public String toString() { // We check the internal buffer first to that no further parsing is triggered by calling toString() // as it is frequently invoked by the debugger which causes nasty side-effects otherwise if (itemBuffer.isEmpty()) { return "No Token fetched..."; } if (itemBuffer.size() < 2) { return "Current: " + current(); } return "Current: " + current().toString() + ", Next: " + next().toString(); }
/** * Consumes the current token, expecting it to be as <tt>SYMBOL</tt> with the given content * * @param symbol the expected trigger of the current token */ public void consumeExpectedSymbol(String symbol) { if (current().matches(Token.TokenType.SYMBOL, symbol)) { consume(); } else { addError(current(), "Unexpected token: '%s'. Expected: '%s'", current().getSource(), symbol); } }
/** * Consumes the current token, expecting it to be as <tt>KEYWORD</tt> with the given content * * @param keyword the expected content of the current token */ public void consumeExpectedKeyword(String keyword) { if (current().matches(Token.TokenType.KEYWORD, keyword)) { consume(); } else { addError(current(), "Unexpected token: '%s'. Expected: '%s'", current().getSource(), keyword); } }
@Override public String toString() { // We check the internal buffer first to that no further parsing is triggered by calling toString() // as it is frequently invoked by the debugger which causes nasty side-effects otherwise if (itemBuffer.isEmpty()) { return "No Token fetched..."; } if (itemBuffer.size() < 2) { return "Current: " + current(); } return "Current: " + current().toString() + ", Next: " + next().toString(); }
/** * Consumes the current token, expecting it to be as <tt>KEYWORD</tt> with the given content * * @param keyword the expected content of the current token */ public void consumeExpectedKeyword(String keyword) { if (current().matches(Token.TokenType.KEYWORD, keyword)) { consume(); } else { addError(current(), "Unexpected token: '%s'. Expected: '%s'", current().getSource(), keyword); } }
/** * Consumes the current token, expecting it to be as <tt>SYMBOL</tt> with the given content * * @param symbol the expected trigger of the current token */ public void consumeExpectedSymbol(String symbol) { if (current().matches(Token.TokenType.SYMBOL, symbol)) { consume(); } else { addError(current(), "Unexpected token: '%s'. Expected: '%s'", current().getSource(), symbol); } }
/** * Signals that the given token is expected. * <p> * If the current input is pointing at the specified token, it will be consumed. If not, an error will be added * to the error list and the input remains unchanged. * * @param type the type of the expected token * @param trigger the trigger of the expected token */ protected void expect(Token.TokenType type, String trigger) { if (tokenizer.current().matches(type, trigger)) { tokenizer.consume(); } else { errors.add(ParseError.error(tokenizer.current(), String.format("Unexpected token '%s'. Expected: '%s'", tokenizer.current().getSource(), trigger))); } } }
/** * Signals that the given token is expected. * <p> * If the current input is pointing at the specified token, it will be consumed. If not, an error will be added * to the error list and the input remains unchanged. * * @param type the type of the expected token * @param trigger the trigger of the expected token */ protected void expect(Token.TokenType type, String trigger) { if (tokenizer.current().matches(type, trigger)) { tokenizer.consume(); } else { errors.add(ParseError.error(tokenizer.current(), String.format("Unexpected token '%s'. Expected: '%s'", tokenizer.current().getSource(), trigger))); } } }
/** * Parser rule for parsing a power. * <p> * A power is an <tt>atom</tt> which might be followed by ^ or ** as operator and another <tt>power</tt>. * * @return a power parsed from the given input */ protected Expression power() { Expression left = atom(); if (tokenizer.current().isSymbol("^") || tokenizer.current().isSymbol("**")) { tokenizer.consume(); Expression right = power(); return reOrder(left, right, BinaryOperation.Op.POWER); } return left; }
/** * Parser rule for parsing a power. * <p> * A power is an <tt>atom</tt> which might be followed by ^ or ** as operator and another <tt>power</tt>. * * @return a power parsed from the given input */ protected Expression power() { Expression left = atom(); if (tokenizer.current().isSymbol("^") || tokenizer.current().isSymbol("**")) { tokenizer.consume(); Expression right = power(); return reOrder(left, right, BinaryOperation.Op.POWER); } return left; }
/** * Parses the expression in <tt>input</tt> * * @return the parsed expression * @throws ParseException if the expression contains one or more errors */ protected Expression parse() throws ParseException { Expression result = expression().simplify(); if (tokenizer.current().isNotEnd()) { Token token = tokenizer.consume(); errors.add(ParseError.error(token, String.format("Unexpected token: '%s'. Expected an expression.", token.getSource()))); } if (!errors.isEmpty()) { throw ParseException.create(errors); } return result; }
/** * Parses the expression in <tt>input</tt> * * @return the parsed expression * @throws ParseException if the expression contains one or more errors */ protected Expression parse() throws ParseException { Expression result = expression().simplify(); if (tokenizer.current().isNotEnd()) { Token token = tokenizer.consume(); errors.add(ParseError.error(token, String.format("Unexpected token: '%s'. Expected an expression.", token.getSource()))); } if (!errors.isEmpty()) { throw ParseException.create(errors); } return result; }
/** * Parser rule for parsing a term. * <p> * A term is a <tt>product</tt> which might be followed by + or - as operator and another <tt>term</tt>. * * @return a term parsed from the given input */ protected Expression term() { Expression left = product(); if (tokenizer.current().isSymbol("+")) { tokenizer.consume(); Expression right = term(); return reOrder(left, right, BinaryOperation.Op.ADD); } if (tokenizer.current().isSymbol("-")) { tokenizer.consume(); Expression right = term(); return reOrder(left, right, BinaryOperation.Op.SUBTRACT); } if (tokenizer.current().isNumber()) { if (tokenizer.current().getContents().startsWith("-")) { Expression right = term(); return reOrder(left, right, BinaryOperation.Op.ADD); } } return left; }
/** * Parser rule for parsing an expression. * <p> * This is the root rule. An expression is a <tt>relationalExpression</tt> which might be followed by a logical * operator (&& or ||) and another <tt>expression</tt>. * * @return an expression parsed from the given input */ protected Expression expression() { Expression left = relationalExpression(); if (tokenizer.current().isSymbol("&&")) { tokenizer.consume(); Expression right = expression(); return reOrder(left, right, BinaryOperation.Op.AND); } if (tokenizer.current().isSymbol("||")) { tokenizer.consume(); Expression right = expression(); return reOrder(left, right, BinaryOperation.Op.OR); } return left; }
/** * Parser rule for parsing an expression. * <p> * This is the root rule. An expression is a <tt>relationalExpression</tt> which might be followed by a logical * operator (&& or ||) and another <tt>expression</tt>. * * @return an expression parsed from the given input */ protected Expression expression() { Expression left = relationalExpression(); if (tokenizer.current().isSymbol("&&")) { tokenizer.consume(); Expression right = expression(); return reOrder(left, right, BinaryOperation.Op.AND); } if (tokenizer.current().isSymbol("||")) { tokenizer.consume(); Expression right = expression(); return reOrder(left, right, BinaryOperation.Op.OR); } return left; }
/** * Parser rule for parsing a product. * <p> * A product is a <tt>power</tt> which might be followed by *, / or % as operator and another <tt>product</tt>. * * @return a product parsed from the given input */ protected Expression product() { Expression left = power(); if (tokenizer.current().isSymbol("*")) { tokenizer.consume(); Expression right = product(); return reOrder(left, right, BinaryOperation.Op.MULTIPLY); } if (tokenizer.current().isSymbol("/")) { tokenizer.consume(); Expression right = product(); return reOrder(left, right, BinaryOperation.Op.DIVIDE); } if (tokenizer.current().isSymbol("%")) { tokenizer.consume(); Expression right = product(); return reOrder(left, right, BinaryOperation.Op.MODULO); } return left; }