private void parseOperatorInSelector(StringBuilder sb) { while (tokenizer.current().isSymbol(":") || tokenizer.current().isSymbol("::")) { sb.append(tokenizer.consume().getSource()); sb.append(tokenizer.consume().getSource()); // Consume arguments like :nth-child(2) if (tokenizer.current().isSymbol("(")) { consumeArgument(sb); } } }
private void readValue(StringBuilder sb) { if (!tokenizer.current().isSymbol("]")) { sb.append(tokenizer.consume().getSource()); } }
private void consumeArgument(StringBuilder sb) { sb.append(tokenizer.consume().getSource()); int braces = 1; while (!tokenizer.current().isEnd() && braces > 0) { if (tokenizer.current().isSymbol("(")) { braces++; } if (tokenizer.current().isSymbol(")")) { braces--; } sb.append(tokenizer.consume().getSource()); } }
private void readOperator(StringBuilder sb) { if (!tokenizer.current().isSymbol("]")) { if (!tokenizer.current().isSymbol("=", "~=", "|=", "^=", "$=", "*=")) { tokenizer.addError(tokenizer.current(), "Unexpected token: '%s'. Expected an operation.", tokenizer.current().getSource()); } sb.append(tokenizer.consume().getTrigger()); } }
/** * 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; }
private void consumeExpectedComma() { if (tokenizer.current().isSymbol(",")) { tokenizer.consumeExpectedSymbol(","); } else if (!tokenizer.current().isSymbol(")")) { tokenizer.addError(tokenizer.current(), "Unexpected token: '" + tokenizer.consume().getSource() + "'. Expected a comma between the parameters."); } }
/** * Reads and returns a symbol. * <p> * A symbol are one or two characters, which don't match any other token type. In most cases, this will be * operators like + or *. * * @return the parsed symbol as Token */ @SuppressWarnings("squid:S1067") protected Token fetchSymbol() { Token result = Token.create(Token.TokenType.SYMBOL, input.current()); result.addToTrigger(input.consume()); if (result.isSymbol("*") && input.current().is('*') || result.isSymbol("&") && input.current().is('&') || result.isSymbol("|") && input.current().is('|') || result.isSymbol() && input.current().is('=')) { result.addToTrigger(input.consume()); } return result; }
private Attribute parseAttribute() { Attribute attr = new Attribute(tokenizer.consume().getContents()); tokenizer.consumeExpectedSymbol(":"); attr.setExpression(parseExpression(true)); if (tokenizer.current().isSymbol(";") || !tokenizer.next().isSymbol("}")) { tokenizer.consumeExpectedSymbol(";"); } return attr; }
private void parseFilterInSelector(StringBuilder sb) { while (tokenizer.current().isSymbol("[")) { // Consume [ sb.append(tokenizer.consume().getContents()); readAttributeName(sb); readOperator(sb); readValue(sb); readClosingBracket(sb); } }
private void readClosingBracket(StringBuilder sb) { if (!tokenizer.current().isSymbol("]")) { tokenizer.addError(tokenizer.current(), "Unexpected token: '%s'. Expected: ']'", tokenizer.current().getSource()); } else { sb.append(tokenizer.consume().getContents()); } }
private void parseSectionSelector(boolean mediaQuery, Section result) { if (mediaQuery) { parseMediaQuerySelector(result); } else { // Parse selectors like "b div.test" while (tokenizer.more()) { List<String> selector = parseSelector(); result.getSelectors().add(selector); // If another selector is given, swallow the "," and parse the next selector, else we're done. if (!tokenizer.current().isSymbol(",")) { break; } else { tokenizer.consumeExpectedSymbol(","); } } } }
private void readAttributeName(StringBuilder sb) { if (!tokenizer.current().isSymbol("]")) { if (!tokenizer.current().isIdentifier()) { tokenizer.addError(tokenizer.current(), "Unexpected token: '%s'. Expected an attribute name.", tokenizer.current().getSource()); } sb.append(tokenizer.consume().getContents()); } }
private Expression parseExpression(boolean acceptLists) { Expression expression = acceptLists ? parseAtomList() : parseAtom(); while (tokenizer.more()) { if (tokenizer.current().isSymbol("+", "-")) { expression = new Operation(tokenizer.consume().getTrigger(), expression, parseAtom()); } else if (tokenizer.current().isSymbol("*", "/", "%")) { String operation = tokenizer.consume().getTrigger(); Expression next = parseAtom(); expression = joinOperations(expression, operation, next); } else { if (tokenizer.current().isSymbol() && !tokenizer.current().isSymbol("!")) { break; } ValueList list = new ValueList(false); list.add(expression); list.add(acceptLists ? parseAtomList() : parseAtom()); expression = list; } } return expression; }
private void parseExtend(Section result) { // Parse @extend instructions like "@extend .warning" tokenizer.consumeExpectedKeyword(KEYWORD_EXTEND); if (tokenizer.current().isIdentifier() || tokenizer.current().isSpecialIdentifier("#")) { result.addExtends(tokenizer.consume().getSource()); } else { tokenizer.addError(tokenizer.current(), "Unexpected token: '" + tokenizer.current().getSource() + "'. Expected a selector to include."); } if (tokenizer.current().isSymbol(";") || !tokenizer.next().isSymbol("}")) { tokenizer.consumeExpectedSymbol(";"); } }
private void parseMixinAttributes(Mixin mixin) { tokenizer.consumeExpectedSymbol("{"); while (tokenizer.more()) { if (tokenizer.current().isSymbol("}")) { tokenizer.consumeExpectedSymbol("}"); return; } if (isAtAttribute()) { Attribute attr = parseAttribute(); mixin.addAttribute(attr); } else { // If it isn't an attribute it is (hopefully) a subsection parseMixinSubSection(mixin); } } tokenizer.consumeExpectedSymbol("}"); }
private void parseMediaQuerySelector(Section result) { // Parse a media query like @media screen and (min-width: 1200px) tokenizer.consumeExpectedKeyword(KEYWORD_MEDIA); while (true) { if (tokenizer.current().isIdentifier()) { // Handle plain identifiers like "screen" or "print" result.addMediaQuery(new Value(tokenizer.consume().getContents())); } else if (tokenizer.current().isSymbol("(")) { parseMediaQueryFilters(result); } else { return; } // We only handle "and" as conjunction between two filters if (!tokenizer.current().isIdentifier("and")) { return; } else { tokenizer.consume(); } } }
private void parseVariableDeclaration() { Variable var = new Variable(); var.setName(tokenizer.consume().getContents()); tokenizer.consumeExpectedSymbol(":"); var.setValue(parseExpression(true)); if (tokenizer.current().isSymbol("!") && tokenizer.next().hasContent("default")) { var.setDefaultValue(true); tokenizer.consume(); tokenizer.consume(); } result.addVariable(var); tokenizer.consumeExpectedSymbol(";"); }
private void parseMediaQueryFilters(Section result) { // Handle filters like (orientation: landscape) tokenizer.consumeExpectedSymbol("("); if (tokenizer.current().isIdentifier() && tokenizer.next().isSymbol(":")) { parseMediaQueryFilter(result); while (tokenizer.next().hasContent("and")) { tokenizer.consumeExpectedSymbol(")"); tokenizer.consume(); tokenizer.consumeExpectedSymbol("("); parseMediaQueryFilter(result); } } else { tokenizer.addError(tokenizer.current(), "Unexpected symbol: '%s'. Expected an attribute filter.", tokenizer.current().getSource()); } tokenizer.consumeExpectedSymbol(")"); }