Very big code migration started. Still in progress. Tests fail.
This commit is contained in:
Generated
+458
-662
File diff suppressed because it is too large
Load Diff
@@ -7,47 +7,66 @@ import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
|
||||
//TODO: code gets duplicated
|
||||
public class Aliaser {
|
||||
|
||||
public static Aliaser newInstance() {
|
||||
return new Aliaser();
|
||||
}
|
||||
|
||||
//TODO: rename
|
||||
@NotNull
|
||||
private final Map<DeclarationDescriptor, JsName> aliasesForDescriptors = new HashMap<DeclarationDescriptor, JsName>();
|
||||
@NotNull
|
||||
private final Stack<JsName> thisAliases = new Stack<JsName>();
|
||||
private final Map<DeclarationDescriptor, JsName> aliasesForThis = new HashMap<DeclarationDescriptor, JsName>();
|
||||
@NotNull
|
||||
private final Map<DeclarationDescriptor, JsName> aliasesForReceiver = new HashMap<DeclarationDescriptor, JsName>();
|
||||
|
||||
private Aliaser() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsNameRef getAliasForThis() {
|
||||
assert !thisAliases.empty() : "No alias. Use hasAliasForThis function to check.";
|
||||
return thisAliases.peek().makeRef();
|
||||
public JsNameRef getAliasForThis(@NotNull DeclarationDescriptor descriptor) {
|
||||
JsName aliasName = aliasesForThis.get(descriptor.getOriginal());
|
||||
assert aliasName != null : "This " + descriptor.getOriginal() + " doesn't have an alias.";
|
||||
return aliasName.makeRef();
|
||||
}
|
||||
|
||||
public void setAliasForThis(@NotNull JsName alias) {
|
||||
thisAliases.push(alias);
|
||||
public void setAliasForThis(@NotNull DeclarationDescriptor descriptor, @NotNull JsName alias) {
|
||||
aliasesForThis.put(descriptor.getOriginal(), alias);
|
||||
}
|
||||
|
||||
//NOTE: here we are passing alias to check that they are set and removed in consistent order.
|
||||
public void removeAliasForThis(@NotNull JsName aliasToRemove) {
|
||||
assert !thisAliases.empty() : "Error: removing alias, when it is not set.";
|
||||
JsName lastAlias = thisAliases.pop();
|
||||
assert lastAlias.equals(aliasToRemove) : "Error: inconsistent alias removing.";
|
||||
public void removeAliasForThis(@NotNull DeclarationDescriptor descriptor) {
|
||||
JsName removed = aliasesForThis.remove(descriptor.getOriginal());
|
||||
assert removed != null;
|
||||
}
|
||||
|
||||
public boolean hasAliasForThis() {
|
||||
return (!thisAliases.empty());
|
||||
public boolean hasAliasForThis(@NotNull DeclarationDescriptor descriptor) {
|
||||
return (aliasesForThis.containsKey(descriptor.getOriginal()));
|
||||
}
|
||||
|
||||
public boolean hasAliasForDeclaration(@NotNull DeclarationDescriptor declaration) {
|
||||
return aliasesForDescriptors.containsKey(declaration.getOriginal());
|
||||
@NotNull
|
||||
public JsNameRef getAliasForReceiver(@NotNull DeclarationDescriptor descriptor) {
|
||||
JsName aliasName = aliasesForReceiver.get(descriptor.getOriginal());
|
||||
assert aliasName != null : "This descriptor doesn't have an alias.";
|
||||
return aliasName.makeRef();
|
||||
}
|
||||
|
||||
public void setAliasForReceiver(@NotNull DeclarationDescriptor descriptor, @NotNull JsName alias) {
|
||||
aliasesForReceiver.put(descriptor.getOriginal(), alias);
|
||||
}
|
||||
|
||||
public void removeAliasForReceiver(@NotNull DeclarationDescriptor descriptor) {
|
||||
JsName removed = aliasesForReceiver.remove(descriptor.getOriginal());
|
||||
assert removed != null;
|
||||
}
|
||||
|
||||
public boolean hasAliasForReceiver(@NotNull DeclarationDescriptor descriptor) {
|
||||
return (aliasesForReceiver.containsKey(descriptor.getOriginal()));
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
public JsName getAliasForDeclaration(@NotNull DeclarationDescriptor declaration) {
|
||||
JsName alias = aliasesForDescriptors.get(declaration.getOriginal());
|
||||
@@ -64,4 +83,10 @@ public class Aliaser {
|
||||
assert (hasAliasForDeclaration(declaration.getOriginal())) : "This declaration does not has an alias!";
|
||||
aliasesForDescriptors.remove(declaration.getOriginal());
|
||||
}
|
||||
|
||||
public boolean hasAliasForDeclaration(@NotNull DeclarationDescriptor declaration) {
|
||||
return aliasesForDescriptors.containsKey(declaration.getOriginal());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -32,11 +32,44 @@ public final class StandardClasses {
|
||||
declareRange(standardClasses);
|
||||
declareString(standardClasses);
|
||||
declareJavaArrayList(standardClasses);
|
||||
declareJavaHasMap(standardClasses);
|
||||
declareJavaStringBuilder(standardClasses);
|
||||
declareTopLevelFunctions(standardClasses);
|
||||
declareJavaCollection(standardClasses);
|
||||
declareMap(standardClasses);
|
||||
declareInteger(standardClasses);
|
||||
return standardClasses;
|
||||
}
|
||||
|
||||
private static void declareMap(@NotNull StandardClasses standardClasses) {
|
||||
String hashMapFQName = "java.util.Map";
|
||||
standardClasses.declareStandardTopLevelObject(hashMapFQName, "Map");
|
||||
standardClasses.declareStandardInnerDeclaration(hashMapFQName, "<init>", "HashMap");
|
||||
declareMethods(standardClasses, hashMapFQName, "size", "put", "get",
|
||||
"isEmpty", "remove", "addAll", "clear", "keySet");
|
||||
}
|
||||
|
||||
private static void declareJavaCollection(@NotNull StandardClasses standardClasses) {
|
||||
String collection = "java.util.Collection";
|
||||
standardClasses.declareStandardTopLevelObject(collection, "Collection");
|
||||
declareMethods(standardClasses, collection, "iterator");
|
||||
}
|
||||
|
||||
private static void declareJavaStringBuilder(@NotNull StandardClasses standardClasses) {
|
||||
String stringBuilderFQName = "java.util.StringBuilder";
|
||||
standardClasses.declareStandardTopLevelObject(stringBuilderFQName, "StringBuilder");
|
||||
standardClasses.declareStandardInnerDeclaration(stringBuilderFQName, "<init>", "StringBuilder");
|
||||
declareMethods(standardClasses, stringBuilderFQName, "append", "toString");
|
||||
}
|
||||
|
||||
private static void declareJavaHasMap(@NotNull StandardClasses standardClasses) {
|
||||
String hashMapFQName = "java.util.HashMap";
|
||||
standardClasses.declareStandardTopLevelObject(hashMapFQName, "HashMap");
|
||||
standardClasses.declareStandardInnerDeclaration(hashMapFQName, "<init>", "HashMap");
|
||||
declareMethods(standardClasses, hashMapFQName, "size", "put", "get",
|
||||
"isEmpty", "remove", "addAll", "clear", "keySet");
|
||||
}
|
||||
|
||||
//TODO: refactor
|
||||
private static void declareTopLevelFunctions(@NotNull StandardClasses standardClasses) {
|
||||
String parseIntFQName = "js.parseInt";
|
||||
|
||||
@@ -12,6 +12,7 @@ import org.jetbrains.jet.lang.psi.JetPropertyAccessor;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.k2js.translate.intrinsic.Intrinsics;
|
||||
import org.jetbrains.k2js.translate.utils.BindingUtils;
|
||||
import org.jetbrains.k2js.translate.utils.TranslationUtils;
|
||||
|
||||
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getFQName;
|
||||
|
||||
@@ -165,14 +166,15 @@ public final class TranslationContext {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public TemporaryVariable newAliasForThis() {
|
||||
TemporaryVariable aliasForThis = dynamicContext.declareTemporary(new JsThisRef());
|
||||
aliaser().setAliasForThis(aliasForThis.name());
|
||||
public TemporaryVariable newAliasForThis(@NotNull DeclarationDescriptor descriptor) {
|
||||
JsExpression thisQualifier = TranslationUtils.getThisQualifier(this, descriptor);
|
||||
TemporaryVariable aliasForThis = dynamicContext.declareTemporary(thisQualifier);
|
||||
aliaser().setAliasForThis(descriptor, aliasForThis.name());
|
||||
return aliasForThis;
|
||||
}
|
||||
|
||||
public void removeAliasForThis(@NotNull JsName aliasToRemove) {
|
||||
aliaser().removeAliasForThis(aliasToRemove);
|
||||
public void removeAliasForThis(@NotNull DeclarationDescriptor descriptor) {
|
||||
aliaser().removeAliasForThis(descriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -15,7 +15,7 @@ import java.util.List;
|
||||
/**
|
||||
* @author Pavel.Talanov
|
||||
*/
|
||||
//TODO: rework translator to translate everything in the namespace not only in one file
|
||||
//TODO: rework translator to translateAsLocalNameReference everything in the namespace not only in one file
|
||||
// TEST IT
|
||||
public final class NamespaceTranslator extends AbstractTranslator {
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.google.dart.compiler.backend.js.ast.*;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||
@@ -23,6 +24,7 @@ import org.jetbrains.k2js.translate.utils.BindingUtils;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getCompileTimeValue;
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForReferenceExpression;
|
||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.notNullCheck;
|
||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateInitializerForProperty;
|
||||
|
||||
@@ -375,8 +377,10 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
|
||||
@NotNull
|
||||
public JsNode visitThisExpression(@NotNull JetThisExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
if (context.aliaser().hasAliasForThis()) {
|
||||
return context.aliaser().getAliasForThis();
|
||||
DeclarationDescriptor descriptor =
|
||||
getDescriptorForReferenceExpression(context.bindingContext(), expression.getInstanceReference());
|
||||
if (context.aliaser().hasAliasForThis(descriptor)) {
|
||||
return context.aliaser().getAliasForThis(descriptor);
|
||||
}
|
||||
return new JsThisRef();
|
||||
}
|
||||
|
||||
@@ -3,9 +3,13 @@ package org.jetbrains.k2js.translate.expression;
|
||||
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.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.Modality;
|
||||
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.types.JetStandardClasses;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.k2js.translate.context.TemporaryVariable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
@@ -16,6 +20,8 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptor;
|
||||
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.getExpectedReceiverDescriptor;
|
||||
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.getExpectedThisDescriptor;
|
||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.functionWithScope;
|
||||
|
||||
|
||||
@@ -64,11 +70,17 @@ public final class FunctionTranslator extends AbstractTranslator {
|
||||
return new JsPropertyInitializer(functionName.makeRef(), function);
|
||||
}
|
||||
|
||||
|
||||
//TODO: refactor
|
||||
@NotNull
|
||||
public JsExpression translateAsLiteral() {
|
||||
TemporaryVariable aliasForThis = context().newAliasForThis();
|
||||
DeclarationDescriptor expectedThisDescriptor = getExpectedThisDescriptor(descriptor);
|
||||
if (expectedThisDescriptor == null) {
|
||||
return generateFunctionObject();
|
||||
}
|
||||
TemporaryVariable aliasForThis = context().newAliasForThis(expectedThisDescriptor);
|
||||
JsFunction function = generateFunctionObject();
|
||||
context().removeAliasForThis(aliasForThis.name());
|
||||
context().removeAliasForThis(expectedThisDescriptor);
|
||||
return AstUtil.newSequence(aliasForThis.assignmentExpression(), function);
|
||||
}
|
||||
|
||||
@@ -83,8 +95,7 @@ public final class FunctionTranslator extends AbstractTranslator {
|
||||
|
||||
private void restoreContext() {
|
||||
if (isExtensionFunction()) {
|
||||
JsName receiverAlias = functionBodyContext.jsScope().findExistingName(RECEIVER_PARAMETER_NAME);
|
||||
functionBodyContext.removeAliasForThis(receiverAlias);
|
||||
functionBodyContext.removeAliasForThis(getExpectedReceiverDescriptor(descriptor));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,21 +111,20 @@ public final class FunctionTranslator extends AbstractTranslator {
|
||||
throw new AssertionError("Unsupported type of functionDeclaration.");
|
||||
}
|
||||
|
||||
private boolean isLiteral() {
|
||||
return functionDeclaration instanceof JetFunctionLiteralExpression;
|
||||
}
|
||||
|
||||
private boolean isDeclaration() {
|
||||
return (functionDeclaration instanceof JetNamedFunction) ||
|
||||
(functionDeclaration instanceof JetPropertyAccessor);
|
||||
}
|
||||
|
||||
private void translateBody() {
|
||||
JetExpression jetBodyExpression = functionDeclaration.getBodyExpression();
|
||||
//TODO decide if there are cases where this assert is illegal
|
||||
assert jetBodyExpression != null : "Function without body not supported";
|
||||
if (jetBodyExpression == null) {
|
||||
assert descriptor.getModality().equals(Modality.ABSTRACT);
|
||||
return;
|
||||
}
|
||||
JsNode realBody = Translation.translateExpression(jetBodyExpression, functionBodyContext);
|
||||
functionBody.addStatement(wrapWithReturnIfNeeded(realBody, !functionDeclaration.hasBlockBody()));
|
||||
functionBody.addStatement(wrapWithReturnIfNeeded(realBody, mustAddReturnToGeneratedFunctionBody()));
|
||||
}
|
||||
|
||||
private boolean mustAddReturnToGeneratedFunctionBody() {
|
||||
JetType functionReturnType = descriptor.getReturnType();
|
||||
assert functionReturnType != null : "Function return typed type must be resolved.";
|
||||
return (!functionDeclaration.hasBlockBody()) && (!JetStandardClasses.isUnit(functionReturnType));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -173,14 +183,24 @@ public final class FunctionTranslator extends AbstractTranslator {
|
||||
|
||||
private void mayBeAddThisParameterForExtensionFunction(@NotNull List<JsParameter> jsParameters) {
|
||||
if (isExtensionFunction()) {
|
||||
//TODO: dont do this
|
||||
JsName receiver = functionBodyContext.jsScope().declareName(RECEIVER_PARAMETER_NAME);
|
||||
context().aliaser().setAliasForThis(receiver);
|
||||
DeclarationDescriptor expectedReceiverDescriptor = getExpectedReceiverDescriptor(descriptor);
|
||||
context().aliaser().setAliasForReceiver(expectedReceiverDescriptor, receiver);
|
||||
jsParameters.add(new JsParameter(receiver));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isExtensionFunction() {
|
||||
FunctionDescriptor functionDescriptor = getFunctionDescriptor(context().bindingContext(), functionDeclaration);
|
||||
return DescriptorUtils.isExtensionFunction(functionDescriptor);
|
||||
return DescriptorUtils.isExtensionFunction(descriptor);
|
||||
}
|
||||
|
||||
private boolean isLiteral() {
|
||||
return functionDeclaration instanceof JetFunctionLiteralExpression;
|
||||
}
|
||||
|
||||
private boolean isDeclaration() {
|
||||
return (functionDeclaration instanceof JetNamedFunction) ||
|
||||
(functionDeclaration instanceof JetPropertyAccessor);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ public final class ClassInitializerTranslator extends AbstractInitializerTransla
|
||||
@NotNull
|
||||
protected JsFunction generateInitializerFunction() {
|
||||
JsFunction result = functionWithScope(initializerMethodScope);
|
||||
//NOTE: that while we translate constructor parameters we also add property initializer statements
|
||||
//NOTE: that while we translateAsLocalNameReference constructor parameters we also add property initializer statements
|
||||
// for properties declared as constructor parameters
|
||||
result.setParameters(translatePrimaryConstructorParameters());
|
||||
mayBeAddCallToSuperMethod();
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.DefaultValueArgument;
|
||||
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.calls.ResolvedCallImpl;
|
||||
import org.jetbrains.jet.lang.resolve.calls.ResolvedValueArgument;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
@@ -31,6 +32,7 @@ import static org.jetbrains.k2js.translate.utils.TranslationUtils.*;
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
//TODO: write tests on calling backing fields as functions
|
||||
//TODO: constructor receives too many parameters
|
||||
public final class CallTranslator extends AbstractTranslator {
|
||||
|
||||
private static final class Builder {
|
||||
@@ -46,10 +48,9 @@ public final class CallTranslator extends AbstractTranslator {
|
||||
private CallTranslator buildFromUnary(@NotNull JetUnaryExpression unaryExpression) {
|
||||
JsExpression receiver = TranslationUtils.translateBaseExpression(context, unaryExpression);
|
||||
List<JsExpression> arguments = Collections.emptyList();
|
||||
DeclarationDescriptor descriptor = getDescriptorForReferenceExpression
|
||||
(context.bindingContext(), unaryExpression.getOperationReference());
|
||||
assert descriptor instanceof FunctionDescriptor;
|
||||
return new CallTranslator(receiver, arguments, (FunctionDescriptor) descriptor, context);
|
||||
ResolvedCall<?> resolvedCall =
|
||||
getResolvedCall(context.bindingContext(), unaryExpression.getOperationReference());
|
||||
return new CallTranslator(receiver, arguments, resolvedCall, null, context);
|
||||
}
|
||||
|
||||
//TODO: method too long
|
||||
@@ -70,11 +71,9 @@ public final class CallTranslator extends AbstractTranslator {
|
||||
arguments = Arrays.asList(rightExpression);
|
||||
}
|
||||
|
||||
DeclarationDescriptor descriptor = getDescriptorForReferenceExpression
|
||||
(context.bindingContext(), binaryExpression.getOperationReference());
|
||||
assert descriptor instanceof FunctionDescriptor;
|
||||
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
|
||||
return new CallTranslator(receiver, arguments, functionDescriptor, context);
|
||||
ResolvedCall<?> resolvedCall =
|
||||
getResolvedCall(context.bindingContext(), binaryExpression.getOperationReference());
|
||||
return new CallTranslator(receiver, arguments, resolvedCall, null, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -84,19 +83,16 @@ public final class CallTranslator extends AbstractTranslator {
|
||||
JetExpression selectorExpression = dotExpression.getSelectorExpression();
|
||||
assert selectorExpression instanceof JetCallExpression;
|
||||
JetCallExpression callExpression = (JetCallExpression) selectorExpression;
|
||||
FunctionDescriptor descriptor =
|
||||
getFunctionDescriptorForCallExpression(context.bindingContext(), callExpression);
|
||||
ResolvedCall<?> resolvedCall = getResolvedCallForCallExpression(context.bindingContext(), callExpression);
|
||||
List<JsExpression> arguments = translateArgumentsForCallExpression(callExpression, context);
|
||||
return new CallTranslator(receiver, arguments, descriptor, context);
|
||||
return new CallTranslator(receiver, arguments, resolvedCall, null, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private CallTranslator buildFromCallExpression(@NotNull JetCallExpression callExpression) {
|
||||
FunctionDescriptor descriptor =
|
||||
getFunctionDescriptorForCallExpression(context.bindingContext(), callExpression);
|
||||
JsExpression receiver = getImplicitReceiver(context, descriptor);
|
||||
ResolvedCall<?> resolvedCall = getResolvedCallForCallExpression(context.bindingContext(), callExpression);
|
||||
List<JsExpression> arguments = translateArgumentsForCallExpression(callExpression, context);
|
||||
return new CallTranslator(receiver, arguments, descriptor, context);
|
||||
return new CallTranslator(null, arguments, resolvedCall, null, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -126,16 +122,28 @@ public final class CallTranslator extends AbstractTranslator {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression translate(@Nullable JsExpression receiver, @NotNull CallableDescriptor functionDescriptor,
|
||||
public static JsExpression translate(@Nullable JsExpression receiver,
|
||||
@NotNull CallableDescriptor descriptor,
|
||||
@NotNull TranslationContext context) {
|
||||
return translate(receiver, Collections.<JsExpression>emptyList(), functionDescriptor, context);
|
||||
//TODO: HACK!
|
||||
return translate(receiver, Collections.<JsExpression>emptyList(),
|
||||
ResolvedCallImpl.create(descriptor), null, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression translate(@Nullable JsExpression receiver,
|
||||
@NotNull ResolvedCall<?> resolvedCall,
|
||||
@Nullable CallableDescriptor descriptorToCall,
|
||||
@NotNull TranslationContext context) {
|
||||
return translate(receiver, Collections.<JsExpression>emptyList(), resolvedCall, descriptorToCall, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression translate(@Nullable JsExpression receiver, @NotNull List<JsExpression> arguments,
|
||||
@NotNull CallableDescriptor functionDescriptor,
|
||||
@NotNull ResolvedCall<?> resolvedCall,
|
||||
@Nullable CallableDescriptor descriptorToCall,
|
||||
@NotNull TranslationContext context) {
|
||||
return (new CallTranslator(receiver, arguments, functionDescriptor, context)).translate();
|
||||
return (new CallTranslator(receiver, arguments, resolvedCall, descriptorToCall, context)).translate();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -184,15 +192,25 @@ public final class CallTranslator extends AbstractTranslator {
|
||||
@NotNull
|
||||
private final List<JsExpression> arguments;
|
||||
|
||||
@NotNull
|
||||
private final ResolvedCall<?> resolvedCall;
|
||||
|
||||
@NotNull
|
||||
private final CallableDescriptor descriptor;
|
||||
|
||||
private CallTranslator(@Nullable JsExpression receiver, @NotNull List<JsExpression> arguments,
|
||||
@NotNull CallableDescriptor descriptor, @NotNull TranslationContext context) {
|
||||
@NotNull ResolvedCall<? extends CallableDescriptor> resolvedCall,
|
||||
@Nullable CallableDescriptor descriptorToCall,
|
||||
@NotNull TranslationContext context) {
|
||||
super(context);
|
||||
this.receiver = receiver;
|
||||
this.arguments = arguments;
|
||||
this.descriptor = descriptor;
|
||||
this.resolvedCall = resolvedCall;
|
||||
if (descriptorToCall != null) {
|
||||
this.descriptor = descriptorToCall;
|
||||
} else {
|
||||
this.descriptor = resolvedCall.getCandidateDescriptor().getOriginal();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -218,7 +236,7 @@ public final class CallTranslator extends AbstractTranslator {
|
||||
}
|
||||
|
||||
private boolean isExtensionFunction() {
|
||||
return DescriptorUtils.isExtensionFunction(descriptor);
|
||||
return resolvedCall.getReceiverArgument().exists();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -258,13 +276,14 @@ public final class CallTranslator extends AbstractTranslator {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression getterCall(PropertyDescriptor variableDescriptor) {
|
||||
return PropertyAccessTranslator.translateAsPropertyGetterCall(variableDescriptor, context());
|
||||
private JsExpression getterCall(@NotNull PropertyDescriptor variableDescriptor) {
|
||||
return PropertyAccessTranslator.translateAsPropertyGetterCall(variableDescriptor, resolvedCall, context());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression qualifiedMethodReference(@NotNull DeclarationDescriptor descriptor) {
|
||||
JsExpression methodReference = ReferenceTranslator.translateReference(descriptor, context());
|
||||
JsExpression methodReference = ReferenceTranslator.translateAsLocalNameReference(descriptor, context());
|
||||
//TODO: should insert checks for IMPLICIT RECEIVER
|
||||
if (isExtensionFunction()) {
|
||||
return extensionFunctionReference(methodReference);
|
||||
} else if (receiver != null) {
|
||||
@@ -275,7 +294,7 @@ public final class CallTranslator extends AbstractTranslator {
|
||||
|
||||
@NotNull
|
||||
private JsExpression extensionFunctionReference(@NotNull JsExpression methodReference) {
|
||||
JsExpression qualifier = TranslationUtils.getExtensionFunctionImplicitReceiver(context(), descriptor);
|
||||
JsExpression qualifier = TranslationUtils.getImplicitReceiver(context(), resolvedCall.getReceiverArgument());
|
||||
if (qualifier != null) {
|
||||
AstUtil.setQualifier(methodReference, qualifier);
|
||||
}
|
||||
@@ -284,7 +303,8 @@ public final class CallTranslator extends AbstractTranslator {
|
||||
|
||||
@NotNull
|
||||
private JsExpression constructorCall() {
|
||||
JsNew constructorCall = new JsNew(qualifiedMethodReference(descriptor));
|
||||
JsExpression constructorReference = ReferenceTranslator.translateAsFQReference(descriptor, context());
|
||||
JsNew constructorCall = new JsNew(constructorReference);
|
||||
constructorCall.setArguments(arguments);
|
||||
return constructorCall;
|
||||
}
|
||||
|
||||
+22
-36
@@ -7,21 +7,20 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.PropertyGetterDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.PropertySetterDescriptor;
|
||||
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.calls.ResolvedCall;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.Translation;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForReferenceExpression;
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getResolvedCall;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getSelectorAsSimpleName;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.isBackingFieldReference;
|
||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.backingFieldReference;
|
||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.getImplicitReceiver;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
@@ -42,8 +41,9 @@ public final class PropertyAccessTranslator extends AccessTranslator {
|
||||
|
||||
@NotNull
|
||||
public static JsExpression translateAsPropertyGetterCall(@NotNull PropertyDescriptor descriptor,
|
||||
@NotNull ResolvedCall<?> resolvedCall,
|
||||
@NotNull TranslationContext context) {
|
||||
return (newInstance(descriptor, context))
|
||||
return (newInstance(descriptor, resolvedCall, context))
|
||||
.translateAsGet();
|
||||
}
|
||||
|
||||
@@ -56,8 +56,9 @@ public final class PropertyAccessTranslator extends AccessTranslator {
|
||||
|
||||
@NotNull
|
||||
private static PropertyAccessTranslator newInstance(@NotNull PropertyDescriptor descriptor,
|
||||
@NotNull ResolvedCall<?> resolvedCall,
|
||||
@NotNull TranslationContext context) {
|
||||
return new PropertyAccessTranslator(descriptor, null, false, context);
|
||||
return new PropertyAccessTranslator(descriptor, null, false, resolvedCall, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -65,16 +66,21 @@ public final class PropertyAccessTranslator extends AccessTranslator {
|
||||
@NotNull TranslationContext context) {
|
||||
JetExpression qualifier = expression.getReceiverExpression();
|
||||
JetSimpleNameExpression selector = getNotNullSelector(expression);
|
||||
ResolvedCall<?> resolvedCall = getResolvedCall(context.bindingContext(), selector);
|
||||
PropertyDescriptor propertyDescriptor = getPropertyDescriptor(selector, context);
|
||||
boolean isBackingFieldAccess = isBackingFieldReference(selector);
|
||||
return new PropertyAccessTranslator(propertyDescriptor, qualifier, isBackingFieldAccess, context);
|
||||
JsExpression jsQualifier = Translation.translateAsExpression(qualifier, context);
|
||||
return new PropertyAccessTranslator(propertyDescriptor, jsQualifier,
|
||||
isBackingFieldAccess, resolvedCall, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static PropertyAccessTranslator newInstance(@NotNull JetSimpleNameExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
PropertyDescriptor propertyDescriptor = getPropertyDescriptor(expression, context);
|
||||
return new PropertyAccessTranslator(propertyDescriptor, null, isBackingFieldReference(expression), context);
|
||||
ResolvedCall<?> resolvedCall = getResolvedCall(context.bindingContext(), expression);
|
||||
return new PropertyAccessTranslator(propertyDescriptor, null,
|
||||
isBackingFieldReference(expression), resolvedCall, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -121,19 +127,23 @@ public final class PropertyAccessTranslator extends AccessTranslator {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private final JetExpression qualifier;
|
||||
private final JsExpression qualifier;
|
||||
@NotNull
|
||||
private final PropertyDescriptor propertyDescriptor;
|
||||
private final boolean isBackingFieldAccess;
|
||||
@NotNull
|
||||
ResolvedCall<?> resolvedCall;
|
||||
|
||||
private PropertyAccessTranslator(@NotNull PropertyDescriptor descriptor,
|
||||
@Nullable JetExpression qualifier,
|
||||
@Nullable JsExpression qualifier,
|
||||
boolean isBackingFieldAccess,
|
||||
@NotNull ResolvedCall<?> resolvedCall,
|
||||
@NotNull TranslationContext context) {
|
||||
super(context);
|
||||
this.qualifier = qualifier;
|
||||
this.propertyDescriptor = descriptor.getOriginal();
|
||||
this.isBackingFieldAccess = isBackingFieldAccess;
|
||||
this.resolvedCall = resolvedCall;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -153,7 +163,7 @@ public final class PropertyAccessTranslator extends AccessTranslator {
|
||||
|
||||
@NotNull
|
||||
private JsExpression getterCall() {
|
||||
return CallTranslator.translate(translateQualifier(), getGetterDescriptor(), context());
|
||||
return CallTranslator.translate(qualifier, resolvedCall, propertyDescriptor.getGetter(), context());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -168,7 +178,8 @@ public final class PropertyAccessTranslator extends AccessTranslator {
|
||||
|
||||
@NotNull
|
||||
private JsExpression setterCall(@NotNull JsExpression toSetTo) {
|
||||
return CallTranslator.translate(translateQualifier(), Arrays.asList(toSetTo), getSetterDescriptor(), context());
|
||||
return CallTranslator.translate(qualifier, Arrays.asList(toSetTo),
|
||||
resolvedCall, propertyDescriptor.getSetter(), context());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -177,35 +188,10 @@ public final class PropertyAccessTranslator extends AccessTranslator {
|
||||
return AstUtil.newAssignment(backingFieldReference, toSetTo);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression translateQualifier() {
|
||||
if (qualifier != null) {
|
||||
return Translation.translateAsExpression(qualifier, context());
|
||||
}
|
||||
JsExpression implicitReceiver = getImplicitReceiver(context(), propertyDescriptor);
|
||||
assert implicitReceiver != null : "Property can only be a member of class or a namespace.";
|
||||
return implicitReceiver;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static JetSimpleNameExpression getNotNullSelector(@NotNull JetQualifiedExpression qualifiedExpression) {
|
||||
JetSimpleNameExpression selectorExpression = getSelectorAsSimpleName(qualifiedExpression);
|
||||
assert selectorExpression != null : MESSAGE;
|
||||
return selectorExpression;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private PropertyGetterDescriptor getGetterDescriptor() {
|
||||
PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
|
||||
assert getter != null : propertyDescriptor.getName() + " does not have a getter.";
|
||||
return getter;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private PropertySetterDescriptor getSetterDescriptor() {
|
||||
PropertySetterDescriptor setter = propertyDescriptor.getSetter();
|
||||
assert setter != null;
|
||||
return setter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ public final class ReferenceAccessTranslator extends AccessTranslator {
|
||||
return new ReferenceAccessTranslator(expression, context);
|
||||
}
|
||||
|
||||
//TODO: condider evaluating only once
|
||||
|
||||
@NotNull
|
||||
private final JetSimpleNameExpression expression;
|
||||
|
||||
@@ -4,19 +4,18 @@ 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.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForReferenceExpression;
|
||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.getImplicitReceiver;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class ReferenceTranslator extends AbstractTranslator {
|
||||
//TODO: get rid of the class, move to util
|
||||
public final class ReferenceTranslator {
|
||||
|
||||
@NotNull
|
||||
public static JsExpression translateSimpleName(@NotNull JetSimpleNameExpression expression,
|
||||
@@ -26,42 +25,27 @@ public final class ReferenceTranslator extends AbstractTranslator {
|
||||
}
|
||||
DeclarationDescriptor referencedDescriptor =
|
||||
getDescriptorForReferenceExpression(context.bindingContext(), expression);
|
||||
return (new ReferenceTranslator(referencedDescriptor, true, context)).translate();
|
||||
return translateAsLocalNameReference(referencedDescriptor, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression translateReference(@NotNull DeclarationDescriptor referencedDescriptor,
|
||||
@NotNull TranslationContext context) {
|
||||
return (new ReferenceTranslator(referencedDescriptor, false, context)).translate();
|
||||
public static JsExpression translateAsFQReference(@NotNull DeclarationDescriptor referencedDescriptor,
|
||||
@NotNull TranslationContext context) {
|
||||
|
||||
assert context.hasQualifierForDescriptor(referencedDescriptor);
|
||||
JsName referencedName = context.getNameForDescriptor(referencedDescriptor);
|
||||
JsExpression qualifier = context.getQualifierForDescriptor(referencedDescriptor);
|
||||
return AstUtil.qualified(referencedName, qualifier);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final DeclarationDescriptor referencedDescriptor;
|
||||
public static JsExpression translateAsLocalNameReference(@NotNull DeclarationDescriptor referencedDescriptor,
|
||||
@NotNull TranslationContext context) {
|
||||
|
||||
private final boolean shouldQualify;
|
||||
|
||||
private ReferenceTranslator(@NotNull DeclarationDescriptor referencedDescriptor,
|
||||
boolean shouldQualify,
|
||||
@NotNull TranslationContext context) {
|
||||
super(context);
|
||||
this.referencedDescriptor = referencedDescriptor;
|
||||
this.shouldQualify = shouldQualify;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsExpression translate() {
|
||||
JsName referencedName = context().getNameForDescriptor(referencedDescriptor);
|
||||
JsExpression implicitReceiver = getImplicitReceiver(context(), referencedDescriptor);
|
||||
|
||||
return generateReference(referencedName, implicitReceiver);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression generateReference(@NotNull JsName referencedName, @Nullable JsExpression implicitReceiver) {
|
||||
if (shouldQualify && implicitReceiver != null) {
|
||||
return AstUtil.qualified(referencedName, implicitReceiver);
|
||||
} else {
|
||||
return referencedName.makeRef();
|
||||
if (referencedDescriptor.getContainingDeclaration() instanceof NamespaceDescriptor) {
|
||||
return translateAsFQReference(referencedDescriptor, context);
|
||||
}
|
||||
JsName referencedName = context.getNameForDescriptor(referencedDescriptor);
|
||||
return referencedName.makeRef();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,23 +222,13 @@ public final class BindingUtils {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static ResolvedCall<?> getResolvedCall(@NotNull BindingContext context,
|
||||
@NotNull JetExpression expression) {
|
||||
public static ResolvedCall<?> getResolvedCall(@NotNull BindingContext context,
|
||||
@NotNull JetExpression expression) {
|
||||
ResolvedCall<? extends CallableDescriptor> resolvedCall = context.get(BindingContext.RESOLVED_CALL, expression);
|
||||
assert resolvedCall != null : "Must resolve to a call.";
|
||||
return resolvedCall;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static FunctionDescriptor getFunctionDescriptorForCallExpression(@NotNull BindingContext context,
|
||||
@NotNull JetCallExpression expression) {
|
||||
ResolvedCall<?> resolvedCall = getResolvedCallForCallExpression(context, expression);
|
||||
CallableDescriptor descriptor = getDescriptorForResolvedCall(resolvedCall);
|
||||
assert descriptor instanceof FunctionDescriptor :
|
||||
"Callee expression must have resolved call with descriptor of type FunctionDescriptor";
|
||||
return (FunctionDescriptor) descriptor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ResolvedCall<?> getResolvedCallForCallExpression(@NotNull BindingContext context,
|
||||
@NotNull JetCallExpression expression) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
||||
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -136,4 +137,30 @@ public final class DescriptorUtils {
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
//TODO: why callable descriptor
|
||||
@Nullable
|
||||
public static DeclarationDescriptor getExpectedThisDescriptor(@NotNull CallableDescriptor functionDescriptor) {
|
||||
ReceiverDescriptor receiverParameter = functionDescriptor.getReceiverParameter();
|
||||
if (!receiverParameter.exists()) {
|
||||
return null;
|
||||
}
|
||||
DeclarationDescriptor declarationDescriptor =
|
||||
receiverParameter.getType().getConstructor().getDeclarationDescriptor();
|
||||
//TODO: WHY assert?
|
||||
assert declarationDescriptor != null;
|
||||
return declarationDescriptor.getOriginal();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static DeclarationDescriptor getExpectedReceiverDescriptor(@NotNull CallableDescriptor functionDescriptor) {
|
||||
ReceiverDescriptor receiverParameter = functionDescriptor.getReceiverParameter();
|
||||
if (!receiverParameter.exists()) {
|
||||
return null;
|
||||
}
|
||||
DeclarationDescriptor declarationDescriptor =
|
||||
functionDescriptor.getReceiverParameter().getType().getConstructor().getDeclarationDescriptor();
|
||||
assert declarationDescriptor != null;
|
||||
return declarationDescriptor.getOriginal();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,11 @@ import com.google.dart.compiler.backend.js.ast.*;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
||||
import org.jetbrains.k2js.translate.context.NamingScope;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.Translation;
|
||||
@@ -17,7 +17,6 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.*;
|
||||
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.isExtensionFunction;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
@@ -57,6 +56,7 @@ public final class TranslationUtils {
|
||||
return Translation.translateAsExpression(jetExpression, context);
|
||||
}
|
||||
|
||||
//TODO: refactor backing field reference generation to use the generic way
|
||||
@NotNull
|
||||
public static JsNameRef backingFieldReference(@NotNull TranslationContext context,
|
||||
@NotNull JetProperty expression) {
|
||||
@@ -69,7 +69,7 @@ public final class TranslationUtils {
|
||||
@NotNull PropertyDescriptor descriptor) {
|
||||
JsName backingFieldName = context.getNameForDescriptor(descriptor);
|
||||
if (isOwnedByClass(descriptor)) {
|
||||
return getThisQualifiedNameReference(context, backingFieldName);
|
||||
return AstUtil.qualified(backingFieldName, new JsThisRef());
|
||||
}
|
||||
assert isOwnedByNamespace(descriptor)
|
||||
: "Only classes and namespaces may own backing fields.";
|
||||
@@ -109,19 +109,11 @@ public final class TranslationUtils {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static JsNameRef getThisQualifiedNameReference(@NotNull TranslationContext context,
|
||||
@NotNull JsName name) {
|
||||
JsExpression qualifier = getThisQualifier(context);
|
||||
JsNameRef reference = name.makeRef();
|
||||
AstUtil.setQualifier(reference, qualifier);
|
||||
return reference;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static JsExpression getThisQualifier(@NotNull TranslationContext context) {
|
||||
public static JsExpression getThisQualifier(@NotNull TranslationContext context,
|
||||
@NotNull DeclarationDescriptor correspondingDeclaration) {
|
||||
JsExpression qualifier;
|
||||
if (context.aliaser().hasAliasForThis()) {
|
||||
qualifier = context.aliaser().getAliasForThis();
|
||||
if (context.aliaser().hasAliasForThis(correspondingDeclaration)) {
|
||||
qualifier = context.aliaser().getAliasForThis(correspondingDeclaration);
|
||||
} else {
|
||||
qualifier = new JsThisRef();
|
||||
}
|
||||
@@ -200,32 +192,26 @@ public final class TranslationUtils {
|
||||
|
||||
@Nullable
|
||||
public static JsExpression getImplicitReceiver(@NotNull TranslationContext context,
|
||||
@NotNull DeclarationDescriptor referencedDescriptor) {
|
||||
if (referencedDescriptor instanceof FunctionDescriptor) {
|
||||
if (isExtensionFunction((FunctionDescriptor) referencedDescriptor)) {
|
||||
return TranslationUtils.getThisQualifier(context);
|
||||
}
|
||||
}
|
||||
return getImplicitReceiverBasedOnOwner(context, referencedDescriptor);
|
||||
@NotNull ReceiverDescriptor receiverDescriptor) {
|
||||
DeclarationDescriptor correspondingDescriptor =
|
||||
receiverDescriptor.getType().getConstructor().getDeclarationDescriptor();
|
||||
assert correspondingDescriptor != null;
|
||||
return context.aliaser().getAliasForReceiver(correspondingDescriptor);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static JsExpression getExtensionFunctionImplicitReceiver(@NotNull TranslationContext context,
|
||||
@NotNull CallableDescriptor descriptor) {
|
||||
return getImplicitReceiverBasedOnOwner(context, descriptor);
|
||||
public static JsExpression getImplicitThis(@NotNull TranslationContext context,
|
||||
@NotNull ReceiverDescriptor receiverDescriptor) {
|
||||
if (!receiverDescriptor.exists()) {
|
||||
return new JsThisRef();
|
||||
}
|
||||
DeclarationDescriptor correspondingDescriptor =
|
||||
receiverDescriptor.getType().getConstructor().getDeclarationDescriptor();
|
||||
assert correspondingDescriptor != null;
|
||||
if (!context.aliaser().hasAliasForThis(correspondingDescriptor)) {
|
||||
return new JsThisRef();
|
||||
}
|
||||
return context.aliaser().getAliasForThis(correspondingDescriptor);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static JsExpression getImplicitReceiverBasedOnOwner(@NotNull TranslationContext context,
|
||||
@NotNull DeclarationDescriptor referencedDescriptor) {
|
||||
if (isOwnedByClass(referencedDescriptor)) {
|
||||
return TranslationUtils.getThisQualifier(context);
|
||||
}
|
||||
if (isOwnedByNamespace(referencedDescriptor)) {
|
||||
if (context.hasQualifierForDescriptor(referencedDescriptor)) {
|
||||
return context.getQualifierForDescriptor(referencedDescriptor);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,4 +123,10 @@ public class KotlinLibTest extends TranslationTest {
|
||||
new RhinoFunctionResultChecker("test", true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hashMap() throws Exception {
|
||||
runRhinoTest(Arrays.asList(kotlinLibraryPath(), cases("hashMap.js")),
|
||||
new RhinoFunctionResultChecker("test", true));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,12 @@ public final class RhinoSystemOutputChecker implements RhinoResultChecker {
|
||||
throws Exception {
|
||||
runMain(context, scope);
|
||||
String result = getSystemOutput(context, scope);
|
||||
assertTrue("Returned:\n" + result + "\n\nExpected:\n" + expectedResult, result.equals(expectedResult));
|
||||
String trimmedExpected = trimSpace(expectedResult);
|
||||
String trimmedActual = trimSpace(result);
|
||||
System.out.println(trimmedActual);
|
||||
System.out.println(trimmedExpected);
|
||||
assertTrue("Returned:\n" + trimmedActual + "END_OF_RETURNED\nExpected:\n" + trimmedExpected
|
||||
+ "END_OF_EXPECTED\n", trimmedExpected.equals(trimmedActual));
|
||||
}
|
||||
|
||||
private String getSystemOutput(@NotNull Context context, @NotNull Scriptable scope) {
|
||||
@@ -40,4 +45,13 @@ public final class RhinoSystemOutputChecker implements RhinoResultChecker {
|
||||
String callToMain = GenerationUtils.generateCallToMain("Anonymous", arguments);
|
||||
context.evaluateString(scope, callToMain, "function call", 0, null);
|
||||
}
|
||||
|
||||
public String trimSpace(String s) {
|
||||
String[] choppedUpString = s.trim().split("\\s");
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String word : choppedUpString) {
|
||||
sb.append(word);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,17 @@ public final class WebDemoExamples2Test extends TranslationTest {
|
||||
|
||||
@Test
|
||||
public void bottles() throws Exception {
|
||||
testWithMain("bottles", "2", "2");
|
||||
testWithMain("bottles", "");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void life() throws Exception {
|
||||
testWithMain("life", "", "2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void builder() throws Exception {
|
||||
testWithMain("builder", "");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
var map = new Kotlin.HashMap()
|
||||
|
||||
map.put(3, 4)
|
||||
map.put(6, 3)
|
||||
|
||||
function test() {
|
||||
if (map.containsKey(4) || map.containsKey(5)) return false;
|
||||
if (map.containsKey({}) || map.containsKey(11)) return false;
|
||||
if (!map.containsKey(3) || !map.containsKey(6)) return false;
|
||||
var obj = map.get(3);
|
||||
if (obj !== 4) return false;
|
||||
obj = map.get(6);
|
||||
if (obj !== 3) return false;
|
||||
if (map.size() !== 2) return false;
|
||||
map.put(2, 3);
|
||||
if (map.size() !== 3) return false;
|
||||
if (!map.containsKey(2) || !map.containsKey(3) || !map.containsKey(6)) return false;
|
||||
if (!map.containsValue(4) || !map.containsValue(3)) return false;
|
||||
map.put(2, 1000);
|
||||
if (map.size() !== 3) return false;
|
||||
if (map.get(2)!== 1000) return false;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -492,3 +492,524 @@ Kotlin.NumberRange = Kotlin.Class.create({initialize:function (start, size, reve
|
||||
return new Kotlin.RangeIterator(this.get_start(), this.get_size(), this.get_reversed());
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Copyright 2010 Tim Down.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* jshashtable
|
||||
*
|
||||
* jshashtable is a JavaScript implementation of a hash table. It creates a single constructor function called Hashtable
|
||||
* in the global scope.
|
||||
*
|
||||
* Author: Tim Down <tim@timdown.co.uk>
|
||||
* Version: 2.1
|
||||
* Build date: 21 March 2010
|
||||
* Website: http://www.timdown.co.uk/jshashtable
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var FUNCTION = "function";
|
||||
|
||||
var arrayRemoveAt = (typeof Array.prototype.splice == FUNCTION) ?
|
||||
function(arr, idx) {
|
||||
arr.splice(idx, 1);
|
||||
} :
|
||||
|
||||
function(arr, idx) {
|
||||
var itemsAfterDeleted, i, len;
|
||||
if (idx === arr.length - 1) {
|
||||
arr.length = idx;
|
||||
} else {
|
||||
itemsAfterDeleted = arr.slice(idx + 1);
|
||||
arr.length = idx;
|
||||
for (i = 0, len = itemsAfterDeleted.length; i < len; ++i) {
|
||||
arr[idx + i] = itemsAfterDeleted[i];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function hashObject(obj) {
|
||||
var hashCode;
|
||||
if (typeof obj == "string") {
|
||||
return obj;
|
||||
} else if (typeof obj.hashCode == FUNCTION) {
|
||||
// Check the hashCode method really has returned a string
|
||||
hashCode = obj.hashCode();
|
||||
return (typeof hashCode == "string") ? hashCode : hashObject(hashCode);
|
||||
} else if (typeof obj.toString == FUNCTION) {
|
||||
return obj.toString();
|
||||
} else {
|
||||
try {
|
||||
return String(obj);
|
||||
} catch (ex) {
|
||||
// For host objects (such as ActiveObjects in IE) that have no toString() method and throw an error when
|
||||
// passed to String()
|
||||
return Object.prototype.toString.call(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function equals_fixedValueHasEquals(fixedValue, variableValue) {
|
||||
return fixedValue.equals(variableValue);
|
||||
}
|
||||
|
||||
function equals_fixedValueNoEquals(fixedValue, variableValue) {
|
||||
return (typeof variableValue.equals == FUNCTION) ?
|
||||
variableValue.equals(fixedValue) : (fixedValue === variableValue);
|
||||
}
|
||||
|
||||
function createKeyValCheck(kvStr) {
|
||||
return function(kv) {
|
||||
if (kv === null) {
|
||||
throw new Error("null is not a valid " + kvStr);
|
||||
} else if (typeof kv == "undefined") {
|
||||
throw new Error(kvStr + " must not be undefined");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var checkKey = createKeyValCheck("key"), checkValue = createKeyValCheck("value");
|
||||
|
||||
/*----------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
function Bucket(hash, firstKey, firstValue, equalityFunction) {
|
||||
this[0] = hash;
|
||||
this.entries = [];
|
||||
this.addEntry(firstKey, firstValue);
|
||||
|
||||
if (equalityFunction !== null) {
|
||||
this.getEqualityFunction = function() {
|
||||
return equalityFunction;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
var EXISTENCE = 0, ENTRY = 1, ENTRY_INDEX_AND_VALUE = 2;
|
||||
|
||||
function createBucketSearcher(mode) {
|
||||
return function(key) {
|
||||
var i = this.entries.length, entry, equals = this.getEqualityFunction(key);
|
||||
while (i--) {
|
||||
entry = this.entries[i];
|
||||
if ( equals(key, entry[0]) ) {
|
||||
switch (mode) {
|
||||
case EXISTENCE:
|
||||
return true;
|
||||
case ENTRY:
|
||||
return entry;
|
||||
case ENTRY_INDEX_AND_VALUE:
|
||||
return [ i, entry[1] ];
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
function createBucketLister(entryProperty) {
|
||||
return function(aggregatedArr) {
|
||||
var startIndex = aggregatedArr.length;
|
||||
for (var i = 0, len = this.entries.length; i < len; ++i) {
|
||||
aggregatedArr[startIndex + i] = this.entries[i][entryProperty];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Bucket.prototype = {
|
||||
getEqualityFunction: function(searchValue) {
|
||||
return (typeof searchValue.equals == FUNCTION) ? equals_fixedValueHasEquals : equals_fixedValueNoEquals;
|
||||
},
|
||||
|
||||
getEntryForKey: createBucketSearcher(ENTRY),
|
||||
|
||||
getEntryAndIndexForKey: createBucketSearcher(ENTRY_INDEX_AND_VALUE),
|
||||
|
||||
removeEntryForKey: function(key) {
|
||||
var result = this.getEntryAndIndexForKey(key);
|
||||
if (result) {
|
||||
arrayRemoveAt(this.entries, result[0]);
|
||||
return result[1];
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
addEntry: function(key, value) {
|
||||
this.entries[this.entries.length] = [key, value];
|
||||
},
|
||||
|
||||
keys: createBucketLister(0),
|
||||
|
||||
values: createBucketLister(1),
|
||||
|
||||
getEntries: function(entries) {
|
||||
var startIndex = entries.length;
|
||||
for (var i = 0, len = this.entries.length; i < len; ++i) {
|
||||
// Clone the entry stored in the bucket before adding to array
|
||||
entries[startIndex + i] = this.entries[i].slice(0);
|
||||
}
|
||||
},
|
||||
|
||||
containsKey: createBucketSearcher(EXISTENCE),
|
||||
|
||||
containsValue: function(value) {
|
||||
var i = this.entries.length;
|
||||
while (i--) {
|
||||
if ( value === this.entries[i][1] ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
// Supporting functions for searching hashtable buckets
|
||||
|
||||
function searchBuckets(buckets, hash) {
|
||||
var i = buckets.length, bucket;
|
||||
while (i--) {
|
||||
bucket = buckets[i];
|
||||
if (hash === bucket[0]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getBucketForHash(bucketsByHash, hash) {
|
||||
var bucket = bucketsByHash[hash];
|
||||
|
||||
// Check that this is a genuine bucket and not something inherited from the bucketsByHash's prototype
|
||||
return ( bucket && (bucket instanceof Bucket) ) ? bucket : null;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
var Hashtable = function(hashingFunctionParam, equalityFunctionParam) {
|
||||
var that = this;
|
||||
var buckets = [];
|
||||
var bucketsByHash = {};
|
||||
|
||||
var hashingFunction = (typeof hashingFunctionParam == FUNCTION) ? hashingFunctionParam : hashObject;
|
||||
var equalityFunction = (typeof equalityFunctionParam == FUNCTION) ? equalityFunctionParam : null;
|
||||
|
||||
this.put = function(key, value) {
|
||||
checkKey(key);
|
||||
checkValue(value);
|
||||
var hash = hashingFunction(key), bucket, bucketEntry, oldValue = null;
|
||||
|
||||
// Check if a bucket exists for the bucket key
|
||||
bucket = getBucketForHash(bucketsByHash, hash);
|
||||
if (bucket) {
|
||||
// Check this bucket to see if it already contains this key
|
||||
bucketEntry = bucket.getEntryForKey(key);
|
||||
if (bucketEntry) {
|
||||
// This bucket entry is the current mapping of key to value, so replace old value and we're done.
|
||||
oldValue = bucketEntry[1];
|
||||
bucketEntry[1] = value;
|
||||
} else {
|
||||
// The bucket does not contain an entry for this key, so add one
|
||||
bucket.addEntry(key, value);
|
||||
}
|
||||
} else {
|
||||
// No bucket exists for the key, so create one and put our key/value mapping in
|
||||
bucket = new Bucket(hash, key, value, equalityFunction);
|
||||
buckets[buckets.length] = bucket;
|
||||
bucketsByHash[hash] = bucket;
|
||||
}
|
||||
return oldValue;
|
||||
};
|
||||
|
||||
this.get = function(key) {
|
||||
checkKey(key);
|
||||
|
||||
var hash = hashingFunction(key);
|
||||
|
||||
// Check if a bucket exists for the bucket key
|
||||
var bucket = getBucketForHash(bucketsByHash, hash);
|
||||
if (bucket) {
|
||||
// Check this bucket to see if it contains this key
|
||||
var bucketEntry = bucket.getEntryForKey(key);
|
||||
if (bucketEntry) {
|
||||
// This bucket entry is the current mapping of key to value, so return the value.
|
||||
return bucketEntry[1];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
this.containsKey = function(key) {
|
||||
checkKey(key);
|
||||
var bucketKey = hashingFunction(key);
|
||||
|
||||
// Check if a bucket exists for the bucket key
|
||||
var bucket = getBucketForHash(bucketsByHash, bucketKey);
|
||||
|
||||
return bucket ? bucket.containsKey(key) : false;
|
||||
};
|
||||
|
||||
this.containsValue = function(value) {
|
||||
checkValue(value);
|
||||
var i = buckets.length;
|
||||
while (i--) {
|
||||
if (buckets[i].containsValue(value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
this.clear = function() {
|
||||
buckets.length = 0;
|
||||
bucketsByHash = {};
|
||||
};
|
||||
|
||||
this.isEmpty = function() {
|
||||
return !buckets.length;
|
||||
};
|
||||
|
||||
var createBucketAggregator = function(bucketFuncName) {
|
||||
return function() {
|
||||
var aggregated = [], i = buckets.length;
|
||||
while (i--) {
|
||||
buckets[i][bucketFuncName](aggregated);
|
||||
}
|
||||
return aggregated;
|
||||
};
|
||||
};
|
||||
|
||||
this.keys = createBucketAggregator("keys");
|
||||
this.values = createBucketAggregator("values");
|
||||
this.entries = createBucketAggregator("getEntries");
|
||||
|
||||
this.remove = function(key) {
|
||||
checkKey(key);
|
||||
|
||||
var hash = hashingFunction(key), bucketIndex, oldValue = null;
|
||||
|
||||
// Check if a bucket exists for the bucket key
|
||||
var bucket = getBucketForHash(bucketsByHash, hash);
|
||||
|
||||
if (bucket) {
|
||||
// Remove entry from this bucket for this key
|
||||
oldValue = bucket.removeEntryForKey(key);
|
||||
if (oldValue !== null) {
|
||||
// Entry was removed, so check if bucket is empty
|
||||
if (!bucket.entries.length) {
|
||||
// Bucket is empty, so remove it from the bucket collections
|
||||
bucketIndex = searchBuckets(buckets, hash);
|
||||
arrayRemoveAt(buckets, bucketIndex);
|
||||
delete bucketsByHash[hash];
|
||||
}
|
||||
}
|
||||
}
|
||||
return oldValue;
|
||||
};
|
||||
|
||||
this.size = function() {
|
||||
var total = 0, i = buckets.length;
|
||||
while (i--) {
|
||||
total += buckets[i].entries.length;
|
||||
}
|
||||
return total;
|
||||
};
|
||||
|
||||
this.each = function(callback) {
|
||||
var entries = that.entries(), i = entries.length, entry;
|
||||
while (i--) {
|
||||
entry = entries[i];
|
||||
callback(entry[0], entry[1]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
this.putAll = function(hashtable, conflictCallback) {
|
||||
var entries = hashtable.entries();
|
||||
var entry, key, value, thisValue, i = entries.length;
|
||||
var hasConflictCallback = (typeof conflictCallback == FUNCTION);
|
||||
while (i--) {
|
||||
entry = entries[i];
|
||||
key = entry[0];
|
||||
value = entry[1];
|
||||
|
||||
// Check for a conflict. The default behaviour is to overwrite the value for an existing key
|
||||
if ( hasConflictCallback && (thisValue = that.get(key)) ) {
|
||||
value = conflictCallback(key, thisValue, value);
|
||||
}
|
||||
that.put(key, value);
|
||||
}
|
||||
};
|
||||
|
||||
this.clone = function() {
|
||||
var clone = new Hashtable(hashingFunctionParam, equalityFunctionParam);
|
||||
clone.putAll(that);
|
||||
return clone;
|
||||
};
|
||||
|
||||
this.keySet = function() {
|
||||
var res = new Kotlin.HashSet();
|
||||
var keys = this.keys();
|
||||
var i = keys.length;
|
||||
while (i--) {
|
||||
res.add(keys[i]);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
Kotlin.HashTable = Hashtable;
|
||||
})();
|
||||
|
||||
Kotlin.HashMap = Kotlin.Class.create(
|
||||
{
|
||||
initialize : function() {
|
||||
Kotlin.HashTable.call(this);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
Kotlin.StringBuilder = Kotlin.Class.create(
|
||||
{
|
||||
initialize : function() {
|
||||
this.string = "";
|
||||
},
|
||||
append : function(obj) {
|
||||
this.string = this.string + obj.toString();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Copyright 2010 Tim Down.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* HashSet
|
||||
*
|
||||
* This is a JavaScript implementation of HashSet, similar in concept to those found in Java or C#'s standard libraries.
|
||||
* It is distributed as part of jshashtable and depends on jshashtable.js. It creates a single constructor function
|
||||
* called HashSet in the global scope.
|
||||
*
|
||||
* Author: Tim Down <tim@timdown.co.uk>
|
||||
* Version: 2.1
|
||||
* Build date: 27 March 2010
|
||||
* Website: http://www.timdown.co.uk/jshashtable/
|
||||
*/
|
||||
(function() {
|
||||
function HashSet(hashingFunction, equalityFunction) {
|
||||
var hashTable = new Hashtable(hashingFunction, equalityFunction);
|
||||
|
||||
this.add = function(o) {
|
||||
hashTable.put(o, true);
|
||||
};
|
||||
|
||||
this.addAll = function(arr) {
|
||||
var i = arr.length;
|
||||
while (i--) {
|
||||
hashTable.put(arr[i], true);
|
||||
}
|
||||
};
|
||||
|
||||
this.values = function() {
|
||||
return hashTable.keys();
|
||||
};
|
||||
|
||||
this.remove = function(o) {
|
||||
return hashTable.remove(o) ? o : null;
|
||||
};
|
||||
|
||||
this.contains = function(o) {
|
||||
return hashTable.containsKey(o);
|
||||
};
|
||||
|
||||
this.clear = function() {
|
||||
hashTable.clear();
|
||||
};
|
||||
|
||||
this.size = function() {
|
||||
return hashTable.size();
|
||||
};
|
||||
|
||||
this.isEmpty = function() {
|
||||
return hashTable.isEmpty();
|
||||
};
|
||||
|
||||
this.clone = function() {
|
||||
var h = new HashSet(hashingFunction, equalityFunction);
|
||||
h.addAll(hashTable.keys());
|
||||
return h;
|
||||
};
|
||||
|
||||
this.intersection = function(hashSet) {
|
||||
var intersection = new HashSet(hashingFunction, equalityFunction);
|
||||
var values = hashSet.values(), i = values.length, val;
|
||||
while (i--) {
|
||||
val = values[i];
|
||||
if (hashTable.containsKey(val)) {
|
||||
intersection.add(val);
|
||||
}
|
||||
}
|
||||
return intersection;
|
||||
};
|
||||
|
||||
this.union = function(hashSet) {
|
||||
var union = this.clone();
|
||||
var values = hashSet.values(), i = values.length, val;
|
||||
while (i--) {
|
||||
val = values[i];
|
||||
if (!hashTable.containsKey(val)) {
|
||||
union.add(val);
|
||||
}
|
||||
}
|
||||
return union;
|
||||
};
|
||||
|
||||
this.isSubsetOf = function(hashSet) {
|
||||
var values = hashTable.keys(), i = values.length;
|
||||
while (i--) {
|
||||
if (!hashSet.contains(values[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
Kotlin.HashSet = Kotlin.Class.create(
|
||||
{
|
||||
initialize : function() {
|
||||
HashSet.call(this);
|
||||
}
|
||||
}
|
||||
)
|
||||
}());
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Copyright 2010 Tim Down.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
function HashSet(c,a){var b=new Hashtable(c,a);this.add=function(d){b.put(d,true)};this.addAll=function(d){var e=d.length;while(e--){b.put(d[e],true)}};this.values=function(){return b.keys()};this.remove=function(d){return b.remove(d)?d:null};this.contains=function(d){return b.containsKey(d)};this.clear=function(){b.clear()};this.size=function(){return b.size()};this.isEmpty=function(){return b.isEmpty()};this.clone=function(){var d=new HashSet(c,a);d.addAll(b.keys());return d};this.intersection=function(d){var h=new HashSet(c,a);var e=d.values(),f=e.length,g;while(f--){g=e[f];if(b.containsKey(g)){h.add(g)}}return h};this.union=function(d){var g=this.clone();var e=d.values(),f=e.length,h;while(f--){h=e[f];if(!b.containsKey(h)){g.add(h)}}return g};this.isSubsetOf=function(d){var e=b.keys(),f=e.length;while(f--){if(!d.contains(e[f])){return false}}return true}};
|
||||
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* Copyright 2010 Tim Down.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* HashSet
|
||||
*
|
||||
* This is a JavaScript implementation of HashSet, similar in concept to those found in Java or C#'s standard libraries.
|
||||
* It is distributed as part of jshashtable and depends on jshashtable.js. It creates a single constructor function
|
||||
* called HashSet in the global scope.
|
||||
*
|
||||
* Author: Tim Down <tim@timdown.co.uk>
|
||||
* Version: 2.1
|
||||
* Build date: 27 March 2010
|
||||
* Website: http://www.timdown.co.uk/jshashtable/
|
||||
*/
|
||||
|
||||
function HashSet(hashingFunction, equalityFunction) {
|
||||
var hashTable = new Hashtable(hashingFunction, equalityFunction);
|
||||
|
||||
this.add = function(o) {
|
||||
hashTable.put(o, true);
|
||||
};
|
||||
|
||||
this.addAll = function(arr) {
|
||||
var i = arr.length;
|
||||
while (i--) {
|
||||
hashTable.put(arr[i], true);
|
||||
}
|
||||
};
|
||||
|
||||
this.values = function() {
|
||||
return hashTable.keys();
|
||||
};
|
||||
|
||||
this.remove = function(o) {
|
||||
return hashTable.remove(o) ? o : null;
|
||||
};
|
||||
|
||||
this.contains = function(o) {
|
||||
return hashTable.containsKey(o);
|
||||
};
|
||||
|
||||
this.clear = function() {
|
||||
hashTable.clear();
|
||||
};
|
||||
|
||||
this.size = function() {
|
||||
return hashTable.size();
|
||||
};
|
||||
|
||||
this.isEmpty = function() {
|
||||
return hashTable.isEmpty();
|
||||
};
|
||||
|
||||
this.clone = function() {
|
||||
var h = new HashSet(hashingFunction, equalityFunction);
|
||||
h.addAll(hashTable.keys());
|
||||
return h;
|
||||
};
|
||||
|
||||
this.intersection = function(hashSet) {
|
||||
var intersection = new HashSet(hashingFunction, equalityFunction);
|
||||
var values = hashSet.values(), i = values.length, val;
|
||||
while (i--) {
|
||||
val = values[i];
|
||||
if (hashTable.containsKey(val)) {
|
||||
intersection.add(val);
|
||||
}
|
||||
}
|
||||
return intersection;
|
||||
};
|
||||
|
||||
this.union = function(hashSet) {
|
||||
var union = this.clone();
|
||||
var values = hashSet.values(), i = values.length, val;
|
||||
while (i--) {
|
||||
val = values[i];
|
||||
if (!hashTable.containsKey(val)) {
|
||||
union.add(val);
|
||||
}
|
||||
}
|
||||
return union;
|
||||
};
|
||||
|
||||
this.isSubsetOf = function(hashSet) {
|
||||
var values = hashTable.keys(), i = values.length;
|
||||
while (i--) {
|
||||
if (!hashSet.contains(values[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Copyright 2010 Tim Down.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
var Hashtable=(function(){var p="function";var n=(typeof Array.prototype.splice==p)?function(s,r){s.splice(r,1)}:function(u,t){var s,v,r;if(t===u.length-1){u.length=t}else{s=u.slice(t+1);u.length=t;for(v=0,r=s.length;v<r;++v){u[t+v]=s[v]}}};function a(t){var r;if(typeof t=="string"){return t}else{if(typeof t.hashCode==p){r=t.hashCode();return(typeof r=="string")?r:a(r)}else{if(typeof t.toString==p){return t.toString()}else{try{return String(t)}catch(s){return Object.prototype.toString.call(t)}}}}}function g(r,s){return r.equals(s)}function e(r,s){return(typeof s.equals==p)?s.equals(r):(r===s)}function c(r){return function(s){if(s===null){throw new Error("null is not a valid "+r)}else{if(typeof s=="undefined"){throw new Error(r+" must not be undefined")}}}}var q=c("key"),l=c("value");function d(u,s,t,r){this[0]=u;this.entries=[];this.addEntry(s,t);if(r!==null){this.getEqualityFunction=function(){return r}}}var h=0,j=1,f=2;function o(r){return function(t){var s=this.entries.length,v,u=this.getEqualityFunction(t);while(s--){v=this.entries[s];if(u(t,v[0])){switch(r){case h:return true;case j:return v;case f:return[s,v[1]]}}}return false}}function k(r){return function(u){var v=u.length;for(var t=0,s=this.entries.length;t<s;++t){u[v+t]=this.entries[t][r]}}}d.prototype={getEqualityFunction:function(r){return(typeof r.equals==p)?g:e},getEntryForKey:o(j),getEntryAndIndexForKey:o(f),removeEntryForKey:function(s){var r=this.getEntryAndIndexForKey(s);if(r){n(this.entries,r[0]);return r[1]}return null},addEntry:function(r,s){this.entries[this.entries.length]=[r,s]},keys:k(0),values:k(1),getEntries:function(s){var u=s.length;for(var t=0,r=this.entries.length;t<r;++t){s[u+t]=this.entries[t].slice(0)}},containsKey:o(h),containsValue:function(s){var r=this.entries.length;while(r--){if(s===this.entries[r][1]){return true}}return false}};function m(s,t){var r=s.length,u;while(r--){u=s[r];if(t===u[0]){return r}}return null}function i(r,s){var t=r[s];return(t&&(t instanceof d))?t:null}function b(t,r){var w=this;var v=[];var u={};var x=(typeof t==p)?t:a;var s=(typeof r==p)?r:null;this.put=function(B,C){q(B);l(C);var D=x(B),E,A,z=null;E=i(u,D);if(E){A=E.getEntryForKey(B);if(A){z=A[1];A[1]=C}else{E.addEntry(B,C)}}else{E=new d(D,B,C,s);v[v.length]=E;u[D]=E}return z};this.get=function(A){q(A);var B=x(A);var C=i(u,B);if(C){var z=C.getEntryForKey(A);if(z){return z[1]}}return null};this.containsKey=function(A){q(A);var z=x(A);var B=i(u,z);return B?B.containsKey(A):false};this.containsValue=function(A){l(A);var z=v.length;while(z--){if(v[z].containsValue(A)){return true}}return false};this.clear=function(){v.length=0;u={}};this.isEmpty=function(){return !v.length};var y=function(z){return function(){var A=[],B=v.length;while(B--){v[B][z](A)}return A}};this.keys=y("keys");this.values=y("values");this.entries=y("getEntries");this.remove=function(B){q(B);var C=x(B),z,A=null;var D=i(u,C);if(D){A=D.removeEntryForKey(B);if(A!==null){if(!D.entries.length){z=m(v,C);n(v,z);delete u[C]}}}return A};this.size=function(){var A=0,z=v.length;while(z--){A+=v[z].entries.length}return A};this.each=function(C){var z=w.entries(),A=z.length,B;while(A--){B=z[A];C(B[0],B[1])}};this.putAll=function(H,C){var B=H.entries();var E,F,D,z,A=B.length;var G=(typeof C==p);while(A--){E=B[A];F=E[0];D=E[1];if(G&&(z=w.get(F))){D=C(F,z,D)}w.put(F,D)}};this.clone=function(){var z=new b(t,r);z.putAll(w);return z}}return b})();
|
||||
@@ -0,0 +1,370 @@
|
||||
/**
|
||||
* Copyright 2010 Tim Down.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* jshashtable
|
||||
*
|
||||
* jshashtable is a JavaScript implementation of a hash table. It creates a single constructor function called Hashtable
|
||||
* in the global scope.
|
||||
*
|
||||
* Author: Tim Down <tim@timdown.co.uk>
|
||||
* Version: 2.1
|
||||
* Build date: 21 March 2010
|
||||
* Website: http://www.timdown.co.uk/jshashtable
|
||||
*/
|
||||
|
||||
var Hashtable = (function() {
|
||||
var FUNCTION = "function";
|
||||
|
||||
var arrayRemoveAt = (typeof Array.prototype.splice == FUNCTION) ?
|
||||
function(arr, idx) {
|
||||
arr.splice(idx, 1);
|
||||
} :
|
||||
|
||||
function(arr, idx) {
|
||||
var itemsAfterDeleted, i, len;
|
||||
if (idx === arr.length - 1) {
|
||||
arr.length = idx;
|
||||
} else {
|
||||
itemsAfterDeleted = arr.slice(idx + 1);
|
||||
arr.length = idx;
|
||||
for (i = 0, len = itemsAfterDeleted.length; i < len; ++i) {
|
||||
arr[idx + i] = itemsAfterDeleted[i];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function hashObject(obj) {
|
||||
var hashCode;
|
||||
if (typeof obj == "string") {
|
||||
return obj;
|
||||
} else if (typeof obj.hashCode == FUNCTION) {
|
||||
// Check the hashCode method really has returned a string
|
||||
hashCode = obj.hashCode();
|
||||
return (typeof hashCode == "string") ? hashCode : hashObject(hashCode);
|
||||
} else if (typeof obj.toString == FUNCTION) {
|
||||
return obj.toString();
|
||||
} else {
|
||||
try {
|
||||
return String(obj);
|
||||
} catch (ex) {
|
||||
// For host objects (such as ActiveObjects in IE) that have no toString() method and throw an error when
|
||||
// passed to String()
|
||||
return Object.prototype.toString.call(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function equals_fixedValueHasEquals(fixedValue, variableValue) {
|
||||
return fixedValue.equals(variableValue);
|
||||
}
|
||||
|
||||
function equals_fixedValueNoEquals(fixedValue, variableValue) {
|
||||
return (typeof variableValue.equals == FUNCTION) ?
|
||||
variableValue.equals(fixedValue) : (fixedValue === variableValue);
|
||||
}
|
||||
|
||||
function createKeyValCheck(kvStr) {
|
||||
return function(kv) {
|
||||
if (kv === null) {
|
||||
throw new Error("null is not a valid " + kvStr);
|
||||
} else if (typeof kv == "undefined") {
|
||||
throw new Error(kvStr + " must not be undefined");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var checkKey = createKeyValCheck("key"), checkValue = createKeyValCheck("value");
|
||||
|
||||
/*----------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
function Bucket(hash, firstKey, firstValue, equalityFunction) {
|
||||
this[0] = hash;
|
||||
this.entries = [];
|
||||
this.addEntry(firstKey, firstValue);
|
||||
|
||||
if (equalityFunction !== null) {
|
||||
this.getEqualityFunction = function() {
|
||||
return equalityFunction;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
var EXISTENCE = 0, ENTRY = 1, ENTRY_INDEX_AND_VALUE = 2;
|
||||
|
||||
function createBucketSearcher(mode) {
|
||||
return function(key) {
|
||||
var i = this.entries.length, entry, equals = this.getEqualityFunction(key);
|
||||
while (i--) {
|
||||
entry = this.entries[i];
|
||||
if ( equals(key, entry[0]) ) {
|
||||
switch (mode) {
|
||||
case EXISTENCE:
|
||||
return true;
|
||||
case ENTRY:
|
||||
return entry;
|
||||
case ENTRY_INDEX_AND_VALUE:
|
||||
return [ i, entry[1] ];
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
function createBucketLister(entryProperty) {
|
||||
return function(aggregatedArr) {
|
||||
var startIndex = aggregatedArr.length;
|
||||
for (var i = 0, len = this.entries.length; i < len; ++i) {
|
||||
aggregatedArr[startIndex + i] = this.entries[i][entryProperty];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Bucket.prototype = {
|
||||
getEqualityFunction: function(searchValue) {
|
||||
return (typeof searchValue.equals == FUNCTION) ? equals_fixedValueHasEquals : equals_fixedValueNoEquals;
|
||||
},
|
||||
|
||||
getEntryForKey: createBucketSearcher(ENTRY),
|
||||
|
||||
getEntryAndIndexForKey: createBucketSearcher(ENTRY_INDEX_AND_VALUE),
|
||||
|
||||
removeEntryForKey: function(key) {
|
||||
var result = this.getEntryAndIndexForKey(key);
|
||||
if (result) {
|
||||
arrayRemoveAt(this.entries, result[0]);
|
||||
return result[1];
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
addEntry: function(key, value) {
|
||||
this.entries[this.entries.length] = [key, value];
|
||||
},
|
||||
|
||||
keys: createBucketLister(0),
|
||||
|
||||
values: createBucketLister(1),
|
||||
|
||||
getEntries: function(entries) {
|
||||
var startIndex = entries.length;
|
||||
for (var i = 0, len = this.entries.length; i < len; ++i) {
|
||||
// Clone the entry stored in the bucket before adding to array
|
||||
entries[startIndex + i] = this.entries[i].slice(0);
|
||||
}
|
||||
},
|
||||
|
||||
containsKey: createBucketSearcher(EXISTENCE),
|
||||
|
||||
containsValue: function(value) {
|
||||
var i = this.entries.length;
|
||||
while (i--) {
|
||||
if ( value === this.entries[i][1] ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
// Supporting functions for searching hashtable buckets
|
||||
|
||||
function searchBuckets(buckets, hash) {
|
||||
var i = buckets.length, bucket;
|
||||
while (i--) {
|
||||
bucket = buckets[i];
|
||||
if (hash === bucket[0]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getBucketForHash(bucketsByHash, hash) {
|
||||
var bucket = bucketsByHash[hash];
|
||||
|
||||
// Check that this is a genuine bucket and not something inherited from the bucketsByHash's prototype
|
||||
return ( bucket && (bucket instanceof Bucket) ) ? bucket : null;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
function Hashtable(hashingFunctionParam, equalityFunctionParam) {
|
||||
var that = this;
|
||||
var buckets = [];
|
||||
var bucketsByHash = {};
|
||||
|
||||
var hashingFunction = (typeof hashingFunctionParam == FUNCTION) ? hashingFunctionParam : hashObject;
|
||||
var equalityFunction = (typeof equalityFunctionParam == FUNCTION) ? equalityFunctionParam : null;
|
||||
|
||||
this.put = function(key, value) {
|
||||
checkKey(key);
|
||||
checkValue(value);
|
||||
var hash = hashingFunction(key), bucket, bucketEntry, oldValue = null;
|
||||
|
||||
// Check if a bucket exists for the bucket key
|
||||
bucket = getBucketForHash(bucketsByHash, hash);
|
||||
if (bucket) {
|
||||
// Check this bucket to see if it already contains this key
|
||||
bucketEntry = bucket.getEntryForKey(key);
|
||||
if (bucketEntry) {
|
||||
// This bucket entry is the current mapping of key to value, so replace old value and we're done.
|
||||
oldValue = bucketEntry[1];
|
||||
bucketEntry[1] = value;
|
||||
} else {
|
||||
// The bucket does not contain an entry for this key, so add one
|
||||
bucket.addEntry(key, value);
|
||||
}
|
||||
} else {
|
||||
// No bucket exists for the key, so create one and put our key/value mapping in
|
||||
bucket = new Bucket(hash, key, value, equalityFunction);
|
||||
buckets[buckets.length] = bucket;
|
||||
bucketsByHash[hash] = bucket;
|
||||
}
|
||||
return oldValue;
|
||||
};
|
||||
|
||||
this.get = function(key) {
|
||||
checkKey(key);
|
||||
|
||||
var hash = hashingFunction(key);
|
||||
|
||||
// Check if a bucket exists for the bucket key
|
||||
var bucket = getBucketForHash(bucketsByHash, hash);
|
||||
if (bucket) {
|
||||
// Check this bucket to see if it contains this key
|
||||
var bucketEntry = bucket.getEntryForKey(key);
|
||||
if (bucketEntry) {
|
||||
// This bucket entry is the current mapping of key to value, so return the value.
|
||||
return bucketEntry[1];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
this.containsKey = function(key) {
|
||||
checkKey(key);
|
||||
var bucketKey = hashingFunction(key);
|
||||
|
||||
// Check if a bucket exists for the bucket key
|
||||
var bucket = getBucketForHash(bucketsByHash, bucketKey);
|
||||
|
||||
return bucket ? bucket.containsKey(key) : false;
|
||||
};
|
||||
|
||||
this.containsValue = function(value) {
|
||||
checkValue(value);
|
||||
var i = buckets.length;
|
||||
while (i--) {
|
||||
if (buckets[i].containsValue(value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
this.clear = function() {
|
||||
buckets.length = 0;
|
||||
bucketsByHash = {};
|
||||
};
|
||||
|
||||
this.isEmpty = function() {
|
||||
return !buckets.length;
|
||||
};
|
||||
|
||||
var createBucketAggregator = function(bucketFuncName) {
|
||||
return function() {
|
||||
var aggregated = [], i = buckets.length;
|
||||
while (i--) {
|
||||
buckets[i][bucketFuncName](aggregated);
|
||||
}
|
||||
return aggregated;
|
||||
};
|
||||
};
|
||||
|
||||
this.keys = createBucketAggregator("keys");
|
||||
this.values = createBucketAggregator("values");
|
||||
this.entries = createBucketAggregator("getEntries");
|
||||
|
||||
this.remove = function(key) {
|
||||
checkKey(key);
|
||||
|
||||
var hash = hashingFunction(key), bucketIndex, oldValue = null;
|
||||
|
||||
// Check if a bucket exists for the bucket key
|
||||
var bucket = getBucketForHash(bucketsByHash, hash);
|
||||
|
||||
if (bucket) {
|
||||
// Remove entry from this bucket for this key
|
||||
oldValue = bucket.removeEntryForKey(key);
|
||||
if (oldValue !== null) {
|
||||
// Entry was removed, so check if bucket is empty
|
||||
if (!bucket.entries.length) {
|
||||
// Bucket is empty, so remove it from the bucket collections
|
||||
bucketIndex = searchBuckets(buckets, hash);
|
||||
arrayRemoveAt(buckets, bucketIndex);
|
||||
delete bucketsByHash[hash];
|
||||
}
|
||||
}
|
||||
}
|
||||
return oldValue;
|
||||
};
|
||||
|
||||
this.size = function() {
|
||||
var total = 0, i = buckets.length;
|
||||
while (i--) {
|
||||
total += buckets[i].entries.length;
|
||||
}
|
||||
return total;
|
||||
};
|
||||
|
||||
this.each = function(callback) {
|
||||
var entries = that.entries(), i = entries.length, entry;
|
||||
while (i--) {
|
||||
entry = entries[i];
|
||||
callback(entry[0], entry[1]);
|
||||
}
|
||||
};
|
||||
|
||||
this.putAll = function(hashtable, conflictCallback) {
|
||||
var entries = hashtable.entries();
|
||||
var entry, key, value, thisValue, i = entries.length;
|
||||
var hasConflictCallback = (typeof conflictCallback == FUNCTION);
|
||||
while (i--) {
|
||||
entry = entries[i];
|
||||
key = entry[0];
|
||||
value = entry[1];
|
||||
|
||||
// Check for a conflict. The default behaviour is to overwrite the value for an existing key
|
||||
if ( hasConflictCallback && (thisValue = that.get(key)) ) {
|
||||
value = conflictCallback(key, thisValue, value);
|
||||
}
|
||||
that.put(key, value);
|
||||
}
|
||||
};
|
||||
|
||||
this.clone = function() {
|
||||
var clone = new Hashtable(hashingFunctionParam, equalityFunctionParam);
|
||||
clone.putAll(that);
|
||||
return clone;
|
||||
};
|
||||
}
|
||||
|
||||
return Hashtable;
|
||||
})();
|
||||
@@ -29,7 +29,7 @@
|
||||
import js.*
|
||||
|
||||
fun main(args : Array<String>) {
|
||||
if (args.isEmpty) {
|
||||
if (args.isEmpty()) {
|
||||
printBottles(99)
|
||||
}
|
||||
else {
|
||||
@@ -72,4 +72,4 @@ fun bottlesOfBeer(count : Int) : String =
|
||||
// From the std package
|
||||
// This is an extension property, i.e. a property that is defined for the
|
||||
// type Array<T>, but does not sit inside the class Array
|
||||
val <T> Array<T>.isEmpty : Boolean get() = size == 0
|
||||
fun <T> Array<T>.isEmpty() = size == 0
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
/**
|
||||
* This is an example of a Type-Safe Groovy-style Builder
|
||||
*
|
||||
* Builders are good for declaratively describing data in your code.
|
||||
* In this example we show how to describe an HTML page in Kotlin.
|
||||
*
|
||||
* See this page for details:
|
||||
* http://confluence.jetbrains.net/display/Kotlin/Type-safe+Groovy-style+builders
|
||||
*/
|
||||
import js.*
|
||||
import java.util.*
|
||||
|
||||
fun main(args : Array<String>) {
|
||||
val result =
|
||||
html {
|
||||
head {
|
||||
title {+"XML encoding with Kotlin"}
|
||||
}
|
||||
body {
|
||||
h1 {+"XML encoding with Kotlin"}
|
||||
p {+"this format can be used as an alternative markup to XML"}
|
||||
|
||||
// an element with attributes and text content
|
||||
a(href = "http://jetbrains.com/kotlin") {+"Kotlin"}
|
||||
|
||||
// mixed content
|
||||
p {
|
||||
+"This is some"
|
||||
b {+"mixed"}
|
||||
+"text. For more see the"
|
||||
a(href = "http://jetbrains.com/kotlin") {+"Kotlin"}
|
||||
+"project"
|
||||
}
|
||||
p {+"some text"}
|
||||
|
||||
// content generated from command-line arguments
|
||||
p {
|
||||
+"Command line arguments were:"
|
||||
ul {
|
||||
for (arg in args)
|
||||
li {+arg}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
println(result)
|
||||
}
|
||||
|
||||
trait Element {
|
||||
fun render(builder : StringBuilder, indent : String)
|
||||
|
||||
fun toString() : String? {
|
||||
val builder = StringBuilder()
|
||||
render(builder, "")
|
||||
return builder.toString()
|
||||
}
|
||||
}
|
||||
|
||||
class TextElement(val text : String) : Element {
|
||||
override fun render(builder : StringBuilder, indent : String) {
|
||||
builder.append("$indent$text\n")
|
||||
}
|
||||
}
|
||||
|
||||
abstract class Tag(val name : String) : Element {
|
||||
val children = ArrayList<Element>()
|
||||
val attributes = HashMap<String, String>()
|
||||
|
||||
protected fun initTag<T : Element>(tag : T, init : T.() -> Unit) : T {
|
||||
tag.init()
|
||||
children.add(tag)
|
||||
return tag
|
||||
}
|
||||
|
||||
override fun render(builder : StringBuilder, indent : String) {
|
||||
builder.append("$indent<$name${renderAttributes()}>\n")
|
||||
for (c in children) {
|
||||
c.render(builder, indent + " ")
|
||||
}
|
||||
builder.append("$indent</$name>\n")
|
||||
}
|
||||
|
||||
private fun renderAttributes() : String? {
|
||||
val builder = StringBuilder()
|
||||
for (a in attributes.keySet()) {
|
||||
builder.append(" $a=\"${attributes[a]}\"")
|
||||
}
|
||||
return builder.toString()
|
||||
}
|
||||
}
|
||||
|
||||
abstract class TagWithText(name : String) : Tag(name) {
|
||||
fun String.plus() {
|
||||
children.add(TextElement(this))
|
||||
}
|
||||
}
|
||||
|
||||
class HTML() : TagWithText("html") {
|
||||
fun head(init : Head.() -> Unit) = initTag(Head(), init)
|
||||
|
||||
fun body(init : Body.() -> Unit) = initTag(Body(), init)
|
||||
}
|
||||
|
||||
class Head() : TagWithText("head") {
|
||||
fun title(init : Title.() -> Unit) = initTag(Title(), init)
|
||||
}
|
||||
|
||||
class Title() : TagWithText("title")
|
||||
|
||||
abstract class BodyTag(name : String) : TagWithText(name) {
|
||||
fun b(init : B.() -> Unit) = initTag(B(), init)
|
||||
fun p(init : P.() -> Unit) = initTag(P(), init)
|
||||
fun h1(init : H1.() -> Unit) = initTag(H1(), init)
|
||||
fun ul(init : UL.() -> Unit) = initTag(UL(), init)
|
||||
fun a(href : String, init : A.() -> Unit) {
|
||||
val a = initTag(A(), init)
|
||||
a.href = href
|
||||
}
|
||||
}
|
||||
|
||||
class Body() : BodyTag("body")
|
||||
class UL() : BodyTag("ul") {
|
||||
fun li(init : LI.() -> Unit) = initTag(LI(), init)
|
||||
}
|
||||
|
||||
class B() : BodyTag("b")
|
||||
class LI() : BodyTag("li")
|
||||
class P() : BodyTag("p")
|
||||
class H1() : BodyTag("h1")
|
||||
class A() : BodyTag("a") {
|
||||
public var href : String
|
||||
get() = attributes["href"]
|
||||
set(value) {
|
||||
attributes["href"] = value
|
||||
}
|
||||
}
|
||||
|
||||
fun html(init : HTML.() -> Unit) : HTML {
|
||||
val html = HTML()
|
||||
html.init()
|
||||
return html
|
||||
}
|
||||
|
||||
// An excerpt from the Standard Library
|
||||
fun <K, V> Map<K, V>.set(key : K, value : V) = this.put(key, value)
|
||||
@@ -0,0 +1,178 @@
|
||||
/**
|
||||
* This is a straightforward implementation of The Game of Life
|
||||
* See http://en.wikipedia.org/wiki/Conway's_Game_of_Life
|
||||
*/
|
||||
package life
|
||||
|
||||
import java.util.*
|
||||
|
||||
/*
|
||||
* A field where cells live. Effectively immutable
|
||||
*/
|
||||
class Field(
|
||||
val width : Int,
|
||||
val height : Int,
|
||||
// This function tells the constructor which cells are alive
|
||||
// if init(i, j) is true, the cell (i, j) is alive
|
||||
init : (Int, Int) -> Boolean
|
||||
) {
|
||||
private val live : Array<Array<Boolean>> = Array(height) {i -> Array(width) {j -> init(i, j)}}
|
||||
|
||||
private fun liveCount(i : Int, j : Int)
|
||||
= if (i in 0..height-1 &&
|
||||
j in 0..width-1 &&
|
||||
live[i][j]) 1 else 0
|
||||
|
||||
// How many neighbors of (i, j) are alive?
|
||||
fun liveNeighbors(i : Int, j : Int) =
|
||||
liveCount(i - 1, j - 1) +
|
||||
liveCount(i - 1, j) +
|
||||
liveCount(i - 1, j + 1) +
|
||||
liveCount(i, j - 1) +
|
||||
liveCount(i, j + 1) +
|
||||
liveCount(i + 1, j - 1) +
|
||||
liveCount(i + 1, j) +
|
||||
liveCount(i + 1, j + 1)
|
||||
|
||||
// You can say field[i, j], and this function gets called
|
||||
fun get(i : Int, j : Int) = live[i][j]
|
||||
}
|
||||
|
||||
/**
|
||||
* This function takes the present state of the field
|
||||
* and return a new field representing the next moment of time
|
||||
*/
|
||||
fun next(field : Field) : Field {
|
||||
return Field(field.width, field.height) {i, j ->
|
||||
val n = field.liveNeighbors(i, j)
|
||||
if (field[i, j])
|
||||
// (i, j) is alive
|
||||
n in 2..3 // It remains alive iff it has 2 or 3 neighbors
|
||||
else
|
||||
// (i, j) is dead
|
||||
n == 3 // A new cell is born if there are 3 neighbors alive
|
||||
}
|
||||
}
|
||||
|
||||
/** A few colony examples here */
|
||||
fun main(args : Array<String>) {
|
||||
// Simplistic demo
|
||||
printField("***", 3)
|
||||
// "Star burst"
|
||||
printField("""
|
||||
__*__
|
||||
_***_
|
||||
__*__
|
||||
""", 10)
|
||||
// Stable colony
|
||||
printField("""
|
||||
__*__
|
||||
_*_*_
|
||||
__*__
|
||||
""", 3)
|
||||
// Stable from the step 2
|
||||
printField("""
|
||||
__**__
|
||||
__**__
|
||||
__**__
|
||||
""", 3)
|
||||
// Oscillating colony
|
||||
printField("""
|
||||
__**__
|
||||
__**__
|
||||
__**__
|
||||
__**__
|
||||
""", 6)
|
||||
// A fancier oscillating colony
|
||||
printField("""
|
||||
---------------
|
||||
---***---***---
|
||||
---------------
|
||||
-*----*-*----*-
|
||||
-*----*-*----*-
|
||||
-*----*-*----*-
|
||||
---***---***---
|
||||
---------------
|
||||
---***---***---
|
||||
-*----*-*----*-
|
||||
-*----*-*----*-
|
||||
-*----*-*----*-
|
||||
---------------
|
||||
---***---***---
|
||||
---------------
|
||||
""", 10)
|
||||
}
|
||||
|
||||
// UTILITIES
|
||||
|
||||
fun printField(s : String, steps : Int) {
|
||||
var field = makeField(s)
|
||||
for (step in 1..steps) {
|
||||
println("Step: $step")
|
||||
for (i in 0..field.height-1) {
|
||||
for (j in 0..field.width-1) {
|
||||
print(if (field[i, j]) "*" else " ")
|
||||
}
|
||||
println("")
|
||||
}
|
||||
field = next(field)
|
||||
}
|
||||
}
|
||||
|
||||
fun makeField(s : String) : Field {
|
||||
val lines = s.split("\n").sure()
|
||||
val w = max<String?>(lines.toList(), comparator<String?> {o1, o2 ->
|
||||
val l1 : Int = o1?.size ?: 0
|
||||
val l2 = o2?.size ?: 0
|
||||
l1 - l2
|
||||
}).sure()
|
||||
val data = Array(lines.size) {Array(w.size) {false}}
|
||||
|
||||
// workaround
|
||||
for (i in data.indices) {
|
||||
data[i] = Array(w.size) {false}
|
||||
for (j in data[i].indices)
|
||||
data[i][j] = false
|
||||
}
|
||||
|
||||
for (line in lines.indices) {
|
||||
for (x in lines[line].indices) {
|
||||
val c = lines[line].sure()[x]
|
||||
data[line][x] = c == '*'
|
||||
}
|
||||
}
|
||||
|
||||
return Field(w.size, lines.size) {i, j -> data[i][j]}
|
||||
}
|
||||
|
||||
// An excerpt from the Standard Library
|
||||
val String?.indices : IntRange get() = IntRange(0, this.sure().size)
|
||||
|
||||
fun <K, V> Map<K, V>.set(k : K, v : V) { put(k, v) }
|
||||
|
||||
fun comparator<T> (f : (T, T) -> Int) : Comparator<T> = object : Comparator<T> {
|
||||
override fun compare(o1 : T, o2 : T) : Int = f(o1, o2)
|
||||
}
|
||||
|
||||
fun println(message : Any?) {
|
||||
System.out?.println(message)
|
||||
}
|
||||
|
||||
fun print(message : Any?) {
|
||||
System.out?.print(message)
|
||||
}
|
||||
|
||||
val <T> Array<T>.isEmpty : Boolean get() = size == 0
|
||||
|
||||
fun String.split(s : String) = (this as java.lang.String).split(s)
|
||||
|
||||
val String.size : Int
|
||||
get() = length
|
||||
|
||||
fun <T, C: Collection<T>> Array<T>.to(result: C) : C {
|
||||
for (elem in this)
|
||||
result.add(elem)
|
||||
return result
|
||||
}
|
||||
|
||||
fun <T> Array<T>.toList() : List<T> = this.to(ArrayList<T>())
|
||||
@@ -298,4 +298,4 @@ Take one down, pass it around, 1 bottle of beer on the wall.
|
||||
Take one down, pass it around, no more bottles of beer on the wall.
|
||||
|
||||
No more bottles of beer on the wall, no more bottles of beer.
|
||||
Go to the store and buy some more, 99 bottles of beer on the wall.
|
||||
Go to the store and buy some more, 99 bottles of beer on the wall.
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
The "2 bottles of beer" song
|
||||
|
||||
2 bottles of beer on the wall, 2 bottles of beer.
|
||||
Take one down, pass it around, 1 bottle of beer on the wall.
|
||||
|
||||
1 bottle of beer on the wall, 1 bottle of beer.
|
||||
Take one down, pass it around, no more bottles of beer on the wall.
|
||||
|
||||
No more bottles of beer on the wall, no more bottles of beer.
|
||||
Go to the store and buy some more, 2 bottles of beer on the wall.
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
XML encoding with Kotlin
|
||||
</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>
|
||||
XML encoding with Kotlin
|
||||
</h1>
|
||||
<p>
|
||||
this format can be used as an alternative markup to XML
|
||||
</p>
|
||||
<a href="http://jetbrains.com/kotlin">
|
||||
Kotlin
|
||||
</a>
|
||||
<p>
|
||||
This is some
|
||||
<b>
|
||||
mixed
|
||||
</b>
|
||||
text. For more see the
|
||||
<a href="http://jetbrains.com/kotlin">
|
||||
Kotlin
|
||||
</a>
|
||||
project
|
||||
</p>
|
||||
<p>
|
||||
some text
|
||||
</p>
|
||||
<p>
|
||||
Command line arguments were:
|
||||
<ul>
|
||||
</ul>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,323 @@
|
||||
Step: 1
|
||||
***
|
||||
Step: 2
|
||||
*
|
||||
Step: 3
|
||||
|
||||
Step: 1
|
||||
|
||||
*
|
||||
***
|
||||
*
|
||||
|
||||
Step: 2
|
||||
|
||||
***
|
||||
* *
|
||||
***
|
||||
|
||||
Step: 3
|
||||
*
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
*
|
||||
Step: 4
|
||||
*
|
||||
***
|
||||
** **
|
||||
***
|
||||
*
|
||||
Step: 5
|
||||
***
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
***
|
||||
Step: 6
|
||||
***
|
||||
* * *
|
||||
*** **
|
||||
* * *
|
||||
***
|
||||
Step: 7
|
||||
***
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
***
|
||||
Step: 8
|
||||
**
|
||||
* * *
|
||||
*** **
|
||||
* * *
|
||||
**
|
||||
Step: 9
|
||||
***
|
||||
* * *
|
||||
* * *
|
||||
* * *
|
||||
***
|
||||
Step: 10
|
||||
***
|
||||
* *
|
||||
** * *
|
||||
* *
|
||||
***
|
||||
Step: 1
|
||||
|
||||
*
|
||||
* *
|
||||
*
|
||||
|
||||
Step: 2
|
||||
|
||||
*
|
||||
* *
|
||||
*
|
||||
|
||||
Step: 3
|
||||
|
||||
*
|
||||
* *
|
||||
*
|
||||
|
||||
Step: 1
|
||||
|
||||
**
|
||||
**
|
||||
**
|
||||
|
||||
Step: 2
|
||||
|
||||
**
|
||||
* *
|
||||
**
|
||||
|
||||
Step: 3
|
||||
|
||||
**
|
||||
* *
|
||||
**
|
||||
|
||||
Step: 1
|
||||
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
|
||||
Step: 2
|
||||
|
||||
**
|
||||
*
|
||||
*
|
||||
**
|
||||
|
||||
Step: 3
|
||||
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
|
||||
Step: 4
|
||||
|
||||
**
|
||||
*
|
||||
*
|
||||
**
|
||||
|
||||
Step: 5
|
||||
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
|
||||
Step: 6
|
||||
|
||||
**
|
||||
*
|
||||
*
|
||||
**
|
||||
|
||||
Step: 1
|
||||
|
||||
|
||||
*** ***
|
||||
|
||||
* * * *
|
||||
* * * *
|
||||
* * * *
|
||||
*** ***
|
||||
|
||||
*** ***
|
||||
* * * *
|
||||
* * * *
|
||||
* * * *
|
||||
|
||||
*** ***
|
||||
|
||||
|
||||
Step: 2
|
||||
|
||||
* *
|
||||
* *
|
||||
** **
|
||||
|
||||
*** ** ** ***
|
||||
* * * * * *
|
||||
** **
|
||||
|
||||
** **
|
||||
* * * * * *
|
||||
*** ** ** ***
|
||||
|
||||
** **
|
||||
* *
|
||||
* *
|
||||
|
||||
Step: 3
|
||||
|
||||
|
||||
** **
|
||||
** **
|
||||
* * * * * *
|
||||
*** ** ** ***
|
||||
* * * * * *
|
||||
*** ***
|
||||
|
||||
*** ***
|
||||
* * * * * *
|
||||
*** ** ** ***
|
||||
* * * * * *
|
||||
** **
|
||||
** **
|
||||
|
||||
|
||||
Step: 4
|
||||
|
||||
|
||||
*** ***
|
||||
|
||||
* * * *
|
||||
* * * *
|
||||
* * * *
|
||||
*** ***
|
||||
|
||||
*** ***
|
||||
* * * *
|
||||
* * * *
|
||||
* * * *
|
||||
|
||||
*** ***
|
||||
|
||||
|
||||
Step: 5
|
||||
|
||||
* *
|
||||
* *
|
||||
** **
|
||||
|
||||
*** ** ** ***
|
||||
* * * * * *
|
||||
** **
|
||||
|
||||
** **
|
||||
* * * * * *
|
||||
*** ** ** ***
|
||||
|
||||
** **
|
||||
* *
|
||||
* *
|
||||
|
||||
Step: 6
|
||||
|
||||
|
||||
** **
|
||||
** **
|
||||
* * * * * *
|
||||
*** ** ** ***
|
||||
* * * * * *
|
||||
*** ***
|
||||
|
||||
*** ***
|
||||
* * * * * *
|
||||
*** ** ** ***
|
||||
* * * * * *
|
||||
** **
|
||||
** **
|
||||
|
||||
|
||||
Step: 7
|
||||
|
||||
|
||||
*** ***
|
||||
|
||||
* * * *
|
||||
* * * *
|
||||
* * * *
|
||||
*** ***
|
||||
|
||||
*** ***
|
||||
* * * *
|
||||
* * * *
|
||||
* * * *
|
||||
|
||||
*** ***
|
||||
|
||||
|
||||
Step: 8
|
||||
|
||||
* *
|
||||
* *
|
||||
** **
|
||||
|
||||
*** ** ** ***
|
||||
* * * * * *
|
||||
** **
|
||||
|
||||
** **
|
||||
* * * * * *
|
||||
*** ** ** ***
|
||||
|
||||
** **
|
||||
* *
|
||||
* *
|
||||
|
||||
Step: 9
|
||||
|
||||
|
||||
** **
|
||||
** **
|
||||
* * * * * *
|
||||
*** ** ** ***
|
||||
* * * * * *
|
||||
*** ***
|
||||
|
||||
*** ***
|
||||
* * * * * *
|
||||
*** ** ** ***
|
||||
* * * * * *
|
||||
** **
|
||||
** **
|
||||
|
||||
|
||||
Step: 10
|
||||
|
||||
|
||||
*** ***
|
||||
|
||||
* * * *
|
||||
* * * *
|
||||
* * * *
|
||||
*** ***
|
||||
|
||||
*** ***
|
||||
* * * *
|
||||
* * * *
|
||||
* * * *
|
||||
|
||||
*** ***
|
||||
|
||||
Reference in New Issue
Block a user