Help at rigth part
This commit is contained in:
Generated
+611
-356
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
-4
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+5
-5
@@ -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);
|
||||
}
|
||||
|
||||
+2
-2
@@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -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));
|
||||
@@ -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);
|
||||
}
|
||||
Vendored
+388
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user