001: /*
002: * Copyright (c) 2003 The Visigoth Software Society. All rights
003: * reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions
007: * are met:
008: *
009: * 1. Redistributions of source code must retain the above copyright
010: * notice, this list of conditions and the following disclaimer.
011: *
012: * 2. Redistributions in binary form must reproduce the above copyright
013: * notice, this list of conditions and the following disclaimer in
014: * the documentation and/or other materials provided with the
015: * distribution.
016: *
017: * 3. The end-user documentation included with the redistribution, if
018: * any, must include the following acknowledgement:
019: * "This product includes software developed by the
020: * Visigoth Software Society (http://www.visigoths.org/)."
021: * Alternately, this acknowledgement may appear in the software itself,
022: * if and wherever such third-party acknowledgements normally appear.
023: *
024: * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the
025: * project contributors may be used to endorse or promote products derived
026: * from this software without prior written permission. For written
027: * permission, please contact visigoths@visigoths.org.
028: *
029: * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth"
030: * nor may "FreeMarker" or "Visigoth" appear in their names
031: * without prior written permission of the Visigoth Software Society.
032: *
033: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
034: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
035: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
036: * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR
037: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
038: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
039: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
040: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
041: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
042: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
043: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
044: * SUCH DAMAGE.
045: * ====================================================================
046: *
047: * This software consists of voluntary contributions made by many
048: * individuals on behalf of the Visigoth Software Society. For more
049: * information on the Visigoth Software Society, please see
050: * http://www.visigoths.org/
051: */
052:
053: package freemarker.core;
054:
055: import freemarker.template.*;
056: import freemarker.ext.beans.BeanModel;
057:
058: /**
059: * An abstract class for nodes in the parse tree
060: * that represent a FreeMarker expression.
061: */
062: abstract public class Expression extends TemplateObject {
063:
064: abstract TemplateModel _getAsTemplateModel(Environment env)
065: throws TemplateException;
066:
067: abstract boolean isLiteral();
068:
069: // Used to store a constant return value for this expression. Only if it
070: // is possible, of course.
071:
072: TemplateModel constantValue;
073:
074: // Hook in here to set the constant value if possible.
075:
076: void setLocation(Template template, int beginColumn, int beginLine,
077: int endColumn, int endLine) throws ParseException {
078: super .setLocation(template, beginColumn, beginLine, endColumn,
079: endLine);
080: if (isLiteral()) {
081: try {
082: constantValue = _getAsTemplateModel(null);
083: } catch (Exception e) {
084: // deliberately ignore.
085: }
086: }
087: }
088:
089: public final TemplateModel getAsTemplateModel(Environment env)
090: throws TemplateException {
091: return constantValue != null ? constantValue
092: : _getAsTemplateModel(env);
093: }
094:
095: String getStringValue(Environment env) throws TemplateException {
096: return getStringValue(getAsTemplateModel(env), this , env);
097: }
098:
099: static String getStringValue(TemplateModel referentModel,
100: Expression exp, Environment env) throws TemplateException {
101: if (referentModel instanceof TemplateNumberModel) {
102: return env.formatNumber(EvaluationUtil.getNumber(
103: (TemplateNumberModel) referentModel, exp, env));
104: }
105: if (referentModel instanceof TemplateDateModel) {
106: TemplateDateModel dm = (TemplateDateModel) referentModel;
107: return env.formatDate(EvaluationUtil.getDate(dm, exp, env),
108: dm.getDateType());
109: }
110: if (referentModel instanceof TemplateScalarModel) {
111: return EvaluationUtil.getString(
112: (TemplateScalarModel) referentModel, exp, env);
113: }
114: if (env.isClassicCompatible()) {
115: if (referentModel instanceof TemplateBooleanModel) {
116: return ((TemplateBooleanModel) referentModel)
117: .getAsBoolean() ? "true" : "";
118: }
119: if (referentModel == null) {
120: return "";
121: }
122: }
123: assertNonNull(referentModel, exp, env);
124:
125: String msg = "Error " + exp.getStartLocation()
126: + "\nExpecting a string, "
127: + (env.isClassicCompatible() ? "boolean, " : "")
128: + "date or number here, Expression " + exp
129: + " is instead a " + referentModel.getClass().getName();
130: throw new NonStringException(msg, env);
131: }
132:
133: Expression deepClone(String name, Expression subst) {
134: Expression clone = _deepClone(name, subst);
135: clone.copyLocationFrom(this );
136: return clone;
137: }
138:
139: abstract Expression _deepClone(String name, Expression subst);
140:
141: boolean isTrue(Environment env) throws TemplateException {
142: TemplateModel referent = getAsTemplateModel(env);
143: if (referent instanceof TemplateBooleanModel) {
144: return ((TemplateBooleanModel) referent).getAsBoolean();
145: }
146: if (env.isClassicCompatible()) {
147: return referent != null && !isEmpty(referent);
148: }
149: assertNonNull(referent, this , env);
150: String msg = "Error " + getStartLocation()
151: + "\nExpecting a boolean (true/false) expression here"
152: + "\nExpression " + this
153: + " does not evaluate to true/false "
154: + "\nit is an instance of "
155: + referent.getClass().getName();
156: throw new NonBooleanException(msg, env);
157: }
158:
159: static boolean isEmpty(TemplateModel model)
160: throws TemplateModelException {
161: if (model instanceof BeanModel) {
162: return ((BeanModel) model).isEmpty();
163: } else if (model instanceof TemplateSequenceModel) {
164: return ((TemplateSequenceModel) model).size() == 0;
165: } else if (model instanceof TemplateScalarModel) {
166: String s = ((TemplateScalarModel) model).getAsString();
167: return (s == null || s.length() == 0);
168: } else if (model instanceof TemplateCollectionModel) {
169: return !((TemplateCollectionModel) model).iterator()
170: .hasNext();
171: } else if (model instanceof TemplateHashModel) {
172: return ((TemplateHashModel) model).isEmpty();
173: } else if (model instanceof TemplateNumberModel
174: || model instanceof TemplateDateModel
175: || model instanceof TemplateBooleanModel) {
176: return false;
177: } else {
178: return true;
179: }
180: }
181: }
|