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    }