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
011 import java.util.Map;
012
013 import static com.google.dart.compiler.backend.js.ast.JsNumberLiteral.JsDoubleLiteral;
014 import static com.google.dart.compiler.backend.js.ast.JsNumberLiteral.JsIntLiteral;
015
016 /**
017 * A JavaScript program.
018 */
019 public final class JsProgram extends SourceInfoAwareJsNode {
020 private final JsEmpty emptyStatement;
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 JsScope topScope;
030
031 public JsProgram(String unitId) {
032 rootScope = new JsRootScope(this);
033 topScope = new JsScope(rootScope, "Global", unitId);
034 setFragmentCount(1);
035
036 emptyStatement = new JsEmpty();
037 }
038
039 public JsEmpty getEmptyStatement() {
040 return emptyStatement;
041 }
042
043 public JsBlock getFragmentBlock(int fragment) {
044 if (fragment < 0 || fragment >= fragments.length) {
045 throw new IllegalArgumentException("Invalid fragment: " + fragment);
046 }
047 return fragments[fragment].getGlobalBlock();
048 }
049
050 public JsBlock getGlobalBlock() {
051 return getFragmentBlock(0);
052 }
053
054 public JsNumberLiteral getNumberLiteral(double value) {
055 JsDoubleLiteral literal = doubleLiteralMap.get(value);
056 if (literal == null) {
057 literal = new JsDoubleLiteral(value);
058 doubleLiteralMap.put(value, literal);
059 }
060
061 return literal;
062 }
063
064 public JsNumberLiteral getNumberLiteral(int value) {
065 JsIntLiteral literal = intLiteralMap.get(value);
066 if (literal == null) {
067 literal = new JsIntLiteral(value);
068 intLiteralMap.put(value, literal);
069 }
070
071 return literal;
072 }
073
074 /**
075 * Gets the quasi-mythical root scope. This is not the same as the top scope;
076 * all unresolvable identifiers wind up here, because they are considered
077 * external to the program.
078 */
079 public JsRootScope getRootScope() {
080 return rootScope;
081 }
082
083 /**
084 * Gets the top level scope. This is the scope of all the statements in the
085 * main program.
086 */
087 public JsScope getScope() {
088 return topScope;
089 }
090
091 /**
092 * Creates or retrieves a JsStringLiteral from an interned object pool.
093 */
094 public JsStringLiteral getStringLiteral(String value) {
095 JsStringLiteral literal = stringLiteralMap.get(value);
096 if (literal == null) {
097 literal = new JsStringLiteral(value);
098 stringLiteralMap.put(value, literal);
099 }
100 return literal;
101 }
102
103 public void setFragmentCount(int fragments) {
104 this.fragments = new JsProgramFragment[fragments];
105 for (int i = 0; i < fragments; i++) {
106 this.fragments[i] = new JsProgramFragment();
107 }
108 }
109
110 @Override
111 public void accept(JsVisitor v) {
112 v.visitProgram(this);
113 }
114
115 @Override
116 public void acceptChildren(JsVisitor visitor) {
117 for (JsProgramFragment fragment : fragments) {
118 visitor.accept(fragment);
119 }
120 }
121 }