Clover coverage report - Code Coverage for hivemind release 1.0
Coverage timestamp: Wed Sep 22 2004 08:05:25 EDT
file stats: LOC: 225   Methods: 3
NCLOC: 124   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
SymbolExpander.java 100% 100% 100% 100%
coverage
 1   
 //  Copyright 2004 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.hivemind.impl;
 16   
 
 17   
 import org.apache.commons.logging.Log;
 18   
 import org.apache.commons.logging.LogFactory;
 19   
 import org.apache.hivemind.ErrorHandler;
 20   
 import org.apache.hivemind.Location;
 21   
 import org.apache.hivemind.SymbolSource;
 22   
 
 23   
 /**
 24   
  * A simple parser used to identify symbols in a string and expand them via
 25   
  * a {@link org.apache.hivemind.SymbolSource}.
 26   
  *
 27   
  * @author Howard Lewis Ship
 28   
  */
 29   
 public class SymbolExpander
 30   
 {
 31   
     private ErrorHandler _errorHandler;
 32   
     private SymbolSource _source;
 33   
 
 34  107
     public SymbolExpander(ErrorHandler handler, SymbolSource source)
 35   
     {
 36  107
         _errorHandler = handler;
 37  107
         _source = source;
 38   
     }
 39   
 
 40   
     private static final Log LOG = LogFactory.getLog(SymbolExpander.class);
 41   
 
 42   
     private static final int STATE_START = 0;
 43   
     private static final int STATE_DOLLAR = 1;
 44   
     private static final int STATE_COLLECT_SYMBOL_NAME = 2;
 45   
 
 46   
     /**
 47   
      * <p>Identifies symbols in the text and expands them, using the
 48   
      * {@link SymbolSource}.  Returns the modified text.  May return text if text
 49   
      * does not contain any symbols.
 50   
      * 
 51   
      * @param text the text to scan
 52   
      * @param location the location to report errors (undefined symbols)
 53   
      * 
 54   
      * Note: a little cut-n-paste from {@link org.apache.tapestry.script.AbstractTokenRule}.
 55   
      */
 56  4925
     public String expandSymbols(String text, Location location)
 57   
     {
 58  4925
         StringBuffer result = new StringBuffer(text.length());
 59  4925
         char[] buffer = text.toCharArray();
 60  4925
         int state = STATE_START;
 61  4925
         int blockStart = 0;
 62  4925
         int blockLength = 0;
 63  4925
         int symbolStart = -1;
 64  4925
         int symbolLength = 0;
 65  4925
         int i = 0;
 66  4925
         int braceDepth = 0;
 67  4925
         boolean anySymbols = false;
 68   
 
 69  4925
         while (i < buffer.length)
 70   
         {
 71  128138
             char ch = buffer[i];
 72   
 
 73  128138
             switch (state)
 74   
             {
 75   
                 case STATE_START :
 76   
 
 77  128038
                     if (ch == '$')
 78   
                     {
 79  18
                         state = STATE_DOLLAR;
 80  18
                         i++;
 81  18
                         continue;
 82   
                     }
 83   
 
 84  128020
                     blockLength++;
 85  128020
                     i++;
 86  128020
                     continue;
 87   
 
 88   
                 case STATE_DOLLAR :
 89   
 
 90  17
                     if (ch == '{')
 91   
                     {
 92  14
                         state = STATE_COLLECT_SYMBOL_NAME;
 93  14
                         i++;
 94   
 
 95  14
                         symbolStart = i;
 96  14
                         symbolLength = 0;
 97  14
                         braceDepth = 1;
 98   
 
 99  14
                         continue;
 100   
                     }
 101   
                     
 102   
                     // Any time two $$ appear, it is collapsed down to a single $,
 103   
                     // but the next character is passed through un-interpreted (even if it
 104   
                     // is a brace).
 105   
                     
 106  3
                     if (ch == '$')
 107   
                     {                        
 108   
                         // This is effectively a symbol, meaning that the input string
 109   
                         // will not equal the output string.
 110   
                         
 111  2
                         anySymbols = true;
 112   
                         
 113  2
                         if (blockLength > 0)
 114  1
                             result.append(buffer, blockStart, blockLength);      
 115   
                             
 116  2
                         result.append(ch);                                              
 117   
                         
 118  2
                         i++;
 119  2
                         blockStart = i;
 120  2
                         blockLength = 0;
 121  2
                         state = STATE_START;
 122   
                         
 123  2
                         continue;
 124   
                     }
 125   
 
 126   
                     // The '$' was just what it was, not the start of a ${} expression
 127   
                     // block, so include it as part of the static text block.
 128   
 
 129  1
                     blockLength++;
 130   
 
 131  1
                     state = STATE_START;
 132  1
                     continue;
 133   
 
 134   
                 case STATE_COLLECT_SYMBOL_NAME :
 135   
 
 136  83
                     if (ch != '}')
 137   
                     {
 138  69
                         if (ch == '{')
 139  1
                             braceDepth++;
 140   
 
 141  69
                         i++;
 142  69
                         symbolLength++;
 143  69
                         continue;
 144   
                     }
 145   
 
 146  14
                     braceDepth--;
 147   
 
 148  14
                     if (braceDepth > 0)
 149   
                     {
 150  1
                         i++;
 151  1
                         symbolLength++;
 152  1
                         continue;
 153   
                     }
 154   
 
 155   
                     // Hit the closing brace of a symbol.
 156   
 
 157   
                     // Degenerate case:  the string "${}".
 158   
 
 159  13
                     if (symbolLength == 0)
 160  1
                         blockLength += 3;
 161   
 
 162   
                     // Append anything up to the start of the sequence (this is static
 163   
                     // text between symbol references).
 164   
 
 165  13
                     if (blockLength > 0)
 166  7
                         result.append(buffer, blockStart, blockLength);
 167   
 
 168  13
                     if (symbolLength > 0)
 169   
                     {
 170  12
                         String variableName =
 171   
                             text.substring(symbolStart, symbolStart + symbolLength);
 172   
 
 173  12
                         result.append(expandSymbol(variableName, location));
 174   
 
 175  12
                         anySymbols = true;
 176   
                     }
 177   
 
 178  13
                     i++;
 179  13
                     blockStart = i;
 180  13
                     blockLength = 0;
 181   
 
 182   
                     // And drop into state start
 183   
 
 184  13
                     state = STATE_START;
 185   
 
 186  13
                     continue;
 187   
             }
 188   
 
 189   
         }
 190   
 
 191   
         // If get this far without seeing any variables, then just pass
 192   
         // the input back.
 193   
 
 194  4925
         if (!anySymbols)
 195  4912
             return text;
 196   
 
 197   
         // OK, to handle the end.  Couple of degenerate cases where
 198   
         // a ${...} was incomplete, so we adust the block length.
 199   
 
 200  13
         if (state == STATE_DOLLAR)
 201  1
             blockLength++;
 202   
 
 203  13
         if (state == STATE_COLLECT_SYMBOL_NAME)
 204  1
             blockLength += symbolLength + 2;
 205   
 
 206  13
         if (blockLength > 0)
 207  6
             result.append(buffer, blockStart, blockLength);
 208   
 
 209  13
         return result.toString();
 210   
     }
 211   
 
 212  12
     private String expandSymbol(String name, Location location)
 213   
     {
 214  12
         String value = _source.valueForSymbol(name);
 215   
 
 216  12
         if (value != null)
 217  10
             return value;
 218   
 
 219  2
         _errorHandler.error(LOG, ImplMessages.noSuchSymbol(name), location, null);
 220   
 
 221  2
         return "${" + name + "}";
 222   
     }
 223   
 
 224   
 }
 225