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    }