001    /*
002     $Id: Expression.java,v 1.4 2005/02/01 10:46:54 russel Exp $
003    
004     Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
005    
006     Redistribution and use of this software and associated documentation
007     ("Software"), with or without modification, are permitted provided
008     that the following conditions are met:
009    
010     1. Redistributions of source code must retain copyright
011        statements and notices.  Redistributions must also contain a
012        copy of this document.
013    
014     2. Redistributions in binary form must reproduce the
015        above copyright notice, this list of conditions and the
016        following disclaimer in the documentation and/or other
017        materials provided with the distribution.
018    
019     3. The name "groovy" must not be used to endorse or promote
020        products derived from this Software without prior written
021        permission of The Codehaus.  For written permission,
022        please contact info@codehaus.org.
023    
024     4. Products derived from this Software may not be called "groovy"
025        nor may "groovy" appear in their names without prior written
026        permission of The Codehaus. "groovy" is a registered
027        trademark of The Codehaus.
028    
029     5. Due credit should be given to The Codehaus -
030        http://groovy.codehaus.org/
031    
032     THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
033     ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
034     NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
035     FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
036     THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
037     INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
038     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
039     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
040     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
041     STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
042     ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
043     OF THE POSSIBILITY OF SUCH DAMAGE.
044    
045     */
046    package org.codehaus.groovy.ast.expr;
047    
048    import java.util.ArrayList;
049    import java.util.Iterator;
050    import java.util.List;
051    
052    import org.codehaus.groovy.ast.ASTNode;
053    import org.codehaus.groovy.classgen.AsmClassGenerator;
054    import groovy.lang.GroovyRuntimeException;
055    
056    /**
057     * Represents a base class for expressions which evaluate as an object
058     * 
059     * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
060     * @version $Revision: 1.4 $
061     */
062    public abstract class Expression extends ASTNode {
063        protected boolean typeResolved = false;
064    
065        public boolean isResolveFailed() {
066            return resolveFailed;
067        }
068    
069        public void setResolveFailed(boolean resolveFailed) {
070            this.resolveFailed = resolveFailed;
071        }
072    
073        public String getFailure() {
074            return failure;
075        }
076    
077        public void setFailure(String failure) {
078            this.failure = failure;
079        }
080    
081        String failure = "";
082        private boolean resolveFailed = false;
083    
084        public Class getTypeClass() {
085            return typeClass;
086        }
087    
088        public void setTypeClass(Class typeClass) {
089            if (typeClass != null) {
090                this.typeClass = typeClass;
091                type = typeClass.getName();
092                setTypeResolved(true);
093            }
094        }
095    
096        public Class typeClass = null;
097    
098        public String getType() {
099            if (type != null){
100                return type;
101            } else {
102                Class cls = getTypeClass();
103                return cls != null? cls.getName() : null;//"java.lang.Object";
104            }
105        }
106    
107        /**
108         * true if the datatype can be changed, false otherwise.
109         * @return
110         */
111        public boolean isDynamic() {
112            return true;
113        }
114    
115        protected String type = null;
116        /**
117         * Return a copy of the expression calling the transformer on any nested expressions 
118         * @param transformer
119         * @return
120         */
121        public abstract Expression transformExpression(ExpressionTransformer transformer);
122        
123        /**
124         * Transforms the list of expressions
125         * @return a new list of transformed expressions
126         */
127        protected List transformExpressions(List expressions, ExpressionTransformer transformer) {
128            List list = new ArrayList(expressions.size());
129            for (Iterator iter = expressions.iterator(); iter.hasNext(); ) {
130                list.add(transformer.transform((Expression) iter.next()));
131            }
132            return list;
133        }
134    
135        public void setType(String name) {
136            if (name == null)
137                throw new GroovyRuntimeException("cannot set null on type");
138            // handle primitives first
139            if (name.equals("int")) {
140                setTypeClass(Integer.TYPE);
141                return;
142            }
143            else if (name.equals("long")) {
144                setTypeClass(Long.TYPE);
145                return;
146            }
147            else if (name.equals("short")) {
148                setTypeClass(Short.TYPE);
149                return;
150            }
151            else if (name.equals("float")) {
152                setTypeClass(Float.TYPE);
153                return;
154            }
155            else if (name.equals("double")) {
156                setTypeClass(Double.TYPE);
157                return;
158            }
159            else if (name.equals("byte")) {
160                setTypeClass(Byte.TYPE);
161                return;
162            }
163            else if (name.equals("char")) {
164                setTypeClass(Character.TYPE);
165                return;
166            }
167            else if (name.equals("boolean")) {
168                setTypeClass(Boolean.TYPE);
169                return;
170            }
171    
172            if (name.endsWith("[]")) {
173                String prefix = "[";
174                name = name.substring(0, name.length() - 2);
175    
176                if (name.equals("int")) {
177                    type = prefix + "I";
178                }
179                else if (name.equals("long")) {
180                    type = prefix + "J";
181                }
182                else if (name.equals("short")) {
183                    type = prefix + "S";
184                }
185                else if (name.equals("float")) {
186                    type = prefix + "F";
187                }
188                else if (name.equals("double")) {
189                    type = prefix + "D";
190                }
191                else if (name.equals("byte")) {
192                    type = prefix + "B";
193                }
194                else if (name.equals("char")) {
195                    type = prefix + "C";
196                }
197                else if (name.equals("boolean")) {
198                    type = prefix + "Z";
199                } else {
200                    type = prefix + "L" + name + ";";
201                }
202            }
203            else {
204                type = name;
205            }
206            if (type == null) {
207                System.out.println("Expression.setType(): null");
208                System.out.println("name = " + name);
209            }
210            try {
211                this.setTypeClass(Class.forName(type, false, this.getClass().getClassLoader()));
212            } catch (Throwable e) {
213                this.typeResolved = false;
214            }
215        }
216    
217        public boolean isTypeResolved() {
218            return typeResolved;
219        }
220    
221        public void setTypeResolved(boolean b) {
222            this.typeResolved = b;
223            this.resolveFailed = false;
224        }
225    
226        public void resolve(AsmClassGenerator cg) {
227            if (shouldContinue()) {
228                resolveType(cg);
229            }
230        }
231    
232        protected abstract void resolveType(AsmClassGenerator resolver);
233    
234        protected boolean shouldContinue() {
235            return !isResolveFailed() && !isTypeResolved();
236        }
237    
238    }