blob: e06872359055805ada29b7b1280420955d7c2e9f [file] [log] [blame]
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.royale.compiler.internal.css;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.antlr.runtime.CharStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.TokenStream;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.CommonTreeNodeStream;
import org.apache.royale.compiler.css.ICSSDocument;
import org.apache.royale.compiler.css.ICSSFontFace;
import org.apache.royale.compiler.css.ICSSNamespaceDefinition;
import org.apache.royale.compiler.css.ICSSRule;
import org.apache.royale.compiler.internal.css.CSSLexer;
import org.apache.royale.compiler.internal.css.CSSParser;
import org.apache.royale.compiler.internal.css.CSSTree;
import org.apache.royale.compiler.problems.ICompilerProblem;
import org.apache.royale.compiler.problems.UnexpectedExceptionProblem;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
/**
* Implementation of a CSS model.
*/
public class CSSDocument extends CSSNodeBase implements ICSSDocument
{
/** The short name for the default namespace is an empty string. */
private static final String DEFAULT_NAMESPACE_SHORT_NAME = "";
/**
* Parse a CSS document into {@link ICSSDocument} model.
*
* @param input ANTLR input stream. The {@code CharStream#getSourceName()}
* must be implemented in order to make source location work.
* @param problems Parsing problems will be aggregated in this collection.
* @return CSS DOM object.
*/
public static CSSDocument parse(final CharStream input, final Collection<ICompilerProblem> problems)
{
assert input != null : "CSS input can't be null";
assert problems != null : "Problem collection can't be null";
try
{
// parse and build tree
final CSSLexer lexer = new CSSLexer(input);
final CommonTokenStream tokens = new CommonTokenStream(lexer);
final CSSParser parser = new CSSParser(tokens);
final CSSParser.stylesheet_return stylesheet = parser.stylesheet();
final CommonTree ast = (CommonTree)stylesheet.getTree();
final CommonTreeNodeStream nodes = new CommonTreeNodeStream(ast);
nodes.setTokenStream(tokens);
// walk the tree and build definitions
final CSSTree treeWalker = new CSSTree(nodes);
treeWalker.stylesheet();
problems.addAll(lexer.problems);
problems.addAll(parser.problems);
problems.addAll(treeWalker.problems);
// definition models
return treeWalker.model;
}
catch (RecognitionException e)
{
assert false : "RecognitionException must be collected as ICompilerProblem.";
problems.add(new UnexpectedExceptionProblem(e));
return null;
}
}
/**
* Create a root CSS definition.
*
* @param rules CSS rules
* @param namespaces {@code @namespace} statements
* @param fontFaces {@code @font-face} statements
* @param tree root of the AST
*/
protected CSSDocument(final List<CSSRule> rules,
final List<CSSNamespaceDefinition> namespaces,
final List<CSSFontFace> fontFaces,
final CommonTree tree,
final TokenStream tokenStream)
{
super(tree, tokenStream, CSSModelTreeType.DOCUMENT);
assert rules != null : "Rules can't be null.";
assert namespaces != null : "Namespace definitions can't be null";
assert fontFaces != null : "Font face definitions can't be null";
this.rules = new ImmutableList.Builder<ICSSRule>().addAll(rules).build();
this.namespaces = new ImmutableList.Builder<ICSSNamespaceDefinition>().addAll(namespaces).build();
this.fontFaces = new ImmutableList.Builder<ICSSFontFace>().addAll(fontFaces).build();
Map<String, CSSNamespaceDefinition> namespaceMap = new HashMap<String, CSSNamespaceDefinition>();
for (CSSNamespaceDefinition namespace : namespaces)
{
final String prefix = namespace.getPrefix();
final String key = prefix != null ? prefix : DEFAULT_NAMESPACE_SHORT_NAME;
namespaceMap.put(key, namespace);
}
this.namespacesLookup = ImmutableMap.copyOf(namespaceMap);
// setup tree
children.add(new CSSTypedNode(CSSModelTreeType.NAMESPACE_LIST, this.namespaces));
children.add(new CSSTypedNode(CSSModelTreeType.FONT_FACE_LIST, this.fontFaces));
children.add(new CSSTypedNode(CSSModelTreeType.RULE_LIST, this.rules));
}
private final ImmutableList<ICSSRule> rules;
private final ImmutableList<ICSSNamespaceDefinition> namespaces;
private final ImmutableList<ICSSFontFace> fontFaces;
private final ImmutableMap<String, CSSNamespaceDefinition> namespacesLookup;
@Override
public ImmutableList<ICSSRule> getRules()
{
return rules;
}
@Override
public ImmutableList<ICSSNamespaceDefinition> getAtNamespaces()
{
return namespaces;
}
@Override
public String toString()
{
return Joiner.on("\n").join(
Joiner.on("\n").join(namespaces),
Joiner.on("\n").join(fontFaces),
Joiner.on("\n").join(rules));
}
@Override
public ImmutableList<ICSSFontFace> getFontFaces()
{
return fontFaces;
}
@Override
public ICSSNamespaceDefinition getNamespaceDefinition(String prefix)
{
return namespacesLookup.get(prefix);
}
@Override
public ICSSNamespaceDefinition getDefaultNamespaceDefinition()
{
return namespacesLookup.get(DEFAULT_NAMESPACE_SHORT_NAME);
}
}