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
022 private JsProgramFragment[] fragments;
023
024 private final TDoubleObjectHashMap<JsDoubleLiteral> doubleLiteralMap = new TDoubleObjectHashMap<JsDoubleLiteral>();
025 private final TIntObjectHashMap<JsIntLiteral> intLiteralMap = new TIntObjectHashMap<JsIntLiteral>();
026
027 private final JsRootScope rootScope;
028 private final Map<String, JsStringLiteral> stringLiteralMap = new THashMap<String, JsStringLiteral>();
029 private final JsObjectScope topScope;
030
031 public JsProgram(String unitId) {
032 rootScope = new JsRootScope(this);
033 topScope = new JsObjectScope(rootScope, "Global", unitId);
034 setFragmentCount(1);
035 }
036
037 public JsBlock getFragmentBlock(int fragment) {
038 if (fragment < 0 || fragment >= fragments.length) {
039 throw new IllegalArgumentException("Invalid fragment: " + fragment);
040 }
041 return fragments[fragment].getGlobalBlock();
042 }
043
044 public JsBlock getGlobalBlock() {
045 return getFragmentBlock(0);
046 }
047
048 public JsNumberLiteral getNumberLiteral(double value) {
049 JsDoubleLiteral literal = doubleLiteralMap.get(value);
050 if (literal == null) {
051 literal = new JsDoubleLiteral(value);
052 doubleLiteralMap.put(value, literal);
053 }
054
055 return literal;
056 }
057
058 public JsNumberLiteral getNumberLiteral(int value) {
059 JsIntLiteral literal = intLiteralMap.get(value);
060 if (literal == null) {
061 literal = new JsIntLiteral(value);
062 intLiteralMap.put(value, literal);
063 }
064
065 return literal;
066 }
067
068 /**
069 * Gets the quasi-mythical root scope. This is not the same as the top scope;
070 * all unresolvable identifiers wind up here, because they are considered
071 * external to the program.
072 */
073 public JsRootScope getRootScope() {
074 return rootScope;
075 }
076
077 /**
078 * Gets the top level scope. This is the scope of all the statements in the
079 * main program.
080 */
081 public JsObjectScope getScope() {
082 return topScope;
083 }
084
085 /**
086 * Creates or retrieves a JsStringLiteral from an interned object pool.
087 */
088 @NotNull
089 public JsStringLiteral getStringLiteral(String value) {
090 JsStringLiteral literal = stringLiteralMap.get(value);
091 if (literal == null) {
092 literal = new JsStringLiteral(value);
093 stringLiteralMap.put(value, literal);
094 }
095 return literal;
096 }
097
098 public void setFragmentCount(int fragments) {
099 this.fragments = new JsProgramFragment[fragments];
100 for (int i = 0; i < fragments; i++) {
101 this.fragments[i] = new JsProgramFragment();
102 }
103 }
104
105 @Override
106 public void accept(JsVisitor v) {
107 v.visitProgram(this);
108 }
109
110 @Override
111 public void acceptChildren(JsVisitor visitor) {
112 for (JsProgramFragment fragment : fragments) {
113 visitor.accept(fragment);
114 }
115 }
116
117 @Override
118 public void traverse(JsVisitorWithContext v, JsContext ctx) {
119 if (v.visit(this, ctx)) {
120 for (JsProgramFragment fragment : fragments) {
121 v.accept(fragment);
122 }
123 }
124 v.endVisit(this, ctx);
125 }
126
127 @NotNull
128 @Override
129 public JsProgram deepCopy() {
130 throw new UnsupportedOperationException();
131 }
132 }