Save This Page
Home » freemarker-2.3.13 » freemarker.core » [javadoc | source]
    1   /*
    2    * Copyright (c) 2003 The Visigoth Software Society. All rights
    3    * reserved.
    4    *
    5    * Redistribution and use in source and binary forms, with or without
    6    * modification, are permitted provided that the following conditions
    7    * are met:
    8    *
    9    * 1. Redistributions of source code must retain the above copyright
   10    *    notice, this list of conditions and the following disclaimer.
   11    *
   12    * 2. Redistributions in binary form must reproduce the above copyright
   13    *    notice, this list of conditions and the following disclaimer in
   14    *    the documentation and/or other materials provided with the
   15    *    distribution.
   16    *
   17    * 3. The end-user documentation included with the redistribution, if
   18    *    any, must include the following acknowledgement:
   19    *       "This product includes software developed by the
   20    *        Visigoth Software Society (http://www.visigoths.org/)."
   21    *    Alternately, this acknowledgement may appear in the software itself,
   22    *    if and wherever such third-party acknowledgements normally appear.
   23    *
   24    * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the 
   25    *    project contributors may be used to endorse or promote products derived
   26    *    from this software without prior written permission. For written
   27    *    permission, please contact visigoths@visigoths.org.
   28    *
   29    * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth"
   30    *    nor may "FreeMarker" or "Visigoth" appear in their names
   31    *    without prior written permission of the Visigoth Software Society.
   32    *
   33    * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   34    * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   35    * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   36    * DISCLAIMED.  IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR
   37    * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   38    * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   39    * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   40    * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   41    * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   42    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   43    * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   44    * SUCH DAMAGE.
   45    * ====================================================================
   46    *
   47    * This software consists of voluntary contributions made by many
   48    * individuals on behalf of the Visigoth Software Society. For more
   49    * information on the Visigoth Software Society, please see
   50    * http://www.visigoths.org/
   51    */
   52   
   53   package freemarker.core;
   54   
   55   import java.util.ArrayList;
   56   import freemarker.template;
   57   
   58   /**
   59    * A unary operator that uses the string value of an expression as a hash key.
   60    * It associates with the <tt>Identifier</tt> or <tt>Dot</tt> to its left.
   61    */
   62   final class DynamicKeyName extends Expression {
   63   
   64       private final Expression nameExpression;
   65       private final Expression target;
   66   
   67       DynamicKeyName(Expression target, Expression nameExpression) {
   68           this.target = target; 
   69           this.nameExpression = nameExpression;
   70       }
   71   
   72       TemplateModel _getAsTemplateModel(Environment env) throws TemplateException
   73       {
   74           TemplateModel targetModel = target.getAsTemplateModel(env);
   75           assertNonNull(targetModel, target, env);
   76           if (nameExpression instanceof Range) {
   77               return dealWithRangeKey(targetModel, (Range) nameExpression, env);
   78           }
   79           TemplateModel keyModel = nameExpression.getAsTemplateModel(env);
   80           if(keyModel == null) {
   81               if(env.isClassicCompatible()) {
   82                   keyModel = TemplateScalarModel.EMPTY_STRING;
   83               }
   84               else {
   85                   assertNonNull(keyModel, nameExpression, env);
   86               }
   87           }
   88           if (keyModel instanceof TemplateNumberModel) {
   89               int index = EvaluationUtil.getNumber(keyModel, nameExpression, env).intValue();
   90               return dealWithNumericalKey(targetModel, index, env);
   91           }
   92           if (keyModel instanceof TemplateScalarModel) {
   93               String key = EvaluationUtil.getString((TemplateScalarModel)keyModel, nameExpression, env);
   94               return dealWithStringKey(targetModel, key, env);
   95           }
   96           throw invalidTypeException(keyModel, nameExpression, env, "number, range, or string");
   97       }
   98   
   99   
  100       private TemplateModel dealWithNumericalKey(TemplateModel targetModel, 
  101                                                  int index, 
  102                                                  Environment env)
  103           throws TemplateException
  104       {
  105           if (targetModel instanceof TemplateSequenceModel) {
  106               TemplateSequenceModel tsm = (TemplateSequenceModel) targetModel;
  107               int size = Integer.MAX_VALUE;
  108               try {
  109                   size = tsm.size();
  110               } catch (Exception e) {}
  111               return index<size ? tsm.get(index) : null;
  112           } 
  113           
  114           try
  115           {
  116               String s = target.getStringValue(env);
  117               try {
  118                  return new SimpleScalar(s.substring(index, index+1));
  119               } catch (RuntimeException re) {
  120                   throw new TemplateException("", re, env);
  121               }
  122           }
  123           catch(NonStringException e)
  124           {
  125               throw invalidTypeException(targetModel, target, env, "number, sequence, or string");
  126           }
  127       }
  128   
  129   
  130       private TemplateModel dealWithStringKey(TemplateModel targetModel, 
  131                                               String key,
  132                                               Environment env)
  133           throws TemplateException
  134       {
  135           if(targetModel instanceof TemplateHashModel) {
  136               return((TemplateHashModel) targetModel).get(key);
  137           }
  138           throw invalidTypeException(targetModel, target, env, "hash");
  139       }
  140   
  141       private TemplateModel dealWithRangeKey(TemplateModel targetModel, 
  142                                              Range range, 
  143                                              Environment env)
  144           throws TemplateException
  145       {
  146           int start = EvaluationUtil.getNumber(range.left, env).intValue();
  147           int end = 0;
  148           boolean hasRhs = range.hasRhs();
  149           if (hasRhs) {
  150               end = EvaluationUtil.getNumber(range.right, env).intValue();
  151           }
  152           if (targetModel instanceof TemplateSequenceModel) {
  153               TemplateSequenceModel sequence = (TemplateSequenceModel) targetModel;
  154               if (!hasRhs) end = sequence.size() -1;
  155               if (start < 0) {
  156                   String msg = range.left.getStartLocation() + "\nNegative starting index for range, is " + range;
  157                   throw new TemplateException(msg, env);
  158               }
  159               if (end < 0) {
  160                   String msg = range.left.getStartLocation() + "\nNegative ending index for range, is " + range;
  161                   throw new TemplateException(msg, env);
  162               }
  163               if (start >= sequence.size()) {
  164                   String msg = range.left.getStartLocation() 
  165                               + "\nLeft side index of range out of bounds, is " + start
  166                               + ", but the sequence has only " + sequence.size() + " element(s) "
  167                               + "(note that indices are 0 based, and ranges are inclusive).";
  168                   throw new TemplateException(msg, env);
  169               }
  170               if (end >= sequence.size()) {
  171                   String msg = range.right.getStartLocation() 
  172                                + "\nRight side index of range out of bounds, is " + end
  173                                + ", but the sequence has only " + sequence.size() + " element(s)."
  174                                + "(note that indices are 0 based, and ranges are inclusive).";
  175                   throw new TemplateException(msg, env);
  176               }
  177               ArrayList list = new ArrayList(1+Math.abs(start-end));
  178               if (start>end) {
  179                   for (int i = start; i>=end; i--) {
  180                       list.add(sequence.get(i));
  181                   }
  182               }
  183               else {
  184                   for (int i = start; i<=end; i++) {
  185                       list.add(sequence.get(i));
  186                   }
  187               }
  188               return new SimpleSequence(list);
  189           }
  190           
  191           try
  192           {
  193               String s = target.getStringValue(env);
  194               if (!hasRhs) end = s.length() -1;
  195               if (start < 0) {
  196                   String msg = range.left.getStartLocation() + "\nNegative starting index for range " + range + " : " + start;
  197                   throw new TemplateException(msg, env);
  198               }
  199               if (end < 0) {
  200                   String msg = range.left.getStartLocation() + "\nNegative ending index for range " + range + " : " + end;
  201                   throw new TemplateException(msg, env);
  202               }
  203               if (start > s.length()) {
  204                   String msg = range.left.getStartLocation() 
  205                               + "\nLeft side of range out of bounds, is: " + start
  206                               + "\nbut string " + targetModel + " has " + s.length() + " elements.";
  207                   throw new TemplateException(msg, env);
  208               }
  209               if (end > s.length()) {
  210                   String msg = range.right.getStartLocation() 
  211                                + "\nRight side of range out of bounds, is: " + end
  212                                + "\nbut string " + targetModel + " is only " + s.length() + " characters.";
  213                   throw new TemplateException(msg, env);
  214               }
  215               try {
  216                   return new SimpleScalar(s.substring(start, end+1));
  217               } catch (RuntimeException re) {
  218                   String msg = "Error " + getStartLocation();
  219                   throw new TemplateException(msg, re, env);
  220               }
  221           }
  222           catch(NonStringException e)
  223           {
  224               throw invalidTypeException(target.getAsTemplateModel(env), target, env, "number, scalar, or sequence");
  225           }
  226       }
  227   
  228       public String getCanonicalForm() {
  229           return target.getCanonicalForm() 
  230                  + "[" 
  231                  + nameExpression.getCanonicalForm() 
  232                  + "]";
  233       }
  234       
  235       boolean isLiteral() {
  236           return constantValue != null || (target.isLiteral() && nameExpression.isLiteral());
  237       }
  238   
  239       Expression _deepClone(String name, Expression subst) {
  240       	return new DynamicKeyName(target.deepClone(name, subst), nameExpression.deepClone(name, subst));
  241       }
  242   }

Save This Page
Home » freemarker-2.3.13 » freemarker.core » [javadoc | source]