From f4b18c277f74dd0f2e7d0ecdbb6a7d68df729050 Mon Sep 17 00:00:00 2001 From: Pavel Talanov Date: Thu, 10 Nov 2011 14:06:15 +0400 Subject: [PATCH] Added DeclarationExtractor logic. --- .idea/workspace.xml | 349 ++++++++-------- .../compiler/backend/js/ast/JsFunction.java | 376 +++++++++--------- .../declarations/DeclarationExtractor.java | 36 ++ .../k2js/declarations/ExtractionVisitor.java | 65 +++ .../k2js/translate/BindingUtils.java | 54 +++ .../k2js/translate/ClassTranslator.java | 4 +- .../k2js/translate/ExpressionVisitor.java | 1 + .../k2js/translate/FunctionTranslator.java | 15 +- .../k2js/translate/GenerationState.java | 22 +- .../k2js/translate/NamespaceTranslator.java | 6 +- .../k2js/translate/TranslationContext.java | 94 +++-- 11 files changed, 624 insertions(+), 398 deletions(-) create mode 100644 translator/src/org/jetbrains/k2js/declarations/DeclarationExtractor.java create mode 100644 translator/src/org/jetbrains/k2js/declarations/ExtractionVisitor.java create mode 100644 translator/src/org/jetbrains/k2js/translate/BindingUtils.java diff --git a/.idea/workspace.xml b/.idea/workspace.xml index c6da240ed7f..a81f110c286 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -6,15 +6,17 @@ - - + + + - + + + - @@ -39,7 +41,7 @@ - + - + - - + + - + @@ -109,52 +111,56 @@ - + - - + + - + - - + + - + + + + + + + + + + + + - - + + - - + + + + - - + + - - - - - - - - - - + @@ -163,26 +169,28 @@ - + - - + + - + - - + + - - + + + + @@ -191,10 +199,10 @@ - + - + @@ -202,24 +210,6 @@ - - - - - - - - - - - - - - - - - - @@ -250,7 +240,7 @@ - + @@ -272,7 +262,29 @@ - + + + + + + + + + + + + + + + + + + + + + + + @@ -305,22 +317,22 @@ @@ -381,24 +393,6 @@ - + - + @@ -804,7 +798,7 @@ - + @@ -842,7 +836,7 @@ @@ -872,90 +867,119 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -964,34 +988,13 @@ - + - - - - - - - - - - - - - - - - - - - - - diff --git a/js/src/com/google/dart/compiler/backend/js/ast/JsFunction.java b/js/src/com/google/dart/compiler/backend/js/ast/JsFunction.java index 4563ca58bec..f2c7d258791 100644 --- a/js/src/com/google/dart/compiler/backend/js/ast/JsFunction.java +++ b/js/src/com/google/dart/compiler/backend/js/ast/JsFunction.java @@ -14,211 +14,225 @@ import java.util.List; */ public final class JsFunction extends JsLiteral implements HasName { - private static void trace(String title, String code) { - System.out.println("---------------------------"); - System.out.println(title + ":"); - System.out.println("---------------------------"); - System.out.println(code); - } + private static void trace(String title, String code) { + System.out.println("---------------------------"); + System.out.println(title + ":"); + System.out.println("---------------------------"); + System.out.println(code); + } - protected JsBlock body; - protected final List params = new ArrayList(); - protected final JsScope scope; - private boolean artificiallyRescued; - private boolean executeOnce; - private boolean fromDart; - private JsFunction impliedExecute; - private JsName name; - private boolean trace = false; - private boolean traceFirst = true; - private boolean hoisted = false; - private boolean constructor = false; + protected JsBlock body; + protected final List params = new ArrayList(); + protected final JsScope scope; + private boolean artificiallyRescued; + private boolean executeOnce; + private boolean fromDart; + private JsFunction impliedExecute; + private JsName name; + private boolean trace = false; + private boolean traceFirst = true; + private boolean hoisted = false; + private boolean constructor = false; - /** - * Creates an anonymous function. - */ - public JsFunction(JsScope parent) { - this(parent, null, false); - } + /** + * Creates an anonymous function. + */ + public JsFunction(JsScope parent) { + this(parent, null, false); + } - /** - * Creates a function that is not derived from Dart source. - */ - public JsFunction(JsScope parent, JsName name) { - this(parent, name, false); - } + /** + * Creates a function that is not derived from Dart source. + */ + public JsFunction(JsScope parent, JsName name) { + this(parent, name, false); + } - /** - * Creates a named function, possibly derived from Dart source. - */ - public JsFunction(JsScope parent, JsName name, boolean fromDart) { - assert (parent != null); - this.fromDart = fromDart; - setName(name); - String scopeName = (name == null) ? "" : name.getIdent(); - scopeName = "function " + scopeName; - this.scope = new JsScope(parent, scopeName); - } + /** + * Creates a named function, possibly derived from Dart source. + */ + public JsFunction(JsScope parent, JsName name, boolean fromDart) { + assert (parent != null); + this.fromDart = fromDart; + setName(name); + String scopeName = (name == null) ? "" : name.getIdent(); + scopeName = "function " + scopeName; + this.scope = new JsScope(parent, scopeName); + } - public JsBlock getBody() { - return body; - } + public JsBlock getBody() { + return body; + } - /** - * If true, this indicates that only the first invocation of the function will - * have any effects. Subsequent invocations may be considered to be no-op - * calls whose return value is ignored. - */ - public boolean getExecuteOnce() { - return executeOnce; - } + /** + * If true, this indicates that only the first invocation of the function will + * have any effects. Subsequent invocations may be considered to be no-op + * calls whose return value is ignored. + */ + public boolean getExecuteOnce() { + return executeOnce; + } - public JsFunction getImpliedExecute() { - return impliedExecute; - } + public JsFunction getImpliedExecute() { + return impliedExecute; + } - @Override - public JsName getName() { - return name; - } + @Override + public JsName getName() { + return name; + } public void setParameters(List params) { this.params.clear(); this.params.addAll(params); } - public List getParameters() { - return params; - } - - public JsScope getScope() { - return scope; - } - - @Override - public boolean hasSideEffects() { - // If there's a name, the name is assigned to. - return name != null; - } - - public boolean isArtificiallyRescued() { - return artificiallyRescued; - } - - @Override - public boolean isBooleanFalse() { - return false; - } - - @Override - public boolean isBooleanTrue() { - return true; - } - - @Override - public boolean isDefinitelyNotNull() { - return true; - } - - @Override - public boolean isDefinitelyNull() { - return false; - } - - public boolean isFromDart() { - return fromDart; - } - - public void setArtificiallyRescued(boolean rescued) { - this.artificiallyRescued = rescued; - } - - public void setBody(JsBlock body) { - this.body = body; - } - - public void setExecuteOnce(boolean executeOnce) { - this.executeOnce = executeOnce; - } - - public void setFromDart(boolean fromDart) { - this.fromDart = fromDart; - } - - public void setImpliedExecute(JsFunction impliedExecute) { - this.impliedExecute = impliedExecute; - } - - public void setName(JsName name) { - this.name = name; - if (name != null) { - if (isFromDart()) { - name.setStaticRef(this); - } + public List getParameters() { + return params; } - } - public void setTrace() { - this.trace = true; - } - - @Override - public void traverse(JsVisitor v, JsContext ctx) { - String before = null; - if (trace && v instanceof JsModVisitor) { - before = this.toSource(); - if (traceFirst) { - traceFirst = false; - trace("SCRIPT INITIAL", before); - } + public JsScope getScope() { + return scope; } - if (v.visit(this, ctx)) { - v.acceptWithInsertRemove(params); - body = v.accept(body); + + @Override + public boolean hasSideEffects() { + // If there's a name, the name is assigned to. + return name != null; } - v.endVisit(this, ctx); - if (trace && v instanceof JsModVisitor) { - String after = this.toSource(); - if (!after.equals(before)) { - String title = v.getClass().getSimpleName(); - trace(title, after); - } + + public boolean isArtificiallyRescued() { + return artificiallyRescued; } - } - public void setHoisted() { - hoisted = true; - } + @Override + public boolean isBooleanFalse() { + return false; + } - /** Whether the function has been hoisted */ - public boolean isHoisted() { - return hoisted; - } + @Override + public boolean isBooleanTrue() { + return true; + } - /** - * Rebase the function to a new scope. - * @param newScopeParent The scope to add the function to. - */ - public void rebaseScope(JsScope newScopeParent) { - this.scope.rebase(newScopeParent); - } + @Override + public boolean isDefinitelyNotNull() { + return true; + } - @Override - public JsFunction setSourceRef(SourceInfo info) { - super.setSourceRef(info); - return this; - } + @Override + public boolean isDefinitelyNull() { + return false; + } - public boolean isConstructor() { - return this.constructor; - } + public boolean isFromDart() { + return fromDart; + } - public boolean setIsConstructor(boolean constructor) { - return this.constructor = constructor; - } + public void setArtificiallyRescued(boolean rescued) { + this.artificiallyRescued = rescued; + } - @Override - public NodeKind getKind() { - return NodeKind.FUNCTION; - } + public void setBody(JsBlock body) { + this.body = body; + } + + public void setExecuteOnce(boolean executeOnce) { + this.executeOnce = executeOnce; + } + + public void setFromDart(boolean fromDart) { + this.fromDart = fromDart; + } + + public void setImpliedExecute(JsFunction impliedExecute) { + this.impliedExecute = impliedExecute; + } + + public void setName(JsName name) { + this.name = name; + if (name != null) { + if (isFromDart()) { + name.setStaticRef(this); + } + } + } + + public void setTrace() { + this.trace = true; + } + + @Override + public void traverse(JsVisitor v, JsContext ctx) { + String before = null; + if (trace && v instanceof JsModVisitor) { + before = this.toSource(); + if (traceFirst) { + traceFirst = false; + trace("SCRIPT INITIAL", before); + } + } + if (v.visit(this, ctx)) { + v.acceptWithInsertRemove(params); + body = v.accept(body); + } + v.endVisit(this, ctx); + if (trace && v instanceof JsModVisitor) { + String after = this.toSource(); + if (!after.equals(before)) { + String title = v.getClass().getSimpleName(); + trace(title, after); + } + } + } + + public void setHoisted() { + hoisted = true; + } + + /** + * Whether the function has been hoisted + */ + public boolean isHoisted() { + return hoisted; + } + + /** + * Rebase the function to a new scope. + * + * @param newScopeParent The scope to add the function to. + */ + public void rebaseScope(JsScope newScopeParent) { + this.scope.rebase(newScopeParent); + } + + @Override + public JsFunction setSourceRef(SourceInfo info) { + super.setSourceRef(info); + return this; + } + + public boolean isConstructor() { + return this.constructor; + } + + public boolean setIsConstructor(boolean constructor) { + return this.constructor = constructor; + } + + @Override + public NodeKind getKind() { + return NodeKind.FUNCTION; + } + + // Pavel Talanov + // dummy parameter to distinguish from other constructors + private JsFunction(Void dummy, JsScope functionScope) { + this.fromDart = false; + this.scope = functionScope; + } + + public static JsFunction getAnonymousFunctionWithScope(JsScope scope) { + return new JsFunction(null, scope); + } } diff --git a/translator/src/org/jetbrains/k2js/declarations/DeclarationExtractor.java b/translator/src/org/jetbrains/k2js/declarations/DeclarationExtractor.java new file mode 100644 index 00000000000..e49124a4590 --- /dev/null +++ b/translator/src/org/jetbrains/k2js/declarations/DeclarationExtractor.java @@ -0,0 +1,36 @@ +package org.jetbrains.k2js.declarations; + +import com.google.dart.compiler.backend.js.ast.JsScope; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Talanov Pavel + */ +public final class DeclarationExtractor { + private final Map descriptorToScopeMap + = new HashMap(); + + public DeclarationExtractor() { + + } + + public void extractDeclarations(@NotNull DeclarationDescriptor descriptor, JsScope rootScope) { + ExtractionVisitor visitor = new ExtractionVisitor(this); + descriptor.accept(visitor, rootScope); + } + + @NotNull + public JsScope getScope(@NotNull DeclarationDescriptor descriptor) { + JsScope scope = descriptorToScopeMap.get(descriptor); + assert scope != null : "Unknown declaration"; + return scope; + } + + /*package*/ void put(@NotNull DeclarationDescriptor descriptor, @NotNull JsScope scope) { + descriptorToScopeMap.put(descriptor, scope); + } +} diff --git a/translator/src/org/jetbrains/k2js/declarations/ExtractionVisitor.java b/translator/src/org/jetbrains/k2js/declarations/ExtractionVisitor.java new file mode 100644 index 00000000000..c69cc8f0f17 --- /dev/null +++ b/translator/src/org/jetbrains/k2js/declarations/ExtractionVisitor.java @@ -0,0 +1,65 @@ +package org.jetbrains.k2js.declarations; + +import com.google.dart.compiler.backend.js.ast.JsName; +import com.google.dart.compiler.backend.js.ast.JsScope; +import com.intellij.codeInspection.ex.Descriptor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.k2js.translate.Namer; + +/** + * @author Talanov Pavel + */ +public final class ExtractionVisitor extends DeclarationDescriptorVisitor { + + @NotNull private final DeclarationExtractor extractor; + + /*package*/ ExtractionVisitor(@NotNull DeclarationExtractor extractor) { + this.extractor = extractor; + } + + + @Override + public Void visitClassDescriptor(ClassDescriptor descriptor, JsScope enclosingScope) { + String className = descriptor.getName(); + enclosingScope.declareName(className); + JsScope classScope = new JsScope(enclosingScope, "Scope for class " + className); + extractor.put(descriptor, classScope); + for (DeclarationDescriptor memberDescriptor : + descriptor.getDefaultType().getMemberScope().getAllDescriptors()) { + memberDescriptor.accept(this, classScope); + } + return null; + } + + @Override + public Void visitFunctionDescriptor(FunctionDescriptor descriptor, JsScope enclosingScope) { + String functionName = descriptor.getName(); + enclosingScope.declareName(functionName); + JsScope functionScope = new JsScope(enclosingScope, "Scope for function " + functionName); + extractor.put(descriptor, functionScope); + return null; + } + + @Override + public Void visitPropertyDescriptor(PropertyDescriptor descriptor, JsScope enclosingScope) { + String propertyName = descriptor.getName(); + enclosingScope.declareName(Namer.getNameForSetter(propertyName)); + enclosingScope.declareName(Namer.getNameForGetter(propertyName)); + return null; + } + + @Override + public Void visitNamespaceDescriptor(NamespaceDescriptor descriptor, JsScope enclosingScope) { + String namespaceName = descriptor.getName(); + enclosingScope.declareName(namespaceName); + JsScope namespaceScope = new JsScope(enclosingScope, "Scope for namespace " + namespaceName); + extractor.put(descriptor, namespaceScope); + for (DeclarationDescriptor memberDescriptor : + descriptor.getMemberScope().getAllDescriptors()) { + memberDescriptor.accept(this, namespaceScope); + } + return null; + } + +} diff --git a/translator/src/org/jetbrains/k2js/translate/BindingUtils.java b/translator/src/org/jetbrains/k2js/translate/BindingUtils.java new file mode 100644 index 00000000000..0b49e75e897 --- /dev/null +++ b/translator/src/org/jetbrains/k2js/translate/BindingUtils.java @@ -0,0 +1,54 @@ +package org.jetbrains.k2js.translate; + +import com.intellij.codeInsight.hint.ClassDeclarationRangeHandler; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; +import org.jetbrains.jet.lang.psi.JetClass; +import org.jetbrains.jet.lang.psi.JetNamedFunction; +import org.jetbrains.jet.lang.psi.JetNamespace; +import org.jetbrains.jet.lang.resolve.BindingContext; + +import javax.xml.ws.Binding; + +/** + * @author Talanov Pavel + * + * This class contains some code related to BindingContext use. Intention is not to pollute other classes. + */ +public final class BindingUtils { + private BindingUtils() {} + + //TODO generalise methods? + @NotNull + static public ClassDescriptor getClassDescriptor(@NotNull BindingContext context, @NotNull JetClass declaration) { + DeclarationDescriptor descriptor + = context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, declaration); + assert descriptor instanceof ClassDescriptor : "Class should have a descriptor" + + " of type ClassDescriptor"; + return (ClassDescriptor)descriptor; + } + + @NotNull + static public NamespaceDescriptor getNamespaceDescriptor(@NotNull BindingContext context, + @NotNull JetNamespace declaration) { + DeclarationDescriptor descriptor + = context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, declaration); + assert descriptor instanceof NamespaceDescriptor : "Namespace should have a descriptor" + + " of type NamespaceDescriptor"; + return (NamespaceDescriptor)descriptor; + } + + @NotNull + static public FunctionDescriptor getFunctionDescriptor(@NotNull BindingContext context, + @NotNull JetNamedFunction declaration) { + DeclarationDescriptor descriptor = + context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, declaration); + assert descriptor instanceof FunctionDescriptor : "JetNamedFunction should have" + + " descriptor of type FunctionDescriptor."; + return (FunctionDescriptor)descriptor; + } + +} diff --git a/translator/src/org/jetbrains/k2js/translate/ClassTranslator.java b/translator/src/org/jetbrains/k2js/translate/ClassTranslator.java index 4bcf939bb6f..e92007db439 100644 --- a/translator/src/org/jetbrains/k2js/translate/ClassTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/ClassTranslator.java @@ -6,6 +6,7 @@ import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.psi.JetClass; import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.types.JetType; import java.util.ArrayList; @@ -46,7 +47,8 @@ public final class ClassTranslator extends AbstractTranslator { private JsObjectLiteral translateClassDeclarations(JetClass classDeclaration) { List propertyList = new ArrayList(); propertyList.add(generateInitializeMethod(classDeclaration)); - propertyList.addAll(classDeclaration.accept(classBodyVisitor, translationContext().newClass())); + propertyList.addAll(classDeclaration.accept(classBodyVisitor, + translationContext().newClass(classDeclaration))); return new JsObjectLiteral(propertyList); } diff --git a/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java b/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java index ba049aac277..1de62d25e08 100644 --- a/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java +++ b/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java @@ -276,6 +276,7 @@ public final class ExpressionVisitor extends TranslatorVisitor { return null; } + //TODO method too long @Override @NotNull public JsNode visitDotQualifiedExpression(@NotNull JetDotQualifiedExpression expression, diff --git a/translator/src/org/jetbrains/k2js/translate/FunctionTranslator.java b/translator/src/org/jetbrains/k2js/translate/FunctionTranslator.java index 69247208b79..3e9571b48b8 100644 --- a/translator/src/org/jetbrains/k2js/translate/FunctionTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/FunctionTranslator.java @@ -3,10 +3,14 @@ package org.jetbrains.k2js.translate; import com.google.dart.compiler.backend.js.ast.*; import com.google.dart.compiler.util.AstUtil; import com.sun.istack.internal.NotNull; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetNamedFunction; import org.jetbrains.jet.lang.psi.JetParameter; +import org.jetbrains.jet.lang.resolve.BindingContext; +import javax.xml.ws.Binding; import java.util.ArrayList; import java.util.List; @@ -36,8 +40,9 @@ public final class FunctionTranslator extends AbstractTranslator { @NotNull private JsFunction generateFunctionObject(@NotNull JetNamedFunction jetFunction) { JetExpression jetBodyExpression = jetFunction.getBodyExpression(); - JsFunction result = new JsFunction(scope()); - JsNode jsBody = (new ExpressionTranslator(functionBodyContext(result))) + JsFunction result = JsFunction.getAnonymousFunctionWithScope + (translationContext().getScopeForElement(jetFunction)); + JsNode jsBody = (new ExpressionTranslator(functionContext(jetFunction))) .translate(jetBodyExpression); List jsParameters = translateParameters(jetFunction.getValueParameters(), result.getScope()); result.setParameters(jsParameters); @@ -46,8 +51,10 @@ public final class FunctionTranslator extends AbstractTranslator { } @NotNull - private TranslationContext functionBodyContext(@NotNull JsFunction function) { - return translationContext().newFunction(function); + private TranslationContext functionContext(@NotNull JetNamedFunction jetFunction) { + FunctionDescriptor descriptor = + BindingUtils.getFunctionDescriptor(translationContext().bindingContext(), jetFunction); + return translationContext().newFunction(descriptor); } @NotNull diff --git a/translator/src/org/jetbrains/k2js/translate/GenerationState.java b/translator/src/org/jetbrains/k2js/translate/GenerationState.java index 4b44c0d0948..1e7d89bc9a3 100644 --- a/translator/src/org/jetbrains/k2js/translate/GenerationState.java +++ b/translator/src/org/jetbrains/k2js/translate/GenerationState.java @@ -6,12 +6,18 @@ package org.jetbrains.k2js.translate; import com.google.dart.compiler.backend.js.ast.JsProgram; import com.intellij.openapi.project.Project; import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetNamespace; import org.jetbrains.jet.lang.resolve.AnalyzingUtils; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.java.JavaDefaultImports; +import org.jetbrains.k2js.declarations.DeclarationExtractor; +import javax.print.attribute.standard.MediaSize; +import javax.xml.ws.Binding; +import java.beans.beancontext.BeanContext; import java.util.Collections; import java.util.List; @@ -21,19 +27,19 @@ public final class GenerationState { public GenerationState() { } -// public void compile(JetFile psiFile) { -// final JetNamespace namespace = psiFile.getRootNamespace(); -// final BindingContext bindingContext = AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS).analyzeNamespace(namespace, JetControlFlowDataTraceFactory.EMPTY); -// AnalyzingUtils.throwExceptionOnErrors(bindingContext); -// compileCorrectNamespaces(bindingContext, Collections.singletonList(namespace)); -// } - + //TODO method too long public JsProgram compileCorrectNamespaces(BindingContext bindingContext, List namespaces) { //TODO hardcoded JsProgram result = new JsProgram("main"); JetNamespace namespace = namespaces.get(0); - (new NamespaceTranslator(TranslationContext.rootContext(result, bindingContext))).generateAst(namespace); + NamespaceDescriptor descriptor = BindingUtils.getNamespaceDescriptor(bindingContext, namespace); + DeclarationExtractor extractor = new DeclarationExtractor(); + extractor.extractDeclarations(descriptor, result.getRootScope()); + (new NamespaceTranslator(TranslationContext.rootContext(result, bindingContext, extractor))) + .generateAst(namespace); return result; } + + } diff --git a/translator/src/org/jetbrains/k2js/translate/NamespaceTranslator.java b/translator/src/org/jetbrains/k2js/translate/NamespaceTranslator.java index 14eb987582e..e8c79d15cf6 100644 --- a/translator/src/org/jetbrains/k2js/translate/NamespaceTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/NamespaceTranslator.java @@ -23,14 +23,16 @@ public final class NamespaceTranslator extends AbstractTranslator { return program(); } + //TODO logic unclear @NotNull public JsBlock translate(@NotNull JetNamespace namespace) { // TODO support multiple namespaces JsBlock block = program().getFragmentBlock(0); JsName namespaceName = scope().declareName(Namer.getNameForNamespace(namespace.getName())); block.addStatement(namespaceInitStatement(namespaceName)); - JsFunction dummyFunction = new JsFunction(scope()); - TranslationContext newContext = translationContext().newNamespace(namespaceName, dummyFunction); + TranslationContext newContext = translationContext().newNamespace(namespace); + JsFunction dummyFunction = JsFunction.getAnonymousFunctionWithScope + (translationContext().getScopeForElement(namespace)); JsBlock namespaceDeclarations = translateDeclarations(namespace, newContext); block.addStatement(AstUtil.convertToStatement(newNamespace(namespaceName, namespaceDeclarations, dummyFunction))); return block; diff --git a/translator/src/org/jetbrains/k2js/translate/TranslationContext.java b/translator/src/org/jetbrains/k2js/translate/TranslationContext.java index 9380ff5777d..056f3c7f847 100644 --- a/translator/src/org/jetbrains/k2js/translate/TranslationContext.java +++ b/translator/src/org/jetbrains/k2js/translate/TranslationContext.java @@ -4,7 +4,16 @@ import com.google.dart.compiler.backend.js.ast.*; import com.google.dart.compiler.util.AstUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; +import org.jetbrains.jet.lang.psi.JetClass; +import org.jetbrains.jet.lang.psi.JetElement; +import org.jetbrains.jet.lang.psi.JetNamedFunction; +import org.jetbrains.jet.lang.psi.JetNamespace; import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.k2js.declarations.DeclarationExtractor; /** * @author Talanov Pavel @@ -25,64 +34,79 @@ public final class TranslationContext { } @NotNull - public static TranslationContext rootContext(JsProgram program, BindingContext bindingContext) { + public static TranslationContext rootContext(@NotNull JsProgram program, @NotNull BindingContext bindingContext, + @NotNull DeclarationExtractor extractor) { JsScope rootScope = program.getRootScope(); Scopes scopes = new Scopes(rootScope, rootScope, rootScope); - return new TranslationContext(null, - program, bindingContext, scopes); + return new TranslationContext(null, program, bindingContext, scopes, extractor); } @NotNull private final JsProgram program; @NotNull private final BindingContext bindingContext; @NotNull private final Scopes scopes; - @Nullable private final JsName currentNamespace; + @Nullable private final JsName namespaceName; + @NotNull private final DeclarationExtractor extractor; - private TranslationContext(@Nullable JsName currentNamespace, @NotNull JsProgram program, - @NotNull BindingContext bindingContext, @NotNull Scopes scopes) { + private TranslationContext(@Nullable JsName namespaceName, @NotNull JsProgram program, + @NotNull BindingContext bindingContext, @NotNull Scopes scopes, + @NotNull DeclarationExtractor extractor) { this.program = program; this.bindingContext = bindingContext; - this.currentNamespace = currentNamespace; + this.namespaceName = namespaceName; this.scopes = scopes; + this.extractor = extractor; } @NotNull - public TranslationContext newNamespace(@NotNull JsName namespaceName, @NotNull JsFunction namespaceDummyFunction) { - JsScope newScope = namespaceDummyFunction.getScope(); - Scopes newScopes = new Scopes(newScope, newScope, newScope); - return new TranslationContext(namespaceName, program, - bindingContext, newScopes); + public TranslationContext newNamespace(@NotNull JetNamespace declaration) { + return newNamespace(BindingUtils.getNamespaceDescriptor(bindingContext, declaration)); + } + + @NotNull + public TranslationContext newNamespace(@NotNull NamespaceDescriptor descriptor) { + JsScope namespaceScope = extractor.getScope(descriptor); + JsName namespaceName = scopes.enclosingScope.findExistingName(descriptor.getName()); + Scopes newScopes = new Scopes(namespaceScope, namespaceScope, namespaceScope); + return new TranslationContext(namespaceName, program, bindingContext, newScopes, extractor); } @NotNull public TranslationContext newBlock() { Scopes newScopes = new Scopes(new JsScope (scopes.enclosingScope, "Scope for a block"), scopes.classScope, scopes.namespaceScope); - return new TranslationContext(currentNamespace, program, - bindingContext, newScopes); + return new TranslationContext(namespaceName, program, bindingContext, newScopes, extractor); } @NotNull - public TranslationContext newClass() { - JsScope classDummyScope = new JsScope(namespaceScope(), "Scope for a class"); - Scopes newScopes = new Scopes(classDummyScope, classDummyScope, scopes.namespaceScope); - return new TranslationContext(currentNamespace, program, - bindingContext, newScopes); + TranslationContext newClass(@NotNull JetClass declaration) { + return newClass(BindingUtils.getClassDescriptor(bindingContext, declaration)); } @NotNull - public TranslationContext newFunction(@NotNull JsFunction function) { - JsScope functionScope = function.getScope(); + public TranslationContext newClass(@NotNull ClassDescriptor descriptor) { + JsScope classScope = extractor.getScope(descriptor); + Scopes newScopes = new Scopes(classScope, classScope, scopes.namespaceScope); + return new TranslationContext(namespaceName, program, bindingContext, newScopes, extractor); + } + + @NotNull + TranslationContext newFunction(@NotNull JetNamedFunction declaration) { + return newFunction(BindingUtils.getFunctionDescriptor(bindingContext, declaration)); + } + + @NotNull + public TranslationContext newFunction(@NotNull FunctionDescriptor descriptor) { + JsScope functionScope = extractor.getScope(descriptor); Scopes newScopes = new Scopes(functionScope, scopes.classScope, scopes.namespaceScope); - return new TranslationContext(currentNamespace, program, - bindingContext, newScopes); + return new TranslationContext(namespaceName, program, bindingContext, newScopes, extractor); } @NotNull public JsNameRef getNamespaceQualifiedReference(JsName name) { - if (currentNamespace != null) { - return AstUtil.newNameRef(currentNamespace.makeRef(), name); + if (namespaceName != null) { + return AstUtil.newNameRef(namespaceName.makeRef(), name); } return new JsNameRef(name); } @@ -98,22 +122,34 @@ public final class TranslationContext { } @NotNull - JsScope enclosingScope() { + public JsScope enclosingScope() { return scopes.enclosingScope; } @NotNull - JsScope namespaceScope() { + public JsScope namespaceScope() { return scopes.namespaceScope; } @NotNull - JsScope classScope() { + public JsScope classScope() { return scopes.classScope; } @NotNull - JsName declareLocalName(@NotNull String name) { + public JsName declareLocalName(@NotNull String name) { return scopes.enclosingScope.declareFreshName(name); } + + @NotNull + public JsScope getScopeForDescriptor(@NotNull DeclarationDescriptor descriptor) { + return extractor.getScope(descriptor); + } + + @NotNull + public JsScope getScopeForElement(@NotNull JetElement element) { + DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element); + assert descriptor != null : "Element should have a descriptor"; + return getScopeForDescriptor(descriptor); + } }