Expression.java revision 953:221a84ef44c0
1183873Sraj/*
2183873Sraj * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3183873Sraj * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4183873Sraj *
5183873Sraj * This code is free software; you can redistribute it and/or modify it
6183873Sraj * under the terms of the GNU General Public License version 2 only, as
7183873Sraj * published by the Free Software Foundation.  Oracle designates this
8183873Sraj * particular file as subject to the "Classpath" exception as provided
9183873Sraj * by Oracle in the LICENSE file that accompanied this code.
10191954Skuriyama *
11185478Ssam * This code is distributed in the hope that it will be useful, but WITHOUT
12183873Sraj * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13183873Sraj * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14183873Sraj * version 2 for more details (a copy is included in the LICENSE file that
15183873Sraj * accompanied this code).
16183873Sraj *
17183873Sraj * You should have received a copy of the GNU General Public License version
18183873Sraj * 2 along with this work; if not, write to the Free Software Foundation,
19183873Sraj * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20183873Sraj *
21191954Skuriyama * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22183873Sraj * or visit www.oracle.com if you need additional information or have any
23191954Skuriyama * questions.
24191954Skuriyama */
25191954Skuriyama
26191954Skuriyamapackage jdk.nashorn.internal.ir;
27183873Sraj
28191954Skuriyamaimport java.util.function.Function;
29183873Srajimport jdk.nashorn.internal.codegen.types.Type;
30183873Srajimport jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
31183873Sraj
32183873Sraj/**
33183873Sraj * Common superclass for all expression nodes. Expression nodes can have
34183873Sraj * an associated symbol as well as a type.
35191954Skuriyama *
36183873Sraj */
37183873Srajpublic abstract class Expression extends Node {
38183873Sraj    static final String OPT_IDENTIFIER = "%";
39183873Sraj
40191954Skuriyama    private static final Function<Symbol, Type> UNKNOWN_LOCALS = new Function<Symbol, Type>() {
41191954Skuriyama        @Override
42191954Skuriyama        public Type apply(final Symbol t) {
43183873Sraj            return null;
44183873Sraj        }
45191954Skuriyama    };
46183873Sraj
47183873Sraj    Expression(final long token, final int start, final int finish) {
48191954Skuriyama        super(token, start, finish);
49183873Sraj    }
50185090Sraj
51185090Sraj    Expression(final long token, final int finish) {
52183873Sraj        super(token, finish);
53183873Sraj    }
54183873Sraj
55183873Sraj    Expression(final Expression expr) {
56183873Sraj        super(expr);
57183873Sraj    }
58183873Sraj
59183873Sraj    /**
60183873Sraj     * Returns the type of the expression.
61183873Sraj     *
62183873Sraj     * @return the type of the expression.
63183873Sraj     */
64183873Sraj    public final Type getType() {
65183873Sraj        return getType(UNKNOWN_LOCALS);
66183873Sraj    }
67183873Sraj
68183873Sraj    /**
69183873Sraj     * Returns the type of the expression under the specified symbol-to-type mapping. By default delegates to
70183873Sraj     * {@link #getType()} but expressions whose type depends on their subexpressions' types and expressions whose type
71183873Sraj     * depends on symbol type ({@link IdentNode}) will have a special implementation.
72183873Sraj     * @param localVariableTypes a mapping from symbols to their types, used for type calculation.
73183873Sraj     * @return the type of the expression under the specified symbol-to-type mapping.
74183873Sraj     */
75183873Sraj    public abstract Type getType(final Function<Symbol, Type> localVariableTypes);
76183873Sraj
77183873Sraj    /**
78183873Sraj     * 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