/** * With start token being the first non-ignorable token inside the declaration block, iterate * issuing CssDeclaration objects until the block ends. */ private void handleDeclarationBlock( CssToken start, CssTokenIterator iter, final CssContentHandler doc, CssErrorHandler err) throws CssException { while (true) { if (MATCH_CLOSEBRACE.apply(start)) { return; } CssDeclaration decl = handleDeclaration(start, iter, doc, err, false); try { if (decl != null) { doc.declaration(decl); if (debug) { checkState(MATCH_SEMI_CLOSEBRACE.apply(iter.last)); } // continue or return: we may be at "; next decl" or "}" or ";}" if (MATCH_CLOSEBRACE.apply(iter.last)) { return; } else if (MATCH_SEMI.apply(iter.last) && MATCH_CLOSEBRACE.apply(iter.peek())) { iter.next(); return; } else { if (debug) { checkState(MATCH_SEMI.apply(iter.last)); } // we have ';', expect another decl start = iter.next(); // first token after ';' } } else { // #handleDeclaration returned null to signal error // #handleDeclaration has issued errors, we forward start = iter.next(MATCH_SEMI_CLOSEBRACE); if (MATCH_SEMI.apply(start)) { start = iter.next(); } } } catch (NoSuchElementException nse) { err.error( new CssGrammarException( GRAMMAR_PREMATURE_EOF, iter.last.location, "';' " + Messages.get("or") + " '}'")); throw new PrematureEOFException(); } } }
/** * With iter.last at '{', discover the at-rule type. The contents is a ruleset if '{' comes before * ';' or '}'. */ private boolean hasRuleSet(CssAtRule atRule, CssTokenIterator iter) { int debugIndex; if (debug) { checkArgument(iter.last.getChar() == '{'); debugIndex = iter.index(); } List<CssToken> list = iter.list; for (int i = iter.index() + 1; i < list.size(); i++) { CssToken tk = list.get(i); if (MATCH_OPENBRACE.apply(tk)) { return true; } else if (MATCH_SEMI_CLOSEBRACE.apply(tk)) { return false; } } if (debug) { checkState(iter.last.getChar() == '{'); checkState(iter.index() == debugIndex); } return false; }
/** Parse a CSS document. */ public void parse( final Reader reader, final String systemID, final CssErrorHandler err, final CssContentHandler doc) throws IOException, CssException { CssTokenIterator iter = scan(reader, systemID, err); doc.startDocument(); while (iter.hasNext(FILTER_S_CMNT_CDO_CDC)) { CssToken tk = iter.next(FILTER_S_CMNT_CDO_CDC); try { if (tk.type == CssToken.Type.ATKEYWORD) { handleAtRule(tk, iter, doc, err); if (debug) { checkArgument(MATCH_SEMI_CLOSEBRACE.apply(iter.last)); } } else { handleRuleSet(tk, iter, doc, err); if (debug) { checkArgument(MATCH_CLOSEBRACE.apply(iter.last)); } } } catch (PrematureEOFException te) { // The subroutines report premature EOF to ErrHandler // on occurrence; if the listener rethrows it will // be a CssException so we don't catch it here. break; } } doc.endDocument(); }
/** * With start expected to be an IDENT token representing the property name, build the declaration * and return after hitting ';' or '}'. On error, issue to errhandler, return null, caller * forwards. */ private CssDeclaration handleDeclaration( CssToken name, CssTokenIterator iter, CssContentHandler doc, CssErrorHandler err, boolean isStyleAttribute) throws CssException { if (name.type != CssToken.Type.IDENT) { err.error( new CssGrammarException( GRAMMAR_EXPECTING_TOKEN, name.location, name.getChars(), Messages.get("a_property_name"))); return null; } CssDeclaration declaration = new CssDeclaration(name.getChars(), name.location); try { if (!MATCH_COLON.apply(iter.next())) { err.error( new CssGrammarException( GRAMMAR_EXPECTING_TOKEN, name.location, iter.last.getChars(), ":")); return null; } } catch (NoSuchElementException nse) { err.error(new CssGrammarException(GRAMMAR_PREMATURE_EOF, iter.last.location, ":")); throw new PrematureEOFException(); } try { while (true) { CssToken value = iter.next(); if (MATCH_SEMI_CLOSEBRACE.apply(value)) { if (declaration.components.size() < 1) { err.error( new CssGrammarException( GRAMMAR_EXPECTING_TOKEN, iter.last.location, value.getChar(), Messages.get("a_property_value"))); return null; } else { return declaration; } } else { if (!handlePropertyValue(declaration, value, iter, isStyleAttribute)) { err.error( new CssGrammarException( GRAMMAR_UNEXPECTED_TOKEN, iter.last.location, iter.last.getChars())); return null; } else { if (isStyleAttribute && !iter.hasNext()) { return declaration; } } } } } catch (NoSuchElementException nse) { err.error( new CssGrammarException( GRAMMAR_PREMATURE_EOF, iter.last.location, "';' " + Messages.get("or") + " '}'")); throw new PrematureEOFException(); } }