Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * 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.catalina.ssi;
 
 
 import static org.jboss.web.CatalinaMessages.MESSAGES;
 
 import java.util.List;

Represents a parsed expression.

Author(s):
Paul Speed
Version:
$Revision: 1237 $
 
 public class ExpressionParseTree {
    
Contains the current set of completed nodes. This is a workspace for the parser.
 
     private LinkedList nodeStack = new LinkedList();
    
Contains operator nodes that don't yet have values. This is a workspace for the parser.
 
     private LinkedList oppStack = new LinkedList();
    
The root node after the expression has been parsed.
 
     private Node root;
    
The SSIMediator to use when evaluating the expressions.
 
     private SSIMediator ssiMediator;


    
Creates a new parse tree for the specified expression.
 
     public ExpressionParseTree(String exprSSIMediator ssiMediator)
             throws ParseException {
         this. = ssiMediator;
         parseExpression(expr);
     }


    
Evaluates the tree and returns true or false. The specified SSIMediator is used to resolve variable references.
 
     public boolean evaluateTree() {
         return .evaluate();
     }


    
Pushes a new operator onto the opp stack, resolving existing opps as needed.
 
     private void pushOpp(OppNode node) {
         // If node is null then it's just a group marker
         if (node == null) {
             .add(0, node);
             return;
         }
         while (true) {
             if (.size() == 0) break;
             OppNode top = (OppNode).get(0);
             // If the top is a spacer then don't pop
             // anything
             if (top == nullbreak;
             // If the top node has a lower precedence then
             // let it stay
             if (top.getPrecedence() < node.getPrecedence()) break;
             // Remove the top node
             .remove(0);
             // Let it fill its branches
             top.popValues();
             // Stick it on the resolved node stack
             .add(0, top);
         }
         // Add the new node to the opp stack
         .add(0, node);
    }


    
Resolves all pending opp nodes on the stack until the next group marker is reached.
    private void resolveGroup() {
        OppNode top = null;
        while ((top = (OppNode).remove(0)) != null) {
            // Let it fill its branches
            top.popValues();
            // Stick it on the resolved node stack
            .add(0, top);
        }
    }


    
Parses the specified expression into a tree of parse nodes.
    private void parseExpression(String exprthrows ParseException {
        StringNode currStringNode = null;
        // We cheat a little and start an artificial
        // group right away. It makes finishing easier.
        pushOpp(null);
        ExpressionTokenizer et = new ExpressionTokenizer(expr);
        while (et.hasMoreTokens()) {
            int token = et.nextToken();
            if (token != .)
                currStringNode = null;
            switch (token) {
                case . :
                    if (currStringNode == null) {
                        currStringNode = new StringNode(et.getTokenValue());
                        .add(0, currStringNode);
                    } else {
                        // Add to the existing
                        currStringNode.value.append(" ");
                        currStringNode.value.append(et.getTokenValue());
                    }
                    break;
                case . :
                    pushOpp(new AndNode());
                    break;
                case . :
                    pushOpp(new OrNode());
                    break;
                case . :
                    pushOpp(new NotNode());
                    break;
                case . :
                    pushOpp(new EqualNode());
                    break;
                case . :
                    pushOpp(new NotNode());
                    // Sneak the regular node in. The NOT will
                    // be resolved when the next opp comes along.
                    .add(0, new EqualNode());
                    break;
                case . :
                    // Closeout the current group
                    resolveGroup();
                    break;
                case . :
                    // Push a group marker
                    pushOpp(null);
                    break;
                case . :
                    pushOpp(new NotNode());
                    // Similar stategy to NOT_EQ above, except this
                    // is NOT less than
                    .add(0, new LessThanNode());
                    break;
                case . :
                    pushOpp(new NotNode());
                    // Similar stategy to NOT_EQ above, except this
                    // is NOT greater than
                    .add(0, new GreaterThanNode());
                    break;
                case . :
                    pushOpp(new GreaterThanNode());
                    break;
                case . :
                    pushOpp(new LessThanNode());
                    break;
                case . :
                    break;
            }
        }
        // Finish off the rest of the opps
        resolveGroup();
        if (.size() == 0) {
            throw new ParseException(.ssiParseNoNodes(), et.getIndex());
        }
        if (.size() > 1) {
            throw new ParseException(.ssiParseExtraNodes(), et.getIndex());
        }
        if (.size() != 0) {
            throw new ParseException(.ssiParseUnusedNodes(), et.getIndex());
        }
         = (Node).get(0);
    }

    
A node in the expression parse tree.
    private abstract class Node {
        
Return true if the node evaluates to true.
        public abstract boolean evaluate();
    }
    
A node the represents a String value
    private class StringNode extends Node {
        StringBuilder value;
        String resolved = null;
        public StringNode(String value) {
            this. = new StringBuilder(value);
        }


        
Resolves any variable references and returns the value string.
        public String getValue() {
            if ( == null)
                 = .substituteVariables(.toString());
            return ;
        }


        
Returns true if the string is not empty.
        public boolean evaluate() {
            return !(getValue().length() == 0);
        }
        public String toString() {
            return .toString();
        }
    }
    private static final int PRECEDENCE_NOT = 5;
    private static final int PRECEDENCE_COMPARE = 4;
    private static final int PRECEDENCE_LOGICAL = 1;

    
A node implementation that represents an operation.
    private abstract class OppNode extends Node {
        
The left branch.
        Node left;
        
The right branch.
        Node right;


        
Returns a preference level suitable for comparison to other OppNode preference levels.
        public abstract int getPrecedence();


        
Lets the node pop its own branch nodes off the front of the specified list. The default pulls two.
        public void popValues(List values) {
             = (Node)values.remove(0);
             = (Node)values.remove(0);
        }
    }
    private final class NotNode extends OppNode {
        public boolean evaluate() {
            return !.evaluate();
        }
        public int getPrecedence() {
            return ;
        }


        
Overridden to pop only one value.
        public void popValues(List values) {
             = (Node)values.remove(0);
        }
        public String toString() {
            return  + " NOT";
        }
    }
    private final class AndNode extends OppNode {
        public boolean evaluate() {
            if (!.evaluate()) // Short circuit
                return false;
            return .evaluate();
        }
        public int getPrecedence() {
            return ;
        }
        public String toString() {
            return  + " " +  + " AND";
        }
    }
    private final class OrNode extends OppNode {
        public boolean evaluate() {
            if (.evaluate()) // Short circuit
                return true;
            return .evaluate();
        }
        public int getPrecedence() {
            return ;
        }
        public String toString() {
            return  + " " +  + " OR";
        }
    }
    private abstract class CompareNode extends OppNode {
        protected int compareBranches() {
            String val1 = ((StringNode)).getValue();
            String val2 = ((StringNode)).getValue();
            return val1.compareTo(val2);
        }
    }
    private final class EqualNode extends CompareNode {
        public boolean evaluate() {
            return (compareBranches() == 0);
        }
        public int getPrecedence() {
            return ;
        }
        public String toString() {
            return  + " " +  + " EQ";
        }
    }
    private final class GreaterThanNode extends CompareNode {
        public boolean evaluate() {
            return (compareBranches() > 0);
        }
        public int getPrecedence() {
            return ;
        }
        public String toString() {
            return  + " " +  + " GT";
        }
    }
    private final class LessThanNode extends CompareNode {
        public boolean evaluate() {
            return (compareBranches() < 0);
        }
        public int getPrecedence() {
            return ;
        }
        public String toString() {
            return  + " " +  + " LT";
        }
    }
New to GrepCode? Check out our FAQ X