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    }