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