001 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
002 // for details. All rights reserved. Use of this source code is governed by a
003 // BSD-style license that can be found in the LICENSE file.
004
005 package com.google.dart.compiler.backend.js.ast;
006
007 import gnu.trove.TDoubleObjectHashMap;
008 import gnu.trove.THashMap;
009 import gnu.trove.TIntObjectHashMap;
010 import org.jetbrains.annotations.NotNull;
011
012 import java.util.Map;
013
014 import static com.google.dart.compiler.backend.js.ast.JsNumberLiteral.JsDoubleLiteral;
015 import static com.google.dart.compiler.backend.js.ast.JsNumberLiteral.JsIntLiteral;
016
017 /**
018 * A JavaScript program.
019 */
020 public final class JsProgram extends SourceInfoAwareJsNode {
021 @NotNull
022 private final JsEmpty emptyStatement;
023 @NotNull final JsExpression emptyExpression;
024
025 private JsProgramFragment[] fragments;
026
027 private final TDoubleObjectHashMap<JsDoubleLiteral> doubleLiteralMap = new TDoubleObjectHashMap<JsDoubleLiteral>();
028 private final TIntObjectHashMap<JsIntLiteral> intLiteralMap = new TIntObjectHashMap<JsIntLiteral>();
029
030 private final JsRootScope rootScope;
031 private final Map<String, JsStringLiteral> stringLiteralMap = new THashMap<String, JsStringLiteral>();
032 private final JsObjectScope topScope;
033
034 public JsProgram(String unitId) {
035 rootScope = new JsRootScope(this);
036 topScope = new JsObjectScope(rootScope, "Global", unitId);
037 setFragmentCount(1);
038
039 emptyStatement = new JsEmpty();
040 emptyExpression = new JsEmptyExpression();
041 }
042
043 @NotNull
044 public JsEmpty getEmptyStatement() {
045 return emptyStatement;
046 }
047
048 @NotNull
049 public JsExpression getEmptyExpression() {
050 return emptyExpression;
051 }
052
053 public JsBlock getFragmentBlock(int fragment) {
054 if (fragment < 0 || fragment >= fragments.length) {
055 throw new IllegalArgumentException("Invalid fragment: " + fragment);
056 }
057 return fragments[fragment].getGlobalBlock();
058 }
059
060 public JsBlock getGlobalBlock() {
061 return getFragmentBlock(0);
062 }
063
064 public JsNumberLiteral getNumberLiteral(double value) {
065 JsDoubleLiteral literal = doubleLiteralMap.get(value);
066 if (literal == null) {
067 literal = new JsDoubleLiteral(value);
068 doubleLiteralMap.put(value, literal);
069 }
070
071 return literal;
072 }
073
074 public JsNumberLiteral getNumberLiteral(int value) {
075 JsIntLiteral literal = intLiteralMap.get(value);
076 if (literal == null) {
077 literal = new JsIntLiteral(value);
078 intLiteralMap.put(value, literal);
079 }
080
081 return literal;
082 }
083
084 /**
085 * Gets the quasi-mythical root scope. This is not the same as the top scope;
086 * all unresolvable identifiers wind up here, because they are considered
087 * external to the program.
088 */
089 public JsRootScope getRootScope() {
090 return rootScope;
091 }
092
093 /**
094 * Gets the top level scope. This is the scope of all the statements in the
095 * main program.
096 */
097 public JsObjectScope getScope() {
098 return topScope;
099 }
100
101 /**
102 * Creates or retrieves a JsStringLiteral from an interned object pool.
103 */
104 @NotNull
105 public JsStringLiteral getStringLiteral(String value) {
106 JsStringLiteral literal = stringLiteralMap.get(value);
107 if (literal == null) {
108 literal = new JsStringLiteral(value);
109 stringLiteralMap.put(value, literal);
110 }
111 return literal;
112 }
113
114 public void setFragmentCount(int fragments) {
115 this.fragments = new JsProgramFragment[fragments];
116 for (int i = 0; i < fragments; i++) {
117 this.fragments[i] = new JsProgramFragment();
118 }
119 }
120
121 @Override
122 public void accept(JsVisitor v) {
123 v.visitProgram(this);
124 }
125
126 @Override
127 public void acceptChildren(JsVisitor visitor) {
128 for (JsProgramFragment fragment : fragments) {
129 visitor.accept(fragment);
130 }
131 }
132
133 @Override
134 public void traverse(JsVisitorWithContext v, JsContext ctx) {
135 if (v.visit(this, ctx)) {
136 for (JsProgramFragment fragment : fragments) {
137 v.accept(fragment);
138 }
139 }
140 v.endVisit(this, ctx);
141 }
142
143 @NotNull
144 @Override
145 public JsProgram deepCopy() {
146 throw new UnsupportedOperationException();
147 }
148 }