/** * Adds a parse error to the internal problem collector. * <p> * It is preferred to collect as much errors as possible and then fail with an exception instead of failing * at the first problem. Often syntax errors can be worked out by the parser and we can report a set of * errors at once. * * @param pos the position of the error. Note that {@link Token} implements {@link Position}. Therefore the * current token is often a good choice for this parameter. * @param message the message to describe the error. Can contain formatting parameters like %s or %d as defined * by {@link String#format(String, Object...)} * @param parameters Contains the parameters used to format the given message */ public void addError(Position pos, String message, Object... parameters) { getProblemCollector().add(ParseError.error(pos, String.format(message, parameters))); }
/** * Adds a parse error to the internal problem collector. * <p> * It is preferred to collect as much errors as possible and then fail with an exception instead of failing * at the first problem. Often syntax errors can be worked out by the parser and we can report a set of * errors at once. * * @param pos the position of the error. Note that {@link Token} implements {@link Position}. Therefore the * current token is often a good choice for this parameter. * @param message the message to describe the error. Can contain formatting parameters like %s or %d as defined * by {@link String#format(String, Object...)} * @param parameters Contains the parameters used to format the given message */ public void addError(Position pos, String message, Object... parameters) { getProblemCollector().add(ParseError.error(pos, String.format(message, parameters))); }
@Override protected Char fetch() { try { int character = input.read(); if (character == -1) { return null; } if (character == '\n') { line++; pos = 0; } pos++; return new Char((char) character, line, pos); } catch (IOException e) { problemCollector.add(ParseError.error(new Char('\0', line, pos), e.getMessage())); return null; } }
@Override protected Char fetch() { try { int character = input.read(); if (character == -1) { return null; } if (character == '\n') { line++; pos = 0; } pos++; return new Char((char) character, line, pos); } catch (IOException e) { problemCollector.add(ParseError.error(new Char('\0', line, pos), e.getMessage())); return null; } }
/** * Checks if we're looking at an end of block comment */ protected void skipBlockComment() { while (!input.current().isEndOfInput()) { if (isAtEndOfBlockComment()) { return; } input.consume(); } problemCollector.add(ParseError.error(input.current(), "Premature end of block comment")); }
/** * Checks if we're looking at an end of block comment */ protected void skipBlockComment() { while (!input.current().isEndOfInput()) { if (isAtEndOfBlockComment()) { return; } input.consume(); } problemCollector.add(ParseError.error(input.current(), "Premature end of block comment")); }
/** * 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; }
/** * 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))); } } }
Function fun = functionTable.get(funToken.getContents()); if (fun == null) { errors.add(ParseError.error(funToken, String.format("Unknown function: '%s'", funToken.getContents()))); errors.add(ParseError.error(funToken, String.format( "Number of arguments for function '%s' do not match. Expected: %d, Found: %d",
Function fun = functionTable.get(funToken.getContents()); if (fun == null) { errors.add(ParseError.error(funToken, String.format("Unknown function: '%s'", funToken.getContents()))); errors.add(ParseError.error(funToken, String.format( "Number of arguments for function '%s' do not match. Expected: %d, Found: %d",
/** * Reads and returns a string constant. * * @return the parsed string constant a Token */ protected Token fetchString() { char separator = input.current().getValue(); char escapeChar = stringDelimiters.get(input.current().getValue()); Token result = Token.create(Token.TokenType.STRING, input.current()); result.addToTrigger(input.consume()); while (!input.current().isNewLine() && !input.current().is(separator) && !input.current().isEndOfInput()) { if (escapeChar != '\0' && input.current().is(escapeChar)) { result.addToSource(input.consume()); if (!handleStringEscape(separator, escapeChar, result)) { problemCollector.add(ParseError.error(input.next(), String.format("Cannot use '%s' as escaped character", input.next().getStringValue()))); } } else { result.addToContent(input.consume()); } } if (input.current().is(separator)) { result.addToSource(input.consume()); } else { problemCollector.add(ParseError.error(input.current(), "Premature end of string constant")); } return result; }
/** * Reads and returns a string constant. * * @return the parsed string constant a Token */ protected Token fetchString() { char separator = input.current().getValue(); char escapeChar = stringDelimiters.get(input.current().getValue()); Token result = Token.create(Token.TokenType.STRING, input.current()); result.addToTrigger(input.consume()); while (!input.current().isNewLine() && !input.current().is(separator) && !input.current().isEndOfInput()) { if (escapeChar != '\0' && input.current().is(escapeChar)) { result.addToSource(input.consume()); if (!handleStringEscape(separator, escapeChar, result)) { problemCollector.add(ParseError.error(input.next(), String.format("Cannot use '%s' as escaped character", input.next().getStringValue()))); } } else { result.addToContent(input.consume()); } } if (input.current().is(separator)) { result.addToSource(input.consume()); } else { problemCollector.add(ParseError.error(input.current(), "Premature end of string constant")); } return result; }
problemCollector.add(ParseError.error(input.current(), String.format("Invalid character in input: '%s'", input.current().getStringValue())));
problemCollector.add(ParseError.error(input.current(), String.format("Invalid character in input: '%s'", input.current().getStringValue())));
/** * Reads and returns a number. * * @return the parsed number as Token */ protected Token fetchNumber() { Token result = Token.create(Token.TokenType.INTEGER, input.current()); result.addToContent(input.consume()); while (input.current().isDigit() || input.current().is(decimalSeparator) || (input.current() .is(groupingSeparator) && input.next().isDigit())) { if (input.current().is(groupingSeparator)) { result.addToSource(input.consume()); } else if (input.current().is(decimalSeparator)) { if (result.is(Token.TokenType.DECIMAL)) { problemCollector.add(ParseError.error(input.current(), "Unexpected decimal separators")); } else { Token decimalToken = Token.create(Token.TokenType.DECIMAL, result); decimalToken.setContent(result.getContents() + effectiveDecimalSeparator); decimalToken.setSource(result.getSource()); result = decimalToken; } result.addToSource(input.consume()); } else { result.addToContent(input.consume()); } } return result; }
/** * Reads and returns a number. * * @return the parsed number as Token */ protected Token fetchNumber() { Token result = Token.create(Token.TokenType.INTEGER, input.current()); result.addToContent(input.consume()); while (input.current().isDigit() || input.current().is(decimalSeparator) || (input.current() .is(groupingSeparator) && input.next().isDigit())) { if (input.current().is(groupingSeparator)) { result.addToSource(input.consume()); } else if (input.current().is(decimalSeparator)) { if (result.is(Token.TokenType.DECIMAL)) { problemCollector.add(ParseError.error(input.current(), "Unexpected decimal separators")); } else { Token decimalToken = Token.create(Token.TokenType.DECIMAL, result); decimalToken.setContent(result.getContents() + effectiveDecimalSeparator); decimalToken.setSource(result.getSource()); result = decimalToken; } result.addToSource(input.consume()); } else { result.addToContent(input.consume()); } } return result; }