@Override protected boolean isIdentifierChar(Char current) { if (super.isIdentifierChar(current)) { return true; } // CSS selectors can contain "-", "." or "#" as long as it is not the last character of the token return (current.is('-') || current.is('.') || current.is('#')) && !input.next().isWhitepace(); }
/** * Read everything upon (and including) the next line break */ protected void skipToEndOfLine() { while (!input.current().isEndOfInput() && !input.current().isNewLine()) { input.consume(); } }
/** * Determines if the underlying input is looking at a valid character to start an identifier * <p> * By default, only letters can start identifiers * * @return <tt>true</tt> if the underlying input is looking at a valid identifier starter, <tt>false</tt> otherwise */ protected boolean isAtStartOfIdentifier() { return input.current().isLetter(); }
@Override protected Token fetchNumber() { Token token = super.fetchNumber(); // If a number is immediately followed by % or a text like "px" - this belongs to the numeric token. if (input.current().is('%')) { token.addToContent(input.consume()); return token; } while (input.current().isLetter()) { token.addToContent(input.consume()); } return token; }
/** * Reads and returns a special id. * * @return the parsed special id as Token */ protected Token fetchSpecialId() { Token result = Token.create(Token.TokenType.SPECIAL_ID, input.current()); result.addToTrigger(input.consume()); while (isIdentifierChar(input.current())) { result.addToContent(input.consume()); } return handleKeywords(result); }
private boolean continueValue(boolean inQuotes) { if (reader.current().isEndOfInput()) { return false; } if (inQuotes) { return !reader.current().is('"'); } return !reader.current().is(')') && !reader.current().isWhitepace(); }
/** * 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")); }
protected void skipWhitespace(LookaheadReader reader) { while (reader.current().isWhitepace()) { reader.consume(); } }
@Override protected boolean isAtBracket(boolean inSymbol) { // Treat % as single symbol so that 10%; is not tokenized to // "10", "%;" but to "10", "%", ";" // The title of this method might be a bit misleading return super.isAtBracket(inSymbol) || input.current().is('%'); }
/** * 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); } }
/** * Adds the given Char to the content (and the source) but not to the trigger * * @param ch the character to add to the content and source * @return <tt>this</tt> to support fluent method calls */ public Token addToContent(Char ch) { return addToContent(ch.getValue()); }
@Override public void setProblemCollector(List<ParseError> problemCollector) { super.setProblemCollector(problemCollector); this.input.setProblemCollector(problemCollector); }
/** * Reads and returns a special id. * * @return the parsed special id as Token */ protected Token fetchSpecialId() { Token result = Token.create(Token.TokenType.SPECIAL_ID, input.current()); result.addToTrigger(input.consume()); while (isIdentifierChar(input.current())) { result.addToContent(input.consume()); } return handleKeywords(result); }
/** * Read everything upon (and including) the next line break */ protected void skipToEndOfLine() { while (!input.current().isEndOfInput() && !input.current().isNewLine()) { input.consume(); } }
/** * 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>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); } }