/** * Determines if the given Char is a symbol character. * <p> * By default these are all non-control characters, which don't match any other class (letter, digit, whitepsace) * * @param ch the character to check * @return <tt>true</tt> if the given character is a valid symbol character, <tt>false</tt> otherwise */ @SuppressWarnings("squid:S1067") protected boolean isSymbolCharacter(Char ch) { if (ch.isEndOfInput() || ch.isDigit() || ch.isLetter() || ch.isWhitepace()) { return false; } char c = ch.getValue(); if (Character.isISOControl(c)) { return false; } return !(isAtBracket(true) || isAtStartOfBlockComment(false) || isAtStartOfLineComment(false) || isAtStartOfNumber() || isAtStartOfIdentifier() || stringDelimiters.containsKey(ch.getValue())); }
/** * Creates a new token with the given type, using the Char a initial trigger and content. * * @param type the type if this token. The supplied Char will be used as initial part of the trigger to further * specify the token * @param ch first character of the content and trigger of this token. Also specifies the position of the token. * @return a new token which is initialized with the given Char */ public static Token createAndFill(TokenType type, Char ch) { Token result = new Token(); result.type = type; result.line = ch.getLine(); result.pos = ch.getPos(); result.contents = ch.getStringValue(); result.trigger = ch.getStringValue(); result.source = ch.toString(); return result; }
/** * Determines if the given Char is a valid identifier part. * <p> * By default, letters, digits and '_' are valid identifier parts. * * @param current the character to check * @return <tt>true</tt> if the given Char is a valid identifier part, <tt>false</tt> otherwise */ protected boolean isIdentifierChar(Char current) { return current.isDigit() || current.isLetter() || current.is('_'); }
@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(); }
private C parseOR() { List<C> constraints = new ArrayList<>(); while (!reader.current().isEndOfInput() && !reader.current().is(')')) { C inner = parseAND(); if (inner != null) { constraints.add(inner); } if (!isAtOR(reader)) { break; } else { reader.consume(2); } } if (constraints.isEmpty()) { return null; } else { return factory.or(constraints); } }
private boolean continueValue(boolean inQuotes) { if (reader.current().isEndOfInput()) { return false; } if (inQuotes) { return !reader.current().is('"'); } return !reader.current().is(')') && !reader.current().isWhitepace(); }
/** * 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; }
@Override protected Token fetch() { while (input.current().isWhitepace()) { input.consume(); if (input.current().isEndOfInput()) { return null; if (stringDelimiters.containsKey(input.current().getValue())) { return fetchString(); input.current().getStringValue()))); input.consume(); return fetch();
/** * Determines if the underlying input is looking at the start of a number. * <p> * By default this is either indicated by a digit or by '-' followed by a digit or a '.' followed by a digit. * * @return <tt>true</tt> if the current input is the start of a numeric constant, <tt>false</tt> otherwise */ @SuppressWarnings("squid:S1067") protected boolean isAtStartOfNumber() { return input.current().isDigit() || input.current().is('-') && input.next().isDigit() || input.current().is('-') && input.next().is('.') && input.next(2).isDigit() || input.current().is('.') && input.next().isDigit(); }
/** * Determines if the value is a whitespace character like a blank, tab or line break * * @return <tt>true</tt> if the internal value is a whitespace character, <tt>false</tt> otherwise */ public boolean isWhitepace() { return Character.isWhitespace(value) && !isEndOfInput(); }
/** * Reads and returns an identifier * * @return the parsed identifier as Token */ protected Token fetchId() { Token result = Token.create(Token.TokenType.ID, input.current()); result.addToContent(input.consume()); while (isIdentifierChar(input.current())) { result.addToContent(input.consume()); } if (!input.current().isEndOfInput() && specialIdTerminators.contains(input.current().getValue())) { Token specialId = Token.create(Token.TokenType.SPECIAL_ID, result); specialId.setTrigger(input.current().getStringValue()); specialId.setContent(result.getContents()); specialId.setSource(result.getContents()); specialId.addToSource(input.current()); input.consume(); return handleKeywords(specialId); } return handleKeywords(result); }
private String readOp() { if (isNotEqual()) { reader.consume(2); return "<>"; } if (reader.current().is('<') && reader.next().is('=')) { reader.consume(2); return "<="; } if (reader.current().is('>') && reader.next().is('=')) { reader.consume(2); return ">="; } if (reader.current().is('=') || reader.current().is(':')) { reader.consume(); return "="; } if (reader.current().is('>')) { reader.consume(); return ">"; } if (reader.current().is('<')) { reader.consume(); return "<"; } else { throw new IllegalStateException(reader.current().toString()); } }
/** * Adds the given Char to the source of this token, but neither to the trigger nor to the content. * * @param ch the character to add to the source * @return <tt>this</tt> to support fluent method calls */ public Token addToSource(Char ch) { source += ch.getValue(); return this; }
/** * Read everything upon (and including) the next line break */ protected void skipToEndOfLine() { while (!input.current().isEndOfInput() && !input.current().isNewLine()) { input.consume(); } }
protected void skipWhitespace(LookaheadReader reader) { while (reader.current().isWhitepace()) { reader.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(); }
private FieldValue parseValue() { skipWhitespace(reader); if (reader.current().is('"')) { reader.consume(); StringBuilder result = new StringBuilder(); while (!reader.current().isEndOfInput() && !reader.current().is('"')) { if (reader.current().is('\\')) { reader.consume(); } result.append(reader.consume()); } reader.consume(); return new FieldValue(result.toString(), true); } else { return new FieldValue(readValue().getValue(), false); } }
private boolean continueToken(boolean inQuotes) { if (reader.current().isEndOfInput()) { return false; } if (inQuotes) { return !reader.current().is('"'); } return !reader.current().is(')', ':') && !reader.current().isWhitepace() && !isAtOperator(); }