Work on reference expression. Test fixes to follow.

This commit is contained in:
Pavel Talanov
2011-11-30 13:22:48 +04:00
parent ba767e7205
commit f8d342c207
11 changed files with 620 additions and 644 deletions
+427 -459
View File
File diff suppressed because it is too large Load Diff
@@ -74,7 +74,9 @@ public final class DeclarationVisitor extends DeclarationDescriptorVisitor<Void,
public Void visitConstructorDescriptor(@NotNull ConstructorDescriptor descriptor,
@NotNull DeclarationContext context) {
JsName alreadyDeclaredClassName = declarations.getName(descriptor.getContainingDeclaration());
//already defined in
declarations.putName(descriptor, alreadyDeclaredClassName);
declarations.putQualifier(descriptor, context.getQualifier());
return null;
}
@@ -108,7 +110,7 @@ public final class DeclarationVisitor extends DeclarationDescriptorVisitor<Void,
@Override
public Void visitNamespaceDescriptor(@NotNull NamespaceDescriptor descriptor, @NotNull DeclarationContext context) {
DeclarationContext namespaceContext = extractNamespaceDeclaration(descriptor, context);
visitMemberDeclarations(descriptor, namespaceContext);
declareMembers(descriptor, namespaceContext);
return null;
}
@@ -129,7 +131,7 @@ public final class DeclarationVisitor extends DeclarationDescriptorVisitor<Void,
return name;
}
private void visitMemberDeclarations(@NotNull NamespaceDescriptor descriptor, @NotNull DeclarationContext context) {
private void declareMembers(@NotNull NamespaceDescriptor descriptor, @NotNull DeclarationContext context) {
for (DeclarationDescriptor memberDescriptor :
descriptor.getMemberScope().getAllDescriptors()) {
memberDescriptor.accept(this, context);
@@ -62,17 +62,29 @@ public final class Declarations {
return name;
}
public boolean isDeclared(@NotNull DeclarationDescriptor descriptor) {
public boolean hasDeclaredName(@NotNull DeclarationDescriptor descriptor) {
return descriptorToNameMap.containsKey(descriptor.getOriginal());
}
public boolean hasQualifier(@NotNull DeclarationDescriptor descriptor) {
return (descriptorToQualifierMap.get(descriptor) != null);
}
@NotNull
public JsNameRef getQualifier(@NotNull DeclarationDescriptor descriptor) {
JsNameRef qualifier = descriptorToQualifierMap.get(descriptor);
assert qualifier != null : "Cannot be null. Use hasQualifier to check.";
return qualifier;
}
/*package*/ void putScope(@NotNull DeclarationDescriptor descriptor, @NotNull JsScope scope) {
assert !descriptorToScopeMap.containsKey(descriptor) : "Already contains that key!";
descriptorToScopeMap.put(descriptor, scope);
}
//TODO: decide what to do about function overriding
/*package*/ void putName(@NotNull DeclarationDescriptor descriptor, @NotNull JsName name) {
assert !descriptorToNameMap.containsKey(descriptor) : "Already contains that key!";
// assert !descriptorToNameMap.containsKey(descriptor) : "Already contains that key!";
descriptorToNameMap.put(descriptor, name);
}
@@ -14,6 +14,7 @@ import org.jetbrains.k2js.translate.general.TranslatorVisitor;
import org.jetbrains.k2js.translate.operation.BinaryOperationTranslator;
import org.jetbrains.k2js.translate.operation.UnaryOperationTranslator;
import org.jetbrains.k2js.translate.reference.PropertyAccessTranslator;
import org.jetbrains.k2js.translate.reference.ReferenceTranslator;
import org.jetbrains.k2js.translate.utils.BindingUtils;
import java.util.List;
@@ -142,7 +143,7 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
@NotNull
public JsNode visitSimpleNameExpression(@NotNull JetSimpleNameExpression expression,
@NotNull TranslationContext context) {
return Translation.referenceTranslator(context).translateSimpleName(expression);
return ReferenceTranslator.translateSimpleName(expression, context);
}
@@ -98,7 +98,8 @@ public final class PatternTranslator extends AbstractTranslator {
(context().bindingContext(), typeReference);
//TODO should reference class by full name here
JsName className = context().getNameForDescriptor(referencedClass);
return context().getNamespaceQualifiedReference(className);
assert TranslationUtils.hasQualifier(context(), referencedClass);
return TranslationUtils.getQualifiedReference(context(), referencedClass);
}
@NotNull
@@ -18,7 +18,6 @@ import org.jetbrains.k2js.translate.expression.WhenTranslator;
import org.jetbrains.k2js.translate.initializer.ClassInitializerTranslator;
import org.jetbrains.k2js.translate.initializer.NamespaceInitializerTranslator;
import org.jetbrains.k2js.translate.reference.PropertyAccessTranslator;
import org.jetbrains.k2js.translate.reference.ReferenceTranslator;
import org.jetbrains.k2js.translate.utils.BindingUtils;
/**
@@ -57,10 +56,10 @@ public final class Translation {
return PatternTranslator.newInstance(context);
}
@NotNull
static public ReferenceTranslator referenceTranslator(@NotNull TranslationContext context) {
return ReferenceTranslator.newInstance(context);
}
// @NotNull
// static public ReferenceTranslator referenceTranslator(@NotNull TranslationContext context) {
// return ReferenceTranslator.translateSimpleName(context);
// }
@NotNull
static public JsNode translateExpression(@NotNull JetExpression expression, @NotNull TranslationContext context) {
@@ -1,13 +1,10 @@
package org.jetbrains.k2js.translate.general;
import com.google.dart.compiler.backend.js.ast.JsName;
import com.google.dart.compiler.backend.js.ast.JsNameRef;
import com.google.dart.compiler.backend.js.ast.JsProgram;
import com.google.dart.compiler.backend.js.ast.JsScope;
import com.google.dart.compiler.util.AstUtil;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
@@ -45,7 +42,7 @@ public final class TranslationContext {
Namer namer = Namer.newInstance(rootScope);
Aliaser aliaser = Aliaser.aliasesForStandardClasses
(JetStandardLibrary.getJetStandardLibrary(project), namer);
return new TranslationContext(null, program, bindingContext,
return new TranslationContext(program, bindingContext,
scopes, extractor, aliaser, namer);
}
@@ -55,8 +52,6 @@ public final class TranslationContext {
private final BindingContext bindingContext;
@NotNull
private final Scopes scopes;
@Nullable
private final JsName namespaceName;
@NotNull
private final Declarations declarations;
@NotNull
@@ -65,13 +60,12 @@ public final class TranslationContext {
private final Namer namer;
private TranslationContext(@Nullable JsName namespaceName, @NotNull JsProgram program,
private TranslationContext(@NotNull JsProgram program,
@NotNull BindingContext bindingContext, @NotNull Scopes scopes,
@NotNull Declarations declarations, @NotNull Aliaser aliaser,
@NotNull Namer namer) {
this.program = program;
this.bindingContext = bindingContext;
this.namespaceName = namespaceName;
this.scopes = scopes;
this.declarations = declarations;
this.aliaser = aliaser;
@@ -86,9 +80,8 @@ public final class TranslationContext {
@NotNull
public TranslationContext newNamespace(@NotNull NamespaceDescriptor descriptor) {
JsScope namespaceScope = declarations.getScope(descriptor);
JsName namespaceName = getNameForDescriptor(descriptor);
Scopes newScopes = new Scopes(namespaceScope, namespaceScope, namespaceScope);
return new TranslationContext(namespaceName, program, bindingContext, newScopes,
return new TranslationContext(program, bindingContext, newScopes,
declarations, aliaser, namer);
}
@@ -101,7 +94,7 @@ public final class TranslationContext {
public TranslationContext newClass(@NotNull ClassDescriptor descriptor) {
JsScope classScope = declarations.getScope(descriptor);
Scopes newScopes = new Scopes(classScope, classScope, scopes.namespaceScope);
return new TranslationContext(namespaceName, program, bindingContext,
return new TranslationContext(program, bindingContext,
newScopes, declarations, aliaser, namer);
}
@@ -124,7 +117,7 @@ public final class TranslationContext {
public TranslationContext newFunctionDeclaration(@NotNull FunctionDescriptor descriptor) {
JsScope functionScope = declarations.getScope(descriptor);
Scopes newScopes = new Scopes(functionScope, scopes.classScope, scopes.namespaceScope);
return new TranslationContext(namespaceName, program, bindingContext,
return new TranslationContext(program, bindingContext,
newScopes, declarations, aliaser, namer);
}
@@ -132,20 +125,10 @@ public final class TranslationContext {
@NotNull
public TranslationContext newEnclosingScope(@NotNull JsScope enclosingScope) {
Scopes newScopes = new Scopes(enclosingScope, scopes.classScope, scopes.namespaceScope);
return new TranslationContext(namespaceName, program, bindingContext,
return new TranslationContext(program, bindingContext,
newScopes, declarations, aliaser, namer);
}
//TODO: move to namer
@NotNull
public JsNameRef getNamespaceQualifiedReference(@NotNull JsName name) {
if (namespaceName != null) {
return AstUtil.newNameRef(namespaceName.makeRef(), name);
}
return new JsNameRef(name);
}
@NotNull
public BindingContext bindingContext() {
return bindingContext;
@@ -202,7 +185,7 @@ public final class TranslationContext {
}
public boolean isDeclared(@NotNull DeclarationDescriptor descriptor) {
return declarations.isDeclared(descriptor);
return declarations.hasDeclaredName(descriptor);
}
@NotNull
@@ -214,4 +197,9 @@ public final class TranslationContext {
public Namer namer() {
return namer;
}
@NotNull
public Declarations declarations() {
return declarations;
}
}
@@ -18,6 +18,7 @@ import org.jetbrains.k2js.translate.general.AbstractTranslator;
import org.jetbrains.k2js.translate.general.Translation;
import org.jetbrains.k2js.translate.general.TranslationContext;
import org.jetbrains.k2js.translate.utils.BindingUtils;
import org.jetbrains.k2js.translate.utils.TranslationUtils;
/**
* @author Talanov Pavel
@@ -57,6 +58,7 @@ public final class PropertyAccessTranslator extends AbstractTranslator {
return canBePropertyGetterCall(expression);
}
//TODO: delete?
public boolean canBePropertySetterCall(@NotNull JetExpression expression) {
if (expression instanceof JetQualifiedExpression) {
JetSimpleNameExpression selector = getNullableSelector((JetQualifiedExpression) expression);
@@ -91,10 +93,15 @@ public final class PropertyAccessTranslator extends AbstractTranslator {
@NotNull
private JsInvocation resolveAsPropertyGet(@NotNull JetSimpleNameExpression expression) {
JsName getterName = getNotNullGetterName(expression);
JsNameRef getterReference = ReferenceProvider.getReference(getterName, context(), expression);
JsNameRef getterReference = getAccessorReference(getterName);
return AstUtil.newInvocation(getterReference);
}
@NotNull
private JsNameRef getAccessorReference(@NotNull JsName getterName) {
return TranslationUtils.getThisQualifiedNameReference(context(), getterName);
}
@NotNull
public JsInvocation translateAsPropertySetterCall(@NotNull JetExpression expression) {
if (expression instanceof JetDotQualifiedExpression) {
@@ -115,7 +122,7 @@ public final class PropertyAccessTranslator extends AbstractTranslator {
@NotNull
private JsInvocation resolveAsPropertySet(@NotNull JetSimpleNameExpression expression) {
JsName setterName = getNotNullSetterName(expression);
JsNameRef setterReference = ReferenceProvider.getReference(setterName, context(), expression);
JsNameRef setterReference = getAccessorReference(setterName);
return AstUtil.newInvocation(setterReference);
}
@@ -1,74 +0,0 @@
package org.jetbrains.k2js.translate.reference;
import com.google.dart.compiler.backend.js.ast.JsName;
import com.google.dart.compiler.backend.js.ast.JsNameRef;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.k2js.translate.general.TranslationContext;
/**
* @author Talanov Pavel
*/
public final class ReferenceProvider {
@NotNull
private final TranslationContext context;
@NotNull
private final JsName referencedName;
private boolean isBackingFieldAccess;
private boolean requiresThisQualifier;
private boolean requiresNamespaceQualifier;
public static JsNameRef getReference(@NotNull JsName referencedName, @NotNull TranslationContext context,
boolean isBackingFieldAccess) {
return (new ReferenceProvider(referencedName, context, isBackingFieldAccess)).generateCorrectReference();
}
public static JsNameRef getReference(@NotNull JsName referencedName, @NotNull TranslationContext context,
JetSimpleNameExpression expression) {
boolean isBackingFieldAccess = expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER;
return (new ReferenceProvider(referencedName, context, isBackingFieldAccess))
.generateCorrectReference();
}
private ReferenceProvider(@NotNull JsName referencedName, @NotNull TranslationContext context,
boolean isBackingFieldAccess) {
this.context = context;
this.referencedName = referencedName;
this.isBackingFieldAccess = isBackingFieldAccess;
this.requiresThisQualifier = requiresThisQualifier();
this.requiresNamespaceQualifier = requiresNamespaceQualifier();
}
@NotNull
public JsNameRef generateCorrectReference() {
if (requiresNamespaceQualifier) {
return context.getNamespaceQualifiedReference(referencedName);
} else if (requiresThisQualifier) {
return thisQualifiedReference();
}
return referencedName.makeRef();
}
private JsNameRef thisQualifiedReference() {
if (!context.aliaser().hasAliasForThis()) {
return AstUtil.thisQualifiedReference(referencedName);
}
JsNameRef reference = referencedName.makeRef();
AstUtil.setQualifier(reference, context.aliaser().getAliasForThis());
return reference;
}
private boolean requiresNamespaceQualifier() {
return context.namespaceScope().ownsName(referencedName);
}
private boolean requiresThisQualifier() {
JsName name = context.enclosingScope().findExistingName(referencedName.getIdent());
boolean isClassMember = context.classScope().ownsName(name);
return isClassMember || isBackingFieldAccess;
}
}
@@ -1,13 +1,12 @@
package org.jetbrains.k2js.translate.reference;
import com.google.dart.compiler.backend.js.ast.JsExpression;
import com.google.dart.compiler.backend.js.ast.JsInvocation;
import com.google.dart.compiler.backend.js.ast.JsName;
import com.google.dart.compiler.backend.js.ast.JsNameRef;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.k2js.translate.general.AbstractTranslator;
import org.jetbrains.k2js.translate.general.Translation;
import org.jetbrains.k2js.translate.general.TranslationContext;
@@ -17,84 +16,119 @@ import org.jetbrains.k2js.translate.utils.TranslationUtils;
/**
* @author Talanov Pavel
*/
//TODO: implement state
public class ReferenceTranslator extends AbstractTranslator {
@NotNull
static public ReferenceTranslator newInstance(@NotNull TranslationContext context) {
return new ReferenceTranslator(context);
}
private final JetSimpleNameExpression simpleName;
private ReferenceTranslator(@NotNull TranslationContext context) {
super(context);
}
@Nullable
private JsExpression result;
// TODO: refactor put the checks inside resolvers
@NotNull
public JsExpression translateSimpleName(@NotNull JetSimpleNameExpression expression) {
JsExpression result = resolveAsAliasReference(expression);
if (result != null) return result;
result = resolveAsPropertyAccess(expression);
if (result != null) return result;
result = resolveAsGlobalReference(expression);
if (result != null) return result;
result = resolveAsLocalReference(expression);
if (result != null) return result;
throw new AssertionError("Undefined name in this scope: " + expression.getReferencedName());
public static JsExpression translateSimpleName(@NotNull JetSimpleNameExpression expression,
@NotNull TranslationContext context) {
return (new ReferenceTranslator(expression, context)).translateSimpleName();
}
@Nullable
private JsNameRef resolveAsAliasReference(@NotNull JetSimpleNameExpression expression) {
//TODO: decide if this code is meaningful
private ReferenceTranslator(@NotNull JetSimpleNameExpression expression, @NotNull TranslationContext context) {
super(context);
this.simpleName = expression;
this.result = null;
}
@NotNull
public JsExpression translateSimpleName() {
tryResolveAsThisQualifiedExpression();
tryResolveAsAliasReference();
tryResolveAsPropertyAccess();
tryResolveAsGlobalReference();
tryResolveAsLocalReference();
if (result != null) {
return result;
}
throw new AssertionError("Undefined name in this scope: " + simpleName.getReferencedName());
}
private void tryResolveAsThisQualifiedExpression() {
if (alreadyResolved()) return;
DeclarationDescriptor referencedDescriptor =
BindingUtils.getDescriptorForReferenceExpression(context().bindingContext(), expression);
if (referencedDescriptor == null) return null;
BindingUtils.getDescriptorForReferenceExpression(context().bindingContext(), simpleName);
if (!context().aliaser().hasAliasForDeclaration(referencedDescriptor)) {
return null;
}
if (referencedDescriptor == null) return;
if (!context().isDeclared(referencedDescriptor)) return;
return context().aliaser().getAliasForDeclaration(referencedDescriptor);
}
@Nullable
private JsInvocation resolveAsPropertyAccess(@NotNull JetSimpleNameExpression expression) {
PropertyAccessTranslator propertyAccessTranslator = Translation.propertyAccessTranslator(context());
if (propertyAccessTranslator.canBePropertyGetterCall(expression)) {
return propertyAccessTranslator.translateAsPropertyGetterCall(expression);
}
return null;
}
@Nullable
private JsExpression resolveAsGlobalReference(@NotNull JetSimpleNameExpression expression) {
DeclarationDescriptor referencedDescriptor =
BindingUtils.getDescriptorForReferenceExpression(context().bindingContext(), expression);
if (referencedDescriptor == null) {
return null;
}
//TODO: think about the places where we should check for original descriptors
if (!context().isDeclared(referencedDescriptor)) {
return null;
}
JsName referencedName = context().getNameForDescriptor(referencedDescriptor);
return ReferenceProvider.getReference(referencedName, context(), expression);
if (!requiresThisQualifier(simpleName, referencedName)) return;
result = TranslationUtils.getThisQualifiedNameReference(context(), referencedName);
}
@Nullable
private JsExpression resolveAsLocalReference(@NotNull JetSimpleNameExpression expression) {
String name = expression.getReferencedName();
private boolean requiresThisQualifier(@NotNull JetSimpleNameExpression expression,
@NotNull JsName referencedName) {
JsName name = context().enclosingScope().findExistingName(referencedName.getIdent());
boolean isClassMember = context().classScope().ownsName(name);
boolean isBackingFieldAccess = expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER;
return (isBackingFieldAccess || isClassMember);
}
private void tryResolveAsAliasReference() {
//TODO: decide if this code is meaningful
if (alreadyResolved()) return;
DeclarationDescriptor referencedDescriptor =
BindingUtils.getDescriptorForReferenceExpression(context().bindingContext(), simpleName);
if (referencedDescriptor == null) return;
if (!context().aliaser().hasAliasForDeclaration(referencedDescriptor)) return;
result = context().aliaser().getAliasForDeclaration(referencedDescriptor);
}
private boolean alreadyResolved() {
return result != null;
}
private void tryResolveAsPropertyAccess() {
if (alreadyResolved()) return;
PropertyAccessTranslator propertyAccessTranslator = Translation.propertyAccessTranslator(context());
if (!propertyAccessTranslator.canBePropertyGetterCall(simpleName)) return;
result = propertyAccessTranslator.translateAsPropertyGetterCall(simpleName);
}
private void tryResolveAsGlobalReference() {
if (alreadyResolved()) return;
DeclarationDescriptor referencedDescriptor =
BindingUtils.getDescriptorForReferenceExpression(context().bindingContext(), simpleName);
if (referencedDescriptor == null) return;
if (!context().isDeclared(referencedDescriptor)) return;
result = TranslationUtils.getQualifiedReference(context(), referencedDescriptor);
}
private void tryResolveAsLocalReference() {
if (alreadyResolved()) return;
String name = getReferencedName();
JsName localReferencedName = TranslationUtils.getLocalReferencedName(context(), name);
if (localReferencedName == null) return;
result = localReferencedName.makeRef();
}
@NotNull
private String getReferencedName() {
String name = simpleName.getReferencedName();
assert name != null : "SimpleNameExpression should reference a name";
JsName localReferencedName = TranslationUtils.getLocalReferencedName
(context(), name);
if (localReferencedName == null) {
return null;
}
return localReferencedName.makeRef();
return name;
}
}
@@ -6,6 +6,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
import org.jetbrains.jet.lang.psi.JetCallExpression;
import org.jetbrains.jet.lang.psi.JetExpression;
@@ -14,7 +15,6 @@ import org.jetbrains.jet.lang.psi.ValueArgument;
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
import org.jetbrains.k2js.translate.general.Translation;
import org.jetbrains.k2js.translate.general.TranslationContext;
import org.jetbrains.k2js.translate.reference.ReferenceProvider;
import java.util.ArrayList;
import java.util.List;
@@ -68,20 +68,14 @@ public final class TranslationUtils {
static public JsNameRef backingFieldReference(@NotNull TranslationContext context,
@NotNull JetProperty expression) {
JsName backingFieldName = getBackingFieldName(getPropertyName(expression), context);
return generateReference(context, backingFieldName);
return getThisQualifiedNameReference(context, backingFieldName);
}
@NotNull
static public JsNameRef backingFieldReference(@NotNull TranslationContext context,
@NotNull PropertyDescriptor descriptor) {
JsName backingFieldName = getBackingFieldName(descriptor.getName(), context);
return generateReference(context, backingFieldName);
}
@NotNull
private static JsNameRef generateReference(@NotNull TranslationContext context,
@NotNull JsName backingFieldName) {
return ReferenceProvider.getReference(backingFieldName, context, true);
return getThisQualifiedNameReference(context, backingFieldName);
}
@NotNull
@@ -130,4 +124,48 @@ public final class TranslationUtils {
JsNameRef backingFieldReference = backingFieldReference(context, descriptor);
return AstUtil.newAssignmentStatement(backingFieldReference, parameter.getName().makeRef());
}
public static boolean hasQualifier(@NotNull TranslationContext context, @NotNull DeclarationDescriptor descriptor) {
return context.declarations().hasQualifier(descriptor);
}
@NotNull
public static JsNameRef getQualifiedReference(@NotNull TranslationContext context,
@NotNull DeclarationDescriptor descriptor) {
JsName name = context.declarations().getName(descriptor);
JsNameRef reference = name.makeRef();
if (hasQualifier(context, descriptor)) {
JsNameRef qualifier = getQualifier(context, descriptor);
AstUtil.setQualifier(reference, qualifier);
}
return reference;
}
@NotNull
private static JsNameRef getQualifier(@NotNull TranslationContext context,
@NotNull DeclarationDescriptor descriptor) {
return context.declarations().getQualifier(descriptor);
}
@NotNull
public static JsNameRef getThisQualifiedNameReference(@NotNull TranslationContext context,
@NotNull JsName name) {
JsExpression qualifier = getThisQualifier(context);
JsNameRef reference = name.makeRef();
AstUtil.setQualifier(reference, qualifier);
return reference;
}
@NotNull
private static JsExpression getThisQualifier(@NotNull TranslationContext context) {
JsExpression qualifier;
if (context.aliaser().hasAliasForThis()) {
qualifier = context.aliaser().getAliasForThis();
} else {
qualifier = new JsThisRef();
}
return qualifier;
}
}