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