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