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 }