blob: 3aa90e0faf07addc3cdf1ef2cb3ee10cc799e5d6 [file] [log] [blame]
/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.dev.js.ast;
import com.google.gwt.dev.jjs.SourceInfo;
import java.util.ArrayList;
import java.util.List;
/**
* Represents a JavaScript function expression.
*/
public final class JsFunction extends JsLiteral implements HasName {
private static void trace(String title, String code) {
System.out.println("---------------------------");
System.out.println(title + ":");
System.out.println("---------------------------");
System.out.println(code);
}
protected JsBlock body;
protected final List<JsParameter> params = new ArrayList<JsParameter>();
protected final JsScope scope;
private boolean artificiallyRescued;
private boolean executeOnce;
private boolean fromJava;
private JsFunction impliedExecute;
private JsName name;
private boolean trace = false;
private boolean traceFirst = true;
/**
* Creates an anonymous function.
*/
public JsFunction(SourceInfo sourceInfo, JsScope parent) {
this(sourceInfo, parent, null, false);
}
/**
* Creates a function that is not derived from Java source.
*/
public JsFunction(SourceInfo sourceInfo, JsScope parent, JsName name) {
this(sourceInfo, parent, name, false);
}
/**
* Creates a named function, possibly derived from Java source.
*/
public JsFunction(SourceInfo sourceInfo, JsScope parent, JsName name,
boolean fromJava) {
super(sourceInfo);
assert (parent != null);
this.fromJava = fromJava;
setName(name);
String scopeName = (name == null) ? "<anonymous>" : name.getIdent();
scopeName = "function " + scopeName;
this.scope = new JsScope(parent, scopeName);
}
public JsBlock getBody() {
return body;
}
/**
* If true, this indicates that only the first invocation of the function will
* have any effects. Subsequent invocations may be considered to be no-op
* calls whose return value is ignored.
*/
public boolean getExecuteOnce() {
return executeOnce;
}
public JsFunction getImpliedExecute() {
return impliedExecute;
}
public JsName getName() {
return name;
}
public List<JsParameter> getParameters() {
return params;
}
public JsScope getScope() {
return scope;
}
@Override
public boolean hasSideEffects() {
// If there's a name, the name is assigned to.
return name != null;
}
public boolean isArtificiallyRescued() {
return artificiallyRescued;
}
public boolean isBooleanFalse() {
return false;
}
public boolean isBooleanTrue() {
return true;
}
@Override
public boolean isDefinitelyNotNull() {
return true;
}
@Override
public boolean isDefinitelyNull() {
return false;
}
public boolean isFromJava() {
return fromJava;
}
public void setArtificiallyRescued(boolean rescued) {
this.artificiallyRescued = rescued;
}
public void setBody(JsBlock body) {
this.body = body;
}
public void setExecuteOnce(boolean executeOnce) {
this.executeOnce = executeOnce;
}
public void setFromJava(boolean fromJava) {
this.fromJava = fromJava;
}
public void setImpliedExecute(JsFunction impliedExecute) {
this.impliedExecute = impliedExecute;
}
public void setName(JsName name) {
this.name = name;
if (name != null) {
if (isFromJava()) {
name.setStaticRef(this);
}
}
}
public void setTrace() {
this.trace = true;
}
public void traverse(JsVisitor v, JsContext<JsExpression> ctx) {
String before = null;
if (trace && v instanceof JsModVisitor) {
before = this.toSource();
if (traceFirst) {
traceFirst = false;
trace("SCRIPT INITIAL", before);
}
}
if (v.visit(this, ctx)) {
v.acceptWithInsertRemove(params);
body = v.accept(body);
}
v.endVisit(this, ctx);
if (trace && v instanceof JsModVisitor) {
String after = this.toSource();
if (!after.equals(before)) {
String title = v.getClass().getSimpleName();
trace(title, after);
}
}
}
}