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        @NotNull final JsExpression emptyExpression;
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 JsObjectScope topScope;
031    
032        public JsProgram(String unitId) {
033            rootScope = new JsRootScope(this);
034            topScope = new JsObjectScope(rootScope, "Global", unitId);
035            setFragmentCount(1);
036    
037            emptyExpression = new JsEmptyExpression();
038        }
039    
040        @NotNull
041        public JsExpression getEmptyExpression() {
042            return emptyExpression;
043        }
044    
045        public JsBlock getFragmentBlock(int fragment) {
046            if (fragment < 0 || fragment >= fragments.length) {
047                throw new IllegalArgumentException("Invalid fragment: " + fragment);
048            }
049            return fragments[fragment].getGlobalBlock();
050        }
051    
052        public JsBlock getGlobalBlock() {
053            return getFragmentBlock(0);
054        }
055    
056        public JsNumberLiteral getNumberLiteral(double value) {
057            JsDoubleLiteral literal = doubleLiteralMap.get(value);
058            if (literal == null) {
059                literal = new JsDoubleLiteral(value);
060                doubleLiteralMap.put(value, literal);
061            }
062    
063            return literal;
064        }
065    
066        public JsNumberLiteral getNumberLiteral(int value) {
067            JsIntLiteral literal = intLiteralMap.get(value);
068            if (literal == null) {
069                literal = new JsIntLiteral(value);
070                intLiteralMap.put(value, literal);
071            }
072    
073            return literal;
074        }
075    
076        /**
077         * Gets the quasi-mythical root scope. This is not the same as the top scope;
078         * all unresolvable identifiers wind up here, because they are considered
079         * external to the program.
080         */
081        public JsRootScope getRootScope() {
082            return rootScope;
083        }
084    
085        /**
086         * Gets the top level scope. This is the scope of all the statements in the
087         * main program.
088         */
089        public JsObjectScope getScope() {
090            return topScope;
091        }
092    
093        /**
094         * Creates or retrieves a JsStringLiteral from an interned object pool.
095         */
096        @NotNull
097        public JsStringLiteral getStringLiteral(String value) {
098            JsStringLiteral literal = stringLiteralMap.get(value);
099            if (literal == null) {
100                literal = new JsStringLiteral(value);
101                stringLiteralMap.put(value, literal);
102            }
103            return literal;
104        }
105    
106        public void setFragmentCount(int fragments) {
107            this.fragments = new JsProgramFragment[fragments];
108            for (int i = 0; i < fragments; i++) {
109                this.fragments[i] = new JsProgramFragment();
110            }
111        }
112    
113        @Override
114        public void accept(JsVisitor v) {
115            v.visitProgram(this);
116        }
117    
118        @Override
119        public void acceptChildren(JsVisitor visitor) {
120            for (JsProgramFragment fragment : fragments) {
121                visitor.accept(fragment);
122            }
123        }
124    
125        @Override
126        public void traverse(JsVisitorWithContext v, JsContext ctx) {
127            if (v.visit(this, ctx)) {
128                for (JsProgramFragment fragment : fragments) {
129                    v.accept(fragment);
130                }
131            }
132            v.endVisit(this, ctx);
133        }
134    
135        @NotNull
136        @Override
137        public JsProgram deepCopy() {
138            throw new UnsupportedOperationException();
139        }
140    }