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 }