All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gxp.compiler.ifexpand..svn.text-base.IfExpander.svn-base Maven / Gradle / Ivy

Go to download

Google XML Pages (GXP) is a templating system used to generate XML/SGML markup (most often HTML).

The newest version!
/*
 * Copyright (C) 2008 Google Inc.
 *
 * Licensed 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 com.google.gxp.compiler.ifexpand;

import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.gxp.compiler.alerts.AlertSetBuilder;
import com.google.gxp.compiler.alerts.AlertSink;
import com.google.gxp.compiler.alerts.common.BadNodePlacementError;
import com.google.gxp.compiler.base.Expression;
import com.google.gxp.compiler.base.Node;
import com.google.gxp.compiler.base.Util;
import com.google.gxp.compiler.parser.DefaultingParsedElementVisitor;
import com.google.gxp.compiler.parser.GxpNamespace;
import com.google.gxp.compiler.parser.NullElement;
import com.google.gxp.compiler.parser.ParsedAttribute;
import com.google.gxp.compiler.parser.ParsedElement;
import com.google.gxp.compiler.parser.ParsedElementVisitor;
import com.google.gxp.compiler.parser.ParseTree;

import java.util.*;

/**
 * Converts gxp:if and friends into gxp:cond blocks.
 *
 * 
*/ public class IfExpander implements Function { public IfExpandedTree apply(ParseTree parseTree) { AlertSetBuilder alertSetBuilder = new AlertSetBuilder(parseTree.getAlerts()); Worker worker = new Worker(alertSetBuilder); List children = worker.process(parseTree.getChildren()); return new IfExpandedTree(parseTree.getSourcePosition(), alertSetBuilder.buildAndClear(), children); } private static class Worker { private final AlertSink alertSink; // We use this visitor most of the time. private final NormalVisitor normalVisitor = new NormalVisitor(); private final Function normalFunction = new Function() { public ParsedElement apply(ParsedElement node) { ParsedElementVisitor visitor = normalVisitor; return node.acceptVisitor(visitor); } }; Worker(AlertSink alertSink) { this.alertSink = Preconditions.checkNotNull(alertSink); } public List process(List nodes) { return Util.map(nodes, normalFunction); } private abstract class BaseVisitor extends DefaultingParsedElementVisitor { protected List processIfChildren(GxpNamespace.GxpElement node) { IfChildVisitor ifChildVisitor = new IfChildVisitor(node); for (ParsedElement child : node.getChildren()) { child.acceptVisitor(ifChildVisitor); } return ifChildVisitor.get(); } } private class NormalVisitor extends BaseVisitor { @Override protected ParsedElement defaultVisitElement(ParsedElement node) { List newChildren = Lists.newArrayList(); for (ParsedElement child : node.getChildren()) { newChildren.add(child.acceptVisitor(normalVisitor)); } return node.withChildren(newChildren); } private ParsedElement reportBadNodeAndContinue(Node badNode, Node parentNode) { alertSink.add(new BadNodePlacementError(badNode, parentNode)); return new NullElement(badNode); } public ParsedElement visitElifElement(GxpNamespace.GxpElement node) { return reportBadNodeAndContinue(node, null); } public ParsedElement visitElseElement(GxpNamespace.GxpElement node) { return reportBadNodeAndContinue(node, null); } public ParsedElement visitIfElement(GxpNamespace.GxpElement node) { List clauses = processIfChildren(node); List attrs = Collections.emptyList(); return new GxpNamespace.GxpElement( node.getSourcePosition(), node.getDisplayName(), attrs, clauses, GxpNamespace.ElementType.COND); } public Expression visitValue(Expression value) { // There aren't any Values that can contain IfElements, so we don't // need to recurse any further. return value; } } private class IfChildVisitor extends BaseVisitor { // completed clauses private List clauses = Lists.newArrayList(); // for the current clause private List clauseChildren = Lists.newArrayList(); private ParsedElement clauseFromNode; private boolean sawElse = false; IfChildVisitor(GxpNamespace.GxpElement ifNode) { clauseFromNode = ifNode; } private void flush() { if (clauseFromNode != null) { clauses.add(new GxpNamespace.GxpElement( clauseFromNode.getSourcePosition(), clauseFromNode.getDisplayName(), clauseFromNode.getAttributes(), ImmutableList.copyOf(clauseChildren), GxpNamespace.ElementType.CLAUSE)); clauseFromNode = null; clauseChildren = Lists.newArrayList(); } } public List get() { flush(); return Collections.unmodifiableList(clauses); } /** * Adds the specified node to the current clause, after recursively * processing it. */ protected Void addNodeToCurrentClause(ParsedElement node) { clauseChildren.add(node.acceptVisitor(normalVisitor)); return null; } @Override protected Void defaultVisitElement(ParsedElement node) { addNodeToCurrentClause(node); return null; } // For the two functions below I decided to only flush() when encountering // correct nodes. When encountering a superfluous or // we'll just throw away the node and continue with compilation. // // This does have the possible disadvantage of hiding additional alerts from // the user that would have been created durring the compilation of these thrown // away nodes. I decided, in this case, to come down in favor of fewer rather than // more alerts for this type of malformed code. public Void visitElifElement(GxpNamespace.GxpElement node) { if (sawElse) { alertSink.add(new ElifAfterElseError(node)); } else { flush(); clauseFromNode = node; } reportBadChildren(node); return null; } public Void visitElseElement(GxpNamespace.GxpElement node) { if (sawElse) { alertSink.add(new DoubleElseError(node)); } else { flush(); clauseFromNode = node; sawElse = true; } reportBadChildren(node); return null; } private void reportBadChildren(ParsedElement parentNode) { for (Node badNode : parentNode.getChildren()) { alertSink.add(new BadNodePlacementError(badNode, parentNode)); } } public Void visitIfElement(GxpNamespace.GxpElement node) { return addNodeToCurrentClause(node); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy