Help at rigth part

This commit is contained in:
Natalia.Ukhorskaya
2011-11-23 14:55:42 +04:00
parent cc52c0f1c1
commit dca537ce70
95 changed files with 2760 additions and 812 deletions
+611 -356
View File
File diff suppressed because it is too large Load Diff
@@ -268,4 +268,17 @@ public class AstUtil {
result.setStatements(statements);
return result;
}
public static JsPrefixOperation negated(JsExpression expression) {
return new JsPrefixOperation(JsUnaryOperator.NOT, expression);
}
public static JsStatement newAssignmentStatement(JsNameRef nameRef, JsExpression expr) {
return convertToStatement(new JsBinaryOperation(JsBinaryOperator.ASG, nameRef, expr));
}
public static JsExpression extractExpressionFromStatement(JsStatement statement) {
assert statement instanceof JsExprStmt : "Cannot extract exprssion form statement: " + statement;
return (((JsExprStmt) statement).getExpression());
}
}
@@ -11,19 +11,22 @@ import java.util.Map;
/**
* @author Talanov Pavel
*/
public final class DeclarationExtractor {
public final class Declarations {
private final Map<DeclarationDescriptor, JsScope> descriptorToScopeMap
= new HashMap<DeclarationDescriptor, JsScope>();
private final Map<DeclarationDescriptor, JsName> descriptorToNameMap
= new HashMap<DeclarationDescriptor, JsName>();
public DeclarationExtractor() {
private Declarations() {
}
public void extractDeclarations(@NotNull DeclarationDescriptor descriptor, JsScope rootScope) {
ExtractionVisitor visitor = new ExtractionVisitor(this);
@NotNull
static public Declarations extractDeclarations(@NotNull DeclarationDescriptor descriptor, JsScope rootScope) {
Declarations declarations = new Declarations();
ExtractionVisitor visitor = new ExtractionVisitor(declarations);
descriptor.accept(visitor, rootScope);
return declarations;
}
@NotNull
@@ -40,6 +43,10 @@ public final class DeclarationExtractor {
return name;
}
public boolean isDeclared(@NotNull DeclarationDescriptor descriptor) {
return descriptorToNameMap.containsKey(descriptor);
}
/*package*/ void putScope(@NotNull DeclarationDescriptor descriptor, @NotNull JsScope scope) {
descriptorToScopeMap.put(descriptor, scope);
}
@@ -13,32 +13,58 @@ import org.jetbrains.k2js.translate.Namer;
public final class ExtractionVisitor extends DeclarationDescriptorVisitor<Void, JsScope> {
@NotNull
private final DeclarationExtractor extractor;
private final Declarations declarations;
/*package*/ ExtractionVisitor(@NotNull DeclarationExtractor extractor) {
this.extractor = extractor;
/*package*/ ExtractionVisitor(@NotNull Declarations declarations) {
this.declarations = declarations;
}
@Override
public Void visitClassDescriptor(@NotNull ClassDescriptor descriptor, @NotNull JsScope enclosingScope) {
JsScope classScope = extractClassDeclarations(descriptor, enclosingScope);
visitClassMembers(descriptor, classScope);
return null;
}
@NotNull
private JsScope extractClassDeclarations(@NotNull ClassDescriptor descriptor, @NotNull JsScope enclosingScope) {
String className = descriptor.getName();
extractor.putName(descriptor, enclosingScope.declareName(className));
declarations.putName(descriptor, enclosingScope.declareName(className));
JsScope classScope = new JsScope(enclosingScope, "class " + className);
extractor.putScope(descriptor, classScope);
declarations.putScope(descriptor, classScope);
return classScope;
}
private void visitClassMembers(@NotNull ClassDescriptor descriptor, @NotNull JsScope classScope) {
visitClassConstructor(descriptor, classScope);
for (DeclarationDescriptor memberDescriptor :
descriptor.getDefaultType().getMemberScope().getAllDescriptors()) {
memberDescriptor.accept(this, classScope);
}
}
private void visitClassConstructor(@NotNull ClassDescriptor descriptor, @NotNull JsScope classScope) {
for (ConstructorDescriptor constructorDescriptor : descriptor.getConstructors()) {
constructorDescriptor.accept(this, classScope);
}
}
//TODO: think about the ways to make this less hacky
//For now constructor just references the name of the class. Initialize method scope is defined independently.
@Override
public Void visitConstructorDescriptor(@NotNull ConstructorDescriptor descriptor, @NotNull JsScope enclosingScope) {
String className = descriptor.getContainingDeclaration().getName();
JsName alreadyDeclaredClassName = enclosingScope.findExistingName(className);
declarations.putName(descriptor, alreadyDeclaredClassName);
return null;
}
@Override
public Void visitFunctionDescriptor(@NotNull FunctionDescriptor descriptor, @NotNull JsScope enclosingScope) {
String functionName = descriptor.getName();
extractor.putName(descriptor, enclosingScope.declareName(functionName));
declarations.putName(descriptor, enclosingScope.declareName(functionName));
JsScope functionScope = new JsScope(enclosingScope, "function " + functionName);
extractor.putScope(descriptor, functionScope);
declarations.putScope(descriptor, functionScope);
return null;
}
@@ -59,23 +85,35 @@ public final class ExtractionVisitor extends DeclarationDescriptorVisitor<Void,
String accessorName = Namer.getNameForAccessor(propertyName, isGetter);
JsName jsName = enclosingScope.declareName(accessorName);
JsScope accessorScope = new JsScope(enclosingScope, (isGetter ? "getter " : "setter ") + propertyName);
extractor.putScope(descriptor, accessorScope);
extractor.putName(descriptor, jsName);
// Note : We do not put backing field name into extractor because it can't be referenced from outside
declarations.putScope(descriptor, accessorScope);
declarations.putName(descriptor, jsName);
// Note : We do not put backing field name into declarations because it can't be referenced from outside
//TODO: find if there is repetetive code like descriptor.getCorrespondingProperty().getName())
accessorScope.declareName(Namer.getKotlinBackingFieldName(descriptor.getCorrespondingProperty().getName()));
}
@Override
public Void visitNamespaceDescriptor(NamespaceDescriptor descriptor, JsScope enclosingScope) {
JsScope namespaceScope = extractNamespaceDeclaration(descriptor, enclosingScope);
visitMemberDeclarations(descriptor, namespaceScope);
return null;
}
@NotNull
private JsScope extractNamespaceDeclaration(@NotNull NamespaceDescriptor descriptor,
@NotNull JsScope enclosingScope) {
String namespaceName = descriptor.getName();
extractor.putName(descriptor, enclosingScope.declareName(namespaceName));
declarations.putName(descriptor, enclosingScope.declareName(namespaceName));
JsScope namespaceScope = new JsScope(enclosingScope, "namespace " + namespaceName);
extractor.putScope(descriptor, namespaceScope);
declarations.putScope(descriptor, namespaceScope);
return namespaceScope;
}
private void visitMemberDeclarations(@NotNull NamespaceDescriptor descriptor, @NotNull JsScope namespaceScope) {
for (DeclarationDescriptor memberDescriptor :
descriptor.getMemberScope().getAllDescriptors()) {
memberDescriptor.accept(this, namespaceScope);
}
return null;
}
}
@@ -1,9 +1,7 @@
package org.jetbrains.k2js.translate;
import com.google.dart.compiler.backend.js.ast.JsProgram;
import com.google.dart.compiler.backend.js.ast.JsScope;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.resolve.BindingContext;
/**
* @author Talanov Pavel
@@ -13,7 +11,7 @@ public abstract class AbstractTranslator {
@NotNull
private final TranslationContext context;
public AbstractTranslator(@NotNull TranslationContext context) {
protected AbstractTranslator(@NotNull TranslationContext context) {
this.context = context;
}
@@ -26,14 +24,4 @@ public abstract class AbstractTranslator {
protected TranslationContext translationContext() {
return context;
}
@NotNull
protected BindingContext bindingContext() {
return context.bindingContext();
}
@NotNull
protected JsScope scope() {
return context.enclosingScope();
}
}
@@ -61,13 +61,6 @@ public final class BindingUtils {
return getDescriptorForExpression(context, declaration, PropertyDescriptor.class);
}
@NotNull
static public String getPropertyNameForPropertyAccessor(@NotNull BindingContext context,
@NotNull JetPropertyAccessor accessor) {
PropertyAccessorDescriptor descriptor = getPropertyAccessorDescriptor(context, accessor);
return descriptor.getCorrespondingProperty().getName();
}
@NotNull
static public PropertySetterDescriptor getPropertySetterDescriptorForProperty(@NotNull BindingContext context,
@NotNull JetProperty property) {
@@ -91,17 +84,23 @@ public final class BindingUtils {
Collection<? extends JetType> superclassTypes = classDescriptor.getTypeConstructor().getSupertypes();
List<ClassDescriptor> superClassDescriptors = new ArrayList<ClassDescriptor>();
for (JetType type : superclassTypes) {
DeclarationDescriptor superClassDescriptor =
type.getConstructor().getDeclarationDescriptor();
assert superClassDescriptor instanceof ClassDescriptor
: "Superclass descriptor of a type should be of type ClassDescriptor";
if (isNotAny(superClassDescriptor)) {
superClassDescriptors.add((ClassDescriptor) superClassDescriptor);
ClassDescriptor result = getClassDescriptorForType(type);
if (isNotAny(result)) {
superClassDescriptors.add(result);
}
}
return superClassDescriptors;
}
@NotNull
static public ClassDescriptor getClassDescriptorForType(@NotNull JetType type) {
DeclarationDescriptor superClassDescriptor =
type.getConstructor().getDeclarationDescriptor();
assert superClassDescriptor instanceof ClassDescriptor
: "Superclass descriptor of a type should be of type ClassDescriptor";
return (ClassDescriptor) superClassDescriptor;
}
static public boolean hasAncestorClass(@NotNull BindingContext context, @NotNull JetClass classDeclaration) {
List<ClassDescriptor> superclassDescriptors = getSuperclassDescriptors(context, classDeclaration);
return (findAncestorClass(superclassDescriptors) != null);
@@ -113,8 +112,28 @@ public final class BindingUtils {
return isStatement;
}
@NotNull
static public JetType getTypeByReference(@NotNull BindingContext context,
@NotNull JetTypeReference typeReference) {
JetType result = context.get(BindingContext.TYPE, typeReference);
assert result != null : "TypeReference should reference a type";
return result;
}
@NotNull
static public ClassDescriptor getClassDescriptorForTypeReference(@NotNull BindingContext context,
@NotNull JetTypeReference typeReference) {
return getClassDescriptorForType(getTypeByReference(context, typeReference));
}
@Nullable
static public DeclarationDescriptor getDescriptorForReferenceExpression(@NotNull BindingContext context,
@NotNull JetReferenceExpression reference) {
return context.get(BindingContext.REFERENCE_TARGET, reference);
}
//TODO better implementation?
private static boolean isNotAny(@NotNull DeclarationDescriptor superClassDescriptor) {
static private boolean isNotAny(@NotNull DeclarationDescriptor superClassDescriptor) {
return !superClassDescriptor.getName().equals("Any");
}
@@ -153,22 +153,4 @@ public final class ClassBodyVisitor extends TranslatorVisitor<List<JsPropertyIni
// parsed it in initializer visitor => no additional actions are needed
return new ArrayList<JsPropertyInitializer>();
}
// @NotNull
// JsName getNameForGetter(@NotNull String propertyName, @NotNull TranslationContext context) {
// return getNameForAccessor(propertyName, true, context);
// }
//
// @NotNull
// JsName getNameForSetter(@NotNull String propertyName, @NotNull TranslationContext context) {
// return getNameForAccessor(propertyName, false, context);
// }
//
// @NotNull
// JsName getNameForAccessor(@NotNull String propertyName, boolean isGetter,
// @NotNull TranslationContext context) {
// return context.classScope().findExistingName(Namer.getNameForAccessor(propertyName, isGetter));
// }
}
@@ -31,41 +31,27 @@ public final class ClassTranslator extends AbstractTranslator {
}
@NotNull
public JsStatement translateClass(@NotNull JetClass classDeclaration) {
if (!classDeclaration.isTrait()) {
return translateAsClassWithState(classDeclaration);
} else {
return translateAsStatelessTrait(classDeclaration);
}
}
@NotNull
private JsStatement translateAsStatelessTrait(@NotNull JetClass classDeclaration) {
JsObjectLiteral traitLiteral = translateClassDeclarations(classDeclaration);
return AstUtil.convertToStatement
(AstUtil.newAssignment(namespaceQualifiedClassNameReference(classDeclaration), traitLiteral));
}
@NotNull
private JsStatement translateAsClassWithState(@NotNull JetClass jetClassDeclaration) {
JsInvocation jsClassDeclaration = createMethodInvocation();
public JsStatement translateClass(@NotNull JetClass jetClassDeclaration) {
JsInvocation jsClassDeclaration = classCreateMethodInvocation(jetClassDeclaration);
addSuperclassReferences(jetClassDeclaration, jsClassDeclaration);
addClassOwnDeclarations(jetClassDeclaration, jsClassDeclaration);
return classDeclarationStatement(jetClassDeclaration, jsClassDeclaration);
}
@NotNull
private JsInvocation createMethodInvocation() {
JsInvocation jsClassDeclaration = new JsInvocation();
jsClassDeclaration.setQualifier(Namer.creationMethodReference());
return jsClassDeclaration;
private JsInvocation classCreateMethodInvocation(@NotNull JetClass jetClassDeclaration) {
if (jetClassDeclaration.isTrait()) {
return AstUtil.newInvocation(Namer.traitCreationMethodReference());
} else {
return AstUtil.newInvocation(Namer.classCreationMethodReference());
}
}
@NotNull
private JsStatement classDeclarationStatement(@NotNull JetClass classDeclaration,
@NotNull JsInvocation jsClassDeclaration) {
return AstUtil.convertToStatement(AstUtil.newAssignment
(namespaceQualifiedClassNameReference(classDeclaration), jsClassDeclaration));
return AstUtil.newAssignmentStatement
(namespaceQualifiedClassNameReference(classDeclaration), jsClassDeclaration);
}
@NotNull
@@ -11,7 +11,6 @@ import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.constants.NullValue;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.List;
@@ -61,7 +60,7 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
@NotNull TranslationContext context) {
JetExpression returnedExpression = jetReturnExpression.getReturnedExpression();
if (returnedExpression != null) {
JsExpression jsExpression = AstUtil.convertToExpression(returnedExpression.accept(this, context));
JsExpression jsExpression = translateAsExpression(returnedExpression, context);
return new JsReturn(jsExpression);
}
return new JsReturn();
@@ -85,52 +84,6 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
return Translation.operationTranslator(context).translate(expression);
}
//TODO support other cases
@Override
@NotNull
public JsNode visitSimpleNameExpression(@NotNull JetSimpleNameExpression expression,
@NotNull TranslationContext context) {
//TODO: this is only a hack for now
// Problem is that namespace properties do not generate getters and setter actually so they must be referenced
// by name
JsName referencedName = getReferencedName(expression, context);
if (referencedName != null) {
if (requiresNamespaceQualifier(context, referencedName)) {
return context.getNamespaceQualifiedReference(referencedName);
}
JsNameRef nameRef = referencedName.makeRef();
if (requiresThisQualifier(expression, context)) {
nameRef.setQualifier(new JsThisRef());
}
return nameRef;
}
JsInvocation getterCall = Translation.propertyAccessTranslator(context).resolveAsPropertyGet(expression);
if (getterCall != null) {
return getterCall;
}
throw new AssertionError("Undefined name in this scope: " + expression.getReferencedName());
}
private boolean requiresNamespaceQualifier(TranslationContext context, JsName referencedName) {
return context.namespaceScope().ownsName(referencedName);
}
private boolean requiresThisQualifier(@NotNull JetSimpleNameExpression expression,
@NotNull TranslationContext context) {
boolean isClassMember = context.classScope().ownsName(getReferencedName(expression, context));
boolean isBackingFieldAccess = expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER;
return isClassMember || isBackingFieldAccess;
}
@Nullable
private JsName getReferencedName(@NotNull JetSimpleNameExpression expression, @NotNull TranslationContext context) {
String referencedName = expression.getReferencedName();
return context.enclosingScope().findExistingName(referencedName);
}
@Override
@NotNull
// assume it is a local variable declaration
@@ -143,7 +96,7 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
@Override
@NotNull
public JsNode visitCallExpression(JetCallExpression expression, TranslationContext context) {
JsExpression callee = getCallee(expression, context);
JsExpression callee = translateCallee(expression, context);
List<JsExpression> arguments = translateArgumentList(expression.getValueArguments(), context);
if (isConstructorInvocation(expression, context)) {
JsNew constructorCall = new JsNew(callee);
@@ -165,13 +118,12 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
}
@NotNull
private JsExpression getCallee(@NotNull JetCallExpression expression, @NotNull TranslationContext context) {
JetExpression jetCallee = expression.getCalleeExpression();
if (jetCallee == null) {
private JsExpression translateCallee(@NotNull JetCallExpression expression, @NotNull TranslationContext context) {
JetExpression callee = expression.getCalleeExpression();
if (callee == null) {
throw new AssertionError("Call expression with no callee encountered!");
}
JsNode jsCallee = jetCallee.accept(this, context);
return AstUtil.convertToExpression(jsCallee);
return translateAsExpression(callee, context);
}
@Override
@@ -183,9 +135,16 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
} else {
return translateAsConditionalExpression(expression, context);
}
}
@Override
@NotNull
public JsNode visitSimpleNameExpression(@NotNull JetSimpleNameExpression expression,
@NotNull TranslationContext context) {
return Translation.referenceTranslator(context).translateSimpleName(expression);
}
@NotNull
private JsIf translateAsIfStatement(@NotNull JetIfExpression expression,
@NotNull TranslationContext context) {
@@ -227,9 +186,9 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
@NotNull
private JsExpression translateConditionExpression(@Nullable JetExpression expression,
@NotNull TranslationContext context) {
JsNode jsCondition = translateNullableExpression(expression, context);
if (jsCondition == context.program().getEmptyStmt()) {
throw new AssertionError("Empty condition clause!");
JsExpression jsCondition = translateNullableExpression(expression, context);
if (jsCondition == null) {
throw new AssertionError("Empty condition!");
}
return AstUtil.convertToExpression(jsCondition);
}
@@ -240,6 +199,10 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
if (expression == null) {
return null;
}
return translateAsExpression(expression, context);
}
private JsExpression translateAsExpression(JetExpression expression, TranslationContext context) {
return AstUtil.convertToExpression(expression.accept(this, context));
}
@@ -286,31 +249,34 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
return null;
}
//TODO method too long
@Override
@NotNull
public JsNode visitDotQualifiedExpression(@NotNull JetDotQualifiedExpression expression,
@NotNull TranslationContext context) {
return translateQualifiedExpression(expression, context);
}
@NotNull
private JsExpression translateQualifiedExpression(@NotNull JetQualifiedExpression expression,
@NotNull TranslationContext context) {
JsInvocation getterCall = translateAsGetterCall(expression, context);
if (getterCall != null) {
return getterCall;
}
return translateAsQualifiedExpression(expression, context);
return translateAsQualifiedAccess(expression, context);
}
@Nullable
private JsInvocation translateAsGetterCall(@NotNull JetDotQualifiedExpression expression,
private JsInvocation translateAsGetterCall(@NotNull JetQualifiedExpression expression,
@NotNull TranslationContext context) {
return Translation.propertyAccessTranslator(context).resolveAsPropertyGet(expression);
}
@NotNull
private JsNode translateAsQualifiedExpression(@NotNull JetDotQualifiedExpression expression,
@NotNull TranslationContext context) {
JsExpression receiver = AstUtil.convertToExpression(expression.getReceiverExpression().accept(this, context));
JetExpression jetSelector = expression.getSelectorExpression();
assert jetSelector != null : "Selector should not be null in dot qualified expression.";
JsExpression selector = AstUtil.convertToExpression(jetSelector.accept(this, context));
private JsExpression translateAsQualifiedAccess(@NotNull JetQualifiedExpression expression,
@NotNull TranslationContext context) {
JsExpression receiver = translateReceiver(expression, context);
JsExpression selector = translateSelector(expression, context);
assert (selector instanceof JsNameRef || selector instanceof JsInvocation)
: "Selector should be a name reference or a method invocation in dot qualified expression.";
if (selector instanceof JsInvocation) {
@@ -321,13 +287,27 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
}
@NotNull
private JsNode translateAsQualifiedNameReference(@NotNull JsExpression receiver, @NotNull JsNameRef selector) {
private JsExpression translateSelector(@NotNull JetQualifiedExpression expression,
@NotNull TranslationContext context) {
JetExpression jetSelector = expression.getSelectorExpression();
assert jetSelector != null : "Selector should not be null in dot qualified expression.";
return translateAsExpression(jetSelector, context);
}
@NotNull
private JsExpression translateReceiver(@NotNull JetQualifiedExpression expression,
@NotNull TranslationContext context) {
return translateAsExpression(expression.getReceiverExpression(), context);
}
@NotNull
private JsExpression translateAsQualifiedNameReference(@NotNull JsExpression receiver, @NotNull JsNameRef selector) {
selector.setQualifier(receiver);
return selector;
}
@NotNull
private JsNode translateAsQualifiedInvocation(@NotNull JsExpression receiver, @NotNull JsInvocation selector) {
private JsExpression translateAsQualifiedInvocation(@NotNull JsExpression receiver, @NotNull JsInvocation selector) {
JsExpression qualifier = selector.getQualifier();
JsNameRef nameRef = (JsNameRef) qualifier;
nameRef.setQualifier(receiver);
@@ -347,7 +327,62 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
public JsNode visitPostfixExpression(@NotNull JetPostfixExpression expression,
@NotNull TranslationContext context) {
return Translation.operationTranslator(context).translatePostfixOperation(expression);
}
@Override
@NotNull
public JsNode visitIsExpression(@NotNull JetIsExpression expression,
@NotNull TranslationContext context) {
return Translation.patternTranslator(context).translateIsExpression(expression);
}
@Override
@NotNull
public JsNode visitSafeQualifiedExpression(@NotNull JetSafeQualifiedExpression expression,
@NotNull TranslationContext context) {
JsExpression receiver = translateReceiver(expression, context);
JsNullLiteral nullLiteral = context.program().getNullLiteral();
JsBinaryOperation nullCheck = new JsBinaryOperation
(JsBinaryOperator.NEQ, receiver, nullLiteral);
JsExpression thenExpression = translateQualifiedExpression(expression, context);
return new JsConditional(nullCheck, thenExpression, nullLiteral);
}
@Override
@NotNull
public JsNode visitWhenExpression(@NotNull JetWhenExpression expression,
@NotNull TranslationContext context) {
return Translation.translateWhenExpression(expression, context);
}
@Override
@NotNull
public JsNode visitBinaryWithTypeRHSExpression(@NotNull JetBinaryExpressionWithTypeRHS expression,
@NotNull TranslationContext context) {
// we actually do not care for types in js
return Translation.translateExpression(expression.getLeft(), context);
}
@Override
@NotNull
public JsNode visitBreakExpression(@NotNull JetBreakExpression expression,
@NotNull TranslationContext context) {
return new JsBreak();
}
@Override
@NotNull
public JsNode visitContinueExpression(@NotNull JetContinueExpression expression,
@NotNull TranslationContext context) {
return new JsContinue();
}
@Override
@NotNull
public JsNode visitFunctionLiteralExpression(@NotNull JetFunctionLiteralExpression expression,
@NotNull TranslationContext context) {
return Translation.functionTranslator(context).translateAsLiteral(expression.getFunctionLiteral());
}
@@ -2,10 +2,8 @@ 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.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetNamedFunction;
import org.jetbrains.jet.lang.psi.JetParameter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.*;
import java.util.ArrayList;
import java.util.List;
@@ -25,42 +23,87 @@ public final class FunctionTranslator extends AbstractTranslator {
}
@NotNull
public JsStatement translateAsFunction(@NotNull JetNamedFunction jetFunction) {
JsName functionName = translationContext().namespaceScope().declareFreshName(jetFunction.getName());
JsFunction function = generateFunctionObject(jetFunction);
return AstUtil.convertToStatement(AstUtil.newAssignment
(translationContext().getNamespaceQualifiedReference(functionName), function));
public JsStatement translateAsFunctionDeclaration(@NotNull JetNamedFunction expression) {
JsName functionName = translationContext().getNameForElement(expression);
JsFunction function = generateFunctionObject(expression);
return AstUtil.newAssignmentStatement
(translationContext().getNamespaceQualifiedReference(functionName), function);
}
@NotNull
JsPropertyInitializer translateAsMethod(@NotNull JetNamedFunction jetFunction) {
JsName functionName = translationContext().namespaceScope().declareFreshName(jetFunction.getName());
JsFunction function = generateFunctionObject(jetFunction);
JsPropertyInitializer translateAsMethod(@NotNull JetNamedFunction expression) {
JsName functionName = translationContext().getNameForElement(expression);
JsFunction function = generateFunctionObject(expression);
return new JsPropertyInitializer(functionName.makeRef(), function);
}
@NotNull
private JsFunction generateFunctionObject(@NotNull JetNamedFunction jetFunction) {
JsFunction result = JsFunction.getAnonymousFunctionWithScope
(translationContext().getScopeForElement(jetFunction));
List<JsParameter> jsParameters = translateParameters(jetFunction.getValueParameters(), result.getScope());
JsNode jsBody = translateBody(jetFunction);
result.setParameters(jsParameters);
result.setBody(AstUtil.convertToBlock(jsBody));
return result;
JsFunction translateAsLiteral(@NotNull JetFunctionLiteral expression) {
return generateFunctionObject(expression);
}
@NotNull
private JsNode translateBody(@NotNull JetNamedFunction jetFunction) {
JetExpression jetBodyExpression = jetFunction.getBodyExpression();
//TODO support them ffs
assert jetBodyExpression != null : "Function without body not supported at the moment";
JsNode body = Translation.expressionTranslator
(translationContext().newFunction(jetFunction)).translate(jetBodyExpression);
if (jetFunction.hasBlockBody()) {
private JsFunction generateFunctionObject(@NotNull JetFunction jetFunction) {
JsFunction result = createFunctionObject(jetFunction);
result.setParameters(translateParameters(jetFunction.getValueParameters(), result.getScope()));
result.setBody(translateBody(jetFunction, result.getScope()));
return result;
}
private JsFunction createFunctionObject(JetFunction function) {
if (function instanceof JetNamedFunction) {
return JsFunction.getAnonymousFunctionWithScope
(translationContext().getScopeForElement(function));
}
if (function instanceof JetFunctionLiteral) {
return new JsFunction(translationContext().enclosingScope());
}
throw new AssertionError("Unsupported type of function.");
}
@NotNull
private JsBlock translateBody(@NotNull JetFunction function, @NotNull JsScope functionScope) {
JetExpression jetBodyExpression = function.getBodyExpression();
//TODO decide if there are cases where this assert is illegal
assert jetBodyExpression != null : "Function without body not supported";
JsNode body = Translation.translateExpression(jetBodyExpression, functionBodyContext(function, functionScope));
return wrapWithReturnIfNeeded(body, !function.hasBlockBody());
}
@NotNull
private JsBlock wrapWithReturnIfNeeded(@NotNull JsNode body, boolean needsReturn) {
if (!needsReturn) {
return AstUtil.convertToBlock(body);
}
return AstUtil.convertToBlock(new JsReturn(AstUtil.convertToExpression((body))));
if (body instanceof JsExpression) {
return AstUtil.convertToBlock(new JsReturn(AstUtil.convertToExpression(body)));
}
if (body instanceof JsBlock) {
JsBlock bodyBlock = (JsBlock) body;
addReturnToBlockStatement(bodyBlock);
return bodyBlock;
}
throw new AssertionError("Invalid node as function body");
}
private void addReturnToBlockStatement(@NotNull JsBlock bodyBlock) {
List<JsStatement> statements = bodyBlock.getStatements();
int lastIndex = statements.size() - 1;
JsStatement lastStatement = statements.get(lastIndex);
statements.set(lastIndex,
new JsReturn(AstUtil.extractExpressionFromStatement(lastStatement)));
}
@NotNull
private TranslationContext functionBodyContext(@NotNull JetFunction function,
@NotNull JsScope functionScope) {
if (function instanceof JetNamedFunction) {
return translationContext().newFunctionDeclaration((JetNamedFunction) function);
}
if (function instanceof JetFunctionLiteral) {
return translationContext().newFunctionLiteral(functionScope);
}
throw new AssertionError("Unsupported type of function.");
}
@NotNull
@@ -4,10 +4,11 @@
package org.jetbrains.k2js.translate;
import com.google.dart.compiler.backend.js.ast.JsProgram;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
import org.jetbrains.jet.lang.psi.JetNamespace;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.k2js.declarations.DeclarationExtractor;
import org.jetbrains.k2js.declarations.Declarations;
import java.util.List;
@@ -18,14 +19,14 @@ public final class GenerationState {
}
//TODO method too long
public JsProgram compileCorrectNamespaces(BindingContext bindingContext, List<JetNamespace> namespaces) {
@NotNull
public JsProgram compileCorrectNamespaces(@NotNull BindingContext bindingContext, @NotNull List<JetNamespace> namespaces) {
//TODO hardcoded
JsProgram result = new JsProgram("main");
JetNamespace namespace = namespaces.get(0);
NamespaceDescriptor descriptor = BindingUtils.getNamespaceDescriptor(bindingContext, namespace);
DeclarationExtractor extractor = new DeclarationExtractor();
extractor.extractDeclarations(descriptor, result.getRootScope());
Translation.namespaceTranslator(TranslationContext.rootContext(result, bindingContext, extractor))
Declarations declarations = Declarations.extractDeclarations(descriptor, result.getRootScope());
Translation.namespaceTranslator(TranslationContext.rootContext(result, bindingContext, declarations))
.generateAst(namespace);
return result;
}
@@ -121,8 +121,7 @@ public class InitializerVisitor extends TranslatorVisitor<List<JsStatement>> {
@NotNull
private JsStatement translateInitializer(@NotNull JetProperty property, @NotNull TranslationContext context,
@NotNull JetExpression initializer) {
JsExpression initExpression = AstUtil.convertToExpression(Translation.expressionTranslator(context)
.translate(initializer));
JsExpression initExpression = Translation.translateAsExpression(initializer, context);
return assignmentToBackingField(property, initExpression, context);
}
@@ -134,15 +133,14 @@ public class InitializerVisitor extends TranslatorVisitor<List<JsStatement>> {
JsName backingFieldName = getBackingFieldName(propertyName, context);
JsNameRef backingFieldRef = backingFieldName.makeRef();
backingFieldRef.setQualifier(new JsThisRef());
return AstUtil.convertToStatement(AstUtil.newAssignment(backingFieldRef, initExpression));
return AstUtil.newAssignmentStatement(backingFieldRef, initExpression);
}
@Override
@NotNull
public List<JsStatement> visitAnonymousInitializer(@NotNull JetClassInitializer initializer,
@NotNull TranslationContext context) {
return Arrays.asList(AstUtil.convertToStatement
(Translation.expressionTranslator(context).translate(initializer.getBody())));
return Arrays.asList(Translation.translateAsStatement(initializer.getBody(), context));
}
@Override
@@ -8,7 +8,7 @@ import com.google.dart.compiler.util.AstUtil;
*/
/*
* This class is a complete dummy and needs a lot of work
* This class is a complete dummy and should completely change in the future
*/
public final class Namer {
@@ -58,14 +58,22 @@ public final class Namer {
return name;
}
//TODO: dummy
public static JsNameRef classObjectReference() {
//TODO dummy
return AstUtil.newQualifiedNameRef("Class");
}
public static JsNameRef creationMethodReference() {
public static JsNameRef classCreationMethodReference() {
return AstUtil.newQualifiedNameRef("Class.create");
}
public static JsNameRef traitCreationMethodReference() {
return AstUtil.newQualifiedNameRef("Trait.create");
}
public static JsNameRef isOperationReference() {
return AstUtil.newQualifiedNameRef("isType");
}
}
@@ -7,16 +7,16 @@ import org.jetbrains.jet.lang.psi.JetDeclaration;
/**
* @author Talanov Pavel
*/
public final class DeclarationTranslator extends AbstractTranslator {
public final class NamespaceDeclarationTranslator extends AbstractTranslator {
private DeclarationVisitor visitor = new DeclarationVisitor();
private NamespaceDeclarationVisitor visitor = new NamespaceDeclarationVisitor();
@NotNull
public static DeclarationTranslator newInstance(@NotNull TranslationContext context) {
return new DeclarationTranslator(context);
public static NamespaceDeclarationTranslator newInstance(@NotNull TranslationContext context) {
return new NamespaceDeclarationTranslator(context);
}
private DeclarationTranslator(TranslationContext context) {
private NamespaceDeclarationTranslator(TranslationContext context) {
super(context);
}
@@ -14,7 +14,7 @@ import org.jetbrains.jet.lang.psi.JetProperty;
* @author Talanov Pavel
*/
//TODO: rework the class
public class DeclarationVisitor extends TranslatorVisitor<JsStatement> {
public class NamespaceDeclarationVisitor extends TranslatorVisitor<JsStatement> {
@NotNull
@Override
@@ -41,7 +41,7 @@ public class DeclarationVisitor extends TranslatorVisitor<JsStatement> {
@NotNull
@Override
public JsStatement visitNamedFunction(@NotNull JetNamedFunction expression, @NotNull TranslationContext context) {
return AstUtil.convertToStatement(Translation.functionTranslator(context).translateAsFunction(expression));
return AstUtil.convertToStatement(Translation.functionTranslator(context).translateAsFunctionDeclaration(expression));
}
}
@@ -33,29 +33,30 @@ public final class NamespaceTranslator extends AbstractTranslator {
public JsBlock translate(@NotNull JetNamespace namespace) {
// TODO support multiple namespaces
JsBlock block = program().getFragmentBlock(0);
JsName namespaceName = scope().declareName(Namer.getNameForNamespace(namespace.getName()));
JsName namespaceName = translationContext().enclosingScope().declareName(Namer.getNameForNamespace(namespace.getName()));
block.addStatement(namespaceInitStatement(namespaceName));
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)));
JsInvocation namespaceExpression = newNamespace(namespaceName, namespaceDeclarations, dummyFunction);
block.addStatement(AstUtil.convertToStatement(namespaceExpression));
return block;
}
@NotNull
private JsBlock translateDeclarations(@NotNull JetNamespace namespace, @NotNull TranslationContext newContext) {
DeclarationTranslator declarationTranslator = Translation.declarationTranslator(newContext);
NamespaceDeclarationTranslator namespaceDeclarationTranslator = Translation.declarationTranslator(newContext);
JsBlock namespaceDeclarations = new JsBlock();
for (JetDeclaration declaration : namespace.getDeclarations()) {
namespaceDeclarations.addStatement(declarationTranslator.translateDeclaration(declaration));
namespaceDeclarations.addStatement(namespaceDeclarationTranslator.translateDeclaration(declaration));
}
return namespaceDeclarations;
}
@NotNull
private JsStatement namespaceInitStatement(@NotNull JsName namespaceName) {
return AstUtil.convertToStatement(AstUtil.newAssignment(namespaceName.makeRef(), new JsObjectLiteral()));
return AstUtil.newAssignmentStatement(namespaceName.makeRef(), new JsObjectLiteral());
}
@NotNull
@@ -1,7 +1,6 @@
package org.jetbrains.k2js.translate;
import com.google.dart.compiler.backend.js.ast.*;
import com.google.dart.compiler.util.AstUtil;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -42,8 +41,7 @@ public final class OperationTranslator extends AbstractTranslator {
private JsExpression translateBaseExpression(@NotNull JetUnaryExpression expression) {
JetExpression baseExpression = expression.getBaseExpression();
assert baseExpression != null : "Unary operation should have a base expression";
return AstUtil.convertToExpression
(Translation.translateExpression(baseExpression, translationContext()));
return Translation.translateAsExpression(baseExpression, translationContext());
}
@NotNull
@@ -63,6 +61,7 @@ public final class OperationTranslator extends AbstractTranslator {
return translateAsBinaryOperation(expression);
}
//TODO: think about the ways to improve logic here
@Nullable
public JsInvocation translateAsSetterCall(@NotNull JetBinaryExpression expression) {
JetToken jetOperationToken = getOperationToken(expression);
@@ -80,26 +79,32 @@ public final class OperationTranslator extends AbstractTranslator {
return setterCall;
}
@NotNull
private JetToken getOperationToken(@NotNull JetBinaryExpression expression) {
return (JetToken) expression.getOperationToken();
}
@NotNull
private JsExpression translateAsBinaryOperation(@NotNull JetBinaryExpression expression) {
JsExpression left = AstUtil.convertToExpression
(Translation.translateExpression(expression.getLeft(), translationContext()));
JsExpression left = Translation.translateAsExpression(expression.getLeft(), translationContext());
JsExpression right = translateRightExpression(expression);
JetToken jetOperationToken = getOperationToken(expression);
return new JsBinaryOperation(OperatorTable.getBinaryOperator(jetOperationToken), left, right);
JetToken token = getOperationToken(expression);
if (OperatorTable.hasCorrespondingBinaryOperator(token)) {
return new JsBinaryOperation(OperatorTable.getBinaryOperator(token), left, right);
}
if (OperatorTable.hasCorrespondingFunctionInvocation(token)) {
JsInvocation functionInvocation = OperatorTable.getCorrespondingFunctionInvocation(token);
functionInvocation.setArguments(Arrays.asList(left, right));
return functionInvocation;
}
throw new AssertionError("Unsupported token encountered: " + token.toString());
}
@NotNull
private JsExpression translateRightExpression(@NotNull JetBinaryExpression expression) {
JetExpression rightExpression = expression.getRight();
assert rightExpression != null : "Binary expression should have a right expression";
return AstUtil.convertToExpression
(Translation.translateExpression(rightExpression, translationContext()));
return Translation.translateAsExpression(rightExpression, translationContext());
}
@NotNull
private JetToken getOperationToken(@NotNull JetBinaryExpression expression) {
return (JetToken) expression.getOperationToken();
}
@@ -1,7 +1,10 @@
package org.jetbrains.k2js.translate;
import com.google.dart.compiler.backend.js.ast.JsBinaryOperator;
import com.google.dart.compiler.backend.js.ast.JsInvocation;
import com.google.dart.compiler.backend.js.ast.JsNameRef;
import com.google.dart.compiler.backend.js.ast.JsUnaryOperator;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lexer.JetToken;
import org.jetbrains.jet.lexer.JetTokens;
@@ -14,9 +17,9 @@ import java.util.Map;
*/
public final class OperatorTable {
private static Map<JetToken, JsBinaryOperator> binaryOperatorsMap = new HashMap<JetToken, JsBinaryOperator>();
private static Map<JetToken, JsUnaryOperator> unaryOperatorsMap = new HashMap<JetToken, JsUnaryOperator>();
private static Map<JetToken, JsNameRef> operatorToFunctionNameReference = new HashMap<JetToken, JsNameRef>();
static {
unaryOperatorsMap.put(JetTokens.PLUSPLUS, JsUnaryOperator.INC); //++
@@ -41,22 +44,45 @@ public final class OperatorTable {
binaryOperatorsMap.put(JetTokens.ANDAND, JsBinaryOperator.AND);
binaryOperatorsMap.put(JetTokens.EXCLEQ, JsBinaryOperator.NEQ);
binaryOperatorsMap.put(JetTokens.PERC, JsBinaryOperator.MOD);
binaryOperatorsMap.put(JetTokens.PLUSEQ, JsBinaryOperator.ASG_ADD);
binaryOperatorsMap.put(JetTokens.MINUSEQ, JsBinaryOperator.ASG_SUB);
binaryOperatorsMap.put(JetTokens.DIVEQ, JsBinaryOperator.ASG_DIV);
binaryOperatorsMap.put(JetTokens.MULTEQ, JsBinaryOperator.ASG_MUL);
binaryOperatorsMap.put(JetTokens.PERCEQ, JsBinaryOperator.ASG_MOD);
}
static {
operatorToFunctionNameReference.put(JetTokens.IS_KEYWORD, Namer.isOperationReference());
}
public static boolean hasCorrespondingBinaryOperator(@NotNull JetToken token) {
return binaryOperatorsMap.containsKey(token);
}
static boolean hasCorrespondingFunctionInvocation(@NotNull JetToken token) {
return operatorToFunctionNameReference.containsKey(token);
}
@NotNull
public static JsBinaryOperator getBinaryOperator(@NotNull JetToken token) {
static public JsInvocation getCorrespondingFunctionInvocation(@NotNull JetToken token) {
JsNameRef functionReference = operatorToFunctionNameReference.get(token);
assert functionReference != null : "Token should represent a function call!";
return AstUtil.newInvocation(functionReference);
}
@NotNull
static public JsBinaryOperator getBinaryOperator(@NotNull JetToken token) {
assert JetTokens.OPERATIONS.contains(token) : "Token should represent an operation!";
return binaryOperatorsMap.get(token);
}
@NotNull
public static JsUnaryOperator getUnaryOperator(@NotNull JetToken token) {
static public JsUnaryOperator getUnaryOperator(@NotNull JetToken token) {
assert JetTokens.OPERATIONS.contains(token) : "Token should represent an operation!";
return unaryOperatorsMap.get(token);
}
public static boolean isAssignment(JetToken token) {
static public boolean isAssignment(JetToken token) {
return (token == JetTokens.EQ);
}
}
@@ -0,0 +1,83 @@
package org.jetbrains.k2js.translate;
import com.google.dart.compiler.backend.js.ast.*;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.psi.*;
/**
* @author Talanov Pavel
*/
public final class PatternTranslator extends AbstractTranslator {
@NotNull
public static PatternTranslator newInstance(@NotNull TranslationContext context) {
return new PatternTranslator(context);
}
private PatternTranslator(@NotNull TranslationContext context) {
super(context);
}
@NotNull
public JsExpression translateIsExpression(@NotNull JetIsExpression expression) {
JsExpression left = Translation.translateAsExpression(expression.getLeftHandSide(), translationContext());
JetPattern pattern = getPattern(expression);
JsExpression resultingExpression = translatePattern(pattern, left);
if (expression.isNegated()) {
return AstUtil.negated(resultingExpression);
}
return resultingExpression;
}
@NotNull
private JetPattern getPattern(@NotNull JetIsExpression expression) {
JetPattern pattern = expression.getPattern();
assert pattern != null : "Pattern should not be null";
return pattern;
}
@NotNull
public JsExpression translatePattern(@NotNull JetPattern pattern, @NotNull JsExpression expressionToMatch) {
if (pattern instanceof JetTypePattern) {
return translateTypePattern(expressionToMatch, (JetTypePattern) pattern);
}
if (pattern instanceof JetExpressionPattern) {
return translateExpressionPattern(expressionToMatch, (JetExpressionPattern) pattern);
}
throw new AssertionError("Unsupported pattern type " + pattern.getClass());
}
@NotNull
private JsExpression translateTypePattern(@NotNull JsExpression expressionToMatch,
@NotNull JetTypePattern pattern) {
return AstUtil.newInvocation(Namer.isOperationReference(), expressionToMatch, getClassReference(pattern));
}
@NotNull
private JsExpression getClassReference(@NotNull JetTypePattern pattern) {
JetTypeReference typeReference = pattern.getTypeReference();
assert typeReference != null : "Type pattern should contain a type reference";
return getClassNameReferenceForTypeReference(typeReference);
}
@NotNull
private JsNameRef getClassNameReferenceForTypeReference(@NotNull JetTypeReference typeReference) {
ClassDescriptor referencedClass = BindingUtils.getClassDescriptorForTypeReference
(translationContext().bindingContext(), typeReference);
//TODO should reference class by full name here
JsName className = translationContext().getNameForDescriptor(referencedClass);
return translationContext().getNamespaceQualifiedReference(className);
}
@NotNull
private JsExpression translateExpressionPattern(JsExpression expressionToMatch, JetExpressionPattern pattern) {
JetExpression patternExpression = pattern.getExpression();
assert patternExpression != null : "Expression patter should have an expression.";
JsExpression expressionToMatchAgainst =
Translation.translateAsExpression(patternExpression, translationContext());
//TODO: should call equals method here
return new JsBinaryOperation(JsBinaryOperator.REF_EQ, expressionToMatch, expressionToMatchAgainst);
}
}
@@ -1,9 +1,9 @@
package org.jetbrains.k2js.translate;
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 com.google.dart.compiler.backend.js.ast.JsNode;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -13,6 +13,7 @@ import org.jetbrains.jet.lang.descriptors.PropertyGetterDescriptor;
import org.jetbrains.jet.lang.descriptors.PropertySetterDescriptor;
import org.jetbrains.jet.lang.psi.JetDotQualifiedExpression;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetQualifiedExpression;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
@@ -33,7 +34,7 @@ public final class PropertyAccessTranslator extends AbstractTranslator {
}
@Nullable
public JsInvocation resolveAsPropertyGet(@NotNull JetDotQualifiedExpression expression) {
public JsInvocation resolveAsPropertyGet(@NotNull JetQualifiedExpression expression) {
JetExpression selectorExpression = expression.getSelectorExpression();
assert selectorExpression != null : "Selector should not be null.";
JsName getterName = getPropertyGetterName(selectorExpression);
@@ -54,11 +55,11 @@ public final class PropertyAccessTranslator extends AbstractTranslator {
@NotNull
private JsInvocation translateReceiverAndReturnAccessorInvocation
(@NotNull JetDotQualifiedExpression dotQualifiedExpression, @NotNull JsName accessorName) {
JsNode node = Translation.expressionTranslator(translationContext())
.translate(dotQualifiedExpression.getReceiverExpression());
(@NotNull JetQualifiedExpression qualifiedExpression, @NotNull JsName accessorName) {
JsExpression qualifier = Translation.translateAsExpression
(qualifiedExpression.getReceiverExpression(), translationContext());
JsNameRef result = accessorName.makeRef();
result.setQualifier(AstUtil.convertToExpression(node));
result.setQualifier(qualifier);
return AstUtil.newInvocation(result);
}
@@ -0,0 +1,102 @@
package org.jetbrains.k2js.translate;
import com.google.dart.compiler.backend.js.ast.*;
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;
/**
* @author Talanov Pavel
*/
public class ReferenceTranslator extends AbstractTranslator {
@NotNull
static public ReferenceTranslator newInstance(@NotNull TranslationContext context) {
return new ReferenceTranslator(context);
}
private ReferenceTranslator(@NotNull TranslationContext context) {
super(context);
}
@NotNull
JsExpression translateSimpleName(@NotNull JetSimpleNameExpression expression) {
//TODO: this is only a hack for now
// Problem is that namespace properties do not generate getters and setter actually so they must be referenced
// by name
JsExpression result;
result = resolveAsGlobalReference(expression);
if (result != null) {
return result;
}
result = resolveAsLocalReference(expression);
if (result != null) {
return result;
}
JsInvocation getterCall =
Translation.propertyAccessTranslator(translationContext()).resolveAsPropertyGet(expression);
if (getterCall != null) {
return getterCall;
}
throw new AssertionError("Undefined name in this scope: " + expression.getReferencedName());
}
@Nullable
private JsExpression resolveAsGlobalReference(@NotNull JetSimpleNameExpression expression) {
DeclarationDescriptor referencedDescriptor =
BindingUtils.getDescriptorForReferenceExpression(translationContext().bindingContext(), expression);
if (referencedDescriptor == null) {
return null;
}
if (!translationContext().isDeclared(referencedDescriptor)) {
return null;
}
JsName referencedName = translationContext().getNameForDescriptor(referencedDescriptor);
return generateCorrectReference(expression, referencedName);
}
@Nullable
private JsExpression resolveAsLocalReference(@NotNull JetSimpleNameExpression expression) {
JsName localReferencedName = getLocalReferencedName(expression);
if (localReferencedName == null) {
return null;
}
return generateCorrectReference(expression, localReferencedName);
}
@NotNull
private JsNameRef generateCorrectReference(@NotNull JetSimpleNameExpression expression,
@NotNull JsName referencedName) {
JsNameRef result;
if (requiresNamespaceQualifier(referencedName)) {
result = translationContext().getNamespaceQualifiedReference(referencedName);
} else {
result = referencedName.makeRef();
if (requiresThisQualifier(expression)) {
result.setQualifier(new JsThisRef());
}
}
return result;
}
private boolean requiresNamespaceQualifier(@NotNull JsName referencedName) {
return translationContext().namespaceScope().ownsName(referencedName);
}
private boolean requiresThisQualifier(@NotNull JetSimpleNameExpression expression) {
boolean isClassMember = translationContext().classScope().ownsName(getLocalReferencedName(expression));
boolean isBackingFieldAccess = expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER;
return isClassMember || isBackingFieldAccess;
}
@Nullable
private JsName getLocalReferencedName(@NotNull JetSimpleNameExpression expression) {
String referencedName = expression.getReferencedName();
return translationContext().enclosingScope().findExistingName(referencedName);
}
}
@@ -1,8 +1,12 @@
package org.jetbrains.k2js.translate;
import com.google.dart.compiler.backend.js.ast.JsExpression;
import com.google.dart.compiler.backend.js.ast.JsNode;
import com.google.dart.compiler.backend.js.ast.JsStatement;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetWhenExpression;
/**
* @author Talanov Pavel
@@ -42,12 +46,37 @@ public final class Translation {
}
@NotNull
static public DeclarationTranslator declarationTranslator(@NotNull TranslationContext context) {
return DeclarationTranslator.newInstance(context);
static public NamespaceDeclarationTranslator declarationTranslator(@NotNull TranslationContext context) {
return NamespaceDeclarationTranslator.newInstance(context);
}
@NotNull
static public PatternTranslator patternTranslator(@NotNull TranslationContext context) {
return PatternTranslator.newInstance(context);
}
@NotNull
static public ReferenceTranslator referenceTranslator(@NotNull TranslationContext context) {
return ReferenceTranslator.newInstance(context);
}
@NotNull
static public JsNode translateExpression(@NotNull JetExpression expression, @NotNull TranslationContext context) {
return expressionTranslator(context).translate(expression);
}
@NotNull
static public JsExpression translateAsExpression(@NotNull JetExpression expression, @NotNull TranslationContext context) {
return AstUtil.convertToExpression(translateExpression(expression, context));
}
@NotNull
static public JsStatement translateAsStatement(@NotNull JetExpression expression, @NotNull TranslationContext context) {
return AstUtil.convertToStatement(translateExpression(expression, context));
}
@NotNull
static public JsNode translateWhenExpression(@NotNull JetWhenExpression expression, @NotNull TranslationContext context) {
return WhenTranslator.translateWhenExpression(expression, context);
}
}
@@ -10,7 +10,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.k2js.declarations.DeclarationExtractor;
import org.jetbrains.k2js.declarations.Declarations;
/**
* @author Talanov Pavel
@@ -35,7 +35,7 @@ public final class TranslationContext {
@NotNull
public static TranslationContext rootContext(@NotNull JsProgram program, @NotNull BindingContext bindingContext,
@NotNull DeclarationExtractor extractor) {
@NotNull Declarations extractor) {
JsScope rootScope = program.getRootScope();
Scopes scopes = new Scopes(rootScope, rootScope, rootScope);
return new TranslationContext(null, program, bindingContext, scopes, extractor);
@@ -50,17 +50,17 @@ public final class TranslationContext {
@Nullable
private final JsName namespaceName;
@NotNull
private final DeclarationExtractor extractor;
private final Declarations declarations;
private TranslationContext(@Nullable JsName namespaceName, @NotNull JsProgram program,
@NotNull BindingContext bindingContext, @NotNull Scopes scopes,
@NotNull DeclarationExtractor extractor) {
@NotNull Declarations declarations) {
this.program = program;
this.bindingContext = bindingContext;
this.namespaceName = namespaceName;
this.scopes = scopes;
this.extractor = extractor;
this.declarations = declarations;
}
@NotNull
@@ -70,17 +70,17 @@ public final class TranslationContext {
@NotNull
public TranslationContext newNamespace(@NotNull NamespaceDescriptor descriptor) {
JsScope namespaceScope = extractor.getScope(descriptor);
JsScope namespaceScope = declarations.getScope(descriptor);
JsName namespaceName = scopes.enclosingScope.findExistingName(descriptor.getName());
Scopes newScopes = new Scopes(namespaceScope, namespaceScope, namespaceScope);
return new TranslationContext(namespaceName, program, bindingContext, newScopes, extractor);
return new TranslationContext(namespaceName, program, bindingContext, newScopes, declarations);
}
@NotNull
public TranslationContext newBlock() {
Scopes newScopes = new Scopes(new JsScope
(scopes.enclosingScope, "Scope for a block"), scopes.classScope, scopes.namespaceScope);
return new TranslationContext(namespaceName, program, bindingContext, newScopes, extractor);
return new TranslationContext(namespaceName, program, bindingContext, newScopes, declarations);
}
@NotNull
@@ -90,9 +90,9 @@ public final class TranslationContext {
@NotNull
public TranslationContext newClass(@NotNull ClassDescriptor descriptor) {
JsScope classScope = extractor.getScope(descriptor);
JsScope classScope = declarations.getScope(descriptor);
Scopes newScopes = new Scopes(classScope, classScope, scopes.namespaceScope);
return new TranslationContext(namespaceName, program, bindingContext, newScopes, extractor);
return new TranslationContext(namespaceName, program, bindingContext, newScopes, declarations);
}
@NotNull
@@ -102,26 +102,32 @@ public final class TranslationContext {
@NotNull
public TranslationContext newPropertyAccess(@NotNull PropertyAccessorDescriptor descriptor) {
return newFunction(descriptor);
return newFunctionDeclaration(descriptor);
}
@NotNull
public TranslationContext newFunction(@NotNull JetNamedFunction declaration) {
return newFunction(BindingUtils.getFunctionDescriptor(bindingContext, declaration));
public TranslationContext newFunctionDeclaration(@NotNull JetNamedFunction declaration) {
return newFunctionDeclaration(BindingUtils.getFunctionDescriptor(bindingContext, declaration));
}
@NotNull
public TranslationContext newFunction(@NotNull FunctionDescriptor descriptor) {
JsScope functionScope = extractor.getScope(descriptor);
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, newScopes, extractor);
return new TranslationContext(namespaceName, program, bindingContext, newScopes, declarations);
}
@NotNull
public TranslationContext newFunctionLiteral(@NotNull JsScope correspondingScope) {
Scopes newScopes = new Scopes(correspondingScope, scopes.classScope, scopes.namespaceScope);
return new TranslationContext(namespaceName, program, bindingContext, newScopes, declarations);
}
// Note: Should be used if and only if scope has no corresponding descriptor
@NotNull
public TranslationContext newEnclosingScope(@NotNull JsScope enclosingScope) {
Scopes newScopes = new Scopes(enclosingScope, scopes.classScope, scopes.namespaceScope);
return new TranslationContext(namespaceName, program, bindingContext, newScopes, extractor);
return new TranslationContext(namespaceName, program, bindingContext, newScopes, declarations);
}
@@ -165,7 +171,7 @@ public final class TranslationContext {
@NotNull
public JsScope getScopeForDescriptor(@NotNull DeclarationDescriptor descriptor) {
return extractor.getScope(descriptor);
return declarations.getScope(descriptor);
}
@NotNull
@@ -176,7 +182,7 @@ public final class TranslationContext {
@NotNull
public JsName getNameForDescriptor(@NotNull DeclarationDescriptor descriptor) {
return extractor.getName(descriptor);
return declarations.getName(descriptor);
}
@NotNull
@@ -191,4 +197,8 @@ public final class TranslationContext {
assert descriptor != null : "Element should have a descriptor";
return descriptor;
}
public boolean isDeclared(@NotNull DeclarationDescriptor descriptor) {
return declarations.isDeclared(descriptor);
}
}
@@ -2,7 +2,6 @@ package org.jetbrains.k2js.translate;
import com.google.dart.compiler.backend.js.ast.JsExpression;
import com.google.dart.compiler.backend.js.ast.JsName;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.*;
@@ -45,8 +44,7 @@ public class TranslatorVisitor<T> extends JetVisitor<T, TranslationContext> {
JsExpression jsInitExpression = null;
JetExpression initializer = declaration.getInitializer();
if (initializer != null) {
jsInitExpression = AstUtil.convertToExpression(Translation.expressionTranslator(context)
.translate(initializer));
jsInitExpression = Translation.translateAsExpression(initializer, context);
}
return jsInitExpression;
}
@@ -67,6 +65,6 @@ public class TranslatorVisitor<T> extends JetVisitor<T, TranslationContext> {
if (jetExpression == null) {
throw new AssertionError("Argument with no expression encountered!");
}
return AstUtil.convertToExpression(Translation.translateExpression(jetExpression, context));
return Translation.translateAsExpression(jetExpression, context);
}
}
@@ -0,0 +1,175 @@
package org.jetbrains.k2js.translate;
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.psi.*;
import java.util.ArrayList;
import java.util.List;
/**
* @author Talanov Pavel
*/
//TODO: fix members order
public class WhenTranslator extends AbstractTranslator {
@NotNull
static public JsNode translateWhenExpression(@NotNull JetWhenExpression expression, @NotNull TranslationContext context) {
WhenTranslator translator = new WhenTranslator(expression, context);
return translator.translate();
}
@NotNull
private final JetWhenExpression whenExpression;
@NotNull
private final JsExpression expressionToMatch;
@NotNull
private final JsName dummyCounterName;
private int currentEntryNumber = 0;
private WhenTranslator(@NotNull JetWhenExpression expression, @NotNull TranslationContext context) {
super(context);
this.whenExpression = expression;
this.expressionToMatch = translateExpressionToMatch(whenExpression);
this.dummyCounterName = context.enclosingScope().declareTemporary();
}
@NotNull
JsNode translate() {
JsFor resultingFor = generateDummyFor();
List<JsStatement> entries = translateEntries();
resultingFor.setBody(AstUtil.newBlock(entries));
return resultingFor;
}
@NotNull
private List<JsStatement> translateEntries() {
List<JsStatement> entries = new ArrayList<JsStatement>();
for (JetWhenEntry entry : whenExpression.getEntries()) {
entries.add(surroundWithDummyIf(translateEntry(entry)));
}
return entries;
}
@NotNull
private JsStatement surroundWithDummyIf(@NotNull JsStatement entryStatement) {
JsExpression stepNumberEqualsCurrentEntryNumber = new JsBinaryOperation(JsBinaryOperator.EQ,
dummyCounterName.makeRef(), translationContext().program().getNumberLiteral(currentEntryNumber));
currentEntryNumber++;
return new JsIf(stepNumberEqualsCurrentEntryNumber, entryStatement, null);
}
@NotNull
private JsFor generateDummyFor() {
JsFor result = new JsFor();
result.setInitVars(generateInitStatement());
result.setIncrExpr(generateIncrementStatement());
result.setCondition(generateConditionStatement());
return result;
}
@NotNull
private JsBinaryOperation generateConditionStatement() {
JsNumberLiteral entriesNumber = program().getNumberLiteral(whenExpression.getEntries().size());
return new JsBinaryOperation(JsBinaryOperator.LT, dummyCounterName.makeRef(), entriesNumber);
}
@NotNull
private JsPrefixOperation generateIncrementStatement() {
return new JsPrefixOperation(JsUnaryOperator.INC, dummyCounterName.makeRef());
}
@NotNull
private JsVars generateInitStatement() {
return AstUtil.newVar(dummyCounterName, translationContext().program().getNumberLiteral(0));
}
@NotNull
private JsStatement translateEntry(@NotNull JetWhenEntry entry) {
JsStatement statementToExecute = translateExpressionToExecute(entry);
if (entry.isElse()) {
return statementToExecute;
}
JsExpression condition = translateConditions(entry);
return new JsIf(condition, addDummyBreak(statementToExecute), null);
}
@NotNull
private JsStatement translateExpressionToExecute(@NotNull JetWhenEntry entry) {
JetExpression expressionToExecute = entry.getExpression();
assert expressionToExecute != null : "WhenEntry should have whenExpression to execute.";
return Translation.translateAsStatement(expressionToExecute, translationContext());
}
//TODO: ask what these conditions mean
@NotNull
private JsExpression translateConditions(@NotNull JetWhenEntry entry) {
List<JsExpression> conditions = new ArrayList<JsExpression>();
for (JetWhenCondition condition : entry.getConditions()) {
conditions.add(translateCondition(condition));
}
return anyOfThemIsTrue(conditions);
}
@NotNull
private JsExpression anyOfThemIsTrue(List<JsExpression> conditions) {
assert !conditions.isEmpty() : "When entry (not else) should have at least one condition";
JsExpression current = null;
for (JsExpression condition : conditions) {
current = addCaseCondition(current, condition);
}
assert current != null;
return current;
}
@NotNull
private JsExpression addCaseCondition(@Nullable JsExpression current, @NotNull JsExpression condition) {
if (current == null) {
current = condition;
} else {
current = new JsBinaryOperation(JsBinaryOperator.OR, current, condition);
}
return current;
}
@NotNull
private JsExpression translateCondition(@NotNull JetWhenCondition condition) {
if (condition instanceof JetWhenConditionIsPattern) {
return translatePatternCondition((JetWhenConditionIsPattern) condition);
}
throw new AssertionError("Unsupported when condition " + condition.getClass());
}
@NotNull
private JsBlock addDummyBreak(@NotNull JsStatement statement) {
return AstUtil.newBlock(statement, new JsBreak());
}
@NotNull
private JsExpression translatePatternCondition(@NotNull JetWhenConditionIsPattern condition) {
JsExpression patternMatchExpression = Translation.patternTranslator(translationContext()).
translatePattern(getPattern(condition), expressionToMatch);
if (condition.isNegated()) {
return AstUtil.negated(patternMatchExpression);
}
return patternMatchExpression;
}
@NotNull
private JetPattern getPattern(@NotNull JetWhenConditionIsPattern condition) {
JetPattern pattern = condition.getPattern();
assert pattern != null : "Is condition should have a non null pattern.";
return pattern;
}
@NotNull
private JsExpression translateExpressionToMatch(@NotNull JetWhenExpression expression) {
JetExpression subject = expression.getSubjectExpression();
assert subject != null : "Subject should not be null.";
return Translation.translateAsExpression(subject, translationContext());
}
}
@@ -0,0 +1,22 @@
package org.jetbrains.k2js.test;
import java.util.Arrays;
import java.util.List;
/**
* @author Talanov Pavel
*/
public abstract class AbstractExpressionTest extends TranslationTest {
private final String SUITE = "expression/";
@Override
protected List<String> generateFilenameList(String inputFile) {
return Arrays.asList(inputFile);
}
@Override
protected String suiteDirectoryName() {
return SUITE;
}
}
@@ -5,7 +5,7 @@ import org.junit.Test;
/**
* @author Talanov Pavel
*/
public class BasicClassTest extends AbstractClassTest {
public class BasicClassTest extends IncludeLibraryTest {
final private static String MAIN = "class/";
@@ -24,7 +24,7 @@ public class BasicClassTest extends AbstractClassTest {
testFooBoxIsTrue("methodDeclarationAndCall.kt");
}
//TODO: test excluded. Wait for bugfix and implement functionality
//TODO: wait for bugfix and implement properties as consructor parameter declaration
@Test
public void constructorWithParameter() throws Exception {
testFooBoxIsTrue("constructorWithParameter.kt");
@@ -5,7 +5,7 @@ import org.junit.Test;
/**
* @author Talanov Pavel
*/
public final class ClassInheritanceTest extends AbstractClassTest {
public final class ClassInheritanceTest extends IncludeLibraryTest {
final private static String MAIN = "inheritance/";
@@ -0,0 +1,31 @@
package org.jetbrains.k2js.test;
import org.junit.Test;
/**
* @author Talanov Pavel
*/
public class ConditionalTest extends AbstractExpressionTest {
final private static String MAIN = "conditional/";
@Override
protected String mainDirectory() {
return MAIN;
}
@Test
public void ifElseAsExpression() throws Exception {
testFooBoxIsTrue("ifElseAsExpression.kt");
}
@Test
public void ifElse() throws Exception {
testFunctionOutput("if.kt", "foo", "box", 5);
}
//TODO: test fails due to isStatement issue, include when issue is solved or implement another solution
// @Test
// public void ifElseIf() throws Exception {
// testFunctionOutput("elseif.kt", "foo", "box", 5);
// }
}
@@ -1,122 +0,0 @@
package org.jetbrains.k2js.test;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
/**
* @author Talanov Pavel
* <p/>
* This class tests basic language features and constructs such as constants, local variables, simple loops,
* conditional clauses etc.
*/
public final class ExpressionTest extends TranslationTest {
private static final String MAIN = "expression/";
protected String mainDirectory() {
return MAIN;
}
@Override
protected List<String> generateFilenameList(String inputFile) {
return Arrays.asList(inputFile);
}
@Test
public void currentTest() throws Exception {
testFooBoxIsTrue("test.kt");
}
@Test
public void testAssign() throws Exception {
testFunctionOutput("assign.jet", "foo", "f", 2.0);
}
@Test
public void namespaceProperties() throws Exception {
testFunctionOutput("localProperty.jet", "foo", "box", 50);
}
@Test
public void comparison() throws Exception {
testFooBoxIsTrue("comparison.kt");
}
@Test
public void ifElse() throws Exception {
testFunctionOutput("if.kt", "foo", "box", 5);
}
//TODO: test fails due to isStatement issue, include when issue is solved or implement another solution
// @Test
// public void ifElseIf() throws Exception {
// testFunctionOutput("elseif.kt", "foo", "box", 5);
// }
@Test
public void whileSimpleTest() throws Exception {
testFooBoxIsTrue("while.kt");
}
@Test
public void doWhileSimpleTest() throws Exception {
testFooBoxIsTrue("doWhile.kt");
}
@Test
public void doWhileExecutesAtLeastOnce() throws Exception {
testFooBoxIsTrue("doWhile2.kt");
}
@Test
public void whileDoesntExecuteEvenOnceIfConditionIsFalse() throws Exception {
testFooBoxIsTrue("while2.kt");
}
@Test
public void stringConstant() throws Exception {
testFooBoxIsTrue("stringConstant.kt");
}
@Test
public void stringAssignment() throws Exception {
testFooBoxIsTrue("stringAssignment.kt");
}
@Test
public void functionUsedBeforeDeclaration() throws Exception {
testFooBoxIsTrue("functionUsedBeforeDeclaration.kt");
}
@Test
public void functionWithTwoParametersCall() throws Exception {
testFooBoxIsTrue("functionWithTwoParametersCall.kt");
}
@Test
public void prefixIntOperations() throws Exception {
testFooBoxIsTrue("prefixIntOperations.kt");
}
@Test
public void postfixIntOperations() throws Exception {
testFooBoxIsTrue("postfixIntOperations.kt");
}
@Test
public void notBoolean() throws Exception {
testFooBoxIsTrue("notBoolean.kt");
}
@Test
public void positiveAndNegativeNumbers() throws Exception {
testFooBoxIsTrue("positiveAndNegativeNumbers.kt");
}
@Test
public void ifElseAsExpression() throws Exception {
testFooBoxIsTrue("ifElseAsExpression.kt");
}
}
@@ -0,0 +1,57 @@
package org.jetbrains.k2js.test;
import org.junit.Test;
/**
* @author Talanov Pavel
*/
public class FunctionTest extends AbstractExpressionTest {
final private static String MAIN = "function/";
@Override
protected String mainDirectory() {
return MAIN;
}
@Test
public void functionUsedBeforeDeclaration() throws Exception {
testFooBoxIsTrue("functionUsedBeforeDeclaration.kt");
}
@Test
public void functionWithTwoParametersCall() throws Exception {
testFooBoxIsTrue("functionWithTwoParametersCall.kt");
}
@Test
public void functionLiteral() throws Exception {
testFooBoxIsTrue("functionLiteral.kt");
}
@Test
public void adderClosure() throws Exception {
testFooBoxIsTrue("adderClosure.kt");
}
@Test
public void loopClosure() throws Exception {
testFooBoxIsTrue("loopClosure.kt");
}
@Test
public void functionLiteralAsParameter() throws Exception {
testFooBoxIsTrue("functionLiteralAsParameter.kt");
}
@Test
public void closureWithParameter() throws Exception {
testFooBoxIsOk("closureWithParameter.jet");
}
@Test
public void closureWithParameterAndBoxing() throws Exception {
testFooBoxIsOk("closureWithParameterAndBoxing.jet");
}
}
@@ -6,7 +6,7 @@ import java.util.List;
/**
* @author Talanov Pavel
*/
public abstract class AbstractClassTest extends TranslationTest {
public abstract class IncludeLibraryTest extends TranslationTest {
@Override
protected List<String> generateFilenameList(String inputFile) {
@@ -3,7 +3,6 @@ package org.jetbrains.k2js.test;
import org.junit.Test;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.NativeObject;
import org.mozilla.javascript.Scriptable;
import java.util.Arrays;
@@ -11,8 +10,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.assertTrue;
/**
* @author Talanov Pavel
*/
@@ -30,39 +27,62 @@ public class KotlinLibTest extends TranslationTest {
return MAIN;
}
protected void verifyObjectHasExpectedPropertiesOfExpectedTypes
(NativeObject object, Map<String, Class<? extends Scriptable>> nameToClassMap) {
for (Map.Entry<String, Class<? extends Scriptable>> entry : nameToClassMap.entrySet()) {
String name = entry.getKey();
Class expectedClass = entry.getValue();
assertTrue(object + " must contain key " + name, object.containsKey(name));
assertTrue(object + "'s property " + name + " must be of type " + expectedClass,
expectedClass.isInstance(object.get(name)));
}
private void runPropertyTypeCheck(String objectName, Map<String, Class<? extends Scriptable>> propertyToType)
throws Exception {
runRhinoTest(Arrays.asList(kotlinLibraryPath()), new RhinoPropertyTypesChecker(objectName, propertyToType));
}
@Test
public void kotlinJsLibRunsWithRhino() throws Exception {
Context context = Context.enter();
Scriptable scope = context.initStandardObjects();
// ss
runFileWithRhino(kotlinLibraryPath(), context, scope);
Context.exit();
runRhinoTest(Arrays.asList(kotlinLibraryPath()), new RhinoResultChecker() {
@Override
public void runChecks(Context context, Scriptable scope) throws Exception {
//do nothing
}
});
}
@Test
public void classObjectHasCreateMethod() throws Exception {
final Map<String, Class<? extends Scriptable>> nameToClassMap =
new HashMap<String, Class<? extends Scriptable>>();
nameToClassMap.put("create", Function.class);
runRhinoTest(Arrays.asList(kotlinLibraryPath()),
new RhinoResultChecker() {
@Override
public void runChecks(Context context, Scriptable scope) throws Exception {
NativeObject object = RhinoUtils.extractObject("Class", scope);
verifyObjectHasExpectedPropertiesOfExpectedTypes(object, nameToClassMap);
}
});
final Map<String, Class<? extends Scriptable>> propertyToType
= new HashMap<String, Class<? extends Scriptable>>();
propertyToType.put("create", Function.class);
runPropertyTypeCheck("Class", propertyToType);
}
@Test
public void traitObjectHasCreateMethod() throws Exception {
final Map<String, Class<? extends Scriptable>> propertyToType
= new HashMap<String, Class<? extends Scriptable>>();
propertyToType.put("create", Function.class);
runPropertyTypeCheck("Trait", propertyToType);
}
@Test
public void createdTraitIsJSObject() throws Exception {
final Map<String, Class<? extends Scriptable>> propertyToType
= new HashMap<String, Class<? extends Scriptable>>();
runRhinoTest(Arrays.asList(kotlinLibraryPath(), cases("trait.js")),
new RhinoPropertyTypesChecker("foo", propertyToType));
}
@Test
public void isSameType() throws Exception {
runRhinoTest(Arrays.asList(kotlinLibraryPath(), cases("isSameType.js")),
new RhinoFunctionResultChecker("test", true));
}
@Test
public void isAncestorType() throws Exception {
runRhinoTest(Arrays.asList(kotlinLibraryPath(), cases("isAncestorType.js")),
new RhinoFunctionResultChecker("test", true));
}
@Test
public void isComplexTest() throws Exception {
runRhinoTest(Arrays.asList(kotlinLibraryPath(), cases("isComplexTest.js")),
new RhinoFunctionResultChecker("test", true));
}
}
@@ -0,0 +1,23 @@
package org.jetbrains.k2js.test;
import org.junit.Test;
/**
* @author Talanov Pavel
* <p/>
* This class contains tests that do not fall in any particular category
* most probably because that functionality has very little support
*/
public class MiscTest extends AbstractExpressionTest {
final private static String MAIN = "misc/";
@Override
protected String mainDirectory() {
return MAIN;
}
@Test
public void namespaceProperties() throws Exception {
testFunctionOutput("localProperty.jet", "foo", "box", 50);
}
}
@@ -0,0 +1,45 @@
package org.jetbrains.k2js.test;
import org.junit.Test;
/**
* @author Talanov Pavel
*/
public class OperationTest extends AbstractExpressionTest {
final private static String MAIN = "operation/";
@Override
protected String mainDirectory() {
return MAIN;
}
@Test
public void prefixIntOperations() throws Exception {
testFooBoxIsTrue("prefixIntOperations.kt");
}
@Test
public void postfixIntOperations() throws Exception {
testFooBoxIsTrue("postfixIntOperations.kt");
}
@Test
public void notBoolean() throws Exception {
testFooBoxIsTrue("notBoolean.kt");
}
@Test
public void positiveAndNegativeNumbers() throws Exception {
testFooBoxIsTrue("positiveAndNegativeNumbers.kt");
}
@Test
public void assign() throws Exception {
testFunctionOutput("assign.jet", "foo", "f", 2.0);
}
@Test
public void comparison() throws Exception {
testFooBoxIsTrue("comparison.kt");
}
}
@@ -0,0 +1,52 @@
package org.jetbrains.k2js.test;
import org.junit.Test;
/**
* @author Talanov Pavel
*/
public final class PatternMatchingTest extends IncludeLibraryTest {
final private static String MAIN = "patternMatching/";
@Override
protected String mainDirectory() {
return MAIN;
}
@Test
public void whenType() throws Exception {
testFooBoxIsTrue("whenType.kt");
}
@Test
public void whenNotType() throws Exception {
testFooBoxIsTrue("whenNotType.kt");
}
@Test
public void whenExecutesOnlyOnce() throws Exception {
testFooBoxIsTrue("whenExecutesOnlyOnce.kt");
}
@Test
public void whenValue() throws Exception {
testFooBoxIsTrue("whenValue.kt");
}
@Test
public void whenNotValue() throws Exception {
testFooBoxIsTrue("whenNotValue.kt");
}
@Test
public void whenValueOrType() throws Exception {
testFooBoxIsTrue("whenValueOrType.kt");
}
@Test
public void multipleCases() throws Exception {
testFunctionOutput("multipleCases.kt", "foo", "box", 2.0);
}
}
@@ -5,7 +5,7 @@ import org.junit.Test;
/**
* @author Talanov Pavel
*/
public final class PropertyAccessorTest extends AbstractClassTest {
public final class PropertyAccessorTest extends IncludeLibraryTest {
final private static String MAIN = "propertyAccess/";
@@ -39,6 +39,16 @@ public final class PropertyAccessorTest extends AbstractClassTest {
testFooBoxIsTrue("customSetter.kt");
}
@Test
public void safeCall() throws Exception {
testFooBoxIsTrue("safeCall.kt");
}
@Test
public void safeCallReturnsNullIfFails() throws Exception {
testFooBoxIsTrue("safeCallReturnsNullIfFails.kt");
}
//TODO test
// @Test
// public void namespaceCustomAccessors() throws Exception {
@@ -0,0 +1,26 @@
package org.jetbrains.k2js.test;
import org.junit.Test;
/**
* @author Talanov Pavel
*/
public class RTTITest extends IncludeLibraryTest {
final private static String MAIN = "rtti/";
@Override
protected String mainDirectory() {
return MAIN;
}
@Test
public void isSameClass() throws Exception {
testFooBoxIsTrue("isSameClass.kt");
}
@Test
public void notIsOtherClass() throws Exception {
testFooBoxIsTrue("notIsOtherClass.kt");
}
}
@@ -1,5 +1,6 @@
package org.jetbrains.k2js.test;
import org.jetbrains.annotations.Nullable;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.NativeObject;
@@ -16,27 +17,55 @@ public final class RhinoFunctionResultChecker implements RhinoResultChecker {
final String functionName;
final Object expectedResult;
public RhinoFunctionResultChecker(String namespaceName, String functionName, Object expectedResult) {
public RhinoFunctionResultChecker(@Nullable String namespaceName, String functionName, Object expectedResult) {
this.namespaceName = namespaceName;
this.functionName = functionName;
this.expectedResult = expectedResult;
}
public RhinoFunctionResultChecker(String functionName, Object expectedResult) {
this(null, functionName, expectedResult);
}
@Override
public void runChecks(Context context, Scriptable scope) throws Exception {
Object result = extractAndCallFunctionObject(namespaceName, functionName, context, scope);
assertTrue("Result is not what expected!", result.equals(expectedResult));
assertTrue("Result is not what expected! Expected: " + expectedResult + " Evaluated : " + result,
result.equals(expectedResult));
String report = namespaceName + "." + functionName + "() = " + Context.toString(result);
System.out.println(report);
}
private Object extractAndCallFunctionObject(String namespaceName, String functionName,
Context cx, Scriptable scope) {
NativeObject namespaceObject = RhinoUtils.extractObject(namespaceName, scope);
Object box = namespaceObject.get(functionName, namespaceObject);
assertTrue("Function " + functionName + " not defined in namespace " + namespaceName, box instanceof Function);
Object functionObject;
if (namespaceName != null) {
functionObject = extractFunctionFromObject(namespaceName, functionName, scope);
} else {
functionObject = extractFunctionFromGlobalScope(functionName, scope);
}
return callFunctionAndCheckResults(cx, scope, (Function) functionObject);
}
private Object callFunctionAndCheckResults(Context cx, Scriptable scope, Function functionObject) {
Object functionArgs[] = {};
Function function = (Function) box;
return function.call(cx, scope, scope, functionArgs);
return functionObject.call(cx, scope, scope, functionArgs);
}
private Object extractFunctionFromGlobalScope(String functionName, Scriptable scope) {
Object functionObject;
functionObject = scope.get(functionName, scope);
assertTrue("Function " + functionName + " is not defined in global scope",
functionObject instanceof Function);
return functionObject;
}
private Object extractFunctionFromObject(String namespaceName, String functionName, Scriptable scope) {
Object functionObject;
NativeObject namespaceObject = RhinoUtils.extractObject(namespaceName, scope);
functionObject = namespaceObject.get(functionName, namespaceObject);
assertTrue("Function " + functionName + " is not defined in namespace " + namespaceName,
functionObject instanceof Function);
return functionObject;
}
}
@@ -0,0 +1,41 @@
package org.jetbrains.k2js.test;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.NativeObject;
import org.mozilla.javascript.Scriptable;
import java.util.Map;
import static org.junit.Assert.assertTrue;
/**
* @author Talanov Pavel
*/
public final class RhinoPropertyTypesChecker implements RhinoResultChecker {
final private String objectName;
final private Map<String, Class<? extends Scriptable>> propertyToType;
public RhinoPropertyTypesChecker(String objectName, Map<String, Class<? extends Scriptable>> propertyToType) {
this.objectName = objectName;
this.propertyToType = propertyToType;
}
@Override
public void runChecks(Context context, Scriptable scope) throws Exception {
NativeObject object = RhinoUtils.extractObject(objectName, scope);
verifyObjectHasExpectedPropertiesOfExpectedTypes(object, propertyToType);
}
private void verifyObjectHasExpectedPropertiesOfExpectedTypes
(NativeObject object, Map<String, Class<? extends Scriptable>> nameToClassMap) {
for (Map.Entry<String, Class<? extends Scriptable>> entry : nameToClassMap.entrySet()) {
String name = entry.getKey();
Class expectedClass = entry.getValue();
assertTrue(object + " must contain key " + name, object.containsKey(name));
assertTrue(object + "'s property " + name + " must be of type " + expectedClass,
expectedClass.isInstance(object.get(name)));
}
}
}
@@ -0,0 +1,26 @@
package org.jetbrains.k2js.test;
import org.junit.Test;
/**
* @author Talanov Pavel
*/
public class StringTest extends AbstractExpressionTest {
final private static String MAIN = "string/";
@Override
protected String mainDirectory() {
return MAIN;
}
@Test
public void stringConstant() throws Exception {
testFooBoxIsTrue("stringConstant.kt");
}
@Test
public void stringAssignment() throws Exception {
testFooBoxIsTrue("stringAssignment.kt");
}
}
@@ -5,7 +5,7 @@ import org.junit.Test;
/**
* @author Talanov Pavel
*/
public final class TraitTest extends AbstractClassTest {
public final class TraitTest extends IncludeLibraryTest {
final private static String MAIN = "trait/";
@@ -39,4 +39,15 @@ public final class TraitTest extends AbstractClassTest {
testFooBoxIsTrue("traitExtendsTrait.kt");
}
@Test
public void traitExtendsTwoTraits() throws Exception {
testFooBoxIsTrue("traitExtendsTwoTraits.kt");
}
@Test
public void funDelegation() throws Exception {
testFooBoxIsOk("funDelegation.jet");
}
}
@@ -1,7 +1,6 @@
package org.jetbrains.k2js.test;
import org.jetbrains.k2js.K2JSTranslator;
import org.junit.Before;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
@@ -19,45 +18,55 @@ public abstract class TranslationTest {
final private static String OUT = "out/";
final private String KOTLIN_JS_LIB = TEST_FILES + "kotlin_lib.js";
protected String testFilesDirectory;
protected String testCasesDirectory;
protected String outputDirectory;
@Before
public void setUpClass() {
testCasesDirectory = CASES;
outputDirectory = OUT;
testFilesDirectory = TEST_FILES + mainDirectory();
}
protected abstract String mainDirectory();
protected String kotlinLibraryPath() {
return KOTLIN_JS_LIB;
}
private String getOutputDirectory() {
return testFilesDirectory + outputDirectory;
private String casesDirectoryName() {
return CASES;
}
private String getInputDirectory() {
return testFilesDirectory + testCasesDirectory;
private String outDirectoryName() {
return OUT;
}
private String testFilesPath() {
return TEST_FILES + suiteDirectoryName() + mainDirectory();
}
protected String suiteDirectoryName() {
return "";
}
private String getOutputPath() {
return testFilesPath() + outDirectoryName();
}
private String getInputPath() {
return testFilesPath() + casesDirectoryName();
}
protected void testFunctionOutput(String filename, String namespaceName,
String functionName, Object expectedResult) throws Exception {
translateFile(filename);
runRhinoTest(generateFilenameList(getOutputFilePath(filename)),
new RhinoFunctionResultChecker(namespaceName, functionName, expectedResult));
}
private void translateFile(String filename) {
K2JSTranslator.Arguments args = new K2JSTranslator.Arguments();
args.src = getInputFilePath(filename);
args.outputDir = getOutputFilePath(filename);
K2JSTranslator.translate(args);
runRhinoTest(generateFilenameList(args.outputDir),
new RhinoFunctionResultChecker(namespaceName, functionName, expectedResult));
}
abstract protected List<String> generateFilenameList(String inputfile);
//TODO: refactor filename generation logic
private String getOutputFilePath(String filename) {
return getOutputDirectory() + convertToDotJsFile(filename);
return getOutputPath() + convertToDotJsFile(filename);
}
private String convertToDotJsFile(String filename) {
@@ -65,7 +74,11 @@ public abstract class TranslationTest {
}
private String getInputFilePath(String filename) {
return getInputDirectory() + filename;
return getInputPath() + filename;
}
protected String cases(String filename) {
return getInputFilePath(filename);
}
protected void runFileWithRhino(String inputFile, Context context, Scriptable scope) throws Exception {
@@ -87,4 +100,9 @@ public abstract class TranslationTest {
protected void testFooBoxIsTrue(String filename) throws Exception {
testFunctionOutput(filename, "foo", "box", true);
}
protected void testFooBoxIsOk(String filename) throws Exception {
testFunctionOutput(filename, "foo", "box", "OK");
}
}
@@ -0,0 +1,22 @@
package org.jetbrains.k2js.test;
/**
* @author Talanov Pavel
*/
public class TupleTest extends IncludeLibraryTest {
final private static String MAIN = "tuple/";
@Override
protected String mainDirectory() {
return MAIN;
}
//TODO: excluded because Tuples are not implemented
// @Test
// public void twoElements() throws Exception {
// testFooBoxIsTrue("twoElements.kt");
// }
}
@@ -0,0 +1,55 @@
package org.jetbrains.k2js.test;
import org.junit.Test;
/**
* @author Talanov Pavel
*/
public final class WhileTest extends AbstractExpressionTest {
private static final String MAIN = "while/";
protected String mainDirectory() {
return MAIN;
}
@Test
public void whileSimpleTest() throws Exception {
testFooBoxIsTrue("while.kt");
}
@Test
public void doWhileSimpleTest() throws Exception {
testFooBoxIsTrue("doWhile.kt");
}
@Test
public void doWhileExecutesAtLeastOnce() throws Exception {
testFooBoxIsTrue("doWhile2.kt");
}
@Test
public void whileDoesntExecuteEvenOnceIfConditionIsFalse() throws Exception {
testFooBoxIsTrue("while2.kt");
}
@Test
public void breakWhile() throws Exception {
testFooBoxIsTrue("breakWhile.kt");
}
@Test
public void breakDoWhile() throws Exception {
testFooBoxIsTrue("breakDoWhile.kt");
}
@Test
public void continueWhile() throws Exception {
testFooBoxIsTrue("continueWhile.kt");
}
@Test
public void continueDoWhile() throws Exception {
testFooBoxIsTrue("continueDoWhile.kt");
}
}
@@ -1,9 +0,0 @@
namespace foo
fun box() : Boolean {
val a = 2;
val b = 3;
var c = 4;
return (a < c)
}
@@ -0,0 +1,9 @@
namespace foo
fun box() : Boolean {
var sum = 0
val adder = {(a: Int) => sum += a }
adder(3)
adder(2)
return sum == 5
}
@@ -0,0 +1,9 @@
namespace foo
fun box() : String {
return apply( "OK", {(arg: String) => arg } )
}
fun apply(arg : String, f : fun (p:String) : String) : String {
return f(arg)
}
@@ -0,0 +1,9 @@
namespace foo
fun box() : String {
return if (apply( 5, {(arg: Int) => arg + 13 } ) == 18) "OK" else "fail"
}
fun apply(arg : Int, f : fun (p:Int) : Int) : Int {
return f(arg)
}
@@ -0,0 +1,8 @@
namespace foo
fun box() : Boolean {
var sum = 0
val addFive = {(a: Int) => a + 5 }
sum = addFive(sum)
return sum == 5
}
@@ -0,0 +1,10 @@
namespace foo
fun apply(f : fun(Int) : Int, t : Int) : Int {
return f(t)
}
fun box() : Boolean {
return apply({(a: Int) => a + 5 }, 3) == 8
}
@@ -0,0 +1,17 @@
namespace foo
var b = 0
fun loop(var times : Int) {
while(times > 0) {
val u : fun(value : Int) : Unit = {
b++
}
u(times--)
}
}
fun box() : Boolean {
loop(5)
return b == 5
}
@@ -0,0 +1,13 @@
namespace foo
fun box() : Boolean {
var i = 0
do {
if (i == 3) {
break;
}
++i;
} while ( i < 100)
return i == 3
}
@@ -0,0 +1,13 @@
namespace foo
fun box() : Boolean {
var i = 0
while ( i < 100) {
if (i == 3) {
break;
}
++i;
}
return i == 3
}
@@ -0,0 +1,15 @@
namespace foo
fun box() : Boolean {
var i = 0
var b = true
do {
++i;
if (i >= 1) {
continue;
}
b =false;
} while (i < 100)
return b
}
@@ -0,0 +1,15 @@
namespace foo
fun box() : Boolean {
var i = 0
var b = true
while (i < 100) {
++i;
if (i >= 1) {
continue;
}
b =false;
}
return b
}
@@ -0,0 +1,7 @@
var A = Class.create();
var B = Class.create(A);
var b = new B;
test = function() {
return (isType(b, A) && isType(b, B));
}
@@ -0,0 +1,24 @@
var A = Class.create();
var B = Class.create(A);
var b = new B;
var C = Class.create(B);
var c = new C;
var E = Class.create(A)
var e = new E;
test1 = function() {
b2 = b
return (isType(b, A) && isType(b, B));
}
test2 = function() {
return (isType(c, C) && isType(c, B) && isType(c, A) && (!isType(c, E)));
}
test3 = function() {
return isType(e, E) && !isType(e, B) && !isType(e, C) && isType(e, A)
}
test = function() {
return test1() && test2() && test3()
}
@@ -0,0 +1,8 @@
var A = Class.create();
var B = Class.create(A);
var C = Class.create();
var c = new C;
test = function() {
return ((!isType(c, A)) && !isType(c, B));
}
@@ -0,0 +1,6 @@
var A = Class.create();
var a = new A;
test = function() {
return isType(a, A);
}
@@ -0,0 +1,12 @@
foo = {};
(function(foo){
foo.Test = Trait.create({addFoo:function(s){
return s + 'FOO';
}
});
foo.ExtendedTest = Trait.create(foo.Test, {hooray:function(){
return 'hooray';
}
});
}
(foo));
+37 -4
View File
@@ -6,6 +6,17 @@ function $A(iterable) {
return results;
}
var isType = function(object, class) {
current = object.get_class();
while (current !== class) {
if (current === null) {
return false;
}
current = current.superclass;
}
return true;
}
var emptyFunction = function() {}
var Class = (function() {
@@ -32,10 +43,17 @@ var Class = (function() {
}
klass.addMethods(
{
get_class : function () {
return klass;
}
});
if (parent != null) {
klass.addMethods(
{
'super_init' : function () {
super_init : function () {
this.initializing = this.initializing.superclass;
this.initializing.prototype.initialize.apply(this, arguments)
}
@@ -66,8 +84,6 @@ var Class = (function() {
return function() { return ancestor[m].apply(this, arguments); };
})(property).wrap(method);
// value.valueOf = method.valueOf.bind(method);
// value.toString = method.toString.bind(method);
}
this.prototype[property] = value;
}
@@ -85,8 +101,25 @@ var Class = (function() {
var Trait = (function() {
function add(object, source) {
properties = Object.keys(source);
for (var i = 0, length = properties.length; i < length; i++) {
var property = properties[i];
var value = source[property];
object[property] = value;
}
return this;
}
function create() {
return new Class.create(arguments);
result = {}
for (var i = 0, length = arguments.length; i < length; i++)
{
add(result, arguments[i]);
}
return result;
}
return {
@@ -0,0 +1,17 @@
namespace foo
fun box() : Int {
val c = 3
val d = 5
var z = 0
when(c) {
is 5, is 3 => z++;
else => z = -1000;
}
when(d) {
is 5, is 3 => z++;
else => z = -1000;
}
return z
}
@@ -0,0 +1,15 @@
namespace foo
class A() {
}
fun box() : Boolean {
var a = 0
when(A()) {
is A => a++;
is A => a++;
else => a++;
}
return (a == 1)
}
@@ -0,0 +1,12 @@
namespace foo
class A() {
}
fun box() : Boolean {
when(A()) {
!is A => return false;
else => return true;
}
}
@@ -0,0 +1,10 @@
namespace foo
fun box() : Boolean {
var a = 4
when(a) {
!is 3 => a = 10;
!is 4 => a = 20;
}
return (a == 10)
}
@@ -0,0 +1,12 @@
namespace foo
class A() {
}
fun box() : Boolean {
when(A()) {
is A => return true;
else => return false;
}
}
@@ -0,0 +1,10 @@
namespace foo
fun box() : Boolean {
var a = 4
when(a) {
is 3 => a = 10;
is 4 => a = 20;
}
return (a == 20)
}
@@ -0,0 +1,25 @@
namespace foo
class A() {
}
class B() {
}
fun box() : Boolean {
var c : Int = 0
var a = A() : Any?
var b = null : Any?
when(a) {
is null => c = 10;
is B => c = 10000
is A => c = 20;
}
when(b) {
is null => c += 5
is B => c += 100
}
return (c == 25)
}
@@ -0,0 +1,13 @@
namespace foo
class A() {
fun doSomething() {
}
}
fun box() : Boolean {
var a : A? = null;
a?.doSomething()
return true;
}
@@ -0,0 +1,10 @@
namespace foo
class A() {
val x = 4
}
fun box() : Boolean {
var a : A? = null;
return (a?.x == null);
}
+388
View File
@@ -0,0 +1,388 @@
function $A(iterable) {
if (!iterable) return [];
if ('toArray' in Object(iterable)) return iterable.toArray();
var length = iterable.length || 0, results = new Array(length);
while (length--) results[length] = iterable[length];
return results;
}
var emptyFunction = function() {}
var Class = (function() {
var IS_DONTENUM_BUGGY = (function(){
for (var p in { toString: 1 }) {
if (p === 'toString') return false;
}
return true;
})();
function subclass() {};
function create() {
var parent = null, properties = $A(arguments);
if (Object.isFunction(properties[0]))
parent = properties.shift();
function klass() {
this.initialize.apply(this, arguments);
}
Object.extend(klass, Class.Methods);
klass.superclass = parent;
klass.subclasses = [];
if (parent) {
subclass.prototype = parent.prototype;
klass.prototype = new subclass;
parent.subclasses.push(klass);
}
for (var i = 0, length = properties.length; i < length; i++)
klass.addMethods(properties[i]);
if (!klass.prototype.initialize)
klass.prototype.initialize = emptyFunction;
klass.prototype.constructor = klass;
return klass;
}
function addMethods(source) {
var ancestor = this.superclass && this.superclass.prototype,
properties = Object.keys(source);
if (IS_DONTENUM_BUGGY) {
if (source.toString != Object.prototype.toString)
properties.push("toString");
if (source.valueOf != Object.prototype.valueOf)
properties.push("valueOf");
}
for (var i = 0, length = properties.length; i < length; i++) {
var property = properties[i], value = source[property];
if (ancestor && Object.isFunction(value) &&
value.argumentNames()[0] == "$super") {
var method = value;
value = (function(m) {
return function() { return ancestor[m].apply(this, arguments); };
})(property).wrap(method);
value.valueOf = method.valueOf.bind(method);
value.toString = method.toString.bind(method);
}
this.prototype[property] = value;
}
return this;
}
return {
create: create,
Methods: {
addMethods: addMethods
}
};
})();
var Trait = (function() {
function create() {
var traitClass = Class.create.apply(Class, arguments)
return new traitClass;
}
return {
create: create
};
})();
(function() {
var _toString = Object.prototype.toString,
NULL_TYPE = 'Null',
UNDEFINED_TYPE = 'Undefined',
BOOLEAN_TYPE = 'Boolean',
NUMBER_TYPE = 'Number',
STRING_TYPE = 'String',
OBJECT_TYPE = 'Object',
FUNCTION_CLASS = '[object Function]',
BOOLEAN_CLASS = '[object Boolean]',
NUMBER_CLASS = '[object Number]',
STRING_CLASS = '[object String]',
ARRAY_CLASS = '[object Array]',
DATE_CLASS = '[object Date]';
function Type(o) {
switch(o) {
case null: return NULL_TYPE;
case (void 0): return UNDEFINED_TYPE;
}
var type = typeof o;
switch(type) {
case 'boolean': return BOOLEAN_TYPE;
case 'number': return NUMBER_TYPE;
case 'string': return STRING_TYPE;
}
return OBJECT_TYPE;
}
function extend(destination, source) {
for (var property in source)
destination[property] = source[property];
return destination;
}
function inspect(object) {
try {
if (isUndefined(object)) return 'undefined';
if (object === null) return 'null';
return object.inspect ? object.inspect() : String(object);
} catch (e) {
if (e instanceof RangeError) return '...';
throw e;
}
}
function toJSON(value) {
return Str('', { '': value }, []);
}
function Str(key, holder, stack) {
var value = holder[key],
type = typeof value;
if (Type(value) === OBJECT_TYPE && typeof value.toJSON === 'function') {
value = value.toJSON(key);
}
var _class = _toString.call(value);
switch (_class) {
case NUMBER_CLASS:
case BOOLEAN_CLASS:
case STRING_CLASS:
value = value.valueOf();
}
switch (value) {
case null: return 'null';
case true: return 'true';
case false: return 'false';
}
type = typeof value;
switch (type) {
case 'string':
return value.inspect(true);
case 'number':
return isFinite(value) ? String(value) : 'null';
case 'object':
for (var i = 0, length = stack.length; i < length; i++) {
if (stack[i] === value) { throw new TypeError(); }
}
stack.push(value);
var partial = [];
if (_class === ARRAY_CLASS) {
for (var i = 0, length = value.length; i < length; i++) {
var str = Str(i, value, stack);
partial.push(typeof str === 'undefined' ? 'null' : str);
}
partial = '[' + partial.join(',') + ']';
} else {
var keys = Object.keys(value);
for (var i = 0, length = keys.length; i < length; i++) {
var key = keys[i], str = Str(key, value, stack);
if (typeof str !== "undefined") {
partial.push(key.inspect(true)+ ':' + str);
}
}
partial = '{' + partial.join(',') + '}';
}
stack.pop();
return partial;
}
}
function stringify(object) {
return JSON.stringify(object);
}
function toQueryString(object) {
return $H(object).toQueryString();
}
function toHTML(object) {
return object && object.toHTML ? object.toHTML() : String.interpret(object);
}
function keys(object) {
if (Type(object) !== OBJECT_TYPE) { throw new TypeError(); }
var results = [];
for (var property in object) {
if (object.hasOwnProperty(property)) {
results.push(property);
}
}
return results;
}
function values(object) {
var results = [];
for (var property in object)
results.push(object[property]);
return results;
}
function clone(object) {
return extend({ }, object);
}
function isElement(object) {
return !!(object && object.nodeType == 1);
}
function isArray(object) {
return _toString.call(object) === ARRAY_CLASS;
}
var hasNativeIsArray = (typeof Array.isArray == 'function')
&& Array.isArray([]) && !Array.isArray({});
if (hasNativeIsArray) {
isArray = Array.isArray;
}
function isHash(object) {
return object instanceof Hash;
}
function isFunction(object) {
return _toString.call(object) === FUNCTION_CLASS;
}
function isString(object) {
return _toString.call(object) === STRING_CLASS;
}
function isNumber(object) {
return _toString.call(object) === NUMBER_CLASS;
}
function isDate(object) {
return _toString.call(object) === DATE_CLASS;
}
function isUndefined(object) {
return typeof object === "undefined";
}
extend(Object, {
extend: extend,
inspect: inspect,
toQueryString: toQueryString,
toHTML: toHTML,
keys: Object.keys || keys,
values: values,
clone: clone,
isElement: isElement,
isArray: isArray,
isHash: isHash,
isFunction: isFunction,
isString: isString,
isNumber: isNumber,
isDate: isDate,
isUndefined: isUndefined
});
})();
Object.extend(Function.prototype, (function() {
var slice = Array.prototype.slice;
function update(array, args) {
var arrayLength = array.length, length = args.length;
while (length--) array[arrayLength + length] = args[length];
return array;
}
function merge(array, args) {
array = slice.call(array, 0);
return update(array, args);
}
function argumentNames() {
var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
.replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
.replace(/\s+/g, '').split(',');
return names.length == 1 && !names[0] ? [] : names;
}
function bind(context) {
if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
var __method = this, args = slice.call(arguments, 1);
return function() {
var a = merge(args, arguments);
return __method.apply(context, a);
}
}
function bindAsEventListener(context) {
var __method = this, args = slice.call(arguments, 1);
return function(event) {
var a = update([event || window.event], args);
return __method.apply(context, a);
}
}
function curry() {
if (!arguments.length) return this;
var __method = this, args = slice.call(arguments, 0);
return function() {
var a = merge(args, arguments);
return __method.apply(this, a);
}
}
function delay(timeout) {
var __method = this, args = slice.call(arguments, 1);
timeout = timeout * 1000;
return window.setTimeout(function() {
return __method.apply(__method, args);
}, timeout);
}
function defer() {
var args = update([0.01], arguments);
return this.delay.apply(this, args);
}
function wrap(wrapper) {
var __method = this;
return function() {
var a = update([__method.bind(this)], arguments);
return wrapper.apply(this, a);
}
}
function methodize() {
if (this._methodized) return this._methodized;
var __method = this;
return this._methodized = function() {
var a = update([this], arguments);
return __method.apply(null, a);
};
}
return {
argumentNames: argumentNames,
bind: bind,
bindAsEventListener: bindAsEventListener,
curry: curry,
delay: delay,
defer: defer,
wrap: wrap,
methodize: methodize
}
})());
@@ -0,0 +1,7 @@
namespace foo
class A() {
}
fun box() = (A() is A)
@@ -0,0 +1,11 @@
namespace foo
open class A() {
}
class B() : A() {
}
fun box() = (A() !is B)
@@ -0,0 +1,19 @@
namespace foo
open class Base() {
fun n(n : Int) : Int = n + 1
}
trait Abstract {}
class Derived1() : Base(), Abstract {}
class Derived2() : Abstract, Base() {}
fun test(s : Base) : Boolean = s.n(238) == 239
fun box() : String {
if (!test(Base())) return "Fail #1"
if (!test(Derived1())) return "Fail #2"
if (!test(Derived2())) return "Fail #3"
return "OK"
}
@@ -0,0 +1,25 @@
namespace foo
trait A {
fun addFoo(s:String) : String {
return s + "FOO"
}
}
trait B {
fun hooray() : String {
return "hooray"
}
}
trait AD : A, B {
}
class Test() : AD {
fun eval() : String {
return addFoo(hooray());
}
}
fun box() = (Test().eval() == "hoorayFOO")
@@ -0,0 +1,6 @@
namespace foo
fun box() : Boolean {
val a : (Int, Int) = (1, 2)
return (a._1 == 1)
}