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 }