001 /*
002 // $Id: CallNode.java 247 2009-06-20 05:52:40Z jhyde $
003 // This software is subject to the terms of the Eclipse Public License v1.0
004 // Agreement, available at the following URL:
005 // http://www.eclipse.org/legal/epl-v10.html.
006 // Copyright (C) 2007-2008 Julian Hyde
007 // All Rights Reserved.
008 // You must accept the terms of that agreement to use this software.
009 */
010 package org.olap4j.mdx;
011
012 import java.util.List;
013 import java.util.Arrays;
014
015 import org.olap4j.type.Type;
016
017 /**
018 * A parse tree node representing a call to a function or operator.
019 *
020 * <p>Examples of calls include:<ul>
021 * <li><code>5 + 2</code>, a call to the infix arithmetic operator '+'</li>
022 * <li><code>[Measures].[Unit Sales] IS NULL</code>, a call applying the
023 * {@link Syntax#Postfix postfix} operator
024 * <code>IS NULL</code> to a member expression</li>
025 * <li><code>CrossJoin({[Gender].Children}, {[Store]})</code>, a call to the
026 * <code>CrossJoin</code> function</li>
027 * <li><code>[Gender].Children</code>, a call to the <code>Children</code>
028 * operator, which has {@link Syntax#Property property syntax}</li>
029 * <li><code>[Gender].Properties("FORMAT_STRING")</code>, a call to the
030 * <code>Properties</code> operator, which has
031 * {@link Syntax#Method method syntax}</li>
032 * </ul>
033 *
034 * @author jhyde
035 * @version $Id: CallNode.java 247 2009-06-20 05:52:40Z jhyde $
036 * @since Jan 6, 2006
037 */
038 public class CallNode implements ParseTreeNode {
039
040 private final String name;
041 private final Syntax syntax;
042 private final List<ParseTreeNode> argList;
043 private final ParseRegion region;
044 private Type type;
045
046 /**
047 * Creates a CallNode.
048 *
049 * <p>The <code>syntax</code> argument determines whether this is a prefix,
050 * infix or postfix operator, a function call, and so forth.
051 *
052 * <p>The list of arguments <code>args</code> must be specified, even if
053 * there are zero arguments, and each argument must be not null.
054 *
055 * <p>The type is initially null, but can be set using {@link #setType}
056 * after validation.
057 *
058 * @param region Region of source code
059 * @param name Name of operator or function
060 * @param syntax Syntax of call
061 * @param args List of zero or more arguments
062 */
063 public CallNode(
064 ParseRegion region,
065 String name,
066 Syntax syntax,
067 List<ParseTreeNode> args)
068 {
069 this.region = region;
070 assert name != null;
071 assert syntax != null;
072 assert args != null;
073 this.name = name;
074 this.syntax = syntax;
075 this.argList = args;
076
077 // Check special syntaxes.
078 switch (syntax) {
079 case Braces:
080 assert name.equals("{}");
081 break;
082 case Parentheses:
083 assert name.equals("()");
084 break;
085 case Internal:
086 assert name.startsWith("$");
087 break;
088 default:
089 assert !name.startsWith("$")
090 && !name.equals("{}")
091 && !name.equals("()");
092 break;
093 }
094 }
095
096 /**
097 * Creates an CallNode using a variable number of arguments.
098 *
099 * <p>The <code>syntax</code> argument determines whether this is a prefix,
100 * infix or postfix operator, a function call, and so forth.
101 *
102 * <p>The list of arguments <code>args</code> must be specified, even if
103 * there are zero arguments, and each argument must be not null.
104 *
105 * @param region Region of source code
106 * @param name Name of operator or function
107 * @param syntax Syntax of call
108 * @param args List of zero or more arguments
109 */
110 public CallNode(
111 ParseRegion region,
112 String name,
113 Syntax syntax,
114 ParseTreeNode... args)
115 {
116 this(region, name, syntax, Arrays.asList(args));
117 }
118
119 public ParseRegion getRegion() {
120 return region;
121 }
122
123 /**
124 * Sets the type of this CallNode.
125 *
126 * <p>Typically, this method would be called by the validator when it has
127 * deduced the argument types, chosen between any overloaded functions
128 * or operators, and determined the result type of the function or
129 * operator.
130 *
131 * @param type Result type of this call
132 */
133 public void setType(Type type) {
134 this.type = type;
135 }
136
137 public Type getType() {
138 return type;
139 }
140
141 public void unparse(ParseTreeWriter writer) {
142 syntax.unparse(name, argList, writer);
143 }
144
145 public <T> T accept(ParseTreeVisitor<T> visitor) {
146 final T o = visitor.visit(this);
147 // visit the call's arguments
148 for (ParseTreeNode arg : argList) {
149 arg.accept(visitor);
150 }
151 return o;
152 }
153
154 /**
155 * Returns the name of the function or operator.
156 *
157 * @return name of the function or operator
158 */
159 public String getOperatorName() {
160 return name;
161 }
162
163 /**
164 * Returns the syntax of this call.
165 *
166 * @return the syntax of the call
167 */
168 public Syntax getSyntax() {
169 return syntax;
170 }
171
172 /**
173 * Returns the list of arguments to this call.
174 *
175 * @return list of arguments
176 */
177 public List<ParseTreeNode> getArgList() {
178 return argList;
179 }
180
181 public CallNode deepCopy() {
182 return new CallNode(
183 this.region,
184 this.name,
185 this.syntax,
186 MdxUtil.deepCopyList(argList));
187 }
188 }
189
190 // End CallNode.java