Merge branch 'master' of ../../KotlinJs

This commit is contained in:
pTalanov
2012-02-24 18:17:12 +04:00
551 changed files with 43419 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
k2js
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AntConfiguration">
<defaultAnt bundledAnt="true" />
</component>
</project>
+23
View File
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<option name="DEFAULT_COMPILER" value="Javac" />
<resourceExtensions />
<wildcardResourcePatterns>
<entry name="?*.properties" />
<entry name="?*.xml" />
<entry name="?*.gif" />
<entry name="?*.png" />
<entry name="?*.jpeg" />
<entry name="?*.jpg" />
<entry name="?*.html" />
<entry name="?*.dtd" />
<entry name="?*.tld" />
<entry name="?*.ftl" />
<entry name="?*.jet" />
<entry name="?*.kt" />
</wildcardResourcePatterns>
<annotationProcessing enabled="false" useClasspath="true" />
</component>
</project>
+9
View File
@@ -0,0 +1,9 @@
<component name="CopyrightManager">
<copyright>
<option name="notice" value="Copyright 2000-&amp;#36;today.year JetBrains s.r.o.&#10;&#10;Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);&#10;you may not use this file except in compliance with the License.&#10;You may obtain a copy of the License at&#10;&#10;http://www.apache.org/licenses/LICENSE-2.0&#10;&#10;Unless required by applicable law or agreed to in writing, software&#10;distributed under the License is distributed on an &quot;AS IS&quot; BASIS,&#10;WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&#10;See the License for the specific language governing permissions and&#10;limitations under the License." />
<option name="keyword" value="Copyright" />
<option name="allowReplaceKeyword" value="JetBrains" />
<option name="myName" value="apache" />
<option name="myLocal" value="true" />
</copyright>
</component>
+7
View File
@@ -0,0 +1,7 @@
<component name="CopyrightManager">
<settings default="apache">
<module2copyright>
<element module="All" copyright="apache" />
</module2copyright>
</settings>
</component>
+3
View File
@@ -0,0 +1,3 @@
<component name="ProjectDictionaryState">
<dictionary name="Pavel.Talanov" />
</component>
+5
View File
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
</project>
+8
View File
@@ -0,0 +1,8 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0" is_locked="false">
<option name="myName" value="Project Default" />
<option name="myLocal" value="false" />
<inspection_tool class="SimplifiableIfStatement" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="TrivialIf" enabled="false" level="WARNING" enabled_by_default="false" />
</profile>
</component>
+7
View File
@@ -0,0 +1,7 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="PROJECT_PROFILE" value="Project Default" />
<option name="USE_PROJECT_PROFILE" value="true" />
<version value="1.0" />
</settings>
</component>
+9
View File
@@ -0,0 +1,9 @@
<component name="libraryTable">
<library name="guava-10.0.1">
<CLASSES>
<root url="jar://$PROJECT_DIR$/translator/lib/guava-10.0.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>
+36
View File
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EntryPointsManager">
<entry_points version="2.0" />
</component>
<component name="IdProvider" IDEtalkID="C5E9A8C8EEE7359144ADEDA64003CE1D" />
<component name="JavadocGenerationManager">
<option name="OUTPUT_DIRECTORY" />
<option name="OPTION_SCOPE" value="protected" />
<option name="OPTION_HIERARCHY" value="true" />
<option name="OPTION_NAVIGATOR" value="true" />
<option name="OPTION_INDEX" value="true" />
<option name="OPTION_SEPARATE_INDEX" value="true" />
<option name="OPTION_DOCUMENT_TAG_USE" value="false" />
<option name="OPTION_DOCUMENT_TAG_AUTHOR" value="false" />
<option name="OPTION_DOCUMENT_TAG_VERSION" value="false" />
<option name="OPTION_DOCUMENT_TAG_DEPRECATED" value="true" />
<option name="OPTION_DEPRECATED_LIST" value="true" />
<option name="OTHER_OPTIONS" value="" />
<option name="HEAP_SIZE" />
<option name="LOCALE" />
<option name="OPEN_IN_BROWSER" value="true" />
</component>
<component name="ProjectResources">
<default-html-doctype>http://www.w3.org/1999/xhtml</default-html-doctype>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" assert-keyword="true" jdk-15="true" project-jdk-name="1.6" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
<component name="com.sixrr.metrics.MetricsReloaded">
<option name="selectedProfile" value="Lines of code metrics" />
<option name="autoscroll" value="false" />
<option name="showOnlyWarnings" value="false" />
</component>
</project>
+20
View File
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/../../Kotlin/jet/compiler/backend/backend.iml" filepath="$PROJECT_DIR$/../../Kotlin/jet/compiler/backend/backend.iml" />
<module fileurl="file://$PROJECT_DIR$/../../Kotlin/jet/compiler/cli/cli.iml" filepath="$PROJECT_DIR$/../../Kotlin/jet/compiler/cli/cli.iml" />
<module fileurl="file://$PROJECT_DIR$/../../Kotlin/jet/compiler/tests/compiler-tests.iml" filepath="$PROJECT_DIR$/../../Kotlin/jet/compiler/tests/compiler-tests.iml" />
<module fileurl="file://$PROJECT_DIR$/../../Kotlin/jet/compiler/frontend/frontend.iml" filepath="$PROJECT_DIR$/../../Kotlin/jet/compiler/frontend/frontend.iml" />
<module fileurl="file://$PROJECT_DIR$/../../Kotlin/jet/compiler/frontend.java/frontend.java.iml" filepath="$PROJECT_DIR$/../../Kotlin/jet/compiler/frontend.java/frontend.java.iml" />
<module fileurl="file://$PROJECT_DIR$/js.ast/js.ast.iml" filepath="$PROJECT_DIR$/js.ast/js.ast.iml" />
<module fileurl="file://$PROJECT_DIR$/js.backend/js.backend.iml" filepath="$PROJECT_DIR$/js.backend/js.backend.iml" />
<module fileurl="file://$PROJECT_DIR$/js.examples/js.examples.iml" filepath="$PROJECT_DIR$/js.examples/js.examples.iml" />
<module fileurl="file://$PROJECT_DIR$/js.tests/js.tests.iml" filepath="$PROJECT_DIR$/js.tests/js.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/js.lib/jslib.iml" filepath="$PROJECT_DIR$/js.lib/jslib.iml" />
<module fileurl="file://$PROJECT_DIR$/../../Kotlin/jet/stdlib/stdlib.iml" filepath="$PROJECT_DIR$/../../Kotlin/jet/stdlib/stdlib.iml" />
<module fileurl="file://$PROJECT_DIR$/../../Kotlin/jet/compiler/util/util.iml" filepath="$PROJECT_DIR$/../../Kotlin/jet/compiler/util/util.iml" />
</modules>
</component>
</project>
+5
View File
@@ -0,0 +1,5 @@
<component name="DependencyValidationManager">
<state>
<option name="SKIP_IMPORT_STATEMENTS" value="false" />
</state>
</component>
+125
View File
@@ -0,0 +1,125 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
+1097
View File
File diff suppressed because it is too large Load Diff
+150
View File
@@ -0,0 +1,150 @@
Index: compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java (revision 24a2ec5)
+++ compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java (revision 4229e867af6d744d3b384dfc515cbf89caf363ae)
@@ -173,8 +173,8 @@
List<AnnotationDescriptor> result = Lists.newArrayList();
for (JetAnnotationEntry annotation : annotations) {
AnnotationDescriptor annotationDescriptor = new AnnotationDescriptor();
- result.add(annotationDescriptor);
- trace.record(BindingContext.ANNOTATION, annotation, annotationDescriptor);
+ // result.add(annotationDescriptor);
+ // trace.record(BindingContext.ANNOTATION, annotation, annotationDescriptor);
}
return result;
}
Index: idea/src/META-INF/plugin.xml
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- idea/src/META-INF/plugin.xml (revision 24a2ec5)
+++ idea/src/META-INF/plugin.xml (revision 4229e867af6d744d3b384dfc515cbf89caf363ae)
@@ -1,9 +1,12 @@
<idea-plugin version="2">
<name>Kotlin</name>
<description>Kotlin language support</description>
- <version>@snapshot@</version>
+ <version>1.0</version>
<vendor>JetBrains</vendor>
+ <application-components>
+ </application-components>
+
<project-components>
<component>
<implementation-class>org.jetbrains.jet.plugin.compiler.JetCompilerManager</implementation-class>
@@ -28,16 +31,18 @@
<keyboard-shortcut keymap="$default" first-keystroke="control alt shift T"/>
<add-to-group group-id="CodeMenu" anchor="last"/>
</action>
- <action id="ConvertJavaToKotlin" class="org.jetbrains.jet.plugin.actions.JavaToKotlinAction"
- text="Convert Java File to Kotlin File">
- <keyboard-shortcut keymap="$default" first-keystroke="control alt shift J"/>
- <add-to-group group-id="CodeMenu" anchor="last"/>
- </action>
<action id="ToggleJetErrorReporting" class="org.jetbrains.jet.plugin.actions.ToggleErrorReportingAction"
text="Toggle Error Reporting">
<keyboard-shortcut keymap="$default" first-keystroke="control alt shift E"/>
<add-to-group group-id="CodeMenu" anchor="last"/>
</action>
+
+ <action id="Kotlin.TranslateToJs" class="org.jetbrains.jet.plugin.actions.TranslateToJsAction"
+ text="Translate current namespace and create js files.">
+ <keyboard-shortcut keymap="$default" first-keystroke="control alt shift J"/>
+ <add-to-group group-id="CodeMenu" anchor="last"/>
+ </action>
+
</actions>
<extensions defaultExtensionNs="com.intellij">
Index: idea/src/org/jetbrains/jet/plugin/actions/TranslateToJsAction.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- idea/src/org/jetbrains/jet/plugin/actions/TranslateToJsAction.java (revision 4229e867af6d744d3b384dfc515cbf89caf363ae)
+++ idea/src/org/jetbrains/jet/plugin/actions/TranslateToJsAction.java (revision 4229e867af6d744d3b384dfc515cbf89caf363ae)
@@ -0,0 +1,79 @@
+package org.jetbrains.jet.plugin.actions;
+
+import com.intellij.notification.Notification;
+import com.intellij.notification.NotificationType;
+import com.intellij.notification.Notifications;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.LangDataKeys;
+import com.intellij.openapi.actionSystem.PlatformDataKeys;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiFile;
+import org.jetbrains.jet.lang.psi.JetFile;
+import org.jetbrains.k2js.facade.K2JSTranslator;
+
+/**
+ * @author Pavel Talanov
+ */
+public final class TranslateToJsAction extends AnAction {
+
+ private static void notifyFailure(Throwable exception) {
+ Notifications.Bus.notify(new Notification("JsTranslator", "Translation failed.",
+ "Exception: " + exception.getMessage(),
+ NotificationType.ERROR));
+ }
+
+ private static void notifySuccess(String outputPath) {
+ Notifications.Bus.notify(new Notification("JsTranslator", "Translation successful.",
+ "Generated file: " + outputPath,
+ NotificationType.INFORMATION));
+ }
+
+ public void actionPerformed(AnActionEvent event) {
+
+ final PsiFile psiFile = event.getData(LangDataKeys.PSI_FILE);
+ if (!(psiFile instanceof JetFile)) {
+ return;
+ }
+
+ Runnable task = new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Project project = psiFile.getProject();
+ String outputPath = getOutputPath(psiFile);
+ K2JSTranslator.translateWithCallToMainAndSaveToFile((JetFile) psiFile,
+ outputPath,
+ project);
+ notifySuccess(outputPath);
+ } catch (Throwable e) {
+ e.printStackTrace();
+ notifyFailure(e);
+ }
+ }
+ };
+ ApplicationManager.getApplication().runWriteAction(task);
+ }
+
+ private static String getOutputPath(PsiFile psiFile) {
+ VirtualFile virtualFile = psiFile.getVirtualFile();
+ assert virtualFile != null : "Internal error: Psi file should correspond to actual virtual file";
+ String originalFilePath = virtualFile.getPath();
+
+ //TODO: make platform independent
+ String pathToDir = originalFilePath.substring(0, originalFilePath.lastIndexOf("/") + 1);
+ String generatedFileName = ((JetFile) psiFile).getNamespaceHeader().getName() + ".js";
+ return pathToDir + generatedFileName;
+ }
+
+
+ @Override
+ public void update(AnActionEvent e) {
+ Editor editor = e.getData(PlatformDataKeys.EDITOR);
+ PsiFile psiFile = e.getData(LangDataKeys.PSI_FILE);
+ e.getPresentation().setEnabled(editor != null && psiFile instanceof JetFile);
+ }
+}
+8
View File
@@ -0,0 +1,8 @@
# Below is a list of people and organizations that have contributed
# to the Dart project. Names should be added to the list like so:
#
# Name/Organization <email address>
Google Inc.
Ola Martin Bini <ola.bini@gmail.com>
+48
View File
@@ -0,0 +1,48 @@
This license applies to all parts of Dart that are not externally
maintained libraries. The external maintained libraries used by
Dart are:
JSCRE - in runtime/third_party/jscre
Ant - in third_party/apache_ant
Google App Engine for Java SDK - in third_party/appengine-java-sdk
args4j - in third_party/args4j
Chrome SDK - in third_party/chromesdk
Eclipse - in third_party/eclipse
gsutil = in third_party/gsutil
Guava - in third_party/guava
hamcrest - in third_party/hamcrest
Httplib2 - in third_party/httplib2
Jetty - in third_party/jetty
JSON - in third_party/json
JUnit - in third_party/junit
Ouath - in third_party/oauth2client
Python-scss - in third_party/pyscss
Rhino - in third_party/rhino
The libraries may have their own licenses; we recommend you read them,
as their terms may differ from the terms below.
Copyright 2011, the Dart project authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+23
View File
@@ -0,0 +1,23 @@
Additional IP Rights Grant (Patents)
"This implementation" means the copyrightable works distributed by
Google as part of the Dart Project.
Google hereby grants to you a perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable (except as stated in this
section) patent license to make, have made, use, offer to sell, sell,
import, transfer, and otherwise run, modify and propagate the contents
of this implementation of Dart, where such license applies only to
those patent claims, both currently owned by Google and acquired in
the future, licensable by Google that are necessarily infringed by
this implementation of Dart. This grant does not include claims that
would be infringed only as a consequence of further modification of
this implementation. If you or your agent or exclusive licensee
institute or order or agree to the institution of patent litigation
against any entity (including a cross-claim or counterclaim in a
lawsuit) alleging that this implementation of Dart or any code
incorporated within this implementation of Dart constitutes direct or
contributory patent infringement, or inducement of patent
infringement, then any patent rights granted to you under this License
for this implementation of Dart shall terminate as of the date such
litigation is filed.
+13
View File
@@ -0,0 +1,13 @@
<?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="jdk" jdkName="1.6" jdkType="JavaSDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="guava-10.0.1" level="application" />
</component>
</module>
+13
View File
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<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="jdk" jdkName="1.6" jdkType="JavaSDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="guava-10.0.1" level="application" />
</component>
</module>
@@ -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;
/**
* Exception thrown when the compiler encounters an unexpected internal error.
*/
public class InternalCompilerException extends RuntimeException {
public InternalCompilerException(String message) {
super(message);
}
}
@@ -0,0 +1,44 @@
// 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;
/**
* 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 java.util.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,232 @@
// Copyright 2011, the Dart project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.dart.compiler.backend.js;
import com.google.dart.compiler.InternalCompilerException;
import com.google.dart.compiler.backend.js.ast.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
/**
* Implements actual cloning logic. We rely on the JsExpressions to provide
* traversal logic. The {@link #stack} field is used to accumulate
* already-cloned JsExpression instances. One gotcha that falls out of this is
* that argument lists are on the stack in reverse order, so lists should be
* constructed via inserts, rather than appends.
*/
public class Cloner extends JsVisitor {
protected final Stack<JsExpression> stack = new Stack<JsExpression>();
private boolean successful = true;
/**
* @param expression
* @return Return a clone of the expression tree
*/
public static JsExpression clone(JsExpression expression) {
Cloner c = new Cloner();
c.accept(expression);
return c.getExpression();
}
@Override
public void endVisit(JsArrayAccess x, JsContext ctx) {
JsArrayAccess newExpression = new JsArrayAccess();
newExpression.setIndexExpr(stack.pop());
newExpression.setArrayExpr(stack.pop());
stack.push(newExpression);
}
@Override
public void endVisit(JsArrayLiteral x, JsContext ctx) {
JsArrayLiteral toReturn = new JsArrayLiteral();
List<JsExpression> expressions = toReturn.getExpressions();
int size = x.getExpressions().size();
while (size-- > 0) {
expressions.add(0, stack.pop());
}
stack.push(toReturn);
}
@Override
public void endVisit(JsBinaryOperation x, JsContext ctx) {
JsBinaryOperation toReturn = new JsBinaryOperation(x.getOperator());
toReturn.setArg2(stack.pop());
toReturn.setArg1(stack.pop());
stack.push(toReturn);
}
@Override
public void endVisit(JsBooleanLiteral x, JsContext ctx) {
stack.push(x);
}
@Override
public void endVisit(JsConditional x, JsContext ctx) {
JsConditional toReturn = new JsConditional();
toReturn.setElseExpression(stack.pop());
toReturn.setThenExpression(stack.pop());
toReturn.setTestExpression(stack.pop());
stack.push(toReturn);
}
/**
* The only functions that would get be visited are those being used as
* first-class objects.
*/
@Override
public void endVisit(JsFunction x, JsContext ctx) {
// Set a flag to indicate that we cannot continue, and push a null so
// we don't run out of elements on the stack.
successful = false;
stack.push(null);
}
/**
* Cloning the invocation allows us to modify it without damaging other call
* sites.
*/
@Override
public void endVisit(JsInvocation x, JsContext ctx) {
JsInvocation toReturn = new JsInvocation();
List<JsExpression> params = toReturn.getArguments();
int size = x.getArguments().size();
while (size-- > 0) {
params.add(0, stack.pop());
}
toReturn.setQualifier(stack.pop());
stack.push(toReturn);
}
/**
* Do a deep clone of a JsNameRef. Because JsNameRef chains are shared
* throughout the AST, you can't just go and change their qualifiers when
* re-writing an invocation.
*/
@Override
public void endVisit(JsNameRef x, JsContext ctx) {
JsNameRef toReturn;
JsName name = x.getName();
if (name != null) {
toReturn = new JsNameRef(name);
} else {
toReturn = new JsNameRef(x.getIdent());
}
if (x.getQualifier() != null) {
toReturn.setQualifier(stack.pop());
}
stack.push(toReturn);
}
@Override
public void endVisit(JsNew x, JsContext ctx) {
int size = x.getArguments().size();
List<JsExpression> arguments = new ArrayList<JsExpression>(size);
while (size-- > 0) {
arguments.add(0, stack.pop());
}
JsNew toReturn = new JsNew(stack.pop());
toReturn.getArguments().addAll(arguments);
stack.push(toReturn);
}
@Override
public void endVisit(JsNullLiteral x, JsContext ctx) {
stack.push(x);
}
@Override
public void endVisit(JsNumberLiteral x, JsContext ctx) {
stack.push(x);
}
@Override
public void endVisit(JsObjectLiteral x, JsContext ctx) {
JsObjectLiteral toReturn = new JsObjectLiteral();
List<JsPropertyInitializer> inits = toReturn.getPropertyInitializers();
int size = x.getPropertyInitializers().size();
while (size-- > 0) {
/*
* JsPropertyInitializers are the only non-JsExpression objects that we
* care about, so we just go ahead and create the objects in the loop,
* rather than expecting it to be on the stack and having to perform
* narrowing casts at all stack.pop() invocations.
*/
JsPropertyInitializer newInit = new JsPropertyInitializer();
newInit.setValueExpr(stack.pop());
newInit.setLabelExpr(stack.pop());
inits.add(0, newInit);
}
stack.push(toReturn);
}
@Override
public void endVisit(JsPostfixOperation x, JsContext ctx) {
JsPostfixOperation toReturn = new JsPostfixOperation(x.getOperator());
toReturn.setArg(stack.pop());
stack.push(toReturn);
}
@Override
public void endVisit(JsPrefixOperation x, JsContext ctx) {
JsPrefixOperation toReturn = new JsPrefixOperation(x.getOperator());
toReturn.setArg(stack.pop());
stack.push(toReturn);
}
@Override
public void endVisit(JsRegExp x, JsContext ctx) {
stack.push(x);
}
@Override
public void endVisit(JsStringLiteral x, JsContext ctx) {
stack.push(x);
}
@Override
public void endVisit(JsThisRef x, JsContext ctx) {
stack.push(new JsThisRef());
}
public JsExpression getExpression() {
return (successful && checkStack()) ? stack.peek() : null;
}
private boolean checkStack() {
if (stack.size() > 1) {
throw new InternalCompilerException("Too many expressions on stack");
}
return stack.size() == 1;
}
}
@@ -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;
import com.google.dart.compiler.backend.js.ast.*;
/**
* Searches for method invocations in constructor expressions that would not
* normally be surrounded by parentheses.
*/
public class JsConstructExpressionVisitor extends JsVisitor {
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 = false;
private JsConstructExpressionVisitor() {
}
/**
* We only look at the array expression since the index has its own scope.
*/
@Override
public boolean visit(JsArrayAccess x, JsContext ctx) {
accept(x.getArrayExpr());
return false;
}
/**
* Array literals have their own scoping.
*/
@Override
public boolean visit(JsArrayLiteral x, JsContext ctx) {
return false;
}
/**
* Functions have their own scoping.
*/
@Override
public boolean visit(JsFunction x, JsContext ctx) {
return false;
}
@Override
public boolean visit(JsInvocation x, JsContext ctx) {
containsInvocation = true;
return false;
}
@Override
public boolean visit(JsNameRef x, JsContext ctx) {
if (!x.isLeaf()) {
accept(x.getQualifier());
}
return false;
}
/**
* New constructs bind to the nearest set of parentheses.
*/
@Override
public boolean visit(JsNew x, JsContext ctx) {
return false;
}
/**
* Object literals have their own scope.
*/
@Override
public boolean visit(JsObjectLiteral x, JsContext ctx) {
return false;
}
/**
* We only look at nodes that would not normally be surrounded by parentheses.
*/
@Override
protected <T extends JsVisitable> T doAccept(T node) {
// Assign to Object to prevent 'inconvertible types' toJsAst errors due
// to http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6548436
// reproducible in jdk1.6.0_02.
Object o = node;
if (o instanceof JsExpression) {
JsExpression expression = (JsExpression) o;
int precedence = JsPrecedenceVisitor.exec(expression);
// Only visit expressions that won't automatically be surrounded by
// parentheses
if (precedence < JsPrecedenceVisitor.PRECEDENCE_NEW) {
return node;
}
}
return super.doAccept(node);
}
}
@@ -0,0 +1,119 @@
// 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.*;
/**
* Determines if an expression statement needs to be surrounded by parentheses.
*
* 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.
*
* 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>
*
* 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 JsVisitor {
public static boolean exec(JsExprStmt statement) {
JsFirstExpressionVisitor visitor = new JsFirstExpressionVisitor();
JsExpression expression = statement.getExpression();
// Pure function declarations do not need parentheses
if (expression instanceof JsFunction) {
return false;
}
visitor.accept(statement.getExpression());
return visitor.needsParentheses;
}
private boolean needsParentheses = false;
private JsFirstExpressionVisitor() {
}
@Override
public boolean visit(JsArrayAccess x, JsContext ctx) {
accept(x.getArrayExpr());
return false;
}
@Override
public boolean visit(JsArrayLiteral x, JsContext ctx) {
return false;
}
@Override
public boolean visit(JsBinaryOperation x, JsContext ctx) {
accept(x.getArg1());
return false;
}
@Override
public boolean visit(JsConditional x, JsContext ctx) {
accept(x.getTestExpression());
return false;
}
@Override
public boolean visit(JsFunction x, JsContext ctx) {
needsParentheses = true;
return false;
}
@Override
public boolean visit(JsInvocation x, JsContext ctx) {
accept(x.getQualifier());
return false;
}
@Override
public boolean visit(JsNameRef x, JsContext ctx) {
if (!x.isLeaf()) {
accept(x.getQualifier());
}
return false;
}
@Override
public boolean visit(JsNew x, JsContext ctx) {
return false;
}
@Override
public boolean visit(JsObjectLiteral x, JsContext ctx) {
needsParentheses = true;
return false;
}
@Override
public boolean visit(JsPostfixOperation x, JsContext ctx) {
accept(x.getArg());
return false;
}
@Override
public boolean visit(JsPrefixOperation x, JsContext ctx) {
return false;
}
@Override
public boolean visit(JsRegExp x, JsContext ctx) {
return false;
}
}
@@ -0,0 +1,23 @@
// 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.JsProgram;
/**
* A namer runs through a program and renames the short names of JsNames.
* Namers must assign short names that don't clash and that are valid
* JS-identifiers. Nested JsScopes must not shadow JsNames from outer
* scopes.
* If a JsName is marked as non-obfuscatable then it must retain its short
* name.
*/
public interface JsNamer {
/**
* GlobalNames the shortNames of all JsNames of the program so that they are valid
* JS-identifiers and that there are no clashes and no shadowing.
*/
public void exec(JsProgram program);
}
@@ -0,0 +1,103 @@
// 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.*;
/**
* Fixes any semantic errors introduced by JS AST gen.
*
* <ul>
* <li>Creating clinit calls can put comma expressions as lvalues; the modifying
* operation must be moved inside the comma expression to the last argument.</li>
* </ul>
*/
public class JsNormalizer {
/**
* Resolves any unresolved JsNameRefs.
*/
private static class JsNormalizing extends JsModVisitor {
@Override
public void endVisit(JsBinaryOperation x, JsContext ctx) {
maybeShuffleModifyingBinary(x, ctx);
}
@Override
public void endVisit(JsPostfixOperation x, JsContext ctx) {
maybeShuffleModifyingUnary(x, ctx);
}
@Override
public void endVisit(JsPrefixOperation x, JsContext ctx) {
maybeShuffleModifyingUnary(x, ctx);
}
/**
* Due to the way clinits are constructed, you can end up with a comma
* operation as the argument to a modifying operation, which is illegal.
* Juggle things to put the operator inside of the comma expression.
*/
private void maybeShuffleModifyingBinary(JsBinaryOperation x, JsContext ctx) {
JsBinaryOperator myOp = x.getOperator();
JsExpression lhs = x.getArg1();
if (myOp.isAssignment() && (lhs instanceof JsBinaryOperation)) {
// Find the rightmost comma operation
JsBinaryOperation curLhs = (JsBinaryOperation) lhs;
assert (curLhs.getOperator() == JsBinaryOperator.COMMA);
while (curLhs.getArg2() instanceof JsBinaryOperation) {
curLhs = (JsBinaryOperation) curLhs.getArg2();
assert (curLhs.getOperator() == JsBinaryOperator.COMMA);
}
// curLhs is now the rightmost comma operation; slide our operation in
x.setArg1(curLhs.getArg2());
curLhs.setArg2(x);
// replace myself with the comma expression
ctx.replaceMe(lhs);
}
}
/**
* Due to the way clinits are constructed, you can end up with a comma
* operation as the argument to a modifying operation, which is illegal.
* Juggle things to put the operator inside of the comma expression.
*/
private void maybeShuffleModifyingUnary(JsUnaryOperation x, JsContext ctx) {
JsUnaryOperator myOp = x.getOperator();
JsExpression arg = x.getArg();
if (myOp.isModifying() && (arg instanceof JsBinaryOperation)) {
// Find the rightmost comma operation
JsBinaryOperation curArg = (JsBinaryOperation) arg;
assert (curArg.getOperator() == JsBinaryOperator.COMMA);
while (curArg.getArg2() instanceof JsBinaryOperation) {
curArg = (JsBinaryOperation) curArg.getArg2();
assert (curArg.getOperator() == JsBinaryOperator.COMMA);
}
// curArg is now the rightmost comma operation; slide our operation in
x.setArg(curArg.getArg2());
curArg.setArg2(x);
// replace myself with the comma expression
ctx.replaceMe(arg);
}
}
}
public static void exec(JsProgram program) {
new JsNormalizer(program).execImpl();
}
private final JsProgram program;
private JsNormalizer(JsProgram program) {
this.program = program;
}
private void execImpl() {
JsNormalizing normalizer = new JsNormalizing();
normalizer.accept(program);
}
}
@@ -0,0 +1,92 @@
// 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;
/**
* Indicates inability to parse JavaScript source.
*/
public class JsParserException extends Exception {
/**
* Represents the location of a parser exception.
*/
public static class SourceDetail {
private final String fileName;
private final int line;
private final int lineOffset;
private final String lineSource;
public SourceDetail(int line, String lineSource, int lineOffset, String fileName) {
this.line = line;
this.lineSource = lineSource;
this.lineOffset = lineOffset;
this.fileName = fileName;
}
public String getFileName() {
return fileName;
}
public int getLine() {
return line;
}
public int getLineOffset() {
return lineOffset;
}
public String getLineSource() {
return lineSource;
}
}
private static String createMessageWithDetail(String msg, SourceDetail sourceDetail) {
if (sourceDetail == null) {
return msg;
}
StringBuffer sb = new StringBuffer();
sb.append(sourceDetail.getFileName());
sb.append('(');
sb.append(sourceDetail.getLine());
sb.append(')');
sb.append(": ");
sb.append(msg);
if (sourceDetail.getLineSource() != null) {
sb.append("\n> ");
sb.append(sourceDetail.getLineSource());
sb.append("\n> ");
for (int i = 0, n = sourceDetail.getLineOffset(); i < n; ++i) {
sb.append('-');
}
sb.append('^');
}
return sb.toString();
}
private final SourceDetail sourceDetail;
public JsParserException(String msg) {
this(msg, null);
}
public JsParserException(String msg, int line, String lineSource, int lineOffset, String fileName) {
this(msg, new SourceDetail(line, lineSource, lineOffset, fileName));
}
public JsParserException(String msg, SourceDetail sourceDetail) {
super(createMessageWithDetail(msg, sourceDetail));
this.sourceDetail = sourceDetail;
}
/**
* Provides additional source detail in some cases.
*
* @return additional detail regarding the error, or <code>null</code> if no
* additional detail is available
*/
public SourceDetail getSourceDetail() {
return sourceDetail;
}
}
@@ -0,0 +1,274 @@
// 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.*;
/**
* Precedence indices from "JavaScript - The Definitive Guide" 4th Edition (page
* 57)
*
* Precedence 17 is for indivisible primaries that either don't have children,
* or provide their own delimiters.
*
* Precedence 16 is for really important things that have their own AST classes.
*
* Precedence 15 is for the new construct.
*
* Precedence 14 is for unary operators.
*
* Precedences 12 through 4 are for non-assigning binary operators.
*
* Precedence 3 is for the tertiary conditional.
*
* Precedence 2 is for assignments.
*
* Precedence 1 is for comma operations.
*/
class JsPrecedenceVisitor extends JsVisitor {
static final int PRECEDENCE_NEW = 15;
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;
}
private int answer = -1;
private JsPrecedenceVisitor() {
}
@Override
public boolean visit(JsArrayAccess x, JsContext ctx) {
answer = 16;
return false;
}
@Override
public boolean visit(JsArrayLiteral x, JsContext ctx) {
answer = 17; // primary
return false;
}
@Override
public boolean visit(JsBinaryOperation x, JsContext ctx) {
answer = x.getOperator().getPrecedence();
return false;
}
@Override
public boolean visit(JsBlock x, JsContext ctx) {
throw new RuntimeException("Only expressions have precedence.");
}
@Override
public boolean visit(JsBooleanLiteral x, JsContext ctx) {
answer = 17; // primary
return false;
}
@Override
public boolean visit(JsBreak x, JsContext ctx) {
throw new RuntimeException("Only expressions have precedence.");
}
@Override
public boolean visit(JsCase x, JsContext ctx) {
throw new RuntimeException("Only expressions have precedence.");
}
@Override
public boolean visit(JsCatch x, JsContext ctx) {
throw new RuntimeException("Only expressions have precedence.");
}
@Override
public boolean visit(JsConditional x, JsContext ctx) {
answer = 3;
return false;
}
@Override
public boolean visit(JsContinue x, JsContext ctx) {
throw new RuntimeException("Only expressions have precedence.");
}
@Override
public boolean visit(JsDebugger x, JsContext ctx) {
throw new RuntimeException("Only expressions have precedence.");
}
@Override
public boolean visit(JsDefault x, JsContext ctx) {
throw new RuntimeException("Only expressions have precedence.");
}
@Override
public boolean visit(JsDoWhile x, JsContext ctx) {
throw new RuntimeException("Only expressions have precedence.");
}
@Override
public boolean visit(JsEmpty x, JsContext ctx) {
throw new RuntimeException("Only expressions have precedence.");
}
@Override
public boolean visit(JsExprStmt x, JsContext ctx) {
throw new RuntimeException("Only expressions have precedence.");
}
@Override
public boolean visit(JsFor x, JsContext ctx) {
throw new RuntimeException("Only expressions have precedence.");
}
@Override
public boolean visit(JsForIn x, JsContext ctx) {
throw new RuntimeException("Only expressions have precedence.");
}
@Override
public boolean visit(JsFunction x, JsContext ctx) {
answer = 17; // primary
return false;
}
@Override
public boolean visit(JsIf x, JsContext ctx) {
throw new RuntimeException("Only expressions have precedence.");
}
@Override
public boolean visit(JsInvocation x, JsContext ctx) {
answer = 16;
return false;
}
@Override
public boolean visit(JsLabel x, JsContext ctx) {
throw new RuntimeException("Only expressions have precedence.");
}
@Override
public boolean visit(JsNameRef x, JsContext ctx) {
if (x.isLeaf()) {
answer = 17; // primary
} else {
answer = 16; // property access
}
return false;
}
@Override
public boolean visit(JsNew x, JsContext ctx) {
answer = PRECEDENCE_NEW;
return false;
}
@Override
public boolean visit(JsNullLiteral x, JsContext ctx) {
answer = 17; // primary
return false;
}
@Override
public boolean visit(JsNumberLiteral x, JsContext ctx) {
answer = 17; // primary
return false;
}
@Override
public boolean visit(JsObjectLiteral x, JsContext ctx) {
answer = 17; // primary
return false;
}
@Override
public boolean visit(JsParameter x, JsContext ctx) {
throw new RuntimeException("Only expressions have precedence.");
}
@Override
public boolean visit(JsPostfixOperation x, JsContext ctx) {
answer = x.getOperator().getPrecedence();
return false;
}
@Override
public boolean visit(JsPrefixOperation x, JsContext ctx) {
answer = x.getOperator().getPrecedence();
return false;
}
@Override
public boolean visit(JsProgram x, JsContext ctx) {
throw new RuntimeException("Only expressions have precedence.");
}
@Override
public boolean visit(JsPropertyInitializer x, JsContext ctx) {
answer = 17; // primary
return false;
}
@Override
public boolean visit(JsRegExp x, JsContext ctx) {
answer = 17; // primary
return false;
}
@Override
public boolean visit(JsReturn x, JsContext ctx) {
throw new RuntimeException("Only expressions have precedence.");
}
@Override
public boolean visit(JsStringLiteral x, JsContext ctx) {
answer = 17; // primary
return false;
}
@Override
public boolean visit(JsSwitch x, JsContext ctx) {
throw new RuntimeException("Only expressions have precedence.");
}
@Override
public boolean visit(JsThisRef x, JsContext ctx) {
answer = 17; // primary
return false;
}
@Override
public boolean visit(JsThrow x, JsContext ctx) {
throw new RuntimeException("Only expressions have precedence.");
}
@Override
public boolean visit(JsTry x, JsContext ctx) {
throw new RuntimeException("Only expressions have precedence.");
}
@Override
public boolean visit(JsVars.JsVar x, JsContext ctx) {
throw new RuntimeException("Only expressions have precedence.");
}
@Override
public boolean visit(JsVars x, JsContext ctx) {
throw new RuntimeException("Only expressions have precedence.");
}
@Override
public boolean visit(JsWhile x, JsContext ctx) {
throw new RuntimeException("Only expressions have precedence.");
}
}
@@ -0,0 +1,122 @@
// 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.JsName;
import com.google.dart.compiler.backend.js.ast.JsProgram;
import com.google.dart.compiler.backend.js.ast.JsRootScope;
import com.google.dart.compiler.backend.js.ast.JsScope;
import java.util.*;
/**
* A namer that uses short, readable idents to maximize reability.
*/
public class JsPrettyNamer implements JsNamer {
public JsPrettyNamer() {
this.program = null;
}
@Override
public void exec(JsProgram program) {
new JsPrettyNamer(program).execImpl();
}
/**
* Communicates to a parent scope all the idents used by all child scopes.
*/
private Set<String> childIdents = null;
private final JsProgram program;
/**
* A map containing the next integer to try as an identifier suffix for a
* given JsScope.
*/
private IdentityHashMap<JsScope, HashMap<String, Integer>> startIdentForScope =
new IdentityHashMap<JsScope, HashMap<String, Integer>>();
protected JsPrettyNamer(JsProgram program) {
this.program = program;
}
private void execImpl() {
visit(program.getRootScope());
}
private boolean isLegal(JsScope scope, Set<String> childIdents, String newIdent) {
if (JsReservedIdentifiers.isKeyword(newIdent)) {
return false;
}
if (childIdents.contains(newIdent)) {
// one of my children already claimed this ident
return false;
}
/*
* Never obfuscate a name into an identifier that conflicts with an existing
* unobfuscatable name! It's okay if it conflicts with an existing
* obfuscatable name; that name will get obfuscated out of the way.
*/
return (scope.findExistingUnobfuscatableName(newIdent) == null);
}
private void visit(JsScope scope) {
HashMap<String, Integer> startIdent = startIdentForScope.get(scope);
if (startIdent == null) {
startIdent = new HashMap<String, Integer>();
startIdentForScope.put(scope, startIdent);
}
// Save off the childIdents which is currently being computed for my parent.
Set<String> myChildIdents = childIdents;
/*
* Visit my children first. Reset childIdents so that my children will get a
* clean slate: I do not communicate to my children.
*/
childIdents = new HashSet<String>();
List<JsScope> children = scope.getChildren();
for (Iterator<JsScope> it = children.iterator(); it.hasNext();) {
visit(it.next());
}
JsRootScope rootScope = program.getRootScope();
if (scope == rootScope) {
return;
}
// Visit all my idents.
for (Iterator<JsName> it = scope.getAllNames(); it.hasNext();) {
JsName name = it.next();
if (!name.isObfuscatable()) {
// Unobfuscatable names become themselves.
name.setShortIdent(name.getIdent());
continue;
}
String newIdent = name.getShortIdent();
if (!isLegal(scope, childIdents, newIdent)) {
String checkIdent;
// Start searching using a suffix hint stored in the scope.
// We still do a search in case there is a collision with
// a user-provided identifier
Integer s = startIdent.get(newIdent);
int suffix = (s == null) ? 0 : s.intValue();
do {
checkIdent = newIdent + "_" + suffix++;
} while (!isLegal(scope, childIdents, checkIdent));
startIdent.put(newIdent, suffix);
name.setShortIdent(checkIdent);
} else {
// nothing to do; the short name is already good
}
childIdents.add(name.getShortIdent());
}
myChildIdents.addAll(childIdents);
childIdents = myChildIdents;
}
}
@@ -0,0 +1,140 @@
// 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.*;
/**
* Determines if a statement at the end of a block requires a semicolon.
*
* For example, the following statements require semicolons:<br>
* <ul>
* <li>if (cond);</li>
* <li>while (cond);</li>
* </ul>
*
* The following do not require semicolons:<br>
* <ul>
* <li>return 1</li>
* <li>do {} while(true)</li>
* </ul>
*/
public class JsRequiresSemiVisitor extends JsVisitor {
public static boolean exec(JsStatement lastStatement) {
JsRequiresSemiVisitor visitor = new JsRequiresSemiVisitor();
visitor.accept(lastStatement);
return visitor.needsSemicolon;
}
private boolean needsSemicolon = false;
private JsRequiresSemiVisitor() {
}
@Override
public boolean visit(JsBlock x, JsContext ctx) {
return false;
}
@Override
public boolean visit(JsBreak x, JsContext ctx) {
return false;
}
@Override
public boolean visit(JsDebugger x, JsContext ctx) {
return false;
}
@Override
public boolean visit(JsDoWhile x, JsContext ctx) {
return false;
}
@Override
public boolean visit(JsEmpty x, JsContext ctx) {
return false;
}
@Override
public boolean visit(JsExprStmt x, JsContext ctx) {
return false;
}
@Override
public boolean visit(JsFor x, JsContext ctx) {
if (x.getBody() instanceof JsEmpty) {
needsSemicolon = true;
}
return false;
}
@Override
public boolean visit(JsForIn x, JsContext ctx) {
if (x.getBody() instanceof JsEmpty) {
needsSemicolon = true;
}
return false;
}
@Override
public boolean visit(JsIf x, JsContext ctx) {
JsStatement thenStmt = x.getThenStmt();
JsStatement elseStmt = x.getElseStmt();
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);
}
return false;
}
@Override
public boolean visit(JsLabel x, JsContext ctx) {
if (x.getStmt() instanceof JsEmpty) {
needsSemicolon = true;
}
return false;
}
@Override
public boolean visit(JsReturn x, JsContext ctx) {
return false;
}
@Override
public boolean visit(JsSwitch x, JsContext ctx) {
return false;
}
@Override
public boolean visit(JsThrow x, JsContext ctx) {
return false;
}
@Override
public boolean visit(JsTry x, JsContext ctx) {
return false;
}
@Override
public boolean visit(JsVars x, JsContext ctx) {
return false;
}
@Override
public boolean visit(JsWhile x, JsContext ctx) {
if (x.getBody() instanceof JsEmpty) {
needsSemicolon = true;
}
return false;
}
}
@@ -0,0 +1,223 @@
// 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 java.util.HashSet;
import java.util.Set;
/**
* Determines whether or not a particular string is a JavaScript keyword or not.
*/
public class JsReservedIdentifiers {
private static Set<String> javaScriptKeywords;
private static Set<String> reservedGlobalSymbols;
private static Set<String> reservedPropertySymbols;
static {
javaScriptKeywords = new HashSet<String>();
reservedGlobalSymbols = new HashSet<String>();
reservedPropertySymbols = new HashSet<String>();
initJavaScriptKeywords();
initReservedGlobalSymbols();
initReservedPropertySymbols();
}
public static boolean isKeyword(String s) {
return javaScriptKeywords.contains(s);
}
private static void initJavaScriptKeywords() {
String[] keywords = new String[] {
// These are current keywords
"break", "delete", "function", "return", "typeof", "case", "do", "if", "switch", "var",
"catch", "else", "in", "this", "void", "continue", "false", "instanceof", "throw",
"while", "debugger", "finally", "new", "true", "with", "default", "for",
"null", "try",
// These are future keywords
"abstract", "double", "goto", "native", "static", "boolean", "enum", "implements",
"package", "super", "byte", "export", "import", "private", "synchronized", "char",
"extends", "int", "protected", "throws", "class", "final", "interface", "public",
"transient", "const", "float", "long", "short", "volatile"
};
for (int i = 0; i < keywords.length; i++) {
javaScriptKeywords.add(keywords[i]);
}
}
/**
* @return a set containing all known reserved global identifiers. This set must not be modified.
*/
public static Set<String> getReservedGlobalSymbols() {
return reservedGlobalSymbols;
}
/**
* Returns true if the string s can not be used as a global identifier. The check includes
* JavaScript keywords (as they must not be used either).
* @param s
* @return true if the given String must not be used as a global identifier.
*/
public static boolean isReservedGlobalSymbol(String s) {
return isKeyword(s) || reservedGlobalSymbols.contains(s);
}
private static void initReservedGlobalSymbols() {
// Section references are from Ecma-262
// (http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf)
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",
// TODO: prove why this is necessary or remove it
"call"
};
for (int i = 0; i < commonBuiltins.length; i++) {
reservedGlobalSymbols.add(commonBuiltins[i]);
}
}
/**
* Returns true if the given string can not be used as property symbol. The check excludes
* keywords as JavaScript allow keywords as properties.
* @param s
* @return true if the given string must not be used as a property.
*/
public static boolean isReservedPropertySymbol(String s) {
return reservedPropertySymbols.contains(s);
}
private static void initReservedPropertySymbols() {
// TODO(floitsch): fill in reserved property symbols.
reservedPropertySymbols.add("__PROTO__");
reservedPropertySymbols.add("prototype");
}
private JsReservedIdentifiers() {
}
}
@@ -0,0 +1,39 @@
// 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.util.TextOutput;
import com.google.dart.compiler.backend.js.ast.JsContext;
import com.google.dart.compiler.backend.js.ast.JsProgramFragment;
import com.google.dart.compiler.backend.js.ast.JsBlock;
import com.google.dart.compiler.backend.js.ast.JsProgram;
/**
* Generates JavaScript source from an AST.
*/
public class JsSourceGenerationVisitor extends JsToStringGenerationVisitor {
public JsSourceGenerationVisitor(TextOutput out) {
super(out);
}
@Override
public boolean visit(JsProgram x, JsContext ctx) {
// Descend naturally.
return true;
}
@Override
public boolean visit(JsProgramFragment x, JsContext ctx) {
// Descend naturally.
return true;
}
@Override
public boolean visit(JsBlock x, JsContext ctx) {
printJsBlock(x, false, true);
return false;
}
}
@@ -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;
/**
* An unchecked wrapper exception to interop with Rhino.
*/
class UncheckedJsParserException extends RuntimeException {
private final JsParserException parserException;
public UncheckedJsParserException(JsParserException parserException) {
this.parserException = parserException;
}
public JsParserException getParserException() {
return parserException;
}
}
@@ -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;
/**
* An interface that describes the boolean evaluation of an expression.
*/
public interface CanBooleanEval {
boolean isBooleanFalse();
boolean isBooleanTrue();
}
@@ -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,12 @@
// 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 that have a name.
*/
public interface HasName {
JsName getName();
}
@@ -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;
/**
* Represents a javascript expression for array access.
*/
public final class JsArrayAccess extends JsExpression {
private JsExpression arrayExpr;
private JsExpression indexExpr;
public JsArrayAccess() {
super();
}
public JsArrayAccess(JsExpression arrayExpr, JsExpression indexExpr) {
this.arrayExpr = arrayExpr;
this.indexExpr = indexExpr;
}
public JsExpression getArrayExpr() {
return arrayExpr;
}
public JsExpression getIndexExpr() {
return indexExpr;
}
@Override
public boolean hasSideEffects() {
return arrayExpr.hasSideEffects() || indexExpr.hasSideEffects();
}
@Override
public boolean isDefinitelyNotNull() {
return false;
}
@Override
public boolean isDefinitelyNull() {
return false;
}
public void setArrayExpr(JsExpression arrayExpr) {
this.arrayExpr = arrayExpr;
}
public void setIndexExpr(JsExpression indexExpr) {
this.indexExpr = indexExpr;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
if (v.visit(this, ctx)) {
arrayExpr = v.accept(arrayExpr);
indexExpr = v.accept(indexExpr);
}
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.ARRAY_ACCESS;
}
}
@@ -0,0 +1,67 @@
// 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.ArrayList;
import java.util.List;
/**
* Represents a JavaScript expression for array literals.
*/
public final class JsArrayLiteral extends JsLiteral {
private final List<JsExpression> exprs = new ArrayList<JsExpression>();
public JsArrayLiteral() {
super();
}
public List<JsExpression> getExpressions() {
return exprs;
}
@Override
public boolean hasSideEffects() {
for (JsExpression expr : exprs) {
if (expr.hasSideEffects()) {
return true;
}
}
return false;
}
@Override
public boolean isBooleanFalse() {
return false;
}
@Override
public boolean isBooleanTrue() {
return true;
}
@Override
public boolean isDefinitelyNotNull() {
return true;
}
@Override
public boolean isDefinitelyNull() {
return false;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
if (v.visit(this, ctx)) {
v.acceptWithInsertRemove(exprs);
}
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.ARRAY;
}
}
@@ -0,0 +1,107 @@
// 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 a JavaScript binary operation.
*/
public final class JsBinaryOperation extends JsExpression {
private JsExpression arg1;
private JsExpression arg2;
private final JsBinaryOperator op;
public JsBinaryOperation(JsBinaryOperator op) {
this(op, null, null);
}
public JsBinaryOperation(JsBinaryOperator op, JsExpression arg1, JsExpression arg2) {
this.op = op;
this.arg1 = arg1;
this.arg2 = arg2;
}
public JsExpression getArg1() {
return arg1;
}
public JsExpression getArg2() {
return arg2;
}
public JsBinaryOperator getOperator() {
return op;
}
@Override
public boolean hasSideEffects() {
return op.isAssignment() || arg1.hasSideEffects() || arg2.hasSideEffects();
}
@Override
public boolean isDefinitelyNotNull() {
// Precarious coding, but none of these can have null results.
if (op.getPrecedence() > 5) {
return true;
}
if (op == JsBinaryOperator.OR) {
if (arg1 instanceof CanBooleanEval) {
if (((CanBooleanEval) arg1).isBooleanTrue()) {
assert arg1.isDefinitelyNotNull();
return true;
}
}
}
// AND and OR can return nulls
if (op.isAssignment()) {
if (op == JsBinaryOperator.ASG) {
return arg2.isDefinitelyNotNull();
} else {
// All other ASG's are math ops.
return true;
}
}
if (op == JsBinaryOperator.COMMA) {
return arg2.isDefinitelyNotNull();
}
return false;
}
@Override
public boolean isDefinitelyNull() {
if (op == JsBinaryOperator.AND) {
return arg1.isDefinitelyNull();
}
return false;
}
public void setArg1(JsExpression arg1) {
this.arg1 = arg1;
}
public void setArg2(JsExpression arg2) {
this.arg2 = arg2;
}
@Override
public void traverse(JsVisitor 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);
}
@Override
public NodeKind getKind() {
return NodeKind.BINARY_OP;
}
}
@@ -0,0 +1,120 @@
// 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() {
/*
* Beware, flaky! Maybe I should have added Yet Another Field to
* BinaryOperator?
*/
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,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 java.util.LinkedList;
import java.util.List;
/**
* Represents a JavaScript block statement.
*/
public class JsBlock extends JsStatement {
private final LinkedList<JsStatement> stmts = new LinkedList<JsStatement>();
public JsBlock() {
}
public JsBlock(JsStatement stmt) {
stmts.add(stmt);
}
public List<JsStatement> getStatements() {
return stmts;
}
public void addStatement(JsStatement statement) {
assert statement != null;
stmts.add(statement);
}
public boolean isGlobalBlock() {
return false;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
if (v.visit(this, ctx)) {
v.acceptWithInsertRemove(stmts);
}
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.BLOCK;
}
/*Pavel Talanov*/
public void addVarDeclaration(JsVars vars) {
stmts.offerFirst(vars);
}
public void setStatements(List<JsStatement> statements) {
assert this.stmts.isEmpty() : "Already contains statements.";
this.stmts.addAll(statements);
}
}
@@ -0,0 +1,53 @@
// 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 a JavaScript literal boolean expression.
*/
public final class JsBooleanLiteral extends JsValueLiteral {
private final boolean value;
// Should be interned by JsProgram
JsBooleanLiteral(boolean value) {
this.value = value;
}
public boolean getValue() {
return value;
}
@Override
public boolean isBooleanFalse() {
return value == false;
}
@Override
public boolean isBooleanTrue() {
return value == true;
}
@Override
public boolean isDefinitelyNotNull() {
return true;
}
@Override
public boolean isDefinitelyNull() {
return false;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
v.visit(this, ctx);
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.BOOLEAN;
}
}
@@ -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;
/**
* Represents the JavaScript break statement.
*/
public final class JsBreak extends JsStatement {
private final JsNameRef label;
public JsBreak() {
this(null);
}
public JsBreak(JsNameRef label) {
super();
this.label = label;
}
public JsNameRef getLabel() {
return label;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
if (v.visit(this, ctx)) {
if (label != null) {
v.accept(label);
}
}
v.endVisit(this, ctx);
}
@Override
public boolean unconditionalControlBreak() {
return true;
}
@Override
public NodeKind getKind() {
return NodeKind.BREAK;
}
}
@@ -0,0 +1,39 @@
// 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 JavaScript case statement.
*/
public final class JsCase extends JsSwitchMember {
private JsExpression caseExpr;
public JsCase() {
super();
}
public JsExpression getCaseExpr() {
return caseExpr;
}
public void setCaseExpr(JsExpression caseExpr) {
this.caseExpr = caseExpr;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
if (v.visit(this, ctx)) {
caseExpr = v.accept(caseExpr);
v.acceptWithInsertRemove(stmts);
}
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.CASE;
}
}
@@ -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;
/**
* Represents a JavaScript catch clause.
*/
public class JsCatch extends JsNode implements HasCondition {
protected final JsCatchScope scope;
private JsBlock body;
private JsExpression condition;
private JsParameter param;
public JsCatch(JsScope parent, String ident) {
super();
assert (parent != null);
scope = new JsCatchScope(parent, ident);
param = new JsParameter(scope.findExistingName(ident));
}
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 traverse(JsVisitor v, JsContext ctx) {
if (v.visit(this, ctx)) {
param = v.accept(param);
if (condition != null) {
condition = v.accept(condition);
}
body = v.accept(body);
}
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.CATCH;
}
}
@@ -0,0 +1,75 @@
// 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.Iterator;
import java.util.NoSuchElementException;
/**
* 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, String ident) {
super(parent, "Catch scope");
this.name = new JsName(this, ident, ident, ident);
}
@Override
public JsName declareName(String ident) {
// Declare into parent scope!
return getParent().declareName(ident);
}
@Override
public JsName declareName(String ident, String shortIdent) {
// Declare into parent scope!
return getParent().declareName(ident, shortIdent);
}
@Override
public Iterator<JsName> getAllNames() {
return new Iterator<JsName>() {
private boolean didIterate = false;
@Override
public boolean hasNext() {
return !didIterate;
}
@Override
public JsName next() {
if (didIterate) {
throw new NoSuchElementException();
}
didIterate = true;
return name;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
@Override
protected JsName doCreateName(String ident, String shortIdent, String originalName) {
throw new UnsupportedOperationException("Cannot create a name in a catch scope");
}
@Override
public JsName findExistingNameNoRecurse(String ident) {
if (name.getIdent().equals(ident)) {
return name;
} else {
return null;
}
}
}
@@ -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;
/**
* Represents a JavaScript conditional expression.
*/
public final class JsConditional extends JsExpression {
private JsExpression elseExpr;
private JsExpression testExpr;
private JsExpression thenExpr;
public JsConditional() {
}
public JsConditional(JsExpression testExpr, JsExpression thenExpr, JsExpression elseExpr) {
this.testExpr = testExpr;
this.thenExpr = thenExpr;
this.elseExpr = elseExpr;
}
public JsExpression getElseExpression() {
return elseExpr;
}
public JsExpression getTestExpression() {
return testExpr;
}
public JsExpression getThenExpression() {
return thenExpr;
}
@Override
public boolean hasSideEffects() {
return testExpr.hasSideEffects() || thenExpr.hasSideEffects() || elseExpr.hasSideEffects();
}
@Override
public boolean isDefinitelyNotNull() {
return thenExpr.isDefinitelyNotNull() && elseExpr.isDefinitelyNotNull();
}
@Override
public boolean isDefinitelyNull() {
return thenExpr.isDefinitelyNull() && elseExpr.isDefinitelyNull();
}
public void setElseExpression(JsExpression elseExpr) {
this.elseExpr = elseExpr;
}
public void setTestExpression(JsExpression testExpr) {
this.testExpr = testExpr;
}
public void setThenExpression(JsExpression thenExpr) {
this.thenExpr = thenExpr;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
if (v.visit(this, ctx)) {
testExpr = v.accept(testExpr);
thenExpr = v.accept(thenExpr);
elseExpr = v.accept(elseExpr);
}
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.CONDITIONAL;
}
}
@@ -0,0 +1,27 @@
// 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;
/**
* 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 interface JsContext {
boolean canInsert();
boolean canRemove();
void insertAfter(JsVisitable node);
void insertBefore(JsVisitable node);
boolean isLvalue();
void removeMe();
void replaceMe(JsVisitable node);
}
@@ -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;
/**
* Represents the JavaScript continue statement.
*/
public final class JsContinue extends JsStatement {
private final JsNameRef label;
public JsContinue() {
this(null);
}
public JsContinue(JsNameRef label) {
super();
this.label = label;
}
public JsNameRef getLabel() {
return label;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
if (v.visit(this, ctx)) {
if (label != null) {
v.accept(label);
}
}
v.endVisit(this, ctx);
}
@Override
public boolean unconditionalControlBreak() {
return true;
}
@Override
public NodeKind getKind() {
return NodeKind.CONTINUE;
}
}
@@ -0,0 +1,25 @@
// 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 a JavaScript debugger statement.
*/
public class JsDebugger extends JsStatement {
public JsDebugger() {
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
v.visit(this, ctx);
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.DEBUGGER;
}
}
@@ -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;
/**
* Represents the default option in a JavaScript swtich statement.
*/
public final class JsDefault extends JsSwitchMember {
public JsDefault() {
super();
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
if (v.visit(this, ctx)) {
v.acceptWithInsertRemove(stmts);
}
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.DEFAULT;
}
}
@@ -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;
/**
* Represents a JavaScript do..while statement.
*/
public class JsDoWhile extends JsStatement {
private JsStatement body;
private JsExpression condition;
public JsDoWhile() {
super();
}
public JsDoWhile(JsExpression condition, JsStatement body) {
super();
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 traverse(JsVisitor v, JsContext ctx) {
if (v.visit(this, ctx)) {
body = v.accept(body);
condition = v.accept(condition);
}
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.DO;
}
}
@@ -0,0 +1,26 @@
// 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 an empty statement in JavaScript.
*/
public class JsEmpty extends JsStatement {
// Interned by JsProgram
JsEmpty() {
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
v.visit(this, ctx);
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.EMPTY;
}
}
@@ -0,0 +1,36 @@
// 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 a JavaScript expression statement.
*/
public final class JsExprStmt extends JsStatement {
private JsExpression expr;
public JsExprStmt(JsExpression expr) {
super();
this.expr = expr;
this.setSourceInfo(expr);
}
public JsExpression getExpression() {
return expr;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
if (v.visit(this, ctx)) {
expr = v.accept(expr);
}
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.EXPR_STMT;
}
}
@@ -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.backend.js.ast;
import com.google.dart.compiler.common.SourceInfo;
/**
* An abstract base class for all JavaScript expressions.
*/
public abstract class JsExpression extends JsNode {
protected JsExpression() {
}
/**
* Determines whether the expression can cause side effects.
*/
public abstract boolean hasSideEffects();
/**
* True if the target expression is definitely not null.
*/
public abstract boolean isDefinitelyNotNull();
/**
* True if the target expression is definitely null.
*/
public abstract boolean isDefinitelyNull();
/**
* Determines whether or not this expression is a leaf, such as a
* {@link JsNameRef}, {@link 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;
}
public JsExprStmt makeStmt() {
return new JsExprStmt(this);
}
@Override
public JsExpression setSourceRef(SourceInfo info) {
super.setSourceRef(info);
return 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.common.SourceInfo;
/**
* 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 #getInitExpr()} is used. In the latter case, the comma operator is
* often used to create a compound expression.
*
* <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 JsStatement {
private JsStatement body;
private JsExpression condition;
private JsExpression incrExpr;
private JsExpression initExpr;
private JsVars initVars;
public JsFor() {
super();
}
public JsStatement getBody() {
return body;
}
public JsExpression getCondition() {
return condition;
}
public JsExpression getIncrExpr() {
return incrExpr;
}
public JsExpression getInitExpr() {
return initExpr;
}
public JsVars getInitVars() {
return initVars;
}
public void setBody(JsStatement body) {
this.body = body;
}
public void setCondition(JsExpression condition) {
this.condition = condition;
}
public void setIncrExpr(JsExpression incrExpr) {
this.incrExpr = incrExpr;
}
public void setInitExpr(JsExpression initExpr) {
this.initExpr = initExpr;
}
public void setInitVars(JsVars initVars) {
this.initVars = initVars;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
if (v.visit(this, ctx)) {
assert (!(initExpr != null && initVars != null));
if (initExpr != null) {
initExpr = v.accept(initExpr);
} else if (initVars != null) {
initVars = v.accept(initVars);
}
if (condition != null) {
condition = v.accept(condition);
}
if (incrExpr != null) {
incrExpr = v.accept(incrExpr);
}
body = v.accept(body);
}
v.endVisit(this, ctx);
}
@Override
public JsFor setSourceRef(SourceInfo info) {
super.setSourceRef(info);
return this;
}
@Override
public NodeKind getKind() {
return NodeKind.FOR;
}
}
@@ -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;
/**
* Represents a JavaScript for..in statement.
*/
public class JsForIn extends JsStatement {
private JsStatement body;
private JsExpression iterExpr;
private JsExpression objExpr;
// 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 JsStatement getBody() {
return body;
}
public JsExpression getIterExpr() {
return iterExpr;
}
public JsName getIterVarName() {
return iterVarName;
}
public JsExpression getObjExpr() {
return objExpr;
}
public void setBody(JsStatement body) {
this.body = body;
}
public void setIterExpr(JsExpression iterExpr) {
this.iterExpr = iterExpr;
}
public void setObjExpr(JsExpression objExpr) {
this.objExpr = objExpr;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
if (v.visit(this, ctx)) {
if (iterExpr != null) {
iterExpr = v.acceptLvalue(iterExpr);
}
objExpr = v.accept(objExpr);
body = v.accept(body);
}
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.FOR_IN;
}
}
@@ -0,0 +1,238 @@
// 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.SourceInfo;
import java.util.ArrayList;
import java.util.List;
/**
* Represents a JavaScript function expression.
*/
public final class JsFunction extends JsLiteral implements HasName {
private static void trace(String title, String code) {
System.out.println("---------------------------");
System.out.println(title + ":");
System.out.println("---------------------------");
System.out.println(code);
}
protected JsBlock body;
protected final List<JsParameter> params = new ArrayList<JsParameter>();
protected final JsScope scope;
private boolean artificiallyRescued;
private boolean executeOnce;
private boolean fromDart;
private JsFunction impliedExecute;
private JsName name;
private boolean trace = false;
private boolean traceFirst = true;
private boolean hoisted = false;
private boolean constructor = false;
/**
* Creates an anonymous function.
*/
public JsFunction(JsScope parent) {
this(parent, null, false);
}
/**
* Creates a function that is not derived from Dart source.
*/
public JsFunction(JsScope parent, JsName name) {
this(parent, name, false);
}
/**
* Creates a named function, possibly derived from Dart source.
*/
public JsFunction(JsScope parent, JsName name, boolean fromDart) {
assert (parent != null);
this.fromDart = fromDart;
setName(name);
String scopeName = (name == null) ? "<anonymous>" : name.getIdent();
scopeName = "function " + scopeName;
this.scope = new JsScope(parent, scopeName);
}
public JsBlock getBody() {
return body;
}
/**
* If true, this indicates that only the first invocation of the function will
* have any effects. Subsequent invocations may be considered to be no-op
* calls whose return value is ignored.
*/
public boolean getExecuteOnce() {
return executeOnce;
}
public JsFunction getImpliedExecute() {
return impliedExecute;
}
@Override
public JsName getName() {
return name;
}
public void setParameters(List<JsParameter> params) {
this.params.clear();
this.params.addAll(params);
}
public List<JsParameter> getParameters() {
return params;
}
public JsScope getScope() {
return scope;
}
@Override
public boolean hasSideEffects() {
// If there's a name, the name is assigned to.
return name != null;
}
public boolean isArtificiallyRescued() {
return artificiallyRescued;
}
@Override
public boolean isBooleanFalse() {
return false;
}
@Override
public boolean isBooleanTrue() {
return true;
}
@Override
public boolean isDefinitelyNotNull() {
return true;
}
@Override
public boolean isDefinitelyNull() {
return false;
}
public boolean isFromDart() {
return fromDart;
}
public void setArtificiallyRescued(boolean rescued) {
this.artificiallyRescued = rescued;
}
public void setBody(JsBlock body) {
this.body = body;
}
public void setExecuteOnce(boolean executeOnce) {
this.executeOnce = executeOnce;
}
public void setFromDart(boolean fromDart) {
this.fromDart = fromDart;
}
public void setImpliedExecute(JsFunction impliedExecute) {
this.impliedExecute = impliedExecute;
}
public void setName(JsName name) {
this.name = name;
if (name != null) {
if (isFromDart()) {
name.setStaticRef(this);
}
}
}
public void setTrace() {
this.trace = true;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
String before = null;
if (trace && v instanceof JsModVisitor) {
before = this.toSource();
if (traceFirst) {
traceFirst = false;
trace("SCRIPT INITIAL", before);
}
}
if (v.visit(this, ctx)) {
v.acceptWithInsertRemove(params);
body = v.accept(body);
}
v.endVisit(this, ctx);
if (trace && v instanceof JsModVisitor) {
String after = this.toSource();
if (!after.equals(before)) {
String title = v.getClass().getSimpleName();
trace(title, after);
}
}
}
public void setHoisted() {
hoisted = true;
}
/**
* Whether the function has been hoisted
*/
public boolean isHoisted() {
return hoisted;
}
/**
* Rebase the function to a new scope.
*
* @param newScopeParent The scope to add the function to.
*/
public void rebaseScope(JsScope newScopeParent) {
this.scope.rebase(newScopeParent);
}
@Override
public JsFunction setSourceRef(SourceInfo info) {
super.setSourceRef(info);
return this;
}
public boolean isConstructor() {
return this.constructor;
}
public boolean setIsConstructor(boolean constructor) {
return this.constructor = constructor;
}
@Override
public NodeKind getKind() {
return NodeKind.FUNCTION;
}
// Pavel Talanov
// dummy parameter to distinguish from other constructors
private JsFunction(Void dummy, JsScope functionScope) {
this.fromDart = false;
this.scope = functionScope;
}
public static JsFunction getAnonymousFunctionWithScope(JsScope scope) {
return new JsFunction(null, scope);
}
}
@@ -0,0 +1,19 @@
// 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;
/**
* Represnts a JavaScript block in the global scope.
*/
public class JsGlobalBlock extends JsBlock {
public JsGlobalBlock() {
}
@Override
public boolean isGlobalBlock() {
return true;
}
}
@@ -0,0 +1,65 @@
// 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 a JavaScript if statement.
*/
public final class JsIf extends JsStatement {
private JsExpression ifExpr;
private JsStatement thenStmt;
private JsStatement elseStmt;
public JsIf() {
}
public JsIf(JsExpression ifExpr, JsStatement thenStmt, JsStatement elseStmt) {
this.ifExpr = ifExpr;
this.thenStmt = thenStmt;
this.elseStmt = elseStmt;
}
public JsStatement getElseStmt() {
return elseStmt;
}
public JsExpression getIfExpr() {
return ifExpr;
}
public JsStatement getThenStmt() {
return thenStmt;
}
public void setElseStmt(JsStatement elseStmt) {
this.elseStmt = elseStmt;
}
public void setIfExpr(JsExpression ifExpr) {
this.ifExpr = ifExpr;
}
public void setThenStmt(JsStatement thenStmt) {
this.thenStmt = thenStmt;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
if (v.visit(this, ctx)) {
ifExpr = v.accept(ifExpr);
thenStmt = v.accept(thenStmt);
if (elseStmt != null) {
elseStmt = v.accept(elseStmt);
}
}
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.IF;
}
}
@@ -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 java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Represents a JavaScript invocation.
*/
public final class JsInvocation extends JsExpression implements HasArguments {
private final List<JsExpression> args = new ArrayList<JsExpression>();
private JsExpression qualifier;
public JsInvocation() {
}
@Override
public List<JsExpression> getArguments() {
return args;
}
public JsExpression getQualifier() {
return qualifier;
}
@Override
public boolean hasSideEffects() {
return true;
}
@Override
public boolean isDefinitelyNotNull() {
return false;
}
@Override
public boolean isDefinitelyNull() {
return false;
}
public void setQualifier(JsExpression qualifier) {
this.qualifier = qualifier;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
if (v.visit(this, ctx)) {
qualifier = v.accept(qualifier);
v.acceptList(args);
}
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.INVOKE;
}
// Pavel Talanov
public void setArguments(List<JsExpression> arguments) {
assert this.args.isEmpty() : "Arguments already set.";
this.args.addAll(arguments);
}
public void setArguments(JsExpression... arguments) {
setArguments(Arrays.asList(arguments));
}
}
@@ -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.backend.js.ast;
/**
* Represents a JavaScript label statement.
*/
public class JsLabel extends JsStatement implements HasName {
private final JsName label;
private JsStatement stmt;
public JsLabel(JsName label) {
this.label = label;
}
@Override
public JsName getName() {
return label;
}
public JsStatement getStmt() {
return stmt;
}
public void setStmt(JsStatement stmt) {
this.stmt = stmt;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
if (v.visit(this, ctx)) {
stmt = v.accept(stmt);
}
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.LABEL;
}
}
@@ -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;
/**
* A JavaScript string literal expression.
*/
public abstract class JsLiteral extends JsExpression implements CanBooleanEval {
protected JsLiteral() {
}
}
@@ -0,0 +1,189 @@
// 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.Hack;
import java.util.List;
/**
* A visitor for iterating through and modifying an AST.
*/
public class JsModVisitor extends JsVisitor {
private class ListContext<T extends JsVisitable> implements JsContext {
private List<T> collection;
private int index;
private boolean removed;
private boolean replaced;
@Override
public boolean canInsert() {
return true;
}
@Override
public boolean canRemove() {
return true;
}
@Override
public void insertAfter(JsVisitable node) {
checkRemoved();
collection.add(index + 1, Hack.<T>cast(node));
didChange = true;
}
@Override
public void insertBefore(JsVisitable node) {
checkRemoved();
collection.add(index++, Hack.<T>cast(node));
didChange = true;
}
@Override
public boolean isLvalue() {
return false;
}
@Override
public void removeMe() {
checkState();
collection.remove(index--);
didChange = removed = true;
}
@Override
public void replaceMe(JsVisitable node) {
checkState();
checkReplacement(collection.get(index), node);
collection.set(index, Hack.<T>cast(node));
didChange = replaced = true;
}
protected void traverse(List<T> collection) {
this.collection = collection;
for (index = 0; index < collection.size(); ++index) {
removed = replaced = false;
doTraverse(collection.get(index), this);
}
}
private void checkRemoved() {
if (removed) {
throw new RuntimeException("Node was already removed");
}
}
private void checkState() {
checkRemoved();
if (replaced) {
throw new RuntimeException("Node was already replaced");
}
}
}
private class LvalueContext extends NodeContext<JsExpression> {
@Override
public boolean isLvalue() {
return true;
}
}
private class NodeContext<T extends JsVisitable> implements JsContext {
private T node;
private boolean replaced;
@Override
public boolean canInsert() {
return false;
}
@Override
public boolean canRemove() {
return false;
}
@Override
public void insertAfter(JsVisitable node) {
throw new UnsupportedOperationException();
}
@Override
public void insertBefore(JsVisitable node) {
throw new UnsupportedOperationException();
}
@Override
public boolean isLvalue() {
return false;
}
@Override
public void removeMe() {
throw new UnsupportedOperationException();
}
@Override
public void replaceMe(JsVisitable node) {
if (replaced) {
throw new RuntimeException("Node was already replaced");
}
checkReplacement(this.node, node);
this.node = Hack.<T>cast(node);
didChange = replaced = true;
}
protected T traverse(T node) {
this.node = node;
replaced = false;
doTraverse(node, this);
return this.node;
}
}
protected static <T extends JsVisitable> void checkReplacement(T origNode, T newNode) {
if (newNode == null) {
throw new RuntimeException("Cannot replace with null");
}
if (newNode == origNode) {
throw new RuntimeException("The replacement is the same as the original");
}
}
protected boolean didChange = false;
@Override
public boolean didChange() {
return didChange;
}
@Override
protected <T extends JsVisitable> T doAccept(T node) {
return new NodeContext<T>().traverse(node);
}
@Override
protected <T extends JsVisitable> void doAcceptList(List<T> collection) {
NodeContext<T> ctx = new NodeContext<T>();
for (int i = 0, c = collection.size(); i < c; ++i) {
ctx.traverse(collection.get(i));
if (ctx.replaced) {
collection.set(i, ctx.node);
}
}
}
@Override
protected JsExpression doAcceptLvalue(JsExpression expr) {
return new LvalueContext().traverse(expr);
}
@Override
protected <T extends JsVisitable> void doAcceptWithInsertRemove(List<T> collection) {
new ListContext<T>().traverse(collection);
}
}
@@ -0,0 +1,102 @@
// 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.io.Serializable;
/**
* An abstract base class for named JavaScript objects.
*/
public class JsName implements Serializable {
private final JsScope enclosing;
private final String ident;
private boolean isObfuscatable;
private String shortIdent;
private String originalName;
/**
* A back-reference to the JsNode that the JsName refers to.
*/
private JsNode staticRef;
/**
* @param ident the unmangled ident to use for this name
*/
JsName(JsScope enclosing, String ident, String shortIdent, String originalName) {
this.enclosing = enclosing;
this.ident = ident;
this.shortIdent = shortIdent;
if (originalName != null) {
this.originalName = originalName;
}
this.isObfuscatable = true;
}
public JsScope getEnclosing() {
return enclosing;
}
public String getIdent() {
return ident;
}
public String getShortIdent() {
return shortIdent;
}
public String getOriginalName() {
return originalName;
}
public JsNode getStaticRef() {
return staticRef;
}
public boolean isObfuscatable() {
return isObfuscatable;
}
public JsNameRef makeRef() {
return new JsNameRef(this);
}
public void setObfuscatable(boolean isObfuscatable) {
this.isObfuscatable = isObfuscatable;
}
public void setShortIdent(String shortIdent) {
this.shortIdent = shortIdent;
}
/**
* Should never be called except on immutable stuff.
*/
public void setStaticRef(JsNode node) {
this.staticRef = node;
}
@Override
public String toString() {
return ident;
}
@Override
public int hashCode() {
return ident.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof JsName)) {
return false;
}
JsName other = (JsName) obj;
return ident.equals(other.ident) && enclosing == other.enclosing;
}
}
@@ -0,0 +1,113 @@
// 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 a JavaScript expression that references a name.
*/
public final class JsNameRef extends JsExpression implements CanBooleanEval, HasName {
private String ident;
private JsName name;
private JsExpression qualifier;
public JsNameRef(JsName name) {
this.name = name;
}
public JsNameRef(String ident) {
this.ident = ident;
}
public String getIdent() {
return (name == null) ? ident : name.getIdent();
}
@Override
public JsName getName() {
return name;
}
public JsExpression getQualifier() {
return qualifier;
}
public String getShortIdent() {
return (name == null) ? ident : name.getShortIdent();
}
@Override
public boolean hasSideEffects() {
if (qualifier == null) {
return false;
}
if (!qualifier.isDefinitelyNotNull()) {
// Could trigger NPE.
return true;
}
return qualifier.hasSideEffects();
}
@Override
public boolean isBooleanFalse() {
return isDefinitelyNull();
}
@Override
public boolean isBooleanTrue() {
return false;
}
@Override
public boolean isDefinitelyNotNull() {
// TODO: look for single-assignment of stuff from Java?
return false;
}
@Override
public boolean isDefinitelyNull() {
if (name != null) {
return (name.getEnclosing().getProgram().getUndefinedLiteral().getName() == name);
}
return false;
}
@Override
public boolean isLeaf() {
if (qualifier == null) {
return true;
} else {
return false;
}
}
public boolean isResolved() {
return name != null;
}
public void resolve(JsName name) {
this.name = name;
this.ident = null;
}
public void setQualifier(JsExpression qualifier) {
this.qualifier = qualifier;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
if (v.visit(this, ctx)) {
if (qualifier != null) {
qualifier = v.accept(qualifier);
}
}
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.NAME_REF;
}
}
@@ -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 java.util.ArrayList;
import java.util.List;
/**
* Represents the JavaScript new expression.
*/
public final class JsNew extends JsExpression implements HasArguments {
private final List<JsExpression> args = new ArrayList<JsExpression>();
private JsExpression ctorExpr;
public JsNew(JsExpression ctorExpr) {
this.ctorExpr = ctorExpr;
}
@Override
public List<JsExpression> getArguments() {
return args;
}
public void setArguments(List<JsExpression> arguments) {
args.clear();
args.addAll(arguments);
}
public JsExpression getConstructorExpression() {
return ctorExpr;
}
@Override
public boolean hasSideEffects() {
return true;
}
@Override
public boolean isDefinitelyNotNull() {
// Sadly, in JS it can be!
// TODO: analysis could probably determine most instances cannot be null.
return false;
}
@Override
public boolean isDefinitelyNull() {
return false;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
if (v.visit(this, ctx)) {
ctorExpr = v.accept(ctorExpr);
v.acceptList(args);
}
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.NEW;
}
}
@@ -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 com.google.dart.compiler.backend.js.JsSourceGenerationVisitor;
import com.google.dart.compiler.backend.js.JsToStringGenerationVisitor;
import com.google.dart.compiler.common.AbstractNode;
import com.google.dart.compiler.common.SourceInfo;
import com.google.dart.compiler.util.DefaultTextOutput;
/**
* Base class for all JS AST elements.
*/
public abstract class JsNode extends AbstractNode implements JsVisitable {
protected JsNode() {
}
// Causes source generation to delegate to the one visitor
public final String toSource() {
DefaultTextOutput out = new DefaultTextOutput(false);
JsSourceGenerationVisitor v = new JsSourceGenerationVisitor(out);
v.accept(this);
return out.toString();
}
// Causes source generation to delegate to the one visitor
@Override
public final String toString() {
DefaultTextOutput out = new DefaultTextOutput(false);
JsToStringGenerationVisitor v = new JsToStringGenerationVisitor(out);
v.accept(this);
return out.toString();
}
@Override
public SourceInfo getSourceInfo() {
return this;
}
public JsNode setSourceRef(SourceInfo info) {
if (info != null) {
this.setSourceInfo(info);
}
return this;
}
public abstract NodeKind getKind();
}
@@ -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;
/**
* A JavaScript null literal.
*/
public final class JsNullLiteral extends JsValueLiteral {
// Should only be instantiated in JsProgram
JsNullLiteral() {
}
@Override
public boolean isBooleanFalse() {
return true;
}
@Override
public boolean isBooleanTrue() {
return false;
}
@Override
public boolean isDefinitelyNotNull() {
return false;
}
@Override
public boolean isDefinitelyNull() {
return true;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
v.visit(this, ctx);
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.NULL;
}
}
@@ -0,0 +1,53 @@
// 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 a JavaScript literal decimal expression.
*/
public final class JsNumberLiteral extends JsValueLiteral {
private final double value;
// Should be interned by JsProgram
JsNumberLiteral(double value) {
this.value = value;
}
public double getValue() {
return value;
}
@Override
public boolean isBooleanFalse() {
return value == 0.0;
}
@Override
public boolean isBooleanTrue() {
return value != 0.0;
}
@Override
public boolean isDefinitelyNotNull() {
return true;
}
@Override
public boolean isDefinitelyNull() {
return false;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
v.visit(this, ctx);
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.NUMBER;
}
}
@@ -0,0 +1,72 @@
// 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.ArrayList;
import java.util.List;
/**
* A JavaScript object literal.
*/
public final class JsObjectLiteral extends JsLiteral {
private final List<JsPropertyInitializer> props;
public JsObjectLiteral() {
props = new ArrayList<JsPropertyInitializer>();
}
public JsObjectLiteral(List<JsPropertyInitializer> props) {
assert props != null;
this.props = props;
}
public List<JsPropertyInitializer> getPropertyInitializers() {
return props;
}
@Override
public boolean hasSideEffects() {
for (JsPropertyInitializer prop : props) {
if (prop.hasSideEffects()) {
return true;
}
}
return false;
}
@Override
public boolean isBooleanFalse() {
return false;
}
@Override
public boolean isBooleanTrue() {
return true;
}
@Override
public boolean isDefinitelyNotNull() {
return true;
}
@Override
public boolean isDefinitelyNull() {
return false;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
if (v.visit(this, ctx)) {
v.acceptWithInsertRemove(props);
}
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.OBJECT;
}
}
@@ -0,0 +1,32 @@
// 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 operator.
*/
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,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;
/**
* A JavaScript parameter.
*/
public final class JsParameter extends JsNode implements HasName {
private final JsName name;
public JsParameter(JsName name) {
this.name = name;
name.setStaticRef(this);
}
@Override
public JsName getName() {
return name;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
v.visit(this, ctx);
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.PARAMETER;
}
}
@@ -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;
/**
* A JavaScript postfix operation.
*/
public final class JsPostfixOperation extends JsUnaryOperation {
public JsPostfixOperation(JsUnaryOperator op) {
this(op, null);
}
public JsPostfixOperation(JsUnaryOperator op, JsExpression arg) {
super(op, arg);
}
@Override
public boolean isDefinitelyNotNull() {
return true;
}
@Override
public boolean isDefinitelyNull() {
return false;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
if (v.visit(this, ctx)) {
super.traverse(v, ctx);
}
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.POSTFIX_OP;
}
}
@@ -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;
/**
* A JavaScript prefix operation.
*/
public final class JsPrefixOperation extends JsUnaryOperation implements CanBooleanEval {
public JsPrefixOperation(JsUnaryOperator op) {
this(op, null);
}
public JsPrefixOperation(JsUnaryOperator op, JsExpression arg) {
super(op, arg);
}
@Override
public boolean isBooleanFalse() {
if (getOperator() == JsUnaryOperator.VOID) {
return true;
}
if (getOperator() == JsUnaryOperator.NOT && getArg() instanceof CanBooleanEval) {
CanBooleanEval eval = (CanBooleanEval) getArg();
return eval.isBooleanTrue();
}
return false;
}
@Override
public boolean isBooleanTrue() {
if (getOperator() == JsUnaryOperator.NOT && getArg() instanceof CanBooleanEval) {
CanBooleanEval eval = (CanBooleanEval) getArg();
return eval.isBooleanFalse();
}
if (getOperator() == JsUnaryOperator.TYPEOF) {
return true;
}
return false;
}
@Override
public boolean isDefinitelyNotNull() {
if (getOperator() == JsUnaryOperator.TYPEOF) {
return true;
}
return getOperator() != JsUnaryOperator.VOID;
}
@Override
public boolean isDefinitelyNull() {
return getOperator() == JsUnaryOperator.VOID;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
if (v.visit(this, ctx)) {
super.traverse(v, ctx);
}
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.PREFIX_OP;
}
}
@@ -0,0 +1,174 @@
// 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.HashMap;
import java.util.Map;
/**
* A JavaScript program.
*/
public final class JsProgram extends JsNode {
private final JsStatement debuggerStmt;
private final JsEmpty emptyStmt;
private final JsBooleanLiteral falseLiteral;
private JsProgramFragment[] fragments;
private final Map<String, JsFunction> indexedFunctions = new HashMap<String, JsFunction>();
private final JsNullLiteral nullLiteral;
private final Map<Double, JsNumberLiteral> numberLiteralMap =
new HashMap<Double, JsNumberLiteral>();
private final JsScope objectScope;
private final JsRootScope rootScope;
private final Map<String, JsStringLiteral> stringLiteralMap =
new HashMap<String, JsStringLiteral>();
private final JsScope topScope;
private final JsBooleanLiteral trueLiteral;
/**
* Constructs a JavaScript program object.
*/
public JsProgram(String unitId) {
rootScope = new JsRootScope(this);
topScope = new JsScope(rootScope, "Global", unitId);
objectScope = new JsScope(rootScope, "Object");
setFragmentCount(1);
debuggerStmt = new JsDebugger();
emptyStmt = new JsEmpty();
falseLiteral = new JsBooleanLiteral(false);
nullLiteral = new JsNullLiteral();
trueLiteral = new JsBooleanLiteral(true);
}
public JsBooleanLiteral getBooleanLiteral(boolean truth) {
if (truth) {
return getTrueLiteral();
}
return getFalseLiteral();
}
/**
* Gets the {@link JsStatement} to use whenever parsed source include a
* <code>debugger</code> statement.
*/
public JsStatement getDebuggerStmt() {
return debuggerStmt;
}
public JsEmpty getEmptyStmt() {
return emptyStmt;
}
public JsBooleanLiteral getFalseLiteral() {
return falseLiteral;
}
public JsBlock getFragmentBlock(int fragment) {
if (fragment < 0 || fragment >= fragments.length) {
throw new IllegalArgumentException("Invalid fragment: " + fragment);
}
return fragments[fragment].getGlobalBlock();
}
public int getFragmentCount() {
return this.fragments.length;
}
/**
* Gets the one and only global block.
*/
public JsBlock getGlobalBlock() {
return getFragmentBlock(0);
}
public JsFunction getIndexedFunction(String name) {
return indexedFunctions.get(name);
}
public JsNullLiteral getNullLiteral() {
return nullLiteral;
}
public JsNumberLiteral getNumberLiteral(double value) {
JsNumberLiteral lit = numberLiteralMap.get(value);
if (lit == null) {
lit = new JsNumberLiteral(value);
numberLiteralMap.put(value, lit);
}
return lit;
}
public JsScope getObjectScope() {
return objectScope;
}
/**
* 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 JsScope getScope() {
return topScope;
}
/**
* Creates or retrieves a JsStringLiteral from an interned object pool.
*/
public JsStringLiteral getStringLiteral(String value) {
JsStringLiteral lit = stringLiteralMap.get(value);
if (lit == null) {
lit = new JsStringLiteral(value);
stringLiteralMap.put(value, lit);
}
return lit;
}
public JsBooleanLiteral getTrueLiteral() {
return trueLiteral;
}
public JsNameRef getUndefinedLiteral() {
return new JsNameRef("$Dart$Null");
}
public void setFragmentCount(int fragments) {
this.fragments = new JsProgramFragment[fragments];
for (int i = 0; i < fragments; i++) {
this.fragments[i] = new JsProgramFragment();
}
}
public void setIndexedFunctions(Map<String, JsFunction> indexedFunctions) {
this.indexedFunctions.clear();
this.indexedFunctions.putAll(indexedFunctions);
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
if (v.visit(this, ctx)) {
for (JsProgramFragment fragment : fragments) {
v.accept(fragment);
}
}
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.PROGRAM;
}
}
@@ -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;
/**
* One independently loadable fragment of a {@link JsProgram}.
*/
public class JsProgramFragment extends JsNode {
private final JsGlobalBlock globalBlock;
public JsProgramFragment() {
this.globalBlock = new JsGlobalBlock();
}
public JsBlock getGlobalBlock() {
return globalBlock;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
if (v.visit(this, ctx)) {
v.accept(globalBlock);
}
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.PROGRAM_FRAGMENT;
}
}
@@ -0,0 +1,56 @@
// 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;
/**
* Used in object literals to specify property values by name.
*/
public class JsPropertyInitializer extends JsNode {
private JsExpression labelExpr;
private JsExpression valueExpr;
public JsPropertyInitializer() {
}
public JsPropertyInitializer(JsExpression labelExpr, JsExpression valueExpr) {
this.labelExpr = labelExpr;
this.valueExpr = valueExpr;
}
public JsExpression getLabelExpr() {
return labelExpr;
}
public JsExpression getValueExpr() {
return valueExpr;
}
public boolean hasSideEffects() {
return labelExpr.hasSideEffects() || valueExpr.hasSideEffects();
}
public void setLabelExpr(JsExpression labelExpr) {
this.labelExpr = labelExpr;
}
public void setValueExpr(JsExpression valueExpr) {
this.valueExpr = valueExpr;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
if (v.visit(this, ctx)) {
labelExpr = v.accept(labelExpr);
valueExpr = v.accept(valueExpr);
}
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.PROPERTY_INIT;
}
}
@@ -0,0 +1,64 @@
// 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 regular expression.
*/
public final class JsRegExp extends JsValueLiteral {
private String flags;
private String pattern;
public JsRegExp() {
}
public String getFlags() {
return flags;
}
public String getPattern() {
return pattern;
}
@Override
public boolean isBooleanFalse() {
return false;
}
@Override
public boolean isBooleanTrue() {
return true;
}
@Override
public boolean isDefinitelyNotNull() {
return true;
}
@Override
public boolean isDefinitelyNull() {
return false;
}
public void setFlags(String suffix) {
this.flags = suffix;
}
public void setPattern(String re) {
this.pattern = re;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
v.visit(this, ctx);
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.REGEXP;
}
}
@@ -0,0 +1,48 @@
// 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 return statement.
*/
public final class JsReturn extends JsStatement {
private JsExpression expr;
public JsReturn() {
}
public JsReturn(JsExpression expr) {
this.expr = expr;
}
public JsExpression getExpr() {
return expr;
}
public void setExpr(JsExpression expr) {
this.expr = expr;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
if (v.visit(this, ctx)) {
if (expr != null) {
expr = v.accept(expr);
}
}
v.endVisit(this, ctx);
}
@Override
public boolean unconditionalControlBreak() {
return true;
}
@Override
public NodeKind getKind() {
return NodeKind.RETURN;
}
}
@@ -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 com.google.dart.compiler.backend.js.JsReservedIdentifiers;
/**
* 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 doCreateName(String ident, String shortIdent, String originalName) {
JsName name = super.doCreateName(ident, shortIdent, originalName);
name.setObfuscatable(false);
return name;
}
@Override
public JsName findExistingNameNoRecurse(String ident) {
JsName name = super.findExistingNameNoRecurse(ident);
if (name == null) {
if (JsReservedIdentifiers.getReservedGlobalSymbols().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, ident, ident);
}
}
return name;
}
}
@@ -0,0 +1,308 @@
// 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.Lists;
import com.google.dart.compiler.util.Maps;
import java.io.Serializable;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* 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 class JsScope implements Serializable {
private List<JsScope> children = Collections.emptyList();
private final String description;
private Map<String, JsName> names = Collections.emptyMap();
private JsScope parent;
protected int tempIndex = 0;
private final String scopeId;
/*
* Create a scope with parent.
*/
public JsScope(JsScope parent, String description) {
this(parent, description, null);
}
/**
* Create a scope with parent.
*/
public JsScope(JsScope parent, String description, String scopeId) {
assert (parent != null);
this.scopeId = scopeId;
this.description = description;
this.parent = parent;
parent.children = Lists.add(parent.children, this);
}
/**
* Rebase the function to a new scope.
*
* @param newParent The scope to add the function to.
*/
public void rebase(JsScope newParent) {
detachFromParent();
parent = newParent;
parent.children = Lists.add(parent.children, this);
}
/**
* Rebase the function's children to a new scope.
*
* @param newParent
*/
public void rebaseChildScopes(JsScope newParent) {
if (newParent == this) {
return;
}
parent.children = Lists.addAll(parent.children, children);
for (JsScope child : children) {
child.parent = newParent;
}
children = Collections.emptyList();
}
/**
* Subclasses can detach and become parentless.
*/
protected void detachFromParent() {
JsScope oldParent = parent;
oldParent.children = Lists.remove(
parent.children, oldParent.children.indexOf(this));
parent = null;
}
/**
* Subclasses can be parentless.
*/
protected JsScope(String description) {
this.description = description;
this.parent = null;
this.scopeId = null;
}
/**
* Gets a name object associated with the specified ident in this scope,
* creating it if necessary.<br/>
* If the JsName does not exist yet, a new JsName is created. The ident,
* short name, and original name of the newly created JsName are equal to
* the given ident.
*
* @param ident An identifier that is unique within this scope.
*/
public JsName declareName(String ident) {
JsName name = findExistingNameNoRecurse(ident);
if (name != null) {
return name;
}
return doCreateName(ident, ident, ident);
}
/**
* Creates a new variable with an unique ident in this scope.
* The generated JsName 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
* (unless they use this function).
*/
public JsName declareFreshName(String shortName) {
String ident = shortName;
int counter = 0;
while (findExistingNameNoRecurse(ident) != null) {
ident = shortName + "_" + counter++;
}
return doCreateName(ident, shortName, shortName);
}
String getNextTempName() {
// TODO(ngeoffray): Decide on a convention for temporary variables
// introduced by the compiler.
return "tmp$" + (scopeId != null ? scopeId + "$" : "") + tempIndex++;
}
/**
* 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.
*/
public JsName declareTemporary() {
return declareFreshName(getNextTempName());
}
/**
* Gets a name object associated with the specified ident in this scope,
* creating it if necessary.<br/>
* If the JsName does not exist yet, a new JsName is created with the given
* ident, short name and original name.
*
* @param ident An identifier that is unique within this scope.
* @param shortIdent A "pretty" name that does not have to be unique.
* @throws IllegalArgumentException if ident already exists in this scope but
* the requested short name does not match the existing short name.
*/
public JsName declareName(String ident, String shortIdent) {
return declareName(ident, shortIdent, ident);
}
/**
* Gets a name object associated with the specified ident in this scope,
* creating it if necessary.<br/>
* If the JsName does not exist yet, a new JsName is created. The original
* name stored in the JsName is equal to the (unmangled) specified originalName.
*
* @param ident An identifier that is unique within this scope.
* @param shortIdent A "pretty" name that does not have to be unique.
* @param originalName The original name in the source.
* @throws IllegalArgumentException if ident already exists in this scope but
* the requested short name does not match the existing short name,
* or the original name does not match the existing original name.
*/
public JsName declareName(String ident, String shortIdent, String originalName) {
JsName name = findExistingNameNoRecurse(ident);
if (name != null) {
if (!name.getShortIdent().equals(shortIdent)
|| !nullableEquals(name.getOriginalName(), originalName)) {
throw new IllegalArgumentException("Requested short name " + shortIdent
+ " conflicts with preexisting short name " + name.getShortIdent() + " for identifier "
+ ident);
}
return name;
}
return doCreateName(ident, shortIdent, originalName);
}
boolean nullableEquals(String s1, String s2) {
return (s1 == null) ? (s2 == null) : s1.equals(s2);
}
/**
* 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
*/
public final JsName findExistingName(String ident) {
JsName name = findExistingNameNoRecurse(ident);
if (name == null && parent != null) {
return parent.findExistingName(ident);
}
return name;
}
/**
* Attempts to find an unobfuscatable 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
*/
public final JsName findExistingUnobfuscatableName(String ident) {
JsName name = findExistingNameNoRecurse(ident);
if (name != null && name.isObfuscatable()) {
name = null;
}
if (name == null && parent != null) {
return parent.findExistingUnobfuscatableName(ident);
}
return name;
}
/**
* Returns an iterator for all the names defined by this scope.
*/
public Iterator<JsName> getAllNames() {
return names.values().iterator();
}
/**
* Returns a list of this scope's child scopes.
*/
public final List<JsScope> getChildren() {
return children;
}
/**
* Returns the parent scope of this scope, or <code>null</code> if this is the
* root scope.
*/
public final JsScope getParent() {
return parent;
}
/**
* Returns the associated program.
*/
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;
}
}
/**
* Creates a new name in this scope.
*/
protected JsName doCreateName(String ident, String shortIdent, String originalName) {
JsName name = new JsName(this, ident, shortIdent, originalName);
names = Maps.putOrdered(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
*/
public JsName findExistingNameNoRecurse(String ident) {
return names.get(ident);
}
/**
*
* Checks whether this scope owns this name.
*/
public boolean ownsName(JsName name) {
return names.containsValue(name);
}
}
@@ -0,0 +1,22 @@
// 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;
/**
* Abstract base class for JavaScript statement objects.
*/
public abstract class JsStatement extends JsNode {
protected JsStatement() {
}
/**
* Returns true if this statement definitely causes an abrupt change in flow
* control.
*/
public boolean unconditionalControlBreak() {
return false;
}
}
@@ -0,0 +1,53 @@
// 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 string literal expression.
*/
public final class JsStringLiteral extends 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 boolean isBooleanFalse() {
return value.length() == 0;
}
@Override
public boolean isBooleanTrue() {
return value.length() != 0;
}
@Override
public boolean isDefinitelyNotNull() {
return true;
}
@Override
public boolean isDefinitelyNull() {
return false;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
v.visit(this, ctx);
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.STRING;
}
}
@@ -0,0 +1,47 @@
// 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.ArrayList;
import java.util.List;
/**
* A JavaScript switch statement.
*/
public class JsSwitch extends JsStatement {
private final List<JsSwitchMember> cases = new ArrayList<JsSwitchMember>();
private JsExpression expr;
public JsSwitch() {
super();
}
public List<JsSwitchMember> getCases() {
return cases;
}
public JsExpression getExpr() {
return expr;
}
public void setExpr(JsExpression expr) {
this.expr = expr;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
if (v.visit(this, ctx)) {
expr = v.accept(expr);
v.acceptWithInsertRemove(cases);
}
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.SWITCH;
}
}
@@ -0,0 +1,24 @@
// 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.ArrayList;
import java.util.List;
/**
* A member/case in a JavaScript switch object.
*/
public abstract class JsSwitchMember extends JsNode {
protected final List<JsStatement> stmts = new ArrayList<JsStatement>();
protected JsSwitchMember() {
super();
}
public List<JsStatement> getStmts() {
return stmts;
}
}
@@ -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;
/**
* A JavaScript <code>this</code> reference.
*/
public final class JsThisRef extends JsValueLiteral {
public JsThisRef() {
super();
}
@Override
public boolean isBooleanFalse() {
return false;
}
@Override
public boolean isBooleanTrue() {
return true;
}
@Override
public boolean isDefinitelyNotNull() {
/*
* You'd think that you could get a null this via function.call/apply, but
* in fact you can't: they just make this be the window object instead. So
* it really can't ever be null.
*/
return true;
}
@Override
public boolean isDefinitelyNull() {
return false;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
v.visit(this, ctx);
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.THIS;
}
}
@@ -0,0 +1,48 @@
// 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 <code>throw</code> statement.
*/
public class JsThrow extends JsStatement {
private JsExpression expr;
public JsThrow() {
super();
}
public JsThrow(JsExpression expr) {
super();
this.expr = expr;
}
public JsExpression getExpr() {
return expr;
}
public void setExpr(JsExpression expr) {
this.expr = expr;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
if (v.visit(this, ctx)) {
expr = v.accept(expr);
}
v.endVisit(this, ctx);
}
@Override
public boolean unconditionalControlBreak() {
return true;
}
@Override
public NodeKind getKind() {
return NodeKind.THROW;
}
}
@@ -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.backend.js.ast;
import java.util.ArrayList;
import java.util.List;
/**
* A JavaScript <code>try</code> statement.
*/
public class JsTry extends JsStatement {
private final List<JsCatch> catches = new ArrayList<JsCatch>();
private JsBlock finallyBlock;
private JsBlock tryBlock;
public JsTry() {
super();
}
public List<JsCatch> getCatches() {
return catches;
}
public JsBlock getFinallyBlock() {
return finallyBlock;
}
public JsBlock getTryBlock() {
return tryBlock;
}
public void setFinallyBlock(JsBlock block) {
this.finallyBlock = block;
}
public void setTryBlock(JsBlock block) {
tryBlock = block;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
if (v.visit(this, ctx)) {
tryBlock = v.accept(tryBlock);
v.acceptWithInsertRemove(catches);
if (finallyBlock != null) {
finallyBlock = v.accept(finallyBlock);
}
}
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.TRY;
}
}
@@ -0,0 +1,53 @@
// 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 prefix or postfix operation.
*/
public abstract class JsUnaryOperation extends JsExpression {
private JsExpression arg;
private final JsUnaryOperator op;
public JsUnaryOperation(JsUnaryOperator op) {
this(op, null);
}
public JsUnaryOperation(JsUnaryOperator op, JsExpression arg) {
super();
this.op = op;
this.arg = arg;
}
public JsExpression getArg() {
return arg;
}
public JsUnaryOperator getOperator() {
return op;
}
@Override
public final boolean hasSideEffects() {
return op.isModifying() || arg.hasSideEffects();
}
public void setArg(JsExpression arg) {
this.arg = arg;
}
@Override
public void traverse(JsVisitor 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,24 @@
// 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 string literal expression.
*/
public abstract class JsValueLiteral extends JsLiteral {
protected JsValueLiteral() {
}
@Override
public final boolean hasSideEffects() {
return false;
}
@Override
public final boolean isLeaf() {
return true;
}
}
@@ -0,0 +1,109 @@
// 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.SourceInfo;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* A JavaScript <code>var</code> statement.
*/
public class JsVars extends JsStatement implements Iterable<JsVars.JsVar> {
/**
* A var declared using the JavaScript <code>var</code> statement.
*/
public static class JsVar extends JsNode implements HasName {
private final JsName name;
private JsExpression initExpr;
public JsVar(JsName name) {
this.name = name;
}
public JsVar(JsName name, JsExpression initExpr) {
this.name = name;
this.initExpr = initExpr;
}
public JsExpression getInitExpr() {
return initExpr;
}
@Override
public JsName getName() {
return name;
}
public void setInitExpr(JsExpression initExpr) {
this.initExpr = initExpr;
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
if (v.visit(this, ctx)) {
if (initExpr != null) {
initExpr = v.accept(initExpr);
}
}
v.endVisit(this, ctx);
}
@Override
public JsVar setSourceRef(SourceInfo info) {
super.setSourceRef(info);
return this;
}
@Override
public NodeKind getKind() {
return NodeKind.VAR;
}
}
private final List<JsVar> vars = new ArrayList<JsVar>();
public JsVars() {
}
public void add(JsVar var) {
vars.add(var);
}
public int getNumVars() {
return vars.size();
}
public void insert(JsVar var) {
vars.add(var);
}
public boolean isEmpty() {
return vars.isEmpty();
}
// Iterator returns JsVar objects
@Override
public Iterator<JsVar> iterator() {
return vars.iterator();
}
@Override
public void traverse(JsVisitor v, JsContext ctx) {
if (v.visit(this, ctx)) {
v.acceptWithInsertRemove(vars);
}
v.endVisit(this, ctx);
}
@Override
public NodeKind getKind() {
return NodeKind.VARS;
}
}
@@ -0,0 +1,19 @@
// 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;
/**
* Abstracts the idea that a class can be traversed.
*/
public interface JsVisitable {
/**
* 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(JsVisitor visitor, JsContext ctx);
}
@@ -0,0 +1,430 @@
// 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 nodes that will visit child nodes.
*/
@SuppressWarnings("unused")
public class JsVisitor {
protected static final JsContext LVALUE_CONTEXT = new JsContext() {
@Override
public boolean canInsert() {
return false;
}
@Override
public boolean canRemove() {
return false;
}
@Override
public void insertAfter(JsVisitable node) {
throw new UnsupportedOperationException();
}
@Override
public void insertBefore(JsVisitable node) {
throw new UnsupportedOperationException();
}
@Override
public boolean isLvalue() {
return true;
}
@Override
public void removeMe() {
throw new UnsupportedOperationException();
}
@Override
public void replaceMe(JsVisitable node) {
throw new UnsupportedOperationException();
}
};
protected static final JsContext UNMODIFIABLE_CONTEXT = new JsContext() {
@Override
public boolean canInsert() {
return false;
}
@Override
public boolean canRemove() {
return false;
}
@Override
public void insertAfter(JsVisitable node) {
throw new UnsupportedOperationException();
}
@Override
public void insertBefore(JsVisitable node) {
throw new UnsupportedOperationException();
}
@Override
public boolean isLvalue() {
return false;
}
@Override
public void removeMe() {
throw new UnsupportedOperationException();
}
@Override
public void replaceMe(JsVisitable node) {
throw new UnsupportedOperationException();
}
};
public final <T extends JsVisitable> T accept(T node) {
return this.<T>doAccept(node);
}
public final <T extends JsVisitable> void acceptList(List<T> collection) {
doAcceptList(collection);
}
public JsExpression acceptLvalue(JsExpression expr) {
return doAcceptLvalue(expr);
}
public final <T extends JsVisitable> void acceptWithInsertRemove(List<T> collection) {
doAcceptWithInsertRemove(collection);
}
public boolean didChange() {
throw new UnsupportedOperationException();
}
public void endVisit(JsArrayAccess x, JsContext ctx) {
}
public void endVisit(JsArrayLiteral x, JsContext ctx) {
}
public void endVisit(JsBinaryOperation x, JsContext ctx) {
}
public void endVisit(JsBlock x, JsContext ctx) {
}
public void endVisit(JsBooleanLiteral x, JsContext ctx) {
}
public void endVisit(JsBreak x, JsContext ctx) {
}
public void endVisit(JsCase x, JsContext ctx) {
}
public void endVisit(JsCatch x, JsContext ctx) {
}
public void endVisit(JsConditional x, JsContext ctx) {
}
public void endVisit(JsContinue x, JsContext ctx) {
}
public void endVisit(JsDebugger x, JsContext ctx) {
}
public void endVisit(JsDefault x, JsContext ctx) {
}
public void endVisit(JsDoWhile x, JsContext ctx) {
}
public void endVisit(JsEmpty x, JsContext ctx) {
}
public void endVisit(JsExprStmt x, JsContext ctx) {
}
public void endVisit(JsFor x, JsContext ctx) {
}
public void endVisit(JsForIn x, JsContext ctx) {
}
public void endVisit(JsFunction x, JsContext ctx) {
}
public void endVisit(JsIf x, JsContext ctx) {
}
public void endVisit(JsInvocation x, JsContext ctx) {
}
public void endVisit(JsLabel x, JsContext ctx) {
}
public void endVisit(JsNameRef x, JsContext ctx) {
}
public void endVisit(JsNew x, JsContext ctx) {
}
public void endVisit(JsNullLiteral x, JsContext ctx) {
}
public void endVisit(JsNumberLiteral x, JsContext ctx) {
}
public void endVisit(JsObjectLiteral x, JsContext ctx) {
}
public void endVisit(JsParameter x, JsContext ctx) {
}
public void endVisit(JsPostfixOperation x, JsContext ctx) {
}
public void endVisit(JsPrefixOperation x, JsContext ctx) {
}
public void endVisit(JsProgram x, JsContext ctx) {
}
public void endVisit(JsProgramFragment x, JsContext ctx) {
}
public void endVisit(JsPropertyInitializer x, JsContext ctx) {
}
public void endVisit(JsRegExp x, JsContext ctx) {
}
public void endVisit(JsReturn x, JsContext ctx) {
}
public void endVisit(JsStringLiteral x, JsContext ctx) {
}
public void endVisit(JsSwitch x, JsContext ctx) {
}
public void endVisit(JsThisRef x, JsContext ctx) {
}
public void endVisit(JsThrow x, JsContext ctx) {
}
public void endVisit(JsTry x, JsContext ctx) {
}
public void endVisit(JsVars.JsVar x, JsContext ctx) {
}
public void endVisit(JsVars x, JsContext ctx) {
}
public void endVisit(JsWhile x, JsContext ctx) {
}
public boolean visit(JsArrayAccess x, JsContext ctx) {
return true;
}
public boolean visit(JsArrayLiteral x, JsContext ctx) {
return true;
}
public boolean visit(JsBinaryOperation x, JsContext ctx) {
return true;
}
public boolean visit(JsBlock x, JsContext ctx) {
return true;
}
public boolean visit(JsBooleanLiteral x, JsContext ctx) {
return true;
}
public boolean visit(JsBreak x, JsContext ctx) {
return true;
}
public boolean visit(JsCase x, JsContext ctx) {
return true;
}
public boolean visit(JsCatch x, JsContext ctx) {
return true;
}
public boolean visit(JsConditional x, JsContext ctx) {
return true;
}
public boolean visit(JsContinue x, JsContext ctx) {
return true;
}
public boolean visit(JsDebugger x, JsContext ctx) {
return true;
}
public boolean visit(JsDefault x, JsContext ctx) {
return true;
}
public boolean visit(JsDoWhile x, JsContext ctx) {
return true;
}
public boolean visit(JsEmpty x, JsContext ctx) {
return true;
}
public boolean visit(JsExprStmt x, JsContext ctx) {
return true;
}
public boolean visit(JsFor x, JsContext ctx) {
return true;
}
public boolean visit(JsForIn x, JsContext ctx) {
return true;
}
public boolean visit(JsFunction x, JsContext ctx) {
return true;
}
public boolean visit(JsIf x, JsContext ctx) {
return true;
}
public boolean visit(JsInvocation x, JsContext ctx) {
return true;
}
public boolean visit(JsLabel x, JsContext ctx) {
return true;
}
public boolean visit(JsNameRef x, JsContext ctx) {
return true;
}
public boolean visit(JsNew x, JsContext ctx) {
return true;
}
public boolean visit(JsNullLiteral x, JsContext ctx) {
return true;
}
public boolean visit(JsNumberLiteral x, JsContext ctx) {
return true;
}
public boolean visit(JsObjectLiteral x, JsContext ctx) {
return true;
}
public boolean visit(JsParameter x, JsContext ctx) {
return true;
}
public boolean visit(JsPostfixOperation x, JsContext ctx) {
return true;
}
public boolean visit(JsPrefixOperation x, JsContext ctx) {
return true;
}
public boolean visit(JsProgram x, JsContext ctx) {
return true;
}
public boolean visit(JsProgramFragment x, JsContext ctx) {
return true;
}
public boolean visit(JsPropertyInitializer x, JsContext ctx) {
return true;
}
public boolean visit(JsRegExp x, JsContext ctx) {
return true;
}
public boolean visit(JsReturn x, JsContext ctx) {
return true;
}
public boolean visit(JsStringLiteral x, JsContext ctx) {
return true;
}
public boolean visit(JsSwitch x, JsContext ctx) {
return true;
}
public boolean visit(JsThisRef x, JsContext ctx) {
return true;
}
public boolean visit(JsThrow x, JsContext ctx) {
return true;
}
public boolean visit(JsTry x, JsContext ctx) {
return true;
}
public boolean visit(JsVars.JsVar x, JsContext ctx) {
return true;
}
public boolean visit(JsVars x, JsContext ctx) {
return true;
}
public boolean visit(JsWhile x, JsContext ctx) {
return true;
}
protected <T extends JsVisitable> T doAccept(T node) {
doTraverse(node, UNMODIFIABLE_CONTEXT);
return node;
}
protected <T extends JsVisitable> void doAcceptList(List<T> collection) {
for (T node : collection) {
doTraverse(node, UNMODIFIABLE_CONTEXT);
}
}
protected JsExpression doAcceptLvalue(JsExpression expr) {
doTraverse(expr, LVALUE_CONTEXT);
return expr;
}
protected <T extends JsVisitable> void doAcceptWithInsertRemove(List<T> collection) {
for (T node : collection) {
doTraverse(node, UNMODIFIABLE_CONTEXT);
}
}
protected void doTraverse(JsVisitable node, JsContext ctx) {
node.traverse(this, ctx);
}
}

Some files were not shown because too many files have changed in this diff Show More