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 }