KJS: rename "js.dart-ast" module to "js.ast"

This commit is contained in:
Zalim Bashorov
2017-01-03 17:30:48 +03:00
parent a0491d5258
commit cb4c3ed686
94 changed files with 11 additions and 11 deletions
+5
View File
@@ -0,0 +1,5 @@
Google Dart Js backend was removed - https://code.google.com/p/dart/source/detail?r=4771
According to http://www.apache.org/legal/3party.html we can include "Google Dart Js backend" in source form, because code license is "New BSD License" (Authorized License).
This part of code will be removed when kotlin will be rewritten on kotlin.
+14
View File
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" scope="PROVIDED" name="intellij-core" level="project" />
<orderEntry type="module" module-name="frontend" />
<orderEntry type="module" module-name="util" />
</component>
</module>
@@ -0,0 +1,45 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler;
import java.io.IOException;
import java.io.Reader;
import java.net.URI;
import java.util.Date;
/**
* Abstract interface to a source file.
*/
public interface Source {
/**
* Determines whether the given source exists.
*/
boolean exists();
/**
* Returns the last-modified timestamp for this source, using the same units as
* {@link Date#getTime()}.
*/
long getLastModified();
/**
* Gets the name of this source.
*/
String getName();
/**
* Gets a reader for the dart file's source code. The caller is responsible for closing the
* returned reader.
*/
Reader getSourceReader() throws IOException;
/**
* Gets the identifier for this source. This is used to uniquely identify the
* source, but should not be used to obtain the source content. Use
* {@link #getSourceReader()} to obtain the source content.
*/
URI getUri();
}
@@ -0,0 +1,96 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js;
import com.google.dart.compiler.backend.js.ast.*;
import org.jetbrains.annotations.NotNull;
/**
* Searches for method invocations in constructor expressions that would not
* normally be surrounded by parentheses.
*/
public class JsConstructExpressionVisitor extends RecursiveJsVisitor {
public static boolean exec(JsExpression expression) {
if (JsPrecedenceVisitor.exec(expression) < JsPrecedenceVisitor.PRECEDENCE_NEW) {
return true;
}
JsConstructExpressionVisitor visitor = new JsConstructExpressionVisitor();
visitor.accept(expression);
return visitor.containsInvocation;
}
private boolean containsInvocation;
private JsConstructExpressionVisitor() {
}
/**
* We only look at the array expression since the index has its own scope.
*/
@Override
public void visitArrayAccess(@NotNull JsArrayAccess x) {
accept(x.getArrayExpression());
}
/**
* Array literals have their own scoping.
*/
@Override
public void visitArray(@NotNull JsArrayLiteral x) {
}
/**
* Functions have their own scoping.
*/
@Override
public void visitFunction(@NotNull JsFunction x) {
}
@Override
public void visitInvocation(@NotNull JsInvocation invocation) {
containsInvocation = true;
}
@Override
public void visitNameRef(@NotNull JsNameRef nameRef) {
if (!nameRef.isLeaf()) {
accept(nameRef.getQualifier());
}
}
/**
* New constructs bind to the nearest set of parentheses.
*/
@Override
public void visitNew(@NotNull JsNew x) {
}
/**
* Object literals have their own scope.
*/
@Override
public void visitObjectLiteral(@NotNull JsObjectLiteral x) {
}
/**
* We only look at nodes that would not normally be surrounded by parentheses.
*/
@Override
public <T extends JsNode> void accept(T node) {
// Assign to Object to prevent 'inconvertible types' compile errors due
// to http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6548436
// reproducible in jdk1.6.0_02.
if (node instanceof JsExpression) {
JsExpression expression = (JsExpression) node;
int precedence = JsPrecedenceVisitor.exec(expression);
// Only visit expressions that won't automatically be surrounded by
// parentheses
if (precedence < JsPrecedenceVisitor.PRECEDENCE_NEW) {
return;
}
}
super.accept(node);
}
}
@@ -0,0 +1,105 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js;
import com.google.dart.compiler.backend.js.ast.*;
import com.google.dart.compiler.backend.js.ast.JsExpressionStatement;
import org.jetbrains.annotations.NotNull;
/**
* Determines if an expression statement needs to be surrounded by parentheses.
* <p/>
* The statement or the left-most expression needs to be surrounded by
* parentheses if the left-most expression is an object literal or a function
* object. Function declarations do not need parentheses.
* <p/>
* For example the following require parentheses:<br>
* <ul>
* <li>{ key : 'value'}</li>
* <li>{ key : 'value'}.key</li>
* <li>function () {return 1;}()</li>
* <li>function () {return 1;}.prototype</li>
* </ul>
* <p/>
* The following do not require parentheses:<br>
* <ul>
* <li>var x = { key : 'value'}</li>
* <li>"string" + { key : 'value'}.key</li>
* <li>function func() {}</li>
* <li>function() {}</li>
* </ul>
*/
public class JsFirstExpressionVisitor extends RecursiveJsVisitor {
public static boolean exec(JsExpressionStatement statement) {
JsExpression expression = statement.getExpression();
// Pure function declarations do not need parentheses
if (expression instanceof JsFunction) {
return false;
}
JsFirstExpressionVisitor visitor = new JsFirstExpressionVisitor();
visitor.accept(statement.getExpression());
return visitor.needsParentheses;
}
private boolean needsParentheses = false;
private JsFirstExpressionVisitor() {
}
@Override
public void visitArrayAccess(@NotNull JsArrayAccess x) {
accept(x.getArrayExpression());
}
@Override
public void visitArray(@NotNull JsArrayLiteral x) {
}
@Override
public void visitBinaryExpression(@NotNull JsBinaryOperation x) {
accept(x.getArg1());
}
@Override
public void visitConditional(@NotNull JsConditional x) {
accept(x.getTestExpression());
}
@Override
public void visitFunction(@NotNull JsFunction x) {
needsParentheses = true;
}
@Override
public void visitInvocation(@NotNull JsInvocation invocation) {
accept(invocation.getQualifier());
}
@Override
public void visitNameRef(@NotNull JsNameRef nameRef) {
if (!nameRef.isLeaf()) {
accept(nameRef.getQualifier());
}
}
@Override
public void visitNew(@NotNull JsNew x) {
}
@Override
public void visitObjectLiteral(@NotNull JsObjectLiteral x) {
needsParentheses = true;
}
@Override
public void visitPostfixOperation(@NotNull JsPostfixOperation x) {
accept(x.getArg());
}
@Override
public void visitPrefixOperation(@NotNull JsPrefixOperation x) {
}
}
@@ -0,0 +1,152 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js;
import com.google.dart.compiler.backend.js.ast.*;
import org.jetbrains.annotations.NotNull;
/**
* Precedence indices from "JavaScript - The Definitive Guide" 4th Edition (page
* 57)
* <p/>
* Precedence 17 is for indivisible primaries that either don't have children,
* or provide their own delimiters.
* <p/>
* Precedence 16 is for really important things that have their own AST classes.
* <p/>
* Precedence 15 is for the new construct.
* <p/>
* Precedence 14 is for unary operators.
* <p/>
* Precedences 12 through 4 are for non-assigning binary operators.
* <p/>
* Precedence 3 is for the tertiary conditional.
* <p/>
* Precedence 2 is for assignments.
* <p/>
* Precedence 1 is for comma operations.
*/
class JsPrecedenceVisitor extends JsVisitor {
static final int PRECEDENCE_NEW = 15;
private int answer = -1;
private JsPrecedenceVisitor() {
}
public static int exec(JsExpression expression) {
JsPrecedenceVisitor visitor = new JsPrecedenceVisitor();
visitor.accept(expression);
if (visitor.answer < 0) {
throw new RuntimeException("Precedence must be >= 0!");
}
return visitor.answer;
}
@Override
public void visitArrayAccess(@NotNull JsArrayAccess x) {
answer = 16;
}
@Override
public void visitArray(@NotNull JsArrayLiteral x) {
answer = 17; // primary
}
@Override
public void visitBinaryExpression(@NotNull JsBinaryOperation x) {
answer = x.getOperator().getPrecedence();
}
@Override
public void visitBoolean(@NotNull JsLiteral.JsBooleanLiteral x) {
answer = 17; // primary
}
@Override
public void visitConditional(@NotNull JsConditional x) {
answer = 3;
}
@Override
public void visitFunction(@NotNull JsFunction x) {
answer = 17; // primary
}
@Override
public void visitInvocation(@NotNull JsInvocation invocation) {
answer = 16;
}
@Override
public void visitNameRef(@NotNull JsNameRef nameRef) {
if (nameRef.isLeaf()) {
answer = 17; // primary
}
else {
answer = 16; // property access
}
}
@Override
public void visitNew(@NotNull JsNew x) {
answer = PRECEDENCE_NEW;
}
@Override
public void visitNull(@NotNull JsNullLiteral x) {
answer = 17; // primary
}
@Override
public void visitInt(@NotNull JsNumberLiteral.JsIntLiteral x) {
answer = 17; // primary
}
@Override
public void visitDouble(@NotNull JsNumberLiteral.JsDoubleLiteral x) {
answer = 17; // primary
}
@Override
public void visitObjectLiteral(@NotNull JsObjectLiteral x) {
answer = 17; // primary
}
@Override
public void visitPostfixOperation(@NotNull JsPostfixOperation x) {
answer = x.getOperator().getPrecedence();
}
@Override
public void visitPrefixOperation(@NotNull JsPrefixOperation x) {
answer = x.getOperator().getPrecedence();
}
@Override
public void visitPropertyInitializer(@NotNull JsPropertyInitializer x) {
answer = 17; // primary
}
@Override
public void visitRegExp(@NotNull JsRegExp x) {
answer = 17; // primary
}
@Override
public void visitString(@NotNull JsStringLiteral x) {
answer = 17; // primary
}
@Override
public void visitThis(@NotNull JsLiteral.JsThisRef x) {
answer = 17; // primary
}
@Override
protected void visitElement(@NotNull JsNode node) {
throw new RuntimeException("Only expressions have precedence.");
}
}
@@ -0,0 +1,81 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js;
import com.google.dart.compiler.backend.js.ast.*;
import org.jetbrains.annotations.NotNull;
/**
* Determines if a statement at the end of a block requires a semicolon.
* <p/>
* For example, the following statements require semicolons:<br>
* <ul>
* <li>if (cond);</li>
* <li>while (cond);</li>
* </ul>
* <p/>
* The following do not require semicolons:<br>
* <ul>
* <li>return 1</li>
* <li>do {} while(true)</li>
* </ul>
*/
public class JsRequiresSemiVisitor extends JsVisitor {
private boolean needsSemicolon;
private JsRequiresSemiVisitor() {
}
public static boolean exec(JsStatement lastStatement) {
JsRequiresSemiVisitor visitor = new JsRequiresSemiVisitor();
visitor.accept(lastStatement);
return visitor.needsSemicolon;
}
@Override
public void visitFor(@NotNull JsFor x) {
if (x.getBody() instanceof JsEmpty) {
needsSemicolon = true;
}
}
@Override
public void visitForIn(@NotNull JsForIn x) {
if (x.getBody() instanceof JsEmpty) {
needsSemicolon = true;
}
}
@Override
public void visitIf(@NotNull JsIf x) {
JsStatement thenStmt = x.getThenStatement();
JsStatement elseStmt = x.getElseStatement();
JsStatement toCheck = thenStmt;
if (elseStmt != null) {
toCheck = elseStmt;
}
if (toCheck instanceof JsEmpty) {
needsSemicolon = true;
}
else {
// Must recurse to determine last statement (possible if-else chain).
accept(toCheck);
}
}
@Override
public void visitLabel(@NotNull JsLabel x) {
if (x.getStatement() instanceof JsEmpty) {
needsSemicolon = true;
}
}
@Override
public void visitWhile(@NotNull JsWhile x) {
if (x.getBody() instanceof JsEmpty) {
needsSemicolon = true;
}
}
}
@@ -0,0 +1,151 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js;
import gnu.trove.THashSet;
import java.util.Collections;
import java.util.Set;
/**
* Determines whether or not a particular string is a JavaScript keyword or not.
*/
public class JsReservedIdentifiers {
public static final Set<String> reservedGlobalSymbols;
static {
String[] commonBuiltins = new String[] {
// 15.1.1 Value Properties of the Global Object
"NaN", "Infinity", "undefined",
// 15.1.2 Function Properties of the Global Object
"eval", "parseInt", "parseFloat", "isNan", "isFinite",
// 15.1.3 URI Handling Function Properties
"decodeURI", "decodeURIComponent",
"encodeURI",
"encodeURIComponent",
// 15.1.4 Constructor Properties of the Global Object
"Object", "Function", "Array", "String", "Boolean", "Number", "Date",
"RegExp", "Error", "EvalError", "RangeError", "ReferenceError",
"SyntaxError", "TypeError", "URIError",
// 15.1.5 Other Properties of the Global Object
"Math",
// 10.1.6 Activation Object
"arguments",
// B.2 Additional Properties (non-normative)
"escape", "unescape",
// Window props (https://developer.mozilla.org/en/DOM/window)
"applicationCache", "closed", "Components", "content", "controllers",
"crypto", "defaultStatus", "dialogArguments", "directories",
"document", "frameElement", "frames", "fullScreen", "globalStorage",
"history", "innerHeight", "innerWidth", "length",
"location", "locationbar", "localStorage", "menubar",
"mozInnerScreenX", "mozInnerScreenY", "mozScreenPixelsPerCssPixel",
"name", "navigator", "opener", "outerHeight", "outerWidth",
"pageXOffset", "pageYOffset", "parent", "personalbar", "pkcs11",
"returnValue", "screen", "scrollbars", "scrollMaxX", "scrollMaxY",
"self", "sessionStorage", "sidebar", "status", "statusbar", "toolbar",
"top", "window",
// Window methods (https://developer.mozilla.org/en/DOM/window)
"alert", "addEventListener", "atob", "back", "blur", "btoa",
"captureEvents", "clearInterval", "clearTimeout", "close", "confirm",
"disableExternalCapture", "dispatchEvent", "dump",
"enableExternalCapture", "escape", "find", "focus", "forward",
"GeckoActiveXObject", "getAttention", "getAttentionWithCycleCount",
"getComputedStyle", "getSelection", "home", "maximize", "minimize",
"moveBy", "moveTo", "open", "openDialog", "postMessage", "print",
"prompt", "QueryInterface", "releaseEvents", "removeEventListener",
"resizeBy", "resizeTo", "restore", "routeEvent", "scroll", "scrollBy",
"scrollByLines", "scrollByPages", "scrollTo", "setInterval",
"setResizeable", "setTimeout", "showModalDialog", "sizeToContent",
"stop", "uuescape", "updateCommands", "XPCNativeWrapper",
"XPCSafeJSOjbectWrapper",
// Mozilla Window event handlers, same cite
"onabort", "onbeforeunload", "onchange", "onclick", "onclose",
"oncontextmenu", "ondragdrop", "onerror", "onfocus", "onhashchange",
"onkeydown", "onkeypress", "onkeyup", "onload", "onmousedown",
"onmousemove", "onmouseout", "onmouseover", "onmouseup",
"onmozorientation", "onpaint", "onreset", "onresize", "onscroll",
"onselect", "onsubmit", "onunload",
// Safari Web Content Guide
// http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/SafariWebContent.pdf
// WebKit Window member data, from WebKit DOM Reference
// (http://developer.apple.com/safari/library/documentation/AppleApplications/Reference/WebKitDOMRef/DOMWindow_idl/Classes/DOMWindow/index.html)
// TODO(fredsa) Many, many more functions and member data to add
"ontouchcancel", "ontouchend", "ontouchmove", "ontouchstart",
"ongesturestart", "ongesturechange", "ongestureend",
// extra window methods
"uneval",
// keywords https://developer.mozilla.org/en/New_in_JavaScript_1.7,
// https://developer.mozilla.org/en/New_in_JavaScript_1.8.1
"getPrototypeOf", "let", "yield",
// "future reserved words"
"abstract", "int", "short", "boolean", "interface", "static", "byte",
"long", "char", "final", "native", "synchronized", "float", "package",
"throws", "goto", "private", "transient", "implements", "protected",
"volatile", "double", "public",
// IE methods
// (http://msdn.microsoft.com/en-us/library/ms535873(VS.85).aspx#)
"attachEvent", "clientInformation", "clipboardData", "createPopup",
"dialogHeight", "dialogLeft", "dialogTop", "dialogWidth",
"onafterprint", "onbeforedeactivate", "onbeforeprint",
"oncontrolselect", "ondeactivate", "onhelp", "onresizeend",
// Common browser-defined identifiers not defined in ECMAScript
"event", "external", "Debug", "Enumerator", "Global", "Image",
"ActiveXObject", "VBArray", "Components",
// Functions commonly defined on Object
"toString", "getClass", "constructor", "prototype", "valueOf",
// Client-side JavaScript identifiers, which are needed for linkers
// that don't ensure GWT's window != $wnd, document != $doc, etc.
// Taken from the Rhino book, pg 715
"Anchor", "Applet", "Attr", "Canvas", "CanvasGradient",
"CanvasPattern", "CanvasRenderingContext2D", "CDATASection",
"CharacterData", "Comment", "CSS2Properties", "CSSRule",
"CSSStyleSheet", "Document", "DocumentFragment", "DocumentType",
"DOMException", "DOMImplementation", "DOMParser", "Element", "Event",
"ExternalInterface", "FlashPlayer", "Form", "Frame", "History",
"HTMLCollection", "HTMLDocument", "HTMLElement", "IFrame", "Image",
"Input", "JSObject", "KeyEvent", "Link", "Location", "MimeType",
"MouseEvent", "Navigator", "Node", "NodeList", "Option", "Plugin",
"ProcessingInstruction", "Range", "RangeException", "Screen", "Select",
"Table", "TableCell", "TableRow", "TableSelection", "Text", "TextArea",
"UIEvent", "Window", "XMLHttpRequest", "XMLSerializer",
"XPathException", "XPathResult", "XSLTProcessor",
// These keywords trigger the loading of the java-plugin. For the
// next-generation plugin, this results in starting a new Java process.
"java", "Packages", "netscape", "sun", "JavaObject", "JavaClass",
"JavaArray", "JavaMember",
// GWT-defined identifiers
"$wnd", "$doc", "$entry", "$moduleName", "$moduleBase", "$gwt_version", "$sessionId",
// Identifiers used by JsStackEmulator; later set to obfuscatable
"$stack", "$stackDepth", "$location",
};
reservedGlobalSymbols = new THashSet<String>(commonBuiltins.length);
Collections.addAll(reservedGlobalSymbols, commonBuiltins);
}
private JsReservedIdentifiers() {
}
}
@@ -0,0 +1,20 @@
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.backend.js.JsToStringGenerationVisitor;
import com.google.dart.compiler.backend.js.ast.metadata.HasMetadata;
import com.google.dart.compiler.util.TextOutputImpl;
abstract class AbstractNode extends HasMetadata implements JsNode {
@Override
public String toString() {
TextOutputImpl out = new TextOutputImpl();
new JsToStringGenerationVisitor(out).accept(this);
return out.toString();
}
protected <T extends HasMetadata> T withMetadataFrom(T other) {
this.copyMetadataFrom(other);
//noinspection unchecked
return (T) this;
}
}
@@ -0,0 +1,14 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import java.util.List;
/**
* Implemented by JavaScript objects that accept arguments.
*/
public interface HasArguments {
List<JsExpression> getArguments();
}
@@ -0,0 +1,15 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
/**
* Implemented by JavaScript objects with conditional execution.
*/
public interface HasCondition {
JsExpression getCondition();
void setCondition(JsExpression condition);
}
@@ -0,0 +1,16 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.common.HasSymbol;
/**
* Implemented by JavaScript objects that have a name.
*/
public interface HasName extends HasSymbol {
JsName getName();
void setName(JsName name);
}
@@ -0,0 +1,70 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
/**
* Represents a javascript expression for array access.
*/
public final class JsArrayAccess extends JsExpression {
private JsExpression arrayExpression;
private JsExpression indexExpression;
public JsArrayAccess() {
super();
}
public JsArrayAccess(JsExpression arrayExpression, JsExpression indexExpression) {
this.arrayExpression = arrayExpression;
this.indexExpression = indexExpression;
}
public JsExpression getArrayExpression() {
return arrayExpression;
}
public JsExpression getIndexExpression() {
return indexExpression;
}
public void setArrayExpression(JsExpression arrayExpression) {
this.arrayExpression = arrayExpression;
}
public void setIndexExpression(JsExpression indexExpression) {
this.indexExpression = indexExpression;
}
@Override
public void accept(JsVisitor v) {
v.visitArrayAccess(this);
}
@Override
public void acceptChildren(JsVisitor visitor) {
visitor.accept(arrayExpression);
visitor.accept(indexExpression);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
arrayExpression = v.accept(arrayExpression);
indexExpression = v.accept(indexExpression);
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsArrayAccess deepCopy() {
JsExpression arrayCopy = AstUtil.deepCopy(arrayExpression);
JsExpression indexCopy = AstUtil.deepCopy(indexExpression);
return new JsArrayAccess(arrayCopy, indexCopy).withMetadataFrom(this);
}
}
@@ -0,0 +1,54 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.util.AstUtil;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* Represents a JavaScript expression for array literals.
*/
public final class JsArrayLiteral extends JsLiteral {
private final List<JsExpression> expressions;
public JsArrayLiteral() {
expressions = new SmartList<JsExpression>();
}
public JsArrayLiteral(List<JsExpression> expressions) {
this.expressions = expressions;
}
public List<JsExpression> getExpressions() {
return expressions;
}
@Override
public void accept(JsVisitor v) {
v.visitArray(this);
}
@Override
public void acceptChildren(JsVisitor visitor) {
visitor.acceptWithInsertRemove(expressions);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
v.acceptList(expressions);
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsArrayLiteral deepCopy() {
return new JsArrayLiteral(AstUtil.deepCopy(expressions)).withMetadataFrom(this);
}
}
@@ -0,0 +1,79 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public final class JsBinaryOperation extends JsExpression {
private JsExpression arg1;
private JsExpression arg2;
@NotNull
private final JsBinaryOperator op;
public JsBinaryOperation(@NotNull JsBinaryOperator op, @Nullable JsExpression arg1, @Nullable JsExpression arg2) {
this.op = op;
this.arg1 = arg1;
this.arg2 = arg2;
}
public JsExpression getArg1() {
return arg1;
}
public JsExpression getArg2() {
return arg2;
}
public void setArg1(JsExpression arg1) {
this.arg1 = arg1;
}
public void setArg2(JsExpression arg2) {
this.arg2 = arg2;
}
@NotNull
public JsBinaryOperator getOperator() {
return op;
}
@Override
public void accept(JsVisitor v) {
v.visitBinaryExpression(this);
}
@Override
public void acceptChildren(JsVisitor visitor) {
if (op.isAssignment()) {
visitor.acceptLvalue(arg1);
}
else {
visitor.accept(arg1);
}
visitor.accept(arg2);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
if (op.isAssignment()) {
arg1 = v.acceptLvalue(arg1);
} else {
arg1 = v.accept(arg1);
}
arg2 = v.accept(arg2);
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsExpression deepCopy() {
return new JsBinaryOperation(op, AstUtil.deepCopy(arg1), AstUtil.deepCopy(arg2)).withMetadataFrom(this);
}
}
@@ -0,0 +1,115 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
/**
* Represents the operator in a JavaScript binary operation.
*/
public enum JsBinaryOperator implements JsOperator {
/*
* Precedence indices from "JavaScript - The Definitive Guide" 4th Edition
* (page 57)
*
*
* Precedence 15 is for really important things that have their own AST
* classes.
*
* Precedence 14 is for unary operators.
*/
MUL("*", 13, LEFT | INFIX), DIV("/", 13, LEFT | INFIX), MOD("%", 13, LEFT
| INFIX),
ADD("+", 12, LEFT | INFIX), SUB("-", 12, LEFT | INFIX),
SHL("<<", 11, LEFT | INFIX), SHR(">>", 11, LEFT | INFIX), SHRU(">>>", 11,
LEFT | INFIX),
LT("<", 10, LEFT | INFIX), LTE("<=", 10, LEFT | INFIX), GT(">", 10, LEFT
| INFIX), GTE(">=", 10, LEFT | INFIX), INSTANCEOF("instanceof", 10, LEFT
| INFIX), INOP("in", 10, LEFT | INFIX),
EQ("==", 9, LEFT | INFIX), NEQ("!=", 9, LEFT | INFIX), REF_EQ("===", 9, LEFT
| INFIX), REF_NEQ("!==", 9, LEFT | INFIX),
BIT_AND("&", 8, LEFT | INFIX),
BIT_XOR("^", 7, LEFT | INFIX),
BIT_OR("|", 6, LEFT | INFIX),
AND("&&", 5, LEFT | INFIX),
OR("||", 4, LEFT | INFIX),
// Precedence 3 is for the condition operator.
// These assignment operators are right-associative.
ASG("=", 2, INFIX), ASG_ADD("+=", 2, INFIX), ASG_SUB("-=", 2, INFIX), ASG_MUL(
"*=", 2, INFIX), ASG_DIV("/=", 2, INFIX), ASG_MOD("%=", 2, INFIX), ASG_SHL(
"<<=", 2, INFIX), ASG_SHR(">>=", 2, INFIX), ASG_SHRU(">>>=", 2, INFIX), ASG_BIT_AND(
"&=", 2, INFIX), ASG_BIT_OR("|=", 2, INFIX), ASG_BIT_XOR("^=", 2, INFIX),
COMMA(",", 1, LEFT | INFIX);
private final int mask;
private final int precedence;
private final String symbol;
private JsBinaryOperator(String symbol, int precedence, int mask) {
this.symbol = symbol;
this.precedence = precedence;
this.mask = mask;
}
@Override
public int getPrecedence() {
return precedence;
}
@Override
public String getSymbol() {
return symbol;
}
public boolean isAssignment() {
return getPrecedence() == ASG.getPrecedence();
}
@Override
public boolean isKeyword() {
return this == INSTANCEOF || this == INOP;
}
@Override
public boolean isLeftAssociative() {
return (mask & LEFT) != 0;
}
@Override
public boolean isPrecedenceLessThan(JsOperator other) {
return precedence < other.getPrecedence();
}
@Override
public boolean isValidInfix() {
return (mask & INFIX) != 0;
}
@Override
public boolean isValidPostfix() {
return (mask & POSTFIX) != 0;
}
@Override
public boolean isValidPrefix() {
return (mask & PREFIX) != 0;
}
@Override
public String toString() {
return symbol;
}
}
@@ -0,0 +1,73 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
import com.intellij.util.SmartList;
import java.util.ArrayList;
import java.util.List;
/**
* Represents a JavaScript block statement.
*/
public class JsBlock extends SourceInfoAwareJsNode implements JsStatement {
@NotNull
private final List<JsStatement> statements;
public JsBlock() {
this(new ArrayList<JsStatement>());
}
public JsBlock(JsStatement statement) {
this(new SmartList<JsStatement>(statement));
}
public JsBlock(JsStatement... statements) {
this(new SmartList<JsStatement>(statements));
}
public JsBlock(@NotNull List<JsStatement> statements) {
this.statements = statements;
}
@NotNull
public List<JsStatement> getStatements() {
return statements;
}
public boolean isEmpty() {
return statements.isEmpty();
}
public boolean isGlobalBlock() {
return false;
}
@Override
public void accept(JsVisitor v) {
v.visitBlock(this);
}
@Override
public void acceptChildren(JsVisitor visitor) {
visitor.acceptWithInsertRemove(statements);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
v.acceptStatementList(statements);
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsBlock deepCopy() {
return new JsBlock(AstUtil.deepCopy(statements)).withMetadataFrom(this);
}
}
@@ -0,0 +1,43 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
/**
* Represents the JavaScript break statement.
*/
public final class JsBreak extends JsContinue {
public JsBreak() {
super(null);
}
public JsBreak(JsNameRef label) {
super(label);
}
@Override
public void accept(JsVisitor v) {
v.visitBreak(this);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
if (label != null){
label = v.accept(label);
}
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsBreak deepCopy() {
return new JsBreak(AstUtil.deepCopy(label)).withMetadataFrom(this);
}
}
@@ -0,0 +1,57 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
/**
* Represents the JavaScript case statement.
*/
public final class JsCase extends JsSwitchMember {
private JsExpression caseExpression;
public JsCase() {
super();
}
public JsExpression getCaseExpression() {
return caseExpression;
}
public void setCaseExpression(JsExpression caseExpression) {
this.caseExpression = caseExpression;
}
@Override
public void accept(JsVisitor v) {
v.visitCase(this);
}
@Override
public void acceptChildren(JsVisitor visitor) {
visitor.accept(caseExpression);
super.acceptChildren(visitor);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
caseExpression = v.accept(caseExpression);
v.acceptStatementList(statements);
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsCase deepCopy() {
JsCase caseCopy = new JsCase();
caseCopy.caseExpression = AstUtil.deepCopy(caseExpression);
caseCopy.statements.addAll(AstUtil.deepCopy(statements));
return caseCopy.withMetadataFrom(this);
}
}
@@ -0,0 +1,105 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
/**
* Represents a JavaScript catch clause.
*/
public class JsCatch extends SourceInfoAwareJsNode implements HasCondition {
protected final JsCatchScope scope;
private JsBlock body;
private JsExpression condition;
private JsParameter param;
public JsCatch(JsScope parent, @NotNull String ident) {
super();
assert (parent != null);
scope = new JsCatchScope(parent, ident);
param = new JsParameter(scope.findName(ident));
}
public JsCatch(JsScope parent, @NotNull String ident, @NotNull JsStatement catchBody) {
this(parent, ident);
if (catchBody instanceof JsBlock) {
body = (JsBlock) catchBody;
} else {
body = new JsBlock(catchBody);
}
}
public JsBlock getBody() {
return body;
}
@Override
public JsExpression getCondition() {
return condition;
}
public JsParameter getParameter() {
return param;
}
public JsScope getScope() {
return scope;
}
public void setBody(JsBlock body) {
this.body = body;
}
@Override
public void setCondition(JsExpression condition) {
this.condition = condition;
}
@Override
public void accept(JsVisitor v) {
v.visitCatch(this);
}
@Override
public void acceptChildren(JsVisitor visitor) {
visitor.accept(param);
if (condition != null) {
visitor.accept(condition);
}
visitor.accept(body);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
param = v.accept(param);
if (condition != null) {
condition = v.accept(condition);
}
body = v.acceptStatement(body);
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsCatch deepCopy() {
JsCatchScope scopeCopy = scope.copy();
JsBlock bodyCopy = AstUtil.deepCopy(body);
JsExpression conditionCopy = AstUtil.deepCopy(condition);
JsParameter paramCopy = AstUtil.deepCopy(param);
return new JsCatch(scopeCopy, bodyCopy, conditionCopy, paramCopy).withMetadataFrom(this);
}
private JsCatch(JsCatchScope scope, JsBlock body, JsExpression condition, JsParameter param) {
this.scope = scope;
this.body = body;
this.condition = condition;
this.param = param;
}
}
@@ -0,0 +1,42 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import org.jetbrains.annotations.NotNull;
/**
* A special scope used only for catch blocks. It only holds a single symbol:
* the catch argument's name.
*/
public class JsCatchScope extends JsScope {
private final JsName name;
public JsCatchScope(JsScope parent, @NotNull String ident) {
super(parent, "Catch scope");
name = new JsName(this, ident, false);
}
@Override
@NotNull
public JsName declareName(@NotNull String identifier) {
// Declare into parent scope!
return getParent().declareName(identifier);
}
@Override
public boolean hasOwnName(@NotNull String name) {
return findOwnName(name) != null;
}
@NotNull
public JsCatchScope copy() {
return new JsCatchScope(getParent(), name.getIdent());
}
@Override
protected JsName findOwnName(@NotNull String ident) {
return name.getIdent().equals(ident) ? name : null;
}
}
@@ -0,0 +1,79 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
public final class JsConditional extends JsExpression {
private JsExpression testExpression;
private JsExpression elseExpression;
private JsExpression thenExpression;
public JsConditional() {
}
public JsConditional(JsExpression testExpression, JsExpression thenExpression, JsExpression elseExpression) {
this.testExpression = testExpression;
this.thenExpression = thenExpression;
this.elseExpression = elseExpression;
}
public JsExpression getElseExpression() {
return elseExpression;
}
public JsExpression getTestExpression() {
return testExpression;
}
public JsExpression getThenExpression() {
return thenExpression;
}
public void setElseExpression(JsExpression elseExpression) {
this.elseExpression = elseExpression;
}
public void setTestExpression(JsExpression testExpression) {
this.testExpression = testExpression;
}
public void setThenExpression(JsExpression thenExpression) {
this.thenExpression = thenExpression;
}
@Override
public void accept(JsVisitor v) {
v.visitConditional(this);
}
@Override
public void acceptChildren(JsVisitor visitor) {
visitor.accept(testExpression);
visitor.accept(thenExpression);
visitor.accept(elseExpression);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
testExpression = v.accept(testExpression);
thenExpression = v.accept(thenExpression);
elseExpression = v.accept(elseExpression);
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsConditional deepCopy() {
JsExpression testCopy = AstUtil.deepCopy(testExpression);
JsExpression thenCopy = AstUtil.deepCopy(thenExpression);
JsExpression elseCopy = AstUtil.deepCopy(elseExpression);
return new JsConditional(testCopy, thenCopy, elseCopy).withMetadataFrom(this);
}
}
@@ -0,0 +1,38 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import org.jetbrains.annotations.Nullable;
import java.util.List;
/**
* The context in which a JsNode visitation occurs. This represents the set of
* possible operations a JsVisitor subclass can perform on the currently visited
* node.
*/
public abstract class JsContext<T extends JsNode> {
public <R extends T> void addPrevious(R node) {
throw new UnsupportedOperationException();
}
public <R extends T> void addPrevious(List<R> nodes) {
for (R node : nodes) {
addPrevious(node);
}
}
public <R extends T> void addNext(R node) {
throw new UnsupportedOperationException();
}
public abstract void removeMe();
public abstract <R extends T> void replaceMe(R node);
@Nullable
public abstract T getCurrentNode();
}
@@ -0,0 +1,57 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class JsContinue extends SourceInfoAwareJsNode implements JsStatement {
protected JsNameRef label;
public JsContinue() {
this(null);
}
public JsContinue(@Nullable JsNameRef label) {
super();
this.label = label;
}
public JsNameRef getLabel() {
return label;
}
@Override
public void accept(JsVisitor v) {
v.visitContinue(this);
}
@Override
public void acceptChildren(JsVisitor v) {
if (label != null){
v.accept(label);
}
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
if (label != null){
label = v.accept(label);
}
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsContinue deepCopy() {
if (label == null) return new JsContinue();
return new JsContinue(AstUtil.deepCopy(label)).withMetadataFrom(this);
}
}
@@ -0,0 +1,37 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import org.jetbrains.annotations.NotNull;
/**
* Represents a JavaScript debugger statement.
*/
public class JsDebugger extends SourceInfoAwareJsNode implements JsStatement {
public JsDebugger() {
}
@Override
public void accept(JsVisitor v) {
v.visitDebugger(this);
}
@Override
public void acceptChildren(JsVisitor visitor) {
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
v.visit(this, ctx);
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsDebugger deepCopy() {
return this;
}
}
@@ -0,0 +1,34 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
/**
* Represents the default option in a JavaScript swtich statement.
*/
public final class JsDefault extends JsSwitchMember {
@Override
public void accept(JsVisitor v) {
v.visitDefault(this);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
v.acceptStatementList(statements);
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsDefault deepCopy() {
JsDefault defaultCopy = new JsDefault();
defaultCopy.statements.addAll(AstUtil.deepCopy(statements));
return defaultCopy.withMetadataFrom(this);
}
}
@@ -0,0 +1,43 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
/**
* Represents a JavaScript do..while statement.
*/
public class JsDoWhile extends JsWhile {
public JsDoWhile() {
}
public JsDoWhile(JsExpression condition, JsStatement body) {
super(condition, body);
}
@Override
public void accept(JsVisitor v) {
v.visitDoWhile(this);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
body = v.acceptStatement(body);
condition = v.accept(condition);
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsDoWhile deepCopy() {
JsExpression conditionCopy = AstUtil.deepCopy(condition);
JsStatement bodyCopy = AstUtil.deepCopy(body);
return new JsDoWhile(conditionCopy, bodyCopy).withMetadataFrom(this);
}
}
@@ -0,0 +1,41 @@
package com.google.dart.compiler.backend.js.ast;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.Map;
public class JsDocComment extends JsExpression {
private final Map<String, Object> tags;
public JsDocComment(Map<String, Object> tags) {
this.tags = tags;
}
public Map<String, Object> getTags() {
return tags;
}
public JsDocComment(String tagName, JsNameRef tagValue) {
tags = Collections.<String, Object>singletonMap(tagName, tagValue);
}
public JsDocComment(String tagName, String tagValue) {
tags = Collections.<String, Object>singletonMap(tagName, tagValue);
}
@Override
public void accept(JsVisitor v) {
v.visitDocComment(this);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
}
@NotNull
@Override
public JsDocComment deepCopy() {
return new JsDocComment(tags).withMetadataFrom(this);
}
}
@@ -0,0 +1,21 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast
object JsEmpty : SourceInfoAwareJsNode(), JsStatement {
override fun accept(v: JsVisitor) {
v.visitEmpty(this)
}
override fun traverse(v: JsVisitorWithContext, ctx: JsContext<*>) {
v.visit(this, ctx)
v.endVisit(this, ctx)
}
override fun deepCopy(): JsEmpty {
return this
}
}
@@ -0,0 +1,50 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public abstract class JsExpression extends SourceInfoAwareJsNode {
/**
* Determines whether or not this expression is a leaf, such as a
* {@link JsNameRef}, {@link JsLiteral.JsBooleanLiteral}, and so on. Leaf expressions
* never need to be parenthesized.
*/
public boolean isLeaf() {
// Conservatively say that it isn't a leaf.
// Individual subclasses can speak for themselves if they are a leaf.
return false;
}
@NotNull
public JsStatement makeStmt() {
return new JsExpressionStatement(this);
}
protected abstract static class JsExpressionHasArguments extends JsExpression implements HasArguments {
protected final List<JsExpression> arguments;
public JsExpressionHasArguments(List<JsExpression> arguments) {
this.arguments = arguments;
}
@Override
public List<JsExpression> getArguments() {
return arguments;
}
}
@Override
public JsExpression source(Object info) {
setSource(info);
return this;
}
@NotNull
@Override
public abstract JsExpression deepCopy();
}
@@ -0,0 +1,60 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import org.jetbrains.annotations.NotNull;
public final class JsExpressionStatement extends AbstractNode implements JsStatement {
@NotNull
private JsExpression expression;
public JsExpressionStatement(@NotNull JsExpression expression) {
this.expression = expression;
}
@NotNull
public JsExpression getExpression() {
return expression;
}
@Override
public void accept(JsVisitor v) {
v.visitExpressionStatement(this);
}
@Override
public void acceptChildren(JsVisitor visitor) {
visitor.accept(expression);
}
@Override
public Object getSource() {
return null;
}
@Override
public void setSource(Object info) {
throw new IllegalStateException("You must not set source info for JsExpressionStatement, set for expression");
}
@Override
public JsNode source(Object info) {
throw new IllegalStateException("You must not set source info for JsExpressionStatement, set for expression");
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
expression = v.accept(expression);
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsExpressionStatement deepCopy() {
return new JsExpressionStatement(expression.deepCopy()).withMetadataFrom(this);
}
}
@@ -0,0 +1,152 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
/**
* A <code>for</code> statement. If specified at all, the initializer part is
* either a declaration of one or more variables, in which case
* {@link #getInitVars()} is used, or an expression, in which case
* {@link #getInitExpression()} is used. In the latter case, the comma operator is
* often used to create a compound expression.
* <p/>
* <p/>
* Note that any of the parts of the <code>for</code> loop header can be
* <code>null</code>, although the body will never be null.
*/
public class JsFor extends SourceInfoAwareJsNode implements JsStatement {
private JsStatement body;
private JsExpression condition;
private JsExpression incrementExpression;
private JsExpression initExpression;
private JsVars initVars;
public JsFor(JsVars initVars, JsExpression condition, JsExpression incrementExpression) {
this(initVars, condition, incrementExpression, null);
}
public JsFor(JsVars initVars, JsExpression condition, JsExpression incrementExpression, JsStatement body) {
this.initVars = initVars;
this.incrementExpression = incrementExpression;
this.condition = condition;
this.body = body;
initExpression = null;
}
public JsFor(JsExpression initExpression, JsExpression condition, JsExpression incrementExpression) {
this(initExpression, condition, incrementExpression, null);
}
public JsFor(JsExpression initExpression, JsExpression condition, JsExpression incrementExpression, JsStatement body) {
this.initExpression = initExpression;
this.incrementExpression = incrementExpression;
this.condition = condition;
this.body = body;
initVars = null;
}
public JsStatement getBody() {
return body;
}
public JsExpression getCondition() {
return condition;
}
public JsExpression getIncrementExpression() {
return incrementExpression;
}
public JsExpression getInitExpression() {
return initExpression;
}
public JsVars getInitVars() {
return initVars;
}
public void setBody(JsStatement body) {
this.body = body;
}
@Override
public void accept(JsVisitor v) {
v.visitFor(this);
}
@Override
public void acceptChildren(JsVisitor visitor) {
assert (!(initExpression != null && initVars != null));
if (initExpression != null) {
visitor.accept(initExpression);
}
else if (initVars != null) {
visitor.accept(initVars);
}
if (condition != null) {
visitor.accept(condition);
}
if (incrementExpression != null) {
visitor.accept(incrementExpression);
}
visitor.accept(body);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
assert (!(initExpression != null && initVars != null));
if (initExpression != null) {
initExpression = v.accept(initExpression);
} else if (initVars != null) {
JsStatement newInitVars = v.<JsStatement>acceptStatement(initVars);
if (newInitVars instanceof JsVars) {
initVars = (JsVars) newInitVars;
}
else {
initVars = null;
if (newInitVars instanceof JsExpressionStatement) {
initExpression = ((JsExpressionStatement) newInitVars).getExpression();
} else if (newInitVars != null) {
ctx.addPrevious(newInitVars);
}
}
}
if (condition != null) {
condition = v.accept(condition);
}
if (incrementExpression != null) {
incrementExpression = v.accept(incrementExpression);
}
body = v.acceptStatement(body);
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsFor deepCopy() {
JsStatement bodyCopy = AstUtil.deepCopy(body);
JsExpression conditionCopy = AstUtil.deepCopy(condition);
JsExpression incrementalExprCopy = AstUtil.deepCopy(incrementExpression);
JsFor result;
if (initVars != null) {
result = new JsFor(initVars.deepCopy(), conditionCopy, incrementalExprCopy, bodyCopy);
} else {
result = new JsFor(initExpression.deepCopy(), conditionCopy, incrementalExprCopy, bodyCopy);
}
return result.withMetadataFrom(this);
}
}
@@ -0,0 +1,97 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
public class JsForIn extends SourceInfoAwareJsNode implements JsStatement {
private JsStatement body;
private JsExpression iterExpression;
private JsExpression objectExpression;
// Optional: the name of a new iterator variable to introduce
private final JsName iterVarName;
public JsForIn() {
this(null);
}
public JsForIn(JsName iterVarName) {
this.iterVarName = iterVarName;
}
public JsForIn(JsName iterVarName, JsExpression iterExpression, JsExpression objectExpression, JsStatement body) {
this.iterVarName = iterVarName;
this.iterExpression = iterExpression;
this.objectExpression = objectExpression;
this.body = body;
}
public JsStatement getBody() {
return body;
}
public JsExpression getIterExpression() {
return iterExpression;
}
public JsName getIterVarName() {
return iterVarName;
}
public JsExpression getObjectExpression() {
return objectExpression;
}
public void setBody(JsStatement body) {
this.body = body;
}
public void setIterExpression(JsExpression iterExpression) {
this.iterExpression = iterExpression;
}
public void setObjectExpression(JsExpression objectExpression) {
this.objectExpression = objectExpression;
}
@Override
public void accept(JsVisitor v) {
v.visitForIn(this);
}
@Override
public void acceptChildren(JsVisitor visitor) {
if (iterExpression != null) {
visitor.acceptLvalue(iterExpression);
}
visitor.accept(objectExpression);
visitor.accept(body);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
if (iterExpression != null) {
iterExpression = v.acceptLvalue(iterExpression);
}
objectExpression = v.accept(objectExpression);
body = v.acceptStatement(body);
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsForIn deepCopy() {
JsStatement bodyCopy = AstUtil.deepCopy(body);
JsExpression iterCopy = AstUtil.deepCopy(iterExpression);
JsExpression objectCopy = AstUtil.deepCopy(objectExpression);
return new JsForIn(iterVarName, iterCopy, objectCopy, bodyCopy).withMetadataFrom(this);
}
}
@@ -0,0 +1,104 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.common.Symbol;
import com.google.dart.compiler.util.AstUtil;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public final class JsFunction extends JsLiteral implements HasName {
@NotNull
private JsBlock body;
private List<JsParameter> params;
@NotNull
private final JsFunctionScope scope;
private JsName name;
public JsFunction(@NotNull JsScope parentScope, @NotNull String description) {
this(parentScope, description, null);
}
public JsFunction(@NotNull JsScope parentScope, @NotNull JsBlock body, @NotNull String description) {
this(parentScope, description, null);
this.body = body;
}
private JsFunction(@NotNull JsScope parentScope, @NotNull String description, @Nullable JsName name) {
this.name = name;
scope = new JsFunctionScope(parentScope, name == null ? description : name.getIdent());
}
@NotNull
public JsBlock getBody() {
return body;
}
@Override
public JsName getName() {
return name;
}
@Override
public Symbol getSymbol() {
return name;
}
@NotNull
public List<JsParameter> getParameters() {
if (params == null) {
params = new SmartList<JsParameter>();
}
return params;
}
@NotNull
public JsFunctionScope getScope() {
return scope;
}
public void setBody(@NotNull JsBlock body) {
this.body = body;
}
@Override
public void setName(@Nullable JsName name) {
this.name = name;
}
@Override
public void accept(JsVisitor v) {
v.visitFunction(this);
}
@Override
public void acceptChildren(JsVisitor visitor) {
visitor.acceptWithInsertRemove(getParameters());
visitor.accept(body);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
v.acceptList(getParameters());
body = v.acceptStatement(body);
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsFunction deepCopy() {
JsFunction functionCopy = new JsFunction(scope.getParent(), scope.getDescription(), name);
functionCopy.getScope().copyOwnNames(scope);
functionCopy.setBody(body.deepCopy());
functionCopy.params = AstUtil.deepCopy(params);
return functionCopy.withMetadataFrom(this);
}
}
@@ -0,0 +1,33 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* Represents a JavaScript block in the global scope.
*/
public class JsGlobalBlock extends JsBlock {
public JsGlobalBlock() {
}
@Override
public boolean isGlobalBlock() {
return true;
}
@NotNull
@Override
public JsGlobalBlock deepCopy() {
JsGlobalBlock globalBlockCopy = new JsGlobalBlock();
List<JsStatement> statementscopy = AstUtil.deepCopy(getStatements());
globalBlockCopy.getStatements().addAll(statementscopy);
return globalBlockCopy.withMetadataFrom(this);
}
}
@@ -0,0 +1,96 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Represents a JavaScript if statement.
*/
public final class JsIf extends SourceInfoAwareJsNode implements JsStatement {
@NotNull
private JsExpression ifExpression;
@NotNull
private JsStatement thenStatement;
@Nullable
private JsStatement elseStatement;
public JsIf(@NotNull JsExpression ifExpression, @NotNull JsStatement thenStatement, @Nullable JsStatement elseStatement) {
this.ifExpression = ifExpression;
this.thenStatement = thenStatement;
this.elseStatement = elseStatement;
}
public JsIf(@NotNull JsExpression ifExpression, @NotNull JsStatement thenStatement) {
this(ifExpression, thenStatement, null);
}
@Nullable
public JsStatement getElseStatement() {
return elseStatement;
}
@NotNull
public JsExpression getIfExpression() {
return ifExpression;
}
@NotNull
public JsStatement getThenStatement() {
return thenStatement;
}
public void setElseStatement(@Nullable JsStatement elseStatement) {
this.elseStatement = elseStatement;
}
public void setIfExpression(@NotNull JsExpression ifExpression) {
this.ifExpression = ifExpression;
}
public void setThenStatement(@NotNull JsStatement thenStatement) {
this.thenStatement = thenStatement;
}
@Override
public void accept(JsVisitor v) {
v.visitIf(this);
}
@Override
public void acceptChildren(JsVisitor visitor) {
visitor.accept(ifExpression);
visitor.accept(thenStatement);
if (elseStatement != null) {
visitor.accept(elseStatement);
}
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
ifExpression = v.accept(ifExpression);
thenStatement = v.acceptStatement(thenStatement);
if (elseStatement != null) {
elseStatement = v.acceptStatement(elseStatement);
}
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsIf deepCopy() {
JsExpression ifCopy = AstUtil.deepCopy(ifExpression);
JsStatement thenCopy = AstUtil.deepCopy(thenStatement);
JsStatement elseCopy = AstUtil.deepCopy(elseStatement);
return new JsIf(ifCopy, thenCopy, elseCopy).withMetadataFrom(this);
}
}
@@ -0,0 +1,68 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.util.AstUtil;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public final class JsInvocation extends JsExpression.JsExpressionHasArguments {
@NotNull
private JsExpression qualifier;
public JsInvocation(@NotNull JsExpression qualifier, @NotNull List<JsExpression> arguments) {
super(arguments);
this.qualifier = qualifier;
}
public JsInvocation(@NotNull JsExpression qualifier, JsExpression... arguments) {
this(qualifier, new SmartList<JsExpression>(arguments));
}
@NotNull
@Override
public List<JsExpression> getArguments() {
return arguments;
}
@NotNull
public JsExpression getQualifier() {
return qualifier;
}
public void setQualifier(@NotNull JsExpression qualifier) {
this.qualifier = qualifier;
}
@Override
public void accept(JsVisitor v) {
v.visitInvocation(this);
}
@Override
public void acceptChildren(JsVisitor visitor) {
visitor.accept(qualifier);
visitor.acceptList(arguments);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
qualifier = v.accept(qualifier);
v.acceptList(arguments);
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsInvocation deepCopy() {
JsExpression qualifierCopy = AstUtil.deepCopy(qualifier);
List<JsExpression> argumentsCopy = AstUtil.deepCopy(arguments);
return new JsInvocation(qualifierCopy, argumentsCopy).withMetadataFrom(this);
}
}
@@ -0,0 +1,74 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.common.Symbol;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
/**
* Represents a JavaScript label statement.
*/
public class JsLabel extends SourceInfoAwareJsNode implements JsStatement, HasName {
private JsName label;
private JsStatement statement;
public JsLabel(JsName label) {
this.label = label;
}
public JsLabel(JsName label, JsStatement statement) {
this.label = label;
this.statement = statement;
}
@Override
public JsName getName() {
return label;
}
@Override
public void setName(JsName name) {
label = name;
}
@Override
public Symbol getSymbol() {
return label;
}
public JsStatement getStatement() {
return statement;
}
public void setStatement(JsStatement statement) {
this.statement = statement;
}
@Override
public void accept(JsVisitor v) {
v.visitLabel(this);
}
@Override
public void acceptChildren(JsVisitor visitor) {
visitor.accept(statement);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
statement = v.acceptStatement(statement);
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsLabel deepCopy() {
return new JsLabel(label, AstUtil.deepCopy(statement.deepCopy())).withMetadataFrom(this);
}
}
@@ -0,0 +1,81 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import org.jetbrains.annotations.NotNull;
public abstract class JsLiteral extends JsExpression {
public static final JsValueLiteral THIS = new JsThisRef();
public static final JsNameRef UNDEFINED = new JsNameRef("undefined");
public static final JsNullLiteral NULL = new JsNullLiteral();
public static final JsBooleanLiteral TRUE = new JsBooleanLiteral(true);
public static final JsBooleanLiteral FALSE = new JsBooleanLiteral(false);
public static JsBooleanLiteral getBoolean(boolean truth) {
return truth ? TRUE : FALSE;
}
public static final class JsThisRef extends JsValueLiteral {
private JsThisRef() {
super();
}
@Override
public void accept(JsVisitor v) {
v.visitThis(this);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
v.visit(this, ctx);
v.endVisit(this, ctx);
}
}
public static final class JsBooleanLiteral extends JsValueLiteral {
private final boolean value;
// Should be interned by JsProgram
private JsBooleanLiteral(boolean value) {
this.value = value;
}
public boolean getValue() {
return value;
}
@Override
public void accept(JsVisitor v) {
v.visitBoolean(this);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
v.visit(this, ctx);
v.endVisit(this, ctx);
}
}
/**
* A JavaScript string literal expression.
*/
public abstract static class JsValueLiteral extends JsLiteral {
protected JsValueLiteral() {
}
@Override
public final boolean isLeaf() {
return true;
}
@NotNull
@Override
public JsExpression deepCopy() {
return this;
}
}
}
@@ -0,0 +1,60 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.backend.js.ast.metadata.HasMetadata;
import com.google.dart.compiler.common.Symbol;
import org.jetbrains.annotations.NotNull;
/**
* An abstract base class for named JavaScript objects.
*/
public class JsName extends HasMetadata implements Symbol {
private static int ordinalGenerator;
private final JsScope enclosing;
private final int ordinal;
@NotNull
private final String ident;
private final boolean temporary;
/**
* @param ident the unmangled ident to use for this name
*/
JsName(JsScope enclosing, @NotNull String ident, boolean temporary) {
this.enclosing = enclosing;
this.ident = ident;
this.temporary = temporary;
ordinal = temporary ? ordinalGenerator++ : 0;
}
public int getOrdinal() {
return ordinal;
}
public JsScope getEnclosing() {
return enclosing;
}
public boolean isTemporary() {
return temporary;
}
@NotNull
public String getIdent() {
return ident;
}
@NotNull
public JsNameRef makeRef() {
return new JsNameRef(this);
}
@Override
public String toString() {
return ident;
}
}
@@ -0,0 +1,114 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.common.Symbol;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Represents a JavaScript expression that references a name.
*/
public final class JsNameRef extends JsExpression implements HasName {
private String ident;
private JsName name;
private JsExpression qualifier;
public JsNameRef(@NotNull JsName name) {
this.name = name;
}
public JsNameRef(@NotNull String ident) {
this.ident = ident;
}
public JsNameRef(@NotNull String ident, JsExpression qualifier) {
this.ident = ident;
this.qualifier = qualifier;
}
public JsNameRef(@NotNull String ident, @NotNull String qualifier) {
this(ident, new JsNameRef(qualifier));
}
public JsNameRef(@NotNull JsName name, JsExpression qualifier) {
this.name = name;
this.qualifier = qualifier;
}
@NotNull
public String getIdent() {
return (name == null) ? ident : name.getIdent();
}
@Nullable
@Override
public JsName getName() {
return name;
}
@Override
public void setName(JsName name) {
this.name = name;
}
@Nullable
@Override
public Symbol getSymbol() {
return name;
}
@Nullable
public JsExpression getQualifier() {
return qualifier;
}
@Override
public boolean isLeaf() {
return qualifier == null;
}
public void resolve(JsName name) {
this.name = name;
ident = null;
}
public void setQualifier(JsExpression qualifier) {
this.qualifier = qualifier;
}
@Override
public void accept(JsVisitor v) {
v.visitNameRef(this);
}
@Override
public void acceptChildren(JsVisitor visitor) {
if (qualifier != null) {
visitor.accept(qualifier);
}
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
if (qualifier != null) {
qualifier = v.accept(qualifier);
}
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsNameRef deepCopy() {
JsExpression qualifierCopy = AstUtil.deepCopy(qualifier);
if (name != null) return new JsNameRef(name, qualifierCopy).withMetadataFrom(this);
return new JsNameRef(ident, qualifierCopy).withMetadataFrom(this);
}
}
@@ -0,0 +1,60 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.util.AstUtil;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public final class JsNew extends JsExpression.JsExpressionHasArguments {
private JsExpression constructorExpression;
public JsNew(JsExpression constructorExpression) {
this(constructorExpression, new SmartList<JsExpression>());
}
public JsNew(JsExpression constructorExpression, List<JsExpression> arguments) {
super(arguments);
this.constructorExpression = constructorExpression;
}
public JsExpression getConstructorExpression() {
return constructorExpression;
}
public void setConstructorExpression(JsExpression constructorExpression) {
this.constructorExpression = constructorExpression;
}
@Override
public void accept(JsVisitor v) {
v.visitNew(this);
}
@Override
public void acceptChildren(JsVisitor visitor) {
visitor.accept(constructorExpression);
visitor.acceptList(arguments);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
constructorExpression = v.accept(constructorExpression);
v.acceptList(arguments);
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsNew deepCopy() {
JsExpression constructorCopy = AstUtil.deepCopy(constructorExpression);
List<JsExpression> argumentsCopy = AstUtil.deepCopy(arguments);
return new JsNew(constructorCopy, argumentsCopy).withMetadataFrom(this);
}
}
@@ -0,0 +1,43 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import org.jetbrains.annotations.NotNull;
public interface JsNode {
/**
* Causes this object to have the visitor visit itself and its children.
*
* @param visitor the visitor that should traverse this node
*/
void accept(JsVisitor visitor);
void acceptChildren(JsVisitor visitor);
/**
* Return the source info associated with this object.
*/
Object getSource();
/**
* Set the source info associated with this object.
*
* @param info
*/
void setSource(Object info);
JsNode source(Object info);
@NotNull
JsNode deepCopy();
/**
* Causes this object to have the visitor visit itself and its children.
*
* @param visitor the visitor that should traverse this node
* @param ctx the context of an existing traversal
*/
void traverse(JsVisitorWithContext visitor, JsContext ctx);
}
@@ -0,0 +1,21 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
public final class JsNullLiteral extends JsLiteral.JsValueLiteral {
JsNullLiteral() {
}
@Override
public void accept(JsVisitor v) {
v.visitNull(this);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
v.visit(this, ctx);
v.endVisit(this, ctx);
}
}
@@ -0,0 +1,55 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
public abstract class JsNumberLiteral extends JsLiteral.JsValueLiteral {
public static final JsIntLiteral ZERO = new JsIntLiteral(0);
public static final class JsDoubleLiteral extends JsNumberLiteral {
public final double value;
JsDoubleLiteral(double value) {
this.value = value;
}
@Override
public void accept(JsVisitor v) {
v.visitDouble(this);
}
public String toString() {
return String.valueOf(value);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
v.visit(this, ctx);
v.endVisit(this, ctx);
}
}
public static final class JsIntLiteral extends JsNumberLiteral {
public final int value;
JsIntLiteral(int value) {
this.value = value;
}
@Override
public void accept(JsVisitor v) {
v.visitInt(this);
}
public String toString() {
return String.valueOf(value);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
v.visit(this, ctx);
v.endVisit(this, ctx);
}
}
}
@@ -0,0 +1,66 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.util.AstUtil;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public final class JsObjectLiteral extends JsLiteral {
private final List<JsPropertyInitializer> properties;
private final boolean multiline;
public JsObjectLiteral() {
this(new SmartList<JsPropertyInitializer>());
}
public JsObjectLiteral(boolean multiline) {
this(new SmartList<JsPropertyInitializer>(), multiline);
}
public boolean isMultiline() {
return multiline;
}
public JsObjectLiteral(List<JsPropertyInitializer> properties) {
this(properties, false);
}
public JsObjectLiteral(List<JsPropertyInitializer> properties, boolean multiline) {
this.properties = properties;
this.multiline = multiline;
}
public List<JsPropertyInitializer> getPropertyInitializers() {
return properties;
}
@Override
public void accept(JsVisitor v) {
v.visitObjectLiteral(this);
}
@Override
public void acceptChildren(JsVisitor visitor) {
visitor.acceptWithInsertRemove(properties);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
v.acceptList(properties);
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsObjectLiteral deepCopy() {
return new JsObjectLiteral(AstUtil.deepCopy(properties), multiline).withMetadataFrom(this);
}
}
@@ -0,0 +1,28 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
public interface JsOperator {
int INFIX = 0x02;
int LEFT = 0x01;
int POSTFIX = 0x04;
int PREFIX = 0x08;
int getPrecedence();
String getSymbol();
boolean isKeyword();
boolean isLeftAssociative();
boolean isPrecedenceLessThan(JsOperator other);
boolean isValidInfix();
boolean isValidPostfix();
boolean isValidPrefix();
}
@@ -0,0 +1,54 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.common.Symbol;
import org.jetbrains.annotations.NotNull;
/**
* A JavaScript parameter.
*/
public final class JsParameter extends SourceInfoAwareJsNode implements HasName {
@NotNull
private JsName name;
public JsParameter(@NotNull JsName name) {
this.name = name;
}
@Override
@NotNull
public JsName getName() {
return name;
}
@Override
public void setName(@NotNull JsName name) {
this.name = name;
}
@Override
@NotNull
public Symbol getSymbol() {
return name;
}
@Override
public void accept(JsVisitor v) {
v.visitParameter(this);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
v.visit(this, ctx);
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsParameter deepCopy() {
return new JsParameter(name).withMetadataFrom(this);
}
}
@@ -0,0 +1,33 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
public final class JsPostfixOperation extends JsUnaryOperation {
public JsPostfixOperation(JsUnaryOperator op, JsExpression arg) {
super(op, arg);
}
@Override
public void accept(JsVisitor v) {
v.visitPostfixOperation(this);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
super.traverse(v, ctx);
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsPostfixOperation deepCopy() {
return new JsPostfixOperation(getOperator(), AstUtil.deepCopy(getArg())).withMetadataFrom(this);
}
}
@@ -0,0 +1,33 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
public final class JsPrefixOperation extends JsUnaryOperation {
public JsPrefixOperation(JsUnaryOperator op, JsExpression arg) {
super(op, arg);
}
@Override
public void accept(JsVisitor v) {
v.visitPrefixOperation(this);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
super.traverse(v, ctx);
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsPrefixOperation deepCopy() {
return new JsPrefixOperation(getOperator(), AstUtil.deepCopy(getArg())).withMetadataFrom(this);
}
}
@@ -0,0 +1,132 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import gnu.trove.TDoubleObjectHashMap;
import gnu.trove.THashMap;
import gnu.trove.TIntObjectHashMap;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
import static com.google.dart.compiler.backend.js.ast.JsNumberLiteral.JsDoubleLiteral;
import static com.google.dart.compiler.backend.js.ast.JsNumberLiteral.JsIntLiteral;
/**
* A JavaScript program.
*/
public final class JsProgram extends SourceInfoAwareJsNode {
private JsProgramFragment[] fragments;
private final TDoubleObjectHashMap<JsDoubleLiteral> doubleLiteralMap = new TDoubleObjectHashMap<JsDoubleLiteral>();
private final TIntObjectHashMap<JsIntLiteral> intLiteralMap = new TIntObjectHashMap<JsIntLiteral>();
private final JsRootScope rootScope;
private final Map<String, JsStringLiteral> stringLiteralMap = new THashMap<String, JsStringLiteral>();
private final JsObjectScope topScope;
public JsProgram() {
rootScope = new JsRootScope(this);
topScope = new JsObjectScope(rootScope, "Global");
setFragmentCount(1);
}
public JsBlock getFragmentBlock(int fragment) {
if (fragment < 0 || fragment >= fragments.length) {
throw new IllegalArgumentException("Invalid fragment: " + fragment);
}
return fragments[fragment].getGlobalBlock();
}
public JsBlock getGlobalBlock() {
return getFragmentBlock(0);
}
public JsNumberLiteral getNumberLiteral(double value) {
JsDoubleLiteral literal = doubleLiteralMap.get(value);
if (literal == null) {
literal = new JsDoubleLiteral(value);
doubleLiteralMap.put(value, literal);
}
return literal;
}
public JsNumberLiteral getNumberLiteral(int value) {
JsIntLiteral literal = intLiteralMap.get(value);
if (literal == null) {
literal = new JsIntLiteral(value);
intLiteralMap.put(value, literal);
}
return literal;
}
/**
* Gets the quasi-mythical root scope. This is not the same as the top scope;
* all unresolvable identifiers wind up here, because they are considered
* external to the program.
*/
public JsRootScope getRootScope() {
return rootScope;
}
/**
* Gets the top level scope. This is the scope of all the statements in the
* main program.
*/
public JsObjectScope getScope() {
return topScope;
}
/**
* Creates or retrieves a JsStringLiteral from an interned object pool.
*/
@NotNull
public JsStringLiteral getStringLiteral(String value) {
JsStringLiteral literal = stringLiteralMap.get(value);
if (literal == null) {
literal = new JsStringLiteral(value);
stringLiteralMap.put(value, literal);
}
return literal;
}
public void setFragmentCount(int fragments) {
this.fragments = new JsProgramFragment[fragments];
for (int i = 0; i < fragments; i++) {
this.fragments[i] = new JsProgramFragment();
}
}
@Override
public void accept(JsVisitor v) {
v.visitProgram(this);
}
@Override
public void acceptChildren(JsVisitor visitor) {
for (JsProgramFragment fragment : fragments) {
visitor.accept(fragment);
}
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
for (JsProgramFragment fragment : fragments) {
v.accept(fragment);
}
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsProgram deepCopy() {
throw new UnsupportedOperationException();
}
}
@@ -0,0 +1,46 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import org.jetbrains.annotations.NotNull;
/**
* One independently loadable fragment of a {@link JsProgram}.
*/
public class JsProgramFragment extends SourceInfoAwareJsNode {
private final JsGlobalBlock globalBlock;
public JsProgramFragment() {
globalBlock = new JsGlobalBlock();
}
public JsBlock getGlobalBlock() {
return globalBlock;
}
@Override
public void accept(JsVisitor v) {
v.visitProgramFragment(this);
}
@Override
public void acceptChildren(JsVisitor visitor) {
visitor.accept(globalBlock);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
v.acceptStatement(globalBlock);
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsProgramFragment deepCopy() {
throw new UnsupportedOperationException();
}
}
@@ -0,0 +1,62 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import org.jetbrains.annotations.NotNull;
/**
* Used in object literals to specify property values by name.
*/
public class JsPropertyInitializer extends SourceInfoAwareJsNode {
@NotNull
private JsExpression labelExpr;
@NotNull
private JsExpression valueExpr;
public JsPropertyInitializer(@NotNull JsExpression labelExpr, @NotNull JsExpression valueExpr) {
this.labelExpr = labelExpr;
this.valueExpr = valueExpr;
}
@NotNull
public JsExpression getLabelExpr() {
return labelExpr;
}
@NotNull
public JsExpression getValueExpr() {
return valueExpr;
}
@Override
public void accept(JsVisitor v) {
v.visitPropertyInitializer(this);
}
@Override
public void acceptChildren(JsVisitor visitor) {
visitor.accept(labelExpr);
visitor.accept(valueExpr);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
JsExpression newLabel = v.accept(labelExpr);
JsExpression newValue = v.accept(valueExpr);
assert newLabel != null: "Label cannot be replaced with null";
assert newValue != null: "Value cannot be replaced with null";
labelExpr = newLabel;
valueExpr = newValue;
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsPropertyInitializer deepCopy() {
return new JsPropertyInitializer(labelExpr.deepCopy(), valueExpr.deepCopy()).withMetadataFrom(this);
}
}
@@ -0,0 +1,40 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
public final class JsRegExp extends JsLiteral.JsValueLiteral {
private String flags;
private String pattern;
public JsRegExp() {
}
public String getFlags() {
return flags;
}
public String getPattern() {
return pattern;
}
public void setFlags(String suffix) {
flags = suffix;
}
public void setPattern(String re) {
pattern = re;
}
@Override
public void accept(JsVisitor v) {
v.visitRegExp(this);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
v.visit(this, ctx);
v.endVisit(this, ctx);
}
}
@@ -0,0 +1,58 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
/**
* A JavaScript return statement.
*/
public final class JsReturn extends SourceInfoAwareJsNode implements JsStatement {
private JsExpression expression;
public JsReturn() {
}
public JsReturn(JsExpression expression) {
this.expression = expression;
}
public JsExpression getExpression() {
return expression;
}
public void setExpression(JsExpression expression) {
this.expression = expression;
}
@Override
public void accept(JsVisitor v) {
v.visitReturn(this);
}
@Override
public void acceptChildren(JsVisitor visitor) {
if (expression != null) {
visitor.accept(expression);
}
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
if (expression != null) {
expression = v.accept(expression);
}
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsReturn deepCopy() {
return new JsReturn(AstUtil.deepCopy(expression)).withMetadataFrom(this);
}
}
@@ -0,0 +1,43 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.backend.js.JsReservedIdentifiers;
import org.jetbrains.annotations.NotNull;
/**
* The root scope is the parent of every scope. All identifiers in this scope
* are not obfuscatable. This scope is prefilled with reserved global
* JavaScript symbols.
*/
public final class JsRootScope extends JsScope {
private final JsProgram program;
public JsRootScope(JsProgram program) {
super("Root");
this.program = program;
}
@Override
public JsProgram getProgram() {
return program;
}
@Override
protected JsName findOwnName(@NotNull String ident) {
JsName name = super.findOwnName(ident);
if (name == null) {
if (JsReservedIdentifiers.reservedGlobalSymbols.contains(ident)) {
/*
* Lazily add JsNames for reserved identifiers. Since a JsName for a reserved global symbol
* must report a legitimate enclosing scope, we can't simply have a shared set of symbol
* names.
*/
name = doCreateName(ident);
}
}
return name;
}
}
@@ -0,0 +1,232 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.util.Maps;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* A scope is a factory for creating and allocating
* {@link JsName}s. A JavaScript AST is
* built in terms of abstract name objects without worrying about obfuscation,
* keyword/identifier blacklisting, and so on.
* <p/>
* <p/>
* <p/>
* Scopes are associated with
* {@link JsFunction}s, but the two are
* not equivalent. Functions <i>have</i> scopes, but a scope does not
* necessarily have an associated Function. Examples of this include the
* {@link JsRootScope} and synthetic
* scopes that might be created by a client.
* <p/>
* <p/>
* <p/>
* Scopes can have parents to provide constraints when allocating actual
* identifiers for names. Specifically, names in child scopes are chosen such
* that they do not conflict with names in their parent scopes. The ultimate
* parent is usually the global scope (see
* {@link JsProgram#getRootScope()}),
* but parentless scopes are useful for managing names that are always accessed
* with a qualifier and could therefore never be confused with the global scope
* hierarchy.
*/
public abstract class JsScope {
@NotNull
private final String description;
private Map<String, JsName> names = Collections.emptyMap();
private Map<JsName, Object> temporaryNames;
private Set<JsName> readonlyTemporaryNames = null;
private final JsScope parent;
private static final Pattern FRESH_NAME_SUFFIX = Pattern.compile("[\\$_]\\d+$");
public JsScope(JsScope parent, @NotNull String description) {
this.description = description;
this.parent = parent;
}
protected JsScope(@NotNull String description) {
this.description = description;
parent = null;
}
public Set<JsName> getTemporaryNames() {
if (temporaryNames == null) {
return Collections.emptySet();
}
if (readonlyTemporaryNames == null) {
readonlyTemporaryNames = Collections.unmodifiableSet(temporaryNames.keySet());
}
return readonlyTemporaryNames;
}
@NotNull
public JsScope innerObjectScope(@NotNull String scopeName) {
return new JsObjectScope(this, scopeName);
}
/**
* Gets a name object associated with the specified identifier in this scope,
* creating it if necessary.<br/>
* If the JsName does not exist yet, a new JsName is created. The identifier,
* short name, and original name of the newly created JsName are equal to
* the given identifier.
*
* @param identifier An identifier that is unique within this scope.
*/
@NotNull
public JsName declareName(@NotNull String identifier) {
JsName name = findOwnName(identifier);
return name != null ? name : doCreateName(identifier);
}
/**
* Creates a new variable with an unique ident in this scope.
* The generated JsName is guaranteed to have an identifier that does not clash with any existing variables in the scope.
* Future declarations of variables might however clash with the temporary
* (unless they use this function).
*/
@NotNull
public JsName declareFreshName(@NotNull String suggestedName) {
assert !suggestedName.isEmpty();
String ident = getFreshIdent(suggestedName);
return doCreateName(ident);
}
@NotNull
public JsName declareTemporaryName(@NotNull String suggestedName) {
assert !suggestedName.isEmpty();
JsName name = new JsName(this, suggestedName, true);
if (temporaryNames == null) {
temporaryNames = new WeakHashMap<JsName, Object>();
}
temporaryNames.put(name, this);
return name;
}
/**
* Creates a temporary variable with an unique name in this scope.
* The generated temporary is guaranteed to have an identifier (but not short
* name) that does not clash with any existing variables in the scope.
* Future declarations of variables might however clash with the temporary.
*/
@NotNull
public JsName declareTemporary() {
return declareTemporaryName("tmp$");
}
/**
* Attempts to find the name object for the specified ident, searching in this
* scope, and if not found, in the parent scopes.
*
* @return <code>null</code> if the identifier has no associated name
*/
@Nullable
public final JsName findName(@NotNull String ident) {
JsName name = findOwnName(ident);
if (name == null && parent != null) {
return parent.findName(ident);
}
return name;
}
public boolean hasOwnName(@NotNull String name) {
return names.containsKey(name);
}
private boolean hasName(@NotNull String name) {
return hasOwnName(name) || (parent != null && parent.hasName(name));
}
/**
* Returns the parent scope of this scope, or <code>null</code> if this is the
* root scope.
*/
public final JsScope getParent() {
return parent;
}
public JsProgram getProgram() {
assert (parent != null) : "Subclasses must override getProgram() if they do not set a parent";
return parent.getProgram();
}
@Override
public final String toString() {
if (parent != null) {
return description + "->" + parent;
}
else {
return description;
}
}
public void copyOwnNames(JsScope other) {
names = new HashMap<String, JsName>(names);
names.putAll(other.names);
}
@NotNull
public String getDescription() {
return description;
}
@NotNull
protected JsName doCreateName(@NotNull String ident) {
JsName name = new JsName(this, ident, false);
names = Maps.put(names, ident, name);
return name;
}
/**
* Attempts to find the name object for the specified ident, searching in this
* scope only.
*
* @return <code>null</code> if the identifier has no associated name
*/
protected JsName findOwnName(@NotNull String ident) {
return names.get(ident);
}
/**
* During inlining names can be refreshed multiple times,
* so "a" becomes "a_0", then becomes "a_0_0"
* in case a_0 has been declared in calling scope.
*
* That's ugly. To resolve it, we rename
* clashing names with "[_$]\\d+" suffix,
* incrementing last number.
*
* Fresh name for "a0" should still be "a0_0".
*/
@NotNull
protected String getFreshIdent(@NotNull String suggestedIdent) {
char sep = '_';
String baseName = suggestedIdent;
int counter = 0;
Matcher matcher = FRESH_NAME_SUFFIX.matcher(suggestedIdent);
if (matcher.find()) {
String group = matcher.group();
baseName = matcher.replaceAll("");
sep = group.charAt(0);
counter = Integer.valueOf(group.substring(1));
}
String freshName = suggestedIdent;
while (hasName(freshName)) {
freshName = baseName + sep + counter++;
}
return freshName;
}
}
@@ -0,0 +1,13 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import org.jetbrains.annotations.NotNull;
public interface JsStatement extends JsNode {
@NotNull
@Override
JsStatement deepCopy();
}
@@ -0,0 +1,30 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
public final class JsStringLiteral extends JsLiteral.JsValueLiteral {
private final String value;
// These only get created by JsProgram so that they can be interned.
JsStringLiteral(String value) {
this.value = value;
}
public String getValue() {
return value;
}
@Override
public void accept(JsVisitor v) {
v.visitString(this);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
v.visit(this, ctx);
v.endVisit(this, ctx);
}
}
@@ -0,0 +1,71 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
/**
* A JavaScript switch statement.
*/
public class JsSwitch extends SourceInfoAwareJsNode implements JsStatement {
private final List<JsSwitchMember> cases;
private JsExpression expression;
public JsSwitch() {
super();
cases = new ArrayList<JsSwitchMember>();
}
public JsSwitch(JsExpression expression, List<JsSwitchMember> cases) {
this.expression = expression;
this.cases = cases;
}
public List<JsSwitchMember> getCases() {
return cases;
}
public JsExpression getExpression() {
return expression;
}
public void setExpression(JsExpression expression) {
this.expression = expression;
}
@Override
public void accept(JsVisitor v) {
v.visit(this);
}
@Override
public void acceptChildren(JsVisitor visitor) {
visitor.accept(expression);
visitor.acceptWithInsertRemove(cases);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
expression = v.accept(expression);
v.acceptList(cases);
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsSwitch deepCopy() {
JsExpression expressionCopy = AstUtil.deepCopy(expression);
List<JsSwitchMember> casesCopy = AstUtil.deepCopy(cases);
return new JsSwitch(expressionCopy, casesCopy).withMetadataFrom(this);
}
}
@@ -0,0 +1,34 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* A member/case in a JavaScript switch object.
*/
public abstract class JsSwitchMember extends SourceInfoAwareJsNode {
protected final List<JsStatement> statements = new SmartList<JsStatement>();
protected JsSwitchMember() {
super();
}
public List<JsStatement> getStatements() {
return statements;
}
@Override
public void acceptChildren(JsVisitor visitor) {
visitor.acceptWithInsertRemove(statements);
}
@NotNull
@Override
public abstract JsSwitchMember deepCopy();
}
@@ -0,0 +1,51 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
public class JsThrow extends SourceInfoAwareJsNode implements JsStatement {
private JsExpression expression;
public JsThrow() {
}
public JsThrow(JsExpression expression) {
this.expression = expression;
}
public JsExpression getExpression() {
return expression;
}
public void setExpression(JsExpression expression) {
this.expression = expression;
}
@Override
public void accept(JsVisitor v) {
v.visitThrow(this);
}
@Override
public void acceptChildren(JsVisitor visitor) {
visitor.accept(expression);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
expression = v.accept(expression);
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsThrow deepCopy() {
return new JsThrow(AstUtil.deepCopy(expression)).withMetadataFrom(this);
}
}
@@ -0,0 +1,95 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.util.AstUtil;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
/**
* A JavaScript <code>try</code> statement.
*/
public class JsTry extends SourceInfoAwareJsNode implements JsStatement {
private final List<JsCatch> catches;
private JsBlock finallyBlock;
private JsBlock tryBlock;
public JsTry() {
catches = new SmartList<JsCatch>();
}
public JsTry(JsBlock tryBlock, List<JsCatch> catches, @Nullable JsBlock finallyBlock) {
this.tryBlock = tryBlock;
this.catches = catches;
this.finallyBlock = finallyBlock;
}
public JsTry(JsBlock tryBlock, @Nullable JsCatch jsCatch, @Nullable JsBlock finallyBlock) {
this(tryBlock, new SmartList<JsCatch>(), finallyBlock);
if (jsCatch != null) {
catches.add(jsCatch);
}
}
public List<JsCatch> getCatches() {
return catches;
}
public JsBlock getFinallyBlock() {
return finallyBlock;
}
public JsBlock getTryBlock() {
return tryBlock;
}
public void setFinallyBlock(JsBlock block) {
finallyBlock = block;
}
public void setTryBlock(JsBlock block) {
tryBlock = block;
}
@Override
public void accept(JsVisitor v) {
v.visitTry(this);
}
@Override
public void acceptChildren(JsVisitor visitor) {
visitor.accept(tryBlock);
visitor.acceptWithInsertRemove(catches);
if (finallyBlock != null) {
visitor.accept(finallyBlock);
}
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
tryBlock = v.acceptStatement(tryBlock);
v.acceptList(catches);
if (finallyBlock != null) {
finallyBlock = v.acceptStatement(finallyBlock);
}
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsTry deepCopy() {
JsBlock tryCopy = AstUtil.deepCopy(tryBlock);
List<JsCatch> catchCopy = AstUtil.deepCopy(catches);
JsBlock finallyCopy = AstUtil.deepCopy(finallyBlock);
return new JsTry(tryCopy, catchCopy, finallyCopy).withMetadataFrom(this);
}
}
@@ -0,0 +1,55 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
public abstract class JsUnaryOperation extends JsExpression {
private JsExpression arg;
private final JsUnaryOperator op;
public JsUnaryOperation(JsUnaryOperator op, JsExpression arg) {
super();
this.op = op;
this.arg = arg;
}
public JsExpression getArg() {
return arg;
}
public JsUnaryOperator getOperator() {
return op;
}
public void setArg(JsExpression arg) {
this.arg = arg;
}
@Override
public void acceptChildren(JsVisitor visitor) {
if (op.isModifying()) {
// The delete operator is practically like an assignment of undefined, so
// for practical purposes we're treating it as an lvalue.
visitor.acceptLvalue(arg);
}
else {
visitor.accept(arg);
}
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (op.isModifying()) {
/*
* The delete operator is practically like an assignment of undefined, so for practical
* purposes we're treating it as an lvalue.
*/
arg = v.acceptLvalue(arg);
} else {
arg = v.accept(arg);
}
}
}
@@ -0,0 +1,78 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
/**
* A JavaScript unary operator.
*/
public enum JsUnaryOperator implements JsOperator {
/*
* Precedence indices from "JavaScript - The Definitive Guide" 4th Edition
* (page 57)
*/
BIT_NOT("~", 14, PREFIX), DEC("--", 14, POSTFIX | PREFIX), DELETE("delete", 14, PREFIX), INC(
"++", 14, POSTFIX | PREFIX), NEG("-", 14, PREFIX), POS("+", 14, PREFIX),
NOT("!", 14, PREFIX), TYPEOF("typeof", 14, PREFIX), VOID("void", 14, PREFIX);
private final int mask;
private final int precedence;
private final String symbol;
private JsUnaryOperator(String symbol, int precedence, int mask) {
this.symbol = symbol;
this.precedence = precedence;
this.mask = mask;
}
@Override
public int getPrecedence() {
return precedence;
}
@Override
public String getSymbol() {
return symbol;
}
@Override
public boolean isKeyword() {
return this == DELETE || this == TYPEOF || this == VOID;
}
@Override
public boolean isLeftAssociative() {
return (mask & LEFT) != 0;
}
public boolean isModifying() {
return this == DEC || this == INC || this == DELETE;
}
@Override
public boolean isPrecedenceLessThan(JsOperator other) {
return precedence < other.getPrecedence();
}
@Override
public boolean isValidInfix() {
return (mask & INFIX) != 0;
}
@Override
public boolean isValidPostfix() {
return (mask & POSTFIX) != 0;
}
@Override
public boolean isValidPrefix() {
return (mask & PREFIX) != 0;
}
@Override
public String toString() {
return symbol;
}
}
@@ -0,0 +1,172 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.common.Symbol;
import com.google.dart.compiler.util.AstUtil;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
/**
* A JavaScript <code>var</code> statement.
*/
public class JsVars extends SourceInfoAwareJsNode implements JsStatement, Iterable<JsVars.JsVar> {
private final List<JsVar> vars;
private final boolean multiline;
public JsVars() {
this(new SmartList<JsVar>(), false);
}
public JsVars(boolean multiline) {
this(new SmartList<JsVar>(), multiline);
}
public JsVars(List<JsVar> vars, boolean multiline) {
this.vars = vars;
this.multiline = multiline;
}
public JsVars(JsVar var) {
this(new SmartList<JsVar>(var), false);
}
public JsVars(JsVar... vars) {
this(new SmartList<JsVar>(vars), false);
}
public boolean isMultiline() {
return multiline;
}
/**
* A var declared using the JavaScript <code>var</code> statement.
*/
public static class JsVar extends SourceInfoAwareJsNode implements HasName {
private JsName name;
private JsExpression initExpression;
public JsVar(JsName name) {
this.name = name;
}
public JsVar(JsName name, @Nullable JsExpression initExpression) {
this.name = name;
this.initExpression = initExpression;
}
public JsExpression getInitExpression() {
return initExpression;
}
@Override
public JsName getName() {
return name;
}
@Override
public void setName(JsName name) {
this.name = name;
}
@Override
public Symbol getSymbol() {
return name;
}
public void setInitExpression(JsExpression initExpression) {
this.initExpression = initExpression;
}
@Override
public void accept(JsVisitor v) {
v.visit(this);
}
@Override
public void acceptChildren(JsVisitor visitor) {
if (initExpression != null) {
visitor.accept(initExpression);
}
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
if (initExpression != null) {
initExpression = v.accept(initExpression);
}
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsVar deepCopy() {
if (initExpression == null) return new JsVar(name);
return new JsVar(name, initExpression.deepCopy()).withMetadataFrom(this);
}
}
public void add(JsVar var) {
vars.add(var);
}
public void addAll(Collection<? extends JsVars.JsVar> vars) {
this.vars.addAll(vars);
}
public void addAll(JsVars otherVars) {
this.vars.addAll(otherVars.vars);
}
public void addIfHasInitializer(JsVar var) {
if (var.getInitExpression() != null) {
add(var);
}
}
public boolean isEmpty() {
return vars.isEmpty();
}
@Override
public Iterator<JsVar> iterator() {
return vars.iterator();
}
public List<JsVar> getVars() {
return vars;
}
@Override
public void accept(JsVisitor v) {
v.visitVars(this);
}
@Override
public void acceptChildren(JsVisitor visitor) {
visitor.acceptWithInsertRemove(vars);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
v.acceptList(vars);
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsVars deepCopy() {
return new JsVars(AstUtil.deepCopy(vars), multiline).withMetadataFrom(this);
}
}
@@ -0,0 +1,164 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast
import com.google.dart.compiler.backend.js.ast.JsVars.JsVar
abstract class JsVisitor {
open fun <T : JsNode?> accept(node: T) {
node?.accept(this)
}
fun <T : JsNode> acceptList(collection: List<T>) {
for (node in collection) {
accept(node)
}
}
fun acceptLvalue(expression: JsExpression) {
accept(expression)
}
fun <T : JsNode> acceptWithInsertRemove(collection: List<T>) {
for (node in collection) {
accept(node)
}
}
open fun visitArrayAccess(x: JsArrayAccess): Unit =
visitElement(x)
open fun visitArray(x: JsArrayLiteral): Unit =
visitElement(x)
open fun visitBinaryExpression(x: JsBinaryOperation): Unit =
visitElement(x)
open fun visitBlock(x: JsBlock): Unit =
visitElement(x)
open fun visitBoolean(x: JsLiteral.JsBooleanLiteral): Unit =
visitElement(x)
open fun visitBreak(x: JsBreak): Unit =
visitElement(x)
open fun visitCase(x: JsCase): Unit =
visitElement(x)
open fun visitCatch(x: JsCatch): Unit =
visitElement(x)
open fun visitConditional(x: JsConditional): Unit =
visitElement(x)
open fun visitContinue(x: JsContinue): Unit =
visitElement(x)
open fun visitDebugger(x: JsDebugger): Unit =
visitElement(x)
open fun visitDefault(x: JsDefault): Unit =
visitElement(x)
open fun visitDoWhile(x: JsDoWhile): Unit =
visitElement(x)
open fun visitEmpty(x: JsEmpty): Unit =
visitElement(x)
open fun visitExpressionStatement(x: JsExpressionStatement): Unit =
visitElement(x)
open fun visitFor(x: JsFor): Unit =
visitElement(x)
open fun visitForIn(x: JsForIn): Unit =
visitElement(x)
open fun visitFunction(x: JsFunction): Unit =
visitElement(x)
open fun visitIf(x: JsIf): Unit =
visitElement(x)
open fun visitInvocation(invocation: JsInvocation): Unit =
visitElement(invocation)
open fun visitLabel(x: JsLabel): Unit =
visitElement(x)
open fun visitNameRef(nameRef: JsNameRef): Unit =
visitElement(nameRef)
open fun visitNew(x: JsNew): Unit =
visitElement(x)
open fun visitNull(x: JsNullLiteral): Unit =
visitElement(x)
open fun visitInt(x: JsNumberLiteral.JsIntLiteral): Unit =
visitElement(x)
open fun visitDouble(x: JsNumberLiteral.JsDoubleLiteral): Unit =
visitElement(x)
open fun visitObjectLiteral(x: JsObjectLiteral): Unit =
visitElement(x)
open fun visitParameter(x: JsParameter): Unit =
visitElement(x)
open fun visitPostfixOperation(x: JsPostfixOperation): Unit =
visitElement(x)
open fun visitPrefixOperation(x: JsPrefixOperation): Unit =
visitElement(x)
open fun visitProgram(x: JsProgram): Unit =
visitElement(x)
open fun visitProgramFragment(x: JsProgramFragment): Unit =
visitElement(x)
open fun visitPropertyInitializer(x: JsPropertyInitializer): Unit =
visitElement(x)
open fun visitRegExp(x: JsRegExp): Unit =
visitElement(x)
open fun visitReturn(x: JsReturn): Unit =
visitElement(x)
open fun visitString(x: JsStringLiteral): Unit =
visitElement(x)
open fun visit(x: JsSwitch): Unit =
visitElement(x)
open fun visitThis(x: JsLiteral.JsThisRef): Unit =
visitElement(x)
open fun visitThrow(x: JsThrow): Unit =
visitElement(x)
open fun visitTry(x: JsTry): Unit =
visitElement(x)
open fun visit(x: JsVar): Unit =
visitElement(x)
open fun visitVars(x: JsVars): Unit =
visitElement(x)
open fun visitWhile(x: JsWhile): Unit =
visitElement(x)
open fun visitDocComment(comment: JsDocComment): Unit =
visitElement(comment)
protected open fun visitElement(node: JsNode) {
}
}
@@ -0,0 +1,374 @@
/*
* 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.dart.compiler.backend.js.ast;
/**
* Taken from GWT project with modifications.
* Original:
* repository: https://gwt.googlesource.com/gwt
* revision: e32bf0a95029165d9e6ab457c7ee7ca8b07b908c
* file: dev/core/src/com/google/gwt/dev/js/ast/JsVisitor.java
*/
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* Implemented by nodes that will visit child nodes.
*/
@SuppressWarnings("UnusedParameters")
public abstract class JsVisitorWithContext {
public final <T extends JsNode> T accept(T node) {
if (node == null) return null;
return doAccept(node);
}
public JsExpression acceptLvalue(JsExpression expr) {
if (expr == null) return null;
return doAcceptLvalue(expr);
}
public final <T extends JsNode> void acceptList(List<T> collection) {
doAcceptList(collection);
}
public final <T extends JsStatement> T acceptStatement(T statement) {
if (statement == null) return null;
//noinspection unchecked
return (T) doAcceptStatement(statement);
}
public final void acceptStatementList(List<JsStatement> statements) {
doAcceptStatementList(statements);
}
public void endVisit(@NotNull JsArrayAccess x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsArrayLiteral x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsBinaryOperation x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsBlock x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsLiteral.JsBooleanLiteral x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsBreak x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsCase x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsCatch x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsConditional x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsContinue x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsDebugger x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsDefault x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsDoWhile x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsEmpty x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsExpressionStatement x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsFor x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsForIn x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsFunction x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsIf x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsInvocation x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsLabel x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsName x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsNameRef x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsNew x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsNullLiteral x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsNumberLiteral x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsObjectLiteral x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsParameter x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsPostfixOperation x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsPrefixOperation x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsProgram x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsProgramFragment x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsPropertyInitializer x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsRegExp x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsReturn x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsStringLiteral x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsSwitch x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsLiteral.JsThisRef x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsThrow x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsTry x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsVars.JsVar x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsVars x, @NotNull JsContext ctx) {
}
public void endVisit(@NotNull JsWhile x, @NotNull JsContext ctx) {
}
public boolean visit(@NotNull JsArrayAccess x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsArrayLiteral x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsBinaryOperation x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsBlock x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsLiteral.JsBooleanLiteral x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsBreak x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsCase x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsCatch x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsConditional x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsContinue x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsDebugger x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsDefault x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsDoWhile x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsEmpty x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsExpressionStatement x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsFor x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsForIn x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsFunction x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsIf x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsInvocation x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsLabel x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsName x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsNameRef x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsNew x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsNullLiteral x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsNumberLiteral x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsObjectLiteral x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsParameter x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsPostfixOperation x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsPrefixOperation x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsProgram x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsProgramFragment x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsPropertyInitializer x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsRegExp x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsReturn x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsStringLiteral x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsSwitch x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsLiteral.JsThisRef x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsThrow x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsTry x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsVars.JsVar x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsVars x, @NotNull JsContext ctx) {
return true;
}
public boolean visit(@NotNull JsWhile x, @NotNull JsContext ctx) {
return true;
}
protected abstract <T extends JsNode> T doAccept(T node);
protected abstract JsExpression doAcceptLvalue(JsExpression expr);
protected abstract <T extends JsNode> void doAcceptList(List<T> collection);
protected abstract <T extends JsStatement> JsStatement doAcceptStatement(T statement);
protected abstract void doAcceptStatementList(List<JsStatement> statements);
protected abstract <T extends JsNode> void doTraverse(T node, JsContext ctx) ;
}
@@ -0,0 +1,187 @@
/*
* 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.dart.compiler.backend.js.ast;
/**
* Taken from GWT project with modifications.
* Original:
* repository: https://gwt.googlesource.com/gwt
* revision: e32bf0a95029165d9e6ab457c7ee7ca8b07b908c
* file: dev/core/src/com/google/gwt/dev/js/ast/JsModVisitor.java
*/
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
/**
* A visitor for iterating through and modifying an AST.
*/
public class JsVisitorWithContextImpl extends JsVisitorWithContext {
private final Stack<JsContext<JsStatement>> statementContexts = new Stack<JsContext<JsStatement>>();
public class ListContext<T extends JsNode> extends JsContext<T> {
private List<T> nodes;
private int index;
// Those are reset in every iteration of traverse()
private final List<T> previous = new SmartList<T>();
private final List<T> next = new SmartList<T>();
private boolean removed = false;
@Override
public <R extends T> void addPrevious(R node) {
previous.add(node);
}
@Override
public <R extends T> void addNext(R node) {
next.add(node);
}
@Override
public void removeMe() {
removed = true;
}
@Override
public <R extends T> void replaceMe(R node) {
checkReplacement(nodes.get(index), node);
nodes.set(index, node);
removed = false;
}
@Nullable
@Override
public T getCurrentNode() {
if (!removed && index < nodes.size()) {
return nodes.get(index);
}
return null;
}
protected void traverse(List<T> nodes) {
assert previous.isEmpty(): "addPrevious() was called before traverse()";
assert next.isEmpty(): "addNext() was called before traverse()";
this.nodes = nodes;
for (index = 0; index < nodes.size(); index++) {
removed = false;
previous.clear();
next.clear();
doTraverse(getCurrentNode(), this);
if (!previous.isEmpty()) {
nodes.addAll(index, previous);
index += previous.size();
}
if (removed) {
nodes.remove(index);
index--;
}
if (!next.isEmpty()) {
nodes.addAll(index + 1, next);
index += next.size();
}
}
}
}
private class LvalueContext extends NodeContext<JsExpression> {
}
private class NodeContext<T extends JsNode> extends JsContext<T> {
protected T node;
@Override
public void removeMe() {
throw new UnsupportedOperationException();
}
@Override
public <R extends T> void replaceMe(R node) {
checkReplacement(this.node, node);
this.node = node;
}
@Nullable
@Override
public T getCurrentNode() {
return node;
}
protected T traverse(T node) {
this.node = node;
doTraverse(node, this);
return this.node;
}
}
protected static void checkReplacement(@SuppressWarnings("UnusedParameters") JsNode origNode, JsNode newNode) {
if (newNode == null) throw new RuntimeException("Cannot replace with null");
}
@Override
protected <T extends JsNode> T doAccept(T node) {
return new NodeContext<T>().traverse(node);
}
@Override
protected JsExpression doAcceptLvalue(JsExpression expr) {
return new LvalueContext().traverse(expr);
}
@Override
protected <T extends JsStatement> JsStatement doAcceptStatement(T statement) {
List<JsStatement> statements = new SmartList<JsStatement>(statement);
doAcceptStatementList(statements);
if (statements.size() == 1) {
return statements.get(0);
}
return new JsBlock(statements);
}
@Override
protected void doAcceptStatementList(List<JsStatement> statements) {
ListContext<JsStatement> context = new ListContext<JsStatement>();
statementContexts.push(context);
context.traverse(statements);
statementContexts.pop();
}
@Override
protected <T extends JsNode> void doAcceptList(List<T> collection) {
new ListContext<T>().traverse(collection);
}
@NotNull
protected JsContext<JsStatement> getLastStatementLevelContext() {
return statementContexts.peek();
}
@Override
protected <T extends JsNode> void doTraverse(T node, JsContext ctx) {
node.traverse(this, ctx);
}
}
@@ -0,0 +1,69 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
/**
* A JavaScript <code>while</code> statement.
*/
public class JsWhile extends SourceInfoAwareJsNode implements JsStatement {
protected JsStatement body;
protected JsExpression condition;
public JsWhile() {
}
public JsWhile(JsExpression condition, JsStatement body) {
this.condition = condition;
this.body = body;
}
public JsStatement getBody() {
return body;
}
public JsExpression getCondition() {
return condition;
}
public void setBody(JsStatement body) {
this.body = body;
}
public void setCondition(JsExpression condition) {
this.condition = condition;
}
@Override
public void accept(JsVisitor v) {
v.visitWhile(this);
}
@Override
public void acceptChildren(JsVisitor visitor) {
visitor.accept(condition);
visitor.accept(body);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
condition = v.accept(condition);
body = v.acceptStatement(body);
}
v.endVisit(this, ctx);
}
@NotNull
@Override
public JsWhile deepCopy() {
JsExpression conditionCopy = AstUtil.deepCopy(condition);
JsStatement bodyCopy = AstUtil.deepCopy(body);
return new JsWhile(conditionCopy, bodyCopy).withMetadataFrom(this);
}
}
@@ -0,0 +1,10 @@
package com.google.dart.compiler.backend.js.ast;
import org.jetbrains.annotations.NotNull;
public abstract class RecursiveJsVisitor extends JsVisitor {
@Override
protected void visitElement(@NotNull JsNode node) {
node.acceptChildren(this);
}
}
@@ -0,0 +1,25 @@
package com.google.dart.compiler.backend.js.ast;
public abstract class SourceInfoAwareJsNode extends AbstractNode {
private Object source;
@Override
public Object getSource() {
return source;
}
@Override
public void setSource(Object info) {
source = info;
}
@Override
public void acceptChildren(JsVisitor visitor) {
}
@Override
public JsNode source(Object info) {
source = info;
return this;
}
}
@@ -0,0 +1,141 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* 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.dart.compiler.backend.js.ast
import java.util.Stack
class JsObjectScope(parent: JsScope, description: String) : JsScope(parent, description)
object JsDynamicScope : JsScope(null, "Scope for dynamic declarations") {
override fun doCreateName(name: String) = JsName(this, name, false)
}
open class JsFunctionScope(parent: JsScope, description: String) : JsScope(parent, description) {
private val labelScopes = Stack<LabelScope>()
private val topLabelScope: LabelScope?
get() = if (labelScopes.isNotEmpty()) labelScopes.peek() else null
override fun hasOwnName(name: String): Boolean = RESERVED_WORDS.contains(name) || super.hasOwnName(name)
open fun declareNameUnsafe(identifier: String): JsName = super.declareName(identifier)
open fun enterLabel(label: String): JsName {
val scope = LabelScope(topLabelScope, label)
labelScopes.push(scope)
return scope.labelName
}
open fun exitLabel() {
assert(labelScopes.isNotEmpty()) { "No scope to exit from" }
labelScopes.pop()
}
open fun findLabel(label: String): JsName? =
topLabelScope?.findName(label)
private inner class LabelScope(parent: LabelScope?, val ident: String) : JsScope(parent, "Label scope for $ident") {
val labelName: JsName
init {
val freshIdent = when {
ident in RESERVED_WORDS -> getFreshIdent(ident)
parent != null -> parent.getFreshIdent(ident)
else -> ident
}
labelName = JsName(this@JsFunctionScope, freshIdent, false)
}
override fun findOwnName(name: String): JsName? =
if (name == ident) labelName else null
/**
* Safe call is necessary, because hasOwnName can be called
* in constructor before labelName is initialized (see KT-4394)
*/
@Suppress("UNNECESSARY_SAFE_CALL")
override fun hasOwnName(name: String): Boolean =
name in RESERVED_WORDS
|| name == ident
|| name == labelName?.ident
|| parent?.hasOwnName(name) ?: false
}
companion object {
val RESERVED_WORDS: Set<String> = setOf(
// keywords
"await", "break", "case", "catch", "continue", "debugger", "default", "delete", "do", "else", "finally", "for", "function", "if",
"in", "instanceof", "new", "return", "switch", "this", "throw", "try", "typeof", "var", "void", "while", "with",
// future reserved words
"class", "const", "enum", "export", "extends", "import", "super",
// as future reserved words in strict mode
"implements", "interface", "let", "package", "private", "protected", "public", "static", "yield",
// additional reserved words
"null", "true", "false",
// disallowed as variable names in strict mode
"eval", "arguments",
// global identifiers usually declared in a typical JS interpreter
"NaN", "isNaN", "Infinity", "undefined",
"Error", "Object", "Math", "String", "Number", "Boolean", "Date", "Array", "RegExp", "JSON",
// global identifiers usually declared in know environments (node.js, browser, require.js, WebWorkers, etc)
"require", "define", "module", "window", "self",
// the special Kotlin object
"Kotlin"
)
}
}
class DelegatingJsFunctionScopeWithTemporaryParent(
private val delegatingScope: JsFunctionScope,
parent: JsScope
) : JsFunctionScope(parent, "<delegating scope to delegatingScope>") {
override fun hasOwnName(name: String): Boolean =
delegatingScope.hasOwnName(name)
override fun findOwnName(ident: String): JsName? =
delegatingScope.findOwnName(ident)
override fun declareNameUnsafe(identifier: String): JsName =
delegatingScope.declareNameUnsafe(identifier)
override fun declareName(identifier: String): JsName =
delegatingScope.declareName(identifier)
override fun declareFreshName(suggestedName: String): JsName =
delegatingScope.declareFreshName(suggestedName)
override fun declareTemporary(): JsName =
delegatingScope.declareTemporary()
override fun enterLabel(label: String): JsName =
delegatingScope.enterLabel(label)
override fun exitLabel() =
delegatingScope.exitLabel()
override fun findLabel(label: String): JsName? =
delegatingScope.findLabel(label)
}
@@ -0,0 +1,42 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* 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.dart.compiler.backend.js.ast.metadata
abstract class HasMetadata {
private val metadata: MutableMap<String, Any?> = hashMapOf()
fun <T> getData(key: String): T {
@Suppress("UNCHECKED_CAST")
return metadata[key] as T
}
fun <T> setData(key: String, value: T) {
metadata[key] = value
}
fun hasData(key: String): Boolean {
return metadata.containsKey(key)
}
fun removeData(key: String) {
metadata.remove(key)
}
fun copyMetadataFrom(other: HasMetadata) {
metadata.putAll(other.metadata)
}
}
@@ -0,0 +1,30 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* 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.dart.compiler.backend.js.ast.metadata
import kotlin.reflect.KProperty
class MetadataProperty<in T : HasMetadata, R>(val default: R) {
operator fun getValue(thisRef: T, desc: KProperty<*>): R {
if (!thisRef.hasData(desc.name)) return default
return thisRef.getData<R>(desc.name)
}
operator fun setValue(thisRef: T, desc: KProperty<*>, value: R) {
thisRef.setData(desc.name, value)
}
}
@@ -0,0 +1,127 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* 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.
*/
@file:JvmName("MetadataProperties")
package com.google.dart.compiler.backend.js.ast.metadata
import com.google.dart.compiler.backend.js.ast.*
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.resolve.inline.InlineStrategy
import org.jetbrains.kotlin.types.KotlinType
var JsName.staticRef: JsNode? by MetadataProperty(default = null)
// TODO: move this to module 'js.inliner' and change dependency on 'frontend' to dependency on 'descriptors'
var JsInvocation.inlineStrategy: InlineStrategy? by MetadataProperty(default = null)
var JsInvocation.descriptor: CallableDescriptor? by MetadataProperty(default = null)
var JsInvocation.psiElement: PsiElement? by MetadataProperty(default = null)
var JsNameRef.inlineStrategy: InlineStrategy? by MetadataProperty(default = null)
var JsNameRef.descriptor: CallableDescriptor? by MetadataProperty(default = null)
var JsNameRef.psiElement: PsiElement? by MetadataProperty(default = null)
var JsFunction.isLocal: Boolean by MetadataProperty(default = false)
var JsParameter.hasDefaultValue: Boolean by MetadataProperty(default = false)
var JsInvocation.typeCheck: TypeCheck? by MetadataProperty(default = null)
/**
* For function and lambda bodies indicates what declaration corresponds to.
* When absent (`null`) on body of a named function, this function is from external JS module.
*/
var JsFunction.functionDescriptor: FunctionDescriptor? by MetadataProperty(default = null)
/**
* For return statement specifies corresponding target descriptor given by [functionDescriptor].
* For all JsReturn nodes created by K2JSTranslator, this property is filled, either for local/non-local labeled and non-labeled returns.
*
* Absence of this property (expressed as `null`) means that the corresponding JsReturn got from external JS library.
* In this case we assume that such return can never be non-local.
*/
var JsReturn.returnTarget: FunctionDescriptor? by MetadataProperty(default = null)
var HasMetadata.synthetic: Boolean by MetadataProperty(default = false)
var HasMetadata.sideEffects: SideEffectKind by MetadataProperty(default = SideEffectKind.AFFECTS_STATE)
var JsFunction.coroutineType: KotlinType? by MetadataProperty(default = null)
/**
* Denotes a suspension call-site that is to be processed by coroutine transformer.
* More clearly, denotes invocation that should immediately return from coroutine state machine
*/
var JsInvocation.isSuspend: Boolean by MetadataProperty(default = false)
/**
* Denotes a pre-suspend call-site that is to be processed by coroutine transformer.
* For normal suspend call-sites both [isSuspend] and [isPreSuspend] present.
* For inlined suspend calls fake calls are generated before and after inlined function body.
*/
var JsInvocation.isPreSuspend: Boolean by MetadataProperty(default = false)
/**
* Denotes a fake suspend call for inlining purposes.
*/
var JsInvocation.isFakeSuspend: Boolean by MetadataProperty(default = false)
/**
* Denotes a reference to coroutine's `result` field that contains result of
* last suspended invocation.
*/
var JsNameRef.coroutineResult by MetadataProperty(default = false)
/**
* Denotes a reference to coroutine's `interceptor` field that contains coroutines's interceptor
*/
var JsNameRef.coroutineController by MetadataProperty(default = false)
var JsName.imported by MetadataProperty(default = false)
var JsFunction.coroutineMetadata: CoroutineMetadata? by MetadataProperty(default = null)
class CoroutineMetadata(
val doResumeName: JsName,
val resumeName: JsName,
val stateName: JsName,
val exceptionStateName: JsName,
val finallyPathName: JsName,
val resultName: JsName,
val exceptionName: JsName,
val facadeName: JsName,
val baseClassRef: JsExpression,
val suspendObjectRef: JsExpression,
val hasController: Boolean
)
enum class TypeCheck {
TYPEOF,
INSTANCEOF,
OR_NULL,
AND_PREDICATE
}
enum class SideEffectKind {
AFFECTS_STATE,
DEPENDS_ON_STATE,
PURE
}
@@ -0,0 +1,13 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.common;
public interface HasSymbol {
/**
* @return Return the original user visible name for a Object represented
* in a source map.
*/
Symbol getSymbol();
}
@@ -0,0 +1,59 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.common;
import com.google.dart.compiler.Source;
import java.io.Serializable;
/**
* Tracks file and line information for AST nodes.
*/
public interface SourceInfo extends Serializable {
/**
* The source code provider.
*/
Source getSource();
/**
* @return A 1-based line number into the original source file indicating
* where the source fragment begins.
*/
int getLine();
/**
* @return A 1-based column number into the original source file indicating
* where the source fragment begins.
*/
int getColumn();
/**
* Returns the character index into the original source file indicating
* where the source fragment corresponding to this node begins.
*
* <p>
* The parser supplies useful well-defined source ranges to the nodes it creates.
*
* @return the 0-based character index, or <code>-1</code>
* if no source startPosition information is recorded for this node
* @see #getLength()
* @see HasSourceInfo#setSourceLocation(Source, int, int, int, int)
*/
int getStart();
/**
* Returns the length in characters of the original source file indicating
* where the source fragment corresponding to this node ends.
* <p>
* The parser supplies useful well-defined source ranges to the nodes it creates.
*
* @return a (possibly 0) length, or <code>0</code>
* if no source source position information is recorded for this node
* @see #getStart()
* @see HasSourceInfo#setSourceLocation(Source, int, int, int, int)
*/
int getLength();
}
@@ -0,0 +1,44 @@
package com.google.dart.compiler.common;
import com.google.dart.compiler.Source;
public class SourceInfoImpl implements SourceInfo {
protected Source source = null;
protected int line = -1;
protected int column = -1;
protected int start = -1;
protected int length = -1;
public SourceInfoImpl(Source source, int line, int column, int start, int length) {
this.source = source;
this.line = line;
this.column = column;
this.start = start;
this.length = length;
}
@Override
public Source getSource() {
return source;
}
@Override
public int getLine() {
return line;
}
@Override
public int getColumn() {
return column;
}
@Override
public int getStart() {
return start;
}
@Override
public int getLength() {
return length;
}
}
@@ -0,0 +1,8 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.common;
public interface Symbol {
}
@@ -0,0 +1,55 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.util;
import com.google.dart.compiler.backend.js.ast.*;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
public final class AstUtil {
private AstUtil() {
}
/**
* Returns a sequence of expressions (using the binary sequence operator).
*
* @param exprs - expressions to add to sequence
* @return a sequence of expressions.
*/
public static JsBinaryOperation newSequence(JsExpression... exprs) {
if (exprs.length < 2) {
throw new RuntimeException("newSequence expects at least two arguments");
}
JsExpression result = exprs[exprs.length - 1];
for (int i = exprs.length - 2; i >= 0; i--) {
result = new JsBinaryOperation(JsBinaryOperator.COMMA, exprs[i], result);
}
return (JsBinaryOperation) result;
}
@Nullable
public static <T extends JsNode> T deepCopy(@Nullable T node) {
if (node == null) return null;
//noinspection unchecked
return (T) node.deepCopy();
}
@NotNull
public static <T extends JsNode> List<T> deepCopy(@Nullable List<T> nodes) {
if (nodes == null) return new SmartList<T>();
List<T> nodesCopy = new ArrayList<T>(nodes.size());
for (T node : nodes) {
nodesCopy.add(deepCopy(node));
}
return nodesCopy;
}
}
@@ -0,0 +1,41 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.util;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* Utility methods for operating on memory-efficient maps. All maps of size 0 or
* 1 are assumed to be immutable. All maps of size greater than 1 are assumed to
* be mutable.
*/
public class Maps {
private Maps() {
}
public static <K, V> Map<K, V> put(Map<K, V> map, K key, V value) {
switch (map.size()) {
case 0:
// Empty -> Singleton
return Collections.singletonMap(key, value);
case 1: {
if (map.containsKey(key)) {
return Collections.singletonMap(key, value);
}
// Singleton -> HashMap
Map<K, V> result = new HashMap<K, V>();
result.put(map.keySet().iterator().next(), map.values().iterator().next());
result.put(key, value);
return result;
}
default:
// HashMap
map.put(key, value);
return map;
}
}
}
@@ -0,0 +1,52 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.util;
/**
* Interface used for printing text output.
*/
public interface TextOutput {
int getPosition();
int getLine();
int getColumn();
void indentIn();
void indentOut();
void newline();
void print(char c);
void print(int v);
void print(double v);
void print(char[] s);
void print(CharSequence s);
void printOpt(char c);
void printOpt(char[] s);
void printOpt(String s);
boolean isCompact();
boolean isJustNewlined();
void setOutListener(OutListener outListener);
void maybeIndent();
public interface OutListener {
void newLined();
void indentedAfterNewLine();
}
}
@@ -0,0 +1,181 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.util;
import java.util.Arrays;
public class TextOutputImpl implements TextOutput {
private final boolean compact;
private int identLevel = 0;
private final static int indentGranularity = 2;
private char[][] indents = new char[][] {new char[0]};
private boolean justNewlined;
private final StringBuilder out;
private int position = 0;
private int line = 0;
private int column = 0;
private OutListener outListener;
public TextOutputImpl() {
this(false);
}
public boolean isCompact() {
return compact;
}
public TextOutputImpl(boolean compact) {
this.compact = compact;
out = new StringBuilder();
}
@Override
public String toString() {
return out.toString();
}
@Override
public int getPosition() {
return position;
}
@Override
public int getLine() {
return line;
}
@Override
public int getColumn() {
return column;
}
@Override
public void indentIn() {
++identLevel;
if (identLevel >= indents.length) {
// Cache a new level of indentation string.
char[] newIndentLevel = new char[identLevel * indentGranularity];
Arrays.fill(newIndentLevel, ' ');
char[][] newIndents = new char[indents.length + 1][];
System.arraycopy(indents, 0, newIndents, 0, indents.length);
newIndents[identLevel] = newIndentLevel;
indents = newIndents;
}
}
@Override
public void indentOut() {
--identLevel;
}
@Override
public void newline() {
out.append('\n');
position++;
line++;
column = 0;
justNewlined = true;
if (outListener != null) {
outListener.newLined();
}
}
@Override
public void print(double value) {
maybeIndent();
int oldLength = out.length();
out.append(value);
movePosition(out.length() - oldLength);
}
@Override
public void print(int value) {
maybeIndent();
int oldLength = out.length();
out.append(value);
movePosition(out.length() - oldLength);
}
@Override
public void print(char c) {
maybeIndent();
out.append(c);
movePosition(1);
}
private void movePosition(int l) {
position += l;
column += l;
}
@Override
public void print(char[] s) {
maybeIndent();
printAndCount(s);
}
@Override
public void print(CharSequence s) {
maybeIndent();
printAndCount(s);
}
@Override
public void printOpt(char c) {
if (!compact) {
print(c);
}
}
@Override
public void printOpt(char[] s) {
if (!compact) {
maybeIndent();
printAndCount(s);
}
}
@Override
public void printOpt(String s) {
if (!compact) {
maybeIndent();
printAndCount(s);
}
}
@Override
public void maybeIndent() {
if (justNewlined && !compact) {
printAndCount(indents[identLevel]);
justNewlined = false;
if (outListener != null) {
outListener.indentedAfterNewLine();
}
}
}
private void printAndCount(CharSequence charSequence) {
position += charSequence.length();
column += charSequence.length();
out.append(charSequence);
}
private void printAndCount(char[] chars) {
position += chars.length;
column += chars.length;
out.append(chars);
}
@Override
public boolean isJustNewlined() {
return justNewlined && !compact;
}
@Override
public void setOutListener(OutListener outListener) {
this.outListener = outListener;
}
}