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 freemarker.template;
56 import freemarker.ext.beans.BeanModel;
57
58 /**
59 * An abstract class for nodes in the parse tree
60 * that represent a FreeMarker expression.
61 */
62 abstract public class Expression extends TemplateObject {
63
64 abstract TemplateModel _getAsTemplateModel(Environment env) throws TemplateException;
65 abstract boolean isLiteral();
66
67 // Used to store a constant return value for this expression. Only if it
68 // is possible, of course.
69
70 TemplateModel constantValue;
71
72 // Hook in here to set the constant value if possible.
73
74 void setLocation(Template template, int beginColumn, int beginLine, int endColumn, int endLine)
75 throws
76 ParseException
77 {
78 super.setLocation(template, beginColumn, beginLine, endColumn, endLine);
79 if (isLiteral()) {
80 try {
81 constantValue = _getAsTemplateModel(null);
82 } catch (Exception e) {
83 // deliberately ignore.
84 }
85 }
86 }
87
88 public final TemplateModel getAsTemplateModel(Environment env) throws TemplateException {
89 return constantValue != null ? constantValue : _getAsTemplateModel(env);
90 }
91
92 String getStringValue(Environment env) throws TemplateException {
93 return getStringValue(getAsTemplateModel(env), this, env);
94 }
95
96 static String getStringValue(TemplateModel referentModel, Expression exp, Environment env)
97 throws
98 TemplateException
99 {
100 if (referentModel instanceof TemplateNumberModel) {
101 return env.formatNumber(EvaluationUtil.getNumber((TemplateNumberModel) referentModel, exp, env));
102 }
103 if (referentModel instanceof TemplateDateModel) {
104 TemplateDateModel dm = (TemplateDateModel) referentModel;
105 return env.formatDate(EvaluationUtil.getDate(dm, exp, env), dm.getDateType());
106 }
107 if (referentModel instanceof TemplateScalarModel) {
108 return EvaluationUtil.getString((TemplateScalarModel) referentModel, exp, env);
109 }
110 if(env.isClassicCompatible()) {
111 if (referentModel instanceof TemplateBooleanModel) {
112 return ((TemplateBooleanModel)referentModel).getAsBoolean() ? "true" : "";
113 }
114 if (referentModel == null) {
115 return "";
116 }
117 }
118 assertNonNull(referentModel, exp, env);
119
120 String msg = "Error " + exp.getStartLocation()
121 +"\nExpecting a string, "
122 + (env.isClassicCompatible() ? "boolean, " : "" )
123 + "date or number here, Expression " + exp
124 + " is instead a "
125 + referentModel.getClass().getName();
126 throw new NonStringException(msg, env);
127 }
128
129 Expression deepClone(String name, Expression subst) {
130 Expression clone = _deepClone(name, subst);
131 clone.copyLocationFrom(this);
132 return clone;
133 }
134
135 abstract Expression _deepClone(String name, Expression subst);
136
137 boolean isTrue(Environment env) throws TemplateException {
138 TemplateModel referent = getAsTemplateModel(env);
139 if (referent instanceof TemplateBooleanModel) {
140 return ((TemplateBooleanModel) referent).getAsBoolean();
141 }
142 if (env.isClassicCompatible()) {
143 return referent != null && !isEmpty(referent);
144 }
145 assertNonNull(referent, this, env);
146 String msg = "Error " + getStartLocation()
147 + "\nExpecting a boolean (true/false) expression here"
148 + "\nExpression " + this + " does not evaluate to true/false "
149 + "\nit is an instance of " + referent.getClass().getName();
150 throw new NonBooleanException(msg, env);
151 }
152
153
154 static boolean isEmpty(TemplateModel model) throws TemplateModelException
155 {
156 if (model instanceof BeanModel) {
157 return ((BeanModel) model).isEmpty();
158 } else if (model instanceof TemplateSequenceModel) {
159 return ((TemplateSequenceModel) model).size() == 0;
160 } else if (model instanceof TemplateScalarModel) {
161 String s = ((TemplateScalarModel) model).getAsString();
162 return (s == null || s.length() == 0);
163 } else if (model instanceof TemplateCollectionModel) {
164 return !((TemplateCollectionModel) model).iterator().hasNext();
165 } else if (model instanceof TemplateHashModel) {
166 return ((TemplateHashModel) model).isEmpty();
167 } else if (model instanceof TemplateNumberModel
168 || model instanceof TemplateDateModel
169 || model instanceof TemplateBooleanModel) {
170 return false;
171 } else {
172 return true;
173 }
174 }
175 }