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 java.io.*;
056: import java.util.*;
057: import freemarker.template.*;
058:
059: /**
060: * An element for the unified macro/transform syntax.
061: */
062: final class UnifiedCall extends TemplateElement {
063:
064: private Expression nameExp;
065: private Map namedArgs;
066: private List positionalArgs, bodyParameterNames;
067: boolean legacySyntax, notransform;
068:
069: UnifiedCall(Expression nameExp, Map namedArgs,
070: TemplateElement nestedBlock, List bodyParameterNames) {
071: this .nameExp = nameExp;
072: this .namedArgs = namedArgs;
073: this .nestedBlock = nestedBlock;
074: this .bodyParameterNames = bodyParameterNames;
075: notransform = legacySyntax
076: || (positionalArgs != null && positionalArgs.isEmpty())
077: || (bodyParameterNames != null && !bodyParameterNames
078: .isEmpty());
079: }
080:
081: UnifiedCall(Expression nameExp, List positionalArgs,
082: TemplateElement nestedBlock, List bodyParameterNames) {
083: this .nameExp = nameExp;
084: this .positionalArgs = positionalArgs;
085: if (nestedBlock == TextBlock.EMPTY_BLOCK) {
086: nestedBlock = null;
087: }
088: this .nestedBlock = nestedBlock;
089: this .bodyParameterNames = bodyParameterNames;
090: }
091:
092: void accept(Environment env) throws TemplateException, IOException {
093: TemplateModel tm = nameExp.getAsTemplateModel(env);
094: if (tm == Macro.DO_NOTHING_MACRO)
095: return; // shortcut here.
096: if (!notransform && (tm instanceof TemplateTransformModel)) {
097: Map args;
098: if (namedArgs != null && !namedArgs.isEmpty()) {
099: args = new HashMap();
100: for (Iterator it = namedArgs.entrySet().iterator(); it
101: .hasNext();) {
102: Map.Entry entry = (Map.Entry) it.next();
103: String key = (String) entry.getKey();
104: Expression valueExp = (Expression) entry.getValue();
105: TemplateModel value = valueExp
106: .getAsTemplateModel(env);
107: args.put(key, value);
108: }
109: } else {
110: args = EmptyMap.instance;
111: }
112: env.visit(nestedBlock, (TemplateTransformModel) tm, args);
113: return;
114: }
115: if (tm instanceof Macro) {
116: Macro macro = (Macro) tm;
117: if (macro.isFunction && !legacySyntax) {
118: throw new TemplateException(
119: "Routine "
120: + macro.getName()
121: + " is a function. "
122: + "A function can only be called within the evaluation of an expression.",
123: env);
124: }
125: env.visit(macro, namedArgs, positionalArgs,
126: bodyParameterNames, nestedBlock);
127: return;
128: }
129: if (tm == null) {
130: throw new InvalidReferenceException(this .getStartLocation()
131: + " " + nameExp + " not found.", env);
132: } else if (notransform) {
133: throw new TemplateException(getStartLocation() + ": "
134: + nameExp + " is not a Macro.", env);
135: } else {
136: throw new TemplateException(getStartLocation() + ": "
137: + nameExp + " is not a Macro or Transform.", env);
138: }
139: }
140:
141: public String getCanonicalForm() {
142: StringBuffer buf = new StringBuffer("<@");
143: buf.append(nameExp.getCanonicalForm());
144: if (positionalArgs != null) {
145: for (int i = 0; i < positionalArgs.size(); i++) {
146: Expression arg = (Expression) positionalArgs.get(i);
147: if (i != 0) {
148: buf.append(',');
149: }
150: buf.append(' ');
151: buf.append(arg.getCanonicalForm());
152: }
153: } else {
154: ArrayList keys = new ArrayList(namedArgs.keySet());
155: Collections.sort(keys);
156: for (int i = 0; i < keys.size(); i++) {
157: Expression arg = (Expression) namedArgs
158: .get(keys.get(i));
159: buf.append(' ');
160: buf.append(keys.get(i));
161: buf.append('=');
162: buf.append(arg.getCanonicalForm());
163: }
164: }
165: if (nestedBlock == null) {
166: buf.append("/>");
167: } else {
168: buf.append('>');
169: buf.append(nestedBlock.getCanonicalForm());
170: buf.append("</@");
171: if (nameExp instanceof Identifier
172: || (nameExp instanceof Dot && ((Dot) nameExp)
173: .onlyHasIdentifiers())) {
174: buf.append(nameExp);
175: }
176: buf.append('>');
177: }
178: return buf.toString();
179: }
180:
181: public String getDescription() {
182: return "user-directive " + nameExp;
183: }
184: /*
185: //REVISIT
186: boolean heedsOpeningWhitespace() {
187: return nestedBlock == null;
188: }
189:
190: //REVISIT
191: boolean heedsTrailingWhitespace() {
192: return nestedBlock == null;
193: }*/
194: }
|