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 jdk.nashorn.internal.codegen.types.Type;
29import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
30
31/**
32 * Common superclass for all expression nodes. Expression nodes can have
33 * an associated symbol as well as a type.
34 *
35 */
36public abstract class Expression extends Node {
37    private static final long serialVersionUID = 1L;
38
39    static final String OPT_IDENTIFIER = "%";
40
41    protected Expression(final long token, final int start, final int finish) {
42        super(token, start, finish);
43    }
44
45    Expression(final long token, final int finish) {
46        super(token, finish);
47    }
48
49    Expression(final Expression expr) {
50        super(expr);
51    }
52
53    /**
54     * Returns the type of the expression.
55     *
56     * @return the type of the expression.
57     */
58    public abstract Type getType();
59
60    /**
61     * Returns {@code true} if this expression depends exclusively on state that is constant
62     * or local to the currently running function and thus inaccessible to other functions.
63     * This implies that a local expression must not call any other functions (neither directly
64     * nor implicitly through a getter, setter, or object-to-primitive type conversion).
65     *
66     * @return true if this expression does not depend on state shared with other functions.
67     */
68    public boolean isLocal() {
69        return false;
70    }
71
72    /**
73     * Is this a self modifying assignment?
74     * @return true if self modifying, e.g. a++, or a*= 17
75     */
76    public boolean isSelfModifying() {
77        return false;
78    }
79
80    /**
81     * Returns widest operation type of this operation.
82     *
83     * @return the widest type for this operation
84     */
85    public Type getWidestOperationType() {
86        return Type.OBJECT;
87    }
88
89    /**
90     * Returns true if the type of this expression is narrower than its widest operation type (thus, it is
91     * optimistically typed).
92     * @return true if this expression is optimistically typed.
93     */
94    public final boolean isOptimistic() {
95        return getType().narrowerThan(getWidestOperationType());
96    }
97
98    void optimisticTypeToString(final StringBuilder sb) {
99        optimisticTypeToString(sb, isOptimistic());
100    }
101
102    void optimisticTypeToString(final StringBuilder sb, final boolean optimistic) {
103        sb.append('{');
104        final Type type = getType();
105        final String desc = type == Type.UNDEFINED ? "U" : type.getDescriptor();
106
107        sb.append(desc.charAt(desc.length() - 1) == ';' ? "O" : desc);
108        if (isOptimistic() && optimistic) {
109            sb.append(OPT_IDENTIFIER);
110            final int pp = ((Optimistic)this).getProgramPoint();
111            if (UnwarrantedOptimismException.isValid(pp)) {
112                sb.append('_').append(pp);
113            }
114        }
115        sb.append('}');
116    }
117
118    /**
119     * Returns true if the runtime value of this expression is always false when converted to boolean as per ECMAScript
120     * ToBoolean conversion. Used in control flow calculations.
121     * @return true if this expression's runtime value converted to boolean is always false.
122     */
123    public boolean isAlwaysFalse() {
124        return false;
125    }
126
127    /**
128     * Returns true if the runtime value of this expression is always true when converted to boolean as per ECMAScript
129     * ToBoolean conversion. Used in control flow calculations.
130     * @return true if this expression's runtime value converted to boolean is always true.
131     */
132    public boolean isAlwaysTrue() {
133        return false;
134    }
135
136    /**
137     * Returns true if the expression is not null and {@link #isAlwaysFalse()}.
138     * @param test a test expression used as a predicate of a branch or a loop.
139     * @return true if the expression is not null and {@link #isAlwaysFalse()}.
140     */
141    public static boolean isAlwaysFalse(final Expression test) {
142        return test != null && test.isAlwaysFalse();
143    }
144
145
146    /**
147     * Returns true if the expression is null or {@link #isAlwaysTrue()}. Null is considered to be always true as a
148     * for loop with no test is equivalent to a for loop with always-true test.
149     * @param test a test expression used as a predicate of a branch or a loop.
150     * @return true if the expression is null or {@link #isAlwaysFalse()}.
151     */
152    public static boolean isAlwaysTrue(final Expression test) {
153        return test == null || test.isAlwaysTrue();
154    }
155}
156