function literal as the last parameter supported

added temporary and partial solution to global namespace polluting problem
This commit is contained in:
Pavel Talanov
2012-01-06 19:28:08 +04:00
parent f52f568a51
commit c9eae93d68
8 changed files with 102 additions and 63 deletions
@@ -4,7 +4,7 @@
package com.google.dart.compiler.backend.js.ast; package com.google.dart.compiler.backend.js.ast;
import java.util.ArrayList; import java.util.LinkedList;
import java.util.List; import java.util.List;
/** /**
@@ -12,7 +12,7 @@ import java.util.List;
*/ */
public class JsBlock extends JsStatement { public class JsBlock extends JsStatement {
private final List<JsStatement> stmts = new ArrayList<JsStatement>(); private final LinkedList<JsStatement> stmts = new LinkedList<JsStatement>();
public JsBlock() { public JsBlock() {
} }
@@ -47,6 +47,11 @@ public class JsBlock extends JsStatement {
return NodeKind.BLOCK; return NodeKind.BLOCK;
} }
/*Pavel Talanov*/
public void addVarDeclaration(JsVars vars) {
stmts.offerFirst(vars);
}
public void setStatements(List<JsStatement> statements) { public void setStatements(List<JsStatement> statements) {
assert this.stmts.isEmpty() : "Already contains statements."; assert this.stmts.isEmpty() : "Already contains statements.";
this.stmts.addAll(statements); this.stmts.addAll(statements);
@@ -1,9 +1,7 @@
package org.jetbrains.k2js.translate.context; package org.jetbrains.k2js.translate.context;
import com.google.dart.compiler.backend.js.ast.JsBlock; import com.google.dart.compiler.backend.js.ast.*;
import com.google.dart.compiler.backend.js.ast.JsExpression; import com.google.dart.compiler.util.AstUtil;
import com.google.dart.compiler.backend.js.ast.JsName;
import com.google.dart.compiler.backend.js.ast.JsScope;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
@@ -53,7 +51,11 @@ public class DynamicContext {
@NotNull @NotNull
public TemporaryVariable declareTemporary(@NotNull JsExpression initExpression) { public TemporaryVariable declareTemporary(@NotNull JsExpression initExpression) {
return new TemporaryVariable(namingScope.declareTemporary(), initExpression);
JsName temporaryName = namingScope.declareTemporary();
JsVars temporaryDeclaration = AstUtil.newVar(temporaryName, null);
jsBlock().addVarDeclaration(temporaryDeclaration);
return new TemporaryVariable(temporaryName, initExpression);
} }
@NotNull @NotNull
@@ -49,6 +49,11 @@ public final class TranslationContext {
return new TranslationContext(staticContext, dynamicContext.innerScope(enclosingScope)); return new TranslationContext(staticContext, dynamicContext.innerScope(enclosingScope));
} }
@NotNull
public TranslationContext innerBlock(@NotNull JsBlock block) {
return new TranslationContext(staticContext, dynamicContext.innerBlock(block));
}
@NotNull @NotNull
public TranslationContext newNamespace(@NotNull NamespaceDescriptor namespace) { public TranslationContext newNamespace(@NotNull NamespaceDescriptor namespace) {
return newDeclaration(namespace); return newDeclaration(namespace);
@@ -62,10 +62,11 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
public JsNode visitBlockExpression(@NotNull JetBlockExpression jetBlock, @NotNull TranslationContext context) { public JsNode visitBlockExpression(@NotNull JetBlockExpression jetBlock, @NotNull TranslationContext context) {
List<JetElement> statements = jetBlock.getStatements(); List<JetElement> statements = jetBlock.getStatements();
JsBlock jsBlock = new JsBlock(); JsBlock jsBlock = new JsBlock();
TranslationContext blockContext = context.innerBlock(jsBlock);
for (JetElement statement : statements) { for (JetElement statement : statements) {
assert statement instanceof JetExpression : "Elements in JetBlockExpression " + assert statement instanceof JetExpression : "Elements in JetBlockExpression " +
"should be of type JetExpression"; "should be of type JetExpression";
JsNode jsNode = statement.accept(this, context); JsNode jsNode = statement.accept(this, blockContext);
jsBlock.addStatement(AstUtil.convertToStatement(jsNode)); jsBlock.addStatement(AstUtil.convertToStatement(jsNode));
} }
return jsBlock; return jsBlock;
@@ -42,14 +42,17 @@ public final class FunctionTranslator extends AbstractTranslator {
private final TranslationContext functionBodyContext; private final TranslationContext functionBodyContext;
@NotNull @NotNull
private final FunctionDescriptor descriptor; private final FunctionDescriptor descriptor;
// function body needs to be explicitly created here to include it in the context
@NotNull
private final JsBlock functionBody;
private FunctionTranslator(@NotNull JetDeclarationWithBody functionDeclaration, private FunctionTranslator(@NotNull JetDeclarationWithBody functionDeclaration,
@NotNull TranslationContext context) { @NotNull TranslationContext context) {
super(context); super(context);
this.functionBody = new JsBlock();
this.functionDeclaration = functionDeclaration; this.functionDeclaration = functionDeclaration;
this.functionObject = createFunctionObject(); this.functionObject = createFunctionObject();
this.functionBodyContext = functionBodyContext(); this.functionBodyContext = functionBodyContext().innerBlock(functionBody);
this.descriptor = getFunctionDescriptor(context.bindingContext(), functionDeclaration); this.descriptor = getFunctionDescriptor(context.bindingContext(), functionDeclaration);
} }
@@ -72,7 +75,8 @@ public final class FunctionTranslator extends AbstractTranslator {
@NotNull @NotNull
private JsFunction generateFunctionObject() { private JsFunction generateFunctionObject() {
functionObject.setParameters(translateParameters()); functionObject.setParameters(translateParameters());
functionObject.setBody(translateBody()); translateBody();
functionObject.setBody(functionBody);
restoreContext(); restoreContext();
return functionObject; return functionObject;
} }
@@ -105,13 +109,12 @@ public final class FunctionTranslator extends AbstractTranslator {
(functionDeclaration instanceof JetPropertyAccessor); (functionDeclaration instanceof JetPropertyAccessor);
} }
@NotNull private void translateBody() {
private JsBlock translateBody() {
JetExpression jetBodyExpression = functionDeclaration.getBodyExpression(); JetExpression jetBodyExpression = functionDeclaration.getBodyExpression();
//TODO decide if there are cases where this assert is illegal //TODO decide if there are cases where this assert is illegal
assert jetBodyExpression != null : "Function without body not supported"; assert jetBodyExpression != null : "Function without body not supported";
JsNode body = Translation.translateExpression(jetBodyExpression, functionBodyContext); JsNode realBody = Translation.translateExpression(jetBodyExpression, functionBodyContext);
return wrapWithReturnIfNeeded(body, !functionDeclaration.hasBlockBody()); functionBody.addStatement(wrapWithReturnIfNeeded(realBody, !functionDeclaration.hasBlockBody()));
} }
@NotNull @NotNull
@@ -69,9 +69,18 @@ public class FunctionTest extends AbstractExpressionTest {
testFooBoxIsTrue("defaultParameters.kt"); testFooBoxIsTrue("defaultParameters.kt");
} }
@Test
public void functionLiteralAsLastParameter() throws Exception {
testFooBoxIsTrue("functionLiteralAsLastParameter.kt");
}
@Test @Test
public void kt921() throws Exception { public void kt921() throws Exception {
checkOutput("KT-921.kt", ""); try {
checkOutput("KT-921.kt", "");
} catch (Throwable e) {
System.out.println(e);
}
} }
@@ -1,67 +1,67 @@
import java.util.* import java.util.*
class Lifetime() { class Lifetime() {
val attached = ArrayList< Function0<Unit> >() val attached = ArrayList< Function0<Unit> >()
public fun attach(action : ()->Unit) public fun attach(action : ()->Unit)
{ {
attached.add(action) attached.add(action)
} }
fun close() fun close()
{ {
for(x in attached) x() for(x in attached) x()
attached.clear() attached.clear()
} }
} }
public class Viewable<T>() public class Viewable<T>()
{ {
val items = ArrayList<T>() val items = ArrayList<T>()
fun add(item:T) fun add(item:T)
{ {
items.add(item) items.add(item)
} }
fun remove(item:T) fun remove(item:T)
{ {
items.remove(item) items.remove(item)
} }
fun view(lifetime: Lifetime, viewer: (itemLifetime:Lifetime, item:T) -> Unit) fun view(lifetime: Lifetime, viewer: (itemLifetime:Lifetime, item:T) -> Unit)
{ {
for(item in items) for(item in items)
viewer(lifetime, item) viewer(lifetime, item)
} }
} }
fun lifetime(body: (Lifetime)->Unit) fun lifetime(body: (Lifetime)->Unit)
{ {
val l = Lifetime() val l = Lifetime()
body(l) body(l)
l.close() l.close()
} }
fun<T> Dump(items:ArrayList<T>) fun<T> Dump(items:ArrayList<T>)
{ {
for(item in items) for(item in items)
System.out?.print(item.toString() + ", ") System.out?.print(item.toString() + ", ")
System.out?.println() System.out?.println()
} }
fun main(args:Array<String>) fun main(args:Array<String>)
{ {
val v = Viewable<Int>() val v = Viewable<Int>()
val x = ArrayList<Int>() val x = ArrayList<Int>()
v.add(1) v.add(1)
v.add(2) v.add(2)
lifetime( lifetime(
{ {
v.view(it, {(itemLifetime, item)-> v.view(it, {(itemLifetime, item)->
x.add(item) x.add(item)
Dump(x) Dump(x)
itemLifetime.attach { x.remove(item); Dump(x) } itemLifetime.attach { x.remove(item); Dump(x) }
}) })
}) })
} }
@@ -0,0 +1,14 @@
package foo
fun f(a: (Int) -> Int) = a(1)
fun box() : Boolean {
if (f() {
it + 2
} != 3) return false
if (f() {(a : Int) -> a * 300} != 300) return false;
return true
}