Coverage Report - org.apache.tapestry.script.AbstractTokenRule
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractTokenRule
99% 
100% 
4.75
 
 1  
 // Copyright 2004, 2005 The Apache Software Foundation
 2  
 //
 3  
 // Licensed under the Apache License, Version 2.0 (the "License");
 4  
 // you may not use this file except in compliance with the License.
 5  
 // You may obtain a copy of the License at
 6  
 //
 7  
 //     http://www.apache.org/licenses/LICENSE-2.0
 8  
 //
 9  
 // Unless required by applicable law or agreed to in writing, software
 10  
 // distributed under the License is distributed on an "AS IS" BASIS,
 11  
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12  
 // See the License for the specific language governing permissions and
 13  
 // limitations under the License.
 14  
 
 15  
 package org.apache.tapestry.script;
 16  
 
 17  
 import org.apache.hivemind.Location;
 18  
 import org.apache.tapestry.util.xml.BaseRule;
 19  
 import org.apache.tapestry.util.xml.RuleDirectedParser;
 20  
 
 21  
 /**
 22  
  * Base class for the rules that build {@link org.apache.tapestry.script.IScriptToken}s.
 23  
  * Used with classes that can contain a mix of text and elements (those that
 24  
  * accept "full content").
 25  
  * 
 26  
  *
 27  
  * @author Howard Lewis Ship
 28  
  * @since 3.0
 29  
  **/
 30  
 
 31  128
 abstract class AbstractTokenRule extends BaseRule
 32  
 {
 33  
 
 34  
     private static final int STATE_START = 0;
 35  
     private static final int STATE_DOLLAR = 1;
 36  
     private static final int STATE_COLLECT_EXPRESSION = 2;
 37  
     
 38  
     /**
 39  
      * Adds a token to its parent, the top object on the stack.
 40  
      */
 41  
     protected void addToParent(RuleDirectedParser parser, IScriptToken token)
 42  
     {
 43  22
         IScriptToken parent = (IScriptToken) parser.peek();
 44  
 
 45  22
         parent.addToken(token);
 46  22
     }
 47  
 
 48  
     /**
 49  
      * {@inheritDoc}
 50  
      */
 51  
     public void content(RuleDirectedParser parser, String content)
 52  
     {
 53  25
         IScriptToken token = (IScriptToken) parser.peek();
 54  
 
 55  25
         addTextTokens(token, content, parser.getLocation());
 56  25
     }
 57  
 
 58  
     /**
 59  
      * Parses the provided text and converts it into a series of .
 60  
      */
 61  
     protected void addTextTokens(IScriptToken token, String text, Location location)
 62  
     {
 63  25
         char[] buffer = text.toCharArray();
 64  25
         int state = STATE_START;
 65  25
         int blockStart = 0;
 66  25
         int blockLength = 0;
 67  25
         int expressionStart = -1;
 68  25
         int expressionLength = 0;
 69  25
         int i = 0;
 70  25
         int braceDepth = 0;
 71  
 
 72  369
         while (i < buffer.length)
 73  
         {
 74  344
             char ch = buffer[i];
 75  
 
 76  344
             switch (state)
 77  
             {
 78  
                 case STATE_START :
 79  
 
 80  269
                     if (ch == '$')
 81  
                     {
 82  8
                         state = STATE_DOLLAR;
 83  8
                         i++;
 84  8
                         continue;
 85  
                     }
 86  
 
 87  261
                     blockLength++;
 88  261
                     i++;
 89  261
                     continue;
 90  
 
 91  
                 case STATE_DOLLAR :
 92  
 
 93  7
                     if (ch == '{')
 94  
                     {
 95  6
                         state = STATE_COLLECT_EXPRESSION;
 96  6
                         i++;
 97  
 
 98  6
                         expressionStart = i;
 99  6
                         expressionLength = 0;
 100  6
                         braceDepth = 1;
 101  
 
 102  6
                         continue;
 103  
                     }
 104  
 
 105  
                     // The '$' was just what it was, not the start of a ${} expression
 106  
                     // block, so include it as part of the static text block.
 107  
 
 108  1
                     blockLength++;
 109  
 
 110  1
                     state = STATE_START;
 111  1
                     continue;
 112  
 
 113  
                 case STATE_COLLECT_EXPRESSION :
 114  
 
 115  68
                     if (ch != '}')
 116  
                     {
 117  62
                         if (ch == '{')
 118  1
                             braceDepth++;
 119  
 
 120  62
                         i++;
 121  62
                         expressionLength++;
 122  62
                         continue;
 123  
                     }
 124  
 
 125  6
                     braceDepth--;
 126  
 
 127  6
                     if (braceDepth > 0)
 128  
                     {
 129  1
                         i++;
 130  1
                         expressionLength++;
 131  1
                         continue;
 132  
                     }
 133  
 
 134  
                     // Hit the closing brace of an expression.
 135  
 
 136  
                     // Degenerate case:  the string "${}".
 137  
 
 138  5
                     if (expressionLength == 0)
 139  1
                         blockLength += 3;
 140  
 
 141  5
                     if (blockLength > 0)
 142  5
                         token.addToken(constructStatic(text, blockStart, blockLength, location));
 143  
 
 144  5
                     if (expressionLength > 0)
 145  
                     {
 146  4
                         String expression =
 147  
                             text.substring(expressionStart, expressionStart + expressionLength);
 148  
 
 149  4
                         token.addToken(new InsertToken(expression, location));
 150  
                     }
 151  
 
 152  5
                     i++;
 153  5
                     blockStart = i;
 154  5
                     blockLength = 0;
 155  
 
 156  
                     // And drop into state start
 157  
 
 158  5
                     state = STATE_START;
 159  
 
 160  5
                     continue;
 161  
             }
 162  
 
 163  0
         }
 164  
 
 165  
         // OK, to handle the end.  Couple of degenerate cases where
 166  
         // a ${...} was incomplete, so we adust the block length.
 167  
 
 168  25
         if (state == STATE_DOLLAR)
 169  1
             blockLength++;
 170  
 
 171  25
         if (state == STATE_COLLECT_EXPRESSION)
 172  1
             blockLength += expressionLength + 2;
 173  
 
 174  25
         if (blockLength > 0)
 175  24
             token.addToken(constructStatic(text, blockStart, blockLength, location));
 176  25
     }
 177  
 
 178  
     private IScriptToken constructStatic(
 179  
         String text,
 180  
         int blockStart,
 181  
         int blockLength,
 182  
         Location location)
 183  
     {
 184  29
         String literal = text.substring(blockStart, blockStart + blockLength);
 185  
 
 186  29
         return new StaticToken(literal, location);
 187  
     }
 188  
 }