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