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