Expression.java revision 953:221a84ef44c0
1/*
2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package jdk.nashorn.internal.ir;
27
28import java.util.function.Function;
29import jdk.nashorn.internal.codegen.types.Type;
30import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
31
32/**
33 * Common superclass for all expression nodes. Expression nodes can have
34 * an associated symbol as well as a type.
35 *
36 */
37public abstract class Expression extends Node {
38    static final String OPT_IDENTIFIER = "%";
39
40    private static final Function<Symbol, Type> UNKNOWN_LOCALS = new Function<Symbol, Type>() {
41        @Override
42        public Type apply(final Symbol t) {
43            return null;
44        }
45    };
46
47    Expression(final long token, final int start, final int finish) {
48        super(token, start, finish);
49    }
50
51    Expression(final long token, final int finish) {
52        super(token, finish);
53    }
54
55    Expression(final Expression expr) {
56        super(expr);
57    }
58
59    /**
60     * Returns the type of the expression.
61     *
62     * @return the type of the expression.
63     */
64    public final Type getType() {
65        return getType(UNKNOWN_LOCALS);
66    }
67
68    /**
69     * Returns the type of the expression under the specified symbol-to-type mapping. By default delegates to
70     * {@link #getType()} but expressions whose type depends on their subexpressions' types and expressions whose type
71     * depends on symbol type ({@link IdentNode}) will have a special implementation.
72     * @param localVariableTypes a mapping from symbols to their types, used for type calculation.
73     * @return the type of the expression under the specified symbol-to-type mapping.
74     */
75    public abstract Type getType(final Function<Symbol, Type> localVariableTypes);
76
77    /**
78     * Returns {@code true} if this expression depends exclusively on state that is constant
79     * or local to the currently running function and thus inaccessible to other functions.
80     * This implies that a local expression must not call any other functions (neither directly
81     * nor implicitly through a getter, setter, or object-to-primitive type conversion).
82     *
83     * @return true if this expression does not depend on state shared with other functions.
84     */
85    public boolean isLocal() {
86        return false;
87    }
88
89    /**
90     * Is this a self modifying assignment?
91     * @return true if self modifying, e.g. a++, or a*= 17
92     */
93    public boolean isSelfModifying() {
94        return false;
95    }
96
97    /**
98     * Returns widest operation type of this operation.
99     *
100     * @return the widest type for this operation
101     */
102    public Type getWidestOperationType() {
103        return Type.OBJECT;
104    }
105
106    /**
107     * Returns true if the type of this expression is narrower than its widest operation type (thus, it is
108     * optimistically typed).
109     * @return true if this expression is optimistically typed.
110     */
111    public final boolean isOptimistic() {
112        return getType().narrowerThan(getWidestOperationType());
113    }
114
115    void optimisticTypeToString(final StringBuilder sb) {
116        optimisticTypeToString(sb, isOptimistic());
117    }
118
119    void optimisticTypeToString(final StringBuilder sb, final boolean optimistic) {
120        sb.append('{');
121        final Type type = getType();
122        final String desc = type == Type.UNDEFINED ? "U" : type.getDescriptor();
123
124        sb.append(desc.charAt(desc.length() - 1) == ';' ? "O" : desc);
125        if (isOptimistic() && optimistic) {
126            sb.append(OPT_IDENTIFIER);
127            final int pp = ((Optimistic)this).getProgramPoint();
128            if (UnwarrantedOptimismException.isValid(pp)) {
129                sb.append('_').append(pp);
130            }
131        }
132        sb.append('}');
133    }
134
135    /**
136     * Returns true if the runtime value of this expression is always false when converted to boolean as per ECMAScript
137     * ToBoolean conversion. Used in control flow calculations.
138     * @return true if this expression's runtime value converted to boolean is always false.
139     */
140    public boolean isAlwaysFalse() {
141        return false;
142    }
143
144    /**
145     * Returns true if the runtime value of this expression is always true when converted to boolean as per ECMAScript
146     * ToBoolean conversion. Used in control flow calculations.
147     * @return true if this expression's runtime value converted to boolean is always true.
148     */
149    public boolean isAlwaysTrue() {
150        return false;
151    }
152
153    /**
154     * Returns true if the expression is not null and {@link #isAlwaysFalse()}.
155     * @param test a test expression used as a predicate of a branch or a loop.
156     * @return true if the expression is not null and {@link #isAlwaysFalse()}.
157     */
158    public static boolean isAlwaysFalse(final Expression test) {
159        return test != null && test.isAlwaysFalse();
160    }
161
162
163    /**
164     * Returns true if the expression is null or {@link #isAlwaysTrue()}. Null is considered to be always true as a
165     * for loop with no test is equivalent to a for loop with always-true test.
166     * @param test a test expression used as a predicate of a branch or a loop.
167     * @return true if the expression is null or {@link #isAlwaysFalse()}.
168     */
169    public static boolean isAlwaysTrue(final Expression test) {
170        return test == null || test.isAlwaysTrue();
171    }
172}
173