You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by er...@apache.org on 2012/12/30 17:47:03 UTC
svn commit: r1426963 - in /incubator/flex/whiteboard/mschmalle/falconjx:
compiler.jx.tests/src/org/apache/flex/compiler/internal/js/codegen/goog/
compiler.jx/src/org/apache/flex/compiler/as/codegen/
compiler.jx/src/org/apache/flex/compiler/internal/as/...
Author: erikdebruin
Date: Sun Dec 30 16:47:02 2012
New Revision: 1426963
URL: http://svn.apache.org/viewvc?rev=1426963&view=rev
Log:
Worked my way through the 'Method Member' tests for the 'goog'-ified JS implementation. In order to get the function block closing semicolon in place, I've 'rerouted' some stuff in the AS and JS emitter base classes. I put comments on the relevant sections, please check my implementation and feel free to give brutal feedback :-)
Added:
incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx.tests/src/org/apache/flex/compiler/internal/js/codegen/goog/TestGoogMethodMembers.java (with props)
Modified:
incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx/src/org/apache/flex/compiler/as/codegen/IASEmitter.java
incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx/src/org/apache/flex/compiler/internal/as/codegen/ASAfterNodeStrategy.java
incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx/src/org/apache/flex/compiler/internal/as/codegen/ASEmitter.java
incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx/src/org/apache/flex/compiler/internal/js/codegen/JSEmitter.java
incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx/src/org/apache/flex/compiler/internal/js/codegen/goog/JSGoogDocEmitter.java
incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx/src/org/apache/flex/compiler/internal/js/codegen/goog/JSGoogEmitter.java
Added: incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx.tests/src/org/apache/flex/compiler/internal/js/codegen/goog/TestGoogMethodMembers.java
URL: http://svn.apache.org/viewvc/incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx.tests/src/org/apache/flex/compiler/internal/js/codegen/goog/TestGoogMethodMembers.java?rev=1426963&view=auto
==============================================================================
--- incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx.tests/src/org/apache/flex/compiler/internal/js/codegen/goog/TestGoogMethodMembers.java (added)
+++ incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx.tests/src/org/apache/flex/compiler/internal/js/codegen/goog/TestGoogMethodMembers.java Sun Dec 30 16:47:02 2012
@@ -0,0 +1,192 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ *
+ */
+
+package org.apache.flex.compiler.internal.js.codegen.goog;
+
+import org.apache.flex.compiler.clients.IBackend;
+import org.apache.flex.compiler.internal.as.codegen.TestMethodMembers;
+import org.apache.flex.compiler.internal.js.codegen.JSSharedData;
+import org.apache.flex.compiler.internal.js.driver.goog.GoogBackend;
+import org.apache.flex.compiler.tree.as.IFunctionNode;
+import org.junit.Test;
+
+/**
+ * This class tests the production of 'goog'-ified JS code for Class Method members.
+ *
+ * @author Michael Schmalle
+ * @author Erik de Bruin
+ */
+public class TestGoogMethodMembers extends TestMethodMembers
+{
+ // TODO (erikdebruin)
+ // 1) ideally '@this' should only be included in the annotation if there is
+ // actually a reference to 'this' in the function body
+ // 9) switch 'alternate' indicator to point to 'Wienberg style', not mine ;-)
+ // 10) can we safely ignore the 'public' and custom namespaces?
+
+ @Override
+ @Test
+ public void testMethod()
+ {
+ IFunctionNode node = getMethod("function foo(){}");
+ visitor.visitFunction(node);
+ assertOut("A.prototype.foo = function() {\n};");
+ }
+
+ @Override
+ @Test
+ public void testMethod_withReturnType()
+ {
+ IFunctionNode node = getMethod("function foo():int{\treturn -1;}");
+ visitor.visitFunction(node);
+ assertOut("/**\n * @return {number}\n */\nA.prototype.foo = function() {\n\treturn -1;\n};");
+ }
+
+ @Override
+ @Test
+ public void testMethod_withParameterReturnType()
+ {
+ IFunctionNode node = getMethod("function foo(bar):int{\treturn -1;}");
+ visitor.visitFunction(node);
+ assertOut("/**\n * @param {*} bar\n * @return {number}\n */\nA.prototype.foo = function(bar) {\n\treturn -1;\n};");
+ }
+
+ @Override
+ @Test
+ public void testMethod_withParameterTypeReturnType()
+ {
+ IFunctionNode node = getMethod("function foo(bar:String):int{\treturn -1;}");
+ visitor.visitFunction(node);
+ assertOut("/**\n * @param {string} bar\n * @return {number}\n */\nA.prototype.foo = function(bar) {\n\treturn -1;\n};");
+ }
+
+ @Override
+ @Test
+ public void testMethod_withDefaultParameterTypeReturnType()
+ {
+ IFunctionNode node = getMethod("function foo(bar:String = \"baz\"):int{\treturn -1;}");
+ JSSharedData.OUTPUT_ALTERNATE = true;
+ visitor.visitFunction(node);
+ assertOut("/**\n * @param {string=} bar\n * @return {number}\n */\nA.prototype.foo = function(bar) {\n\tbar = typeof bar !== 'undefined' ? bar : \"baz\";\n\treturn -1;\n};");
+ }
+
+ @Test
+ public void testMethod_withDefaultParameterTypeReturnType_Alternate()
+ {
+ IFunctionNode node = getMethod("function foo(bar:String = \"baz\"):int{\treturn -1;}");
+ visitor.visitFunction(node);
+ assertOut("/**\n * @param {string=} bar\n * @return {number}\n */\nA.prototype.foo = function(bar) {\n\tif (arguments.length < 1) {\n\t\tbar = \"baz\";\n\t}\n\treturn -1;\n};");
+ }
+
+ @Override
+ @Test
+ public void testMethod_withMultipleDefaultParameterTypeReturnType()
+ {
+ IFunctionNode node = getMethod("function foo(bar:String, baz:int = null):int{\treturn -1;}");
+ JSSharedData.OUTPUT_ALTERNATE = true;
+ visitor.visitFunction(node);
+ assertOut("/**\n * @param {string} bar\n * @param {number=} baz\n * @return {number}\n */\nA.prototype.foo = function(bar, baz) {\n\tbaz = typeof baz !== 'undefined' ? baz : null;\n\treturn -1;\n};");
+ }
+
+ @Test
+ public void testMethod_withMultipleDefaultParameterTypeReturnType_Alternate()
+ {
+ IFunctionNode node = getMethod("function foo(bar:String, baz:int = null):int{\treturn -1;}");
+ visitor.visitFunction(node);
+ assertOut("/**\n * @param {string} bar\n * @param {number=} baz\n * @return {number}\n */\nA.prototype.foo = function(bar, baz) {\n\tif (arguments.length < 2) {\n\t\tbaz = null;\n\t}\n\treturn -1;\n};");
+ }
+
+ @Override
+ @Test
+ public void testMethod_withRestParameterTypeReturnType()
+ {
+ IFunctionNode node = getMethod("function foo(bar:String, ...rest):int{\treturn -1;}");
+ visitor.visitFunction(node);
+ assertOut("/**\n * @param {string} bar\n * @param {...} rest\n * @return {number}\n */\nA.prototype.foo = function(bar, rest) {\n\trest = Array.prototype.slice.call(arguments, 1);\n\treturn -1;\n};");
+ }
+
+ @Override
+ @Test
+ public void testMethod_withNamespace()
+ {
+ IFunctionNode node = getMethod("public function foo(bar:String, baz:int = null):int{\treturn -1;}");
+ JSSharedData.OUTPUT_ALTERNATE = true;
+ visitor.visitFunction(node);
+ // we ignore the 'public' namespace completely
+ assertOut("/**\n * @param {string} bar\n * @param {number=} baz\n * @return {number}\n */\nA.prototype.foo = function(bar, baz) {\n\tbaz = typeof baz !== 'undefined' ? baz : null;\n\treturn -1;\n};");
+ }
+
+ @Override
+ @Test
+ public void testMethod_withNamespaceCustom()
+ {
+ IFunctionNode node = getMethod("mx_internal function foo(bar:String, baz:int = null):int{\treturn -1;}");
+ JSSharedData.OUTPUT_ALTERNATE = true;
+ visitor.visitFunction(node);
+ // we ignore the custom namespaces completely (are there side effects I'm missing?)
+ assertOut("/**\n * @param {string} bar\n * @param {number=} baz\n * @return {number}\n */\nA.prototype.foo = function(bar, baz) {\n\tbaz = typeof baz !== 'undefined' ? baz : null;\n\treturn -1;\n};");
+ }
+
+ @Override
+ @Test
+ public void testMethod_withNamespaceModifiers()
+ {
+ IFunctionNode node = getMethod("public static function foo(bar:String, baz:int = null):int{\treturn -1;}");
+ JSSharedData.OUTPUT_ALTERNATE = true;
+ visitor.visitFunction(node);
+ // (erikdebruin) here we actually DO want to declare the method
+ // directly on the 'class' constructor instead of the
+ // prototype!
+ assertOut("/**\n * @param {string} bar\n * @param {number=} baz\n * @return {number}\n */\nA.foo = function(bar, baz) {\n\tbaz = typeof baz !== 'undefined' ? baz : null;\n\treturn -1;\n};");
+ }
+
+ @Override
+ @Test
+ public void testMethod_withNamespaceModifierOverride()
+ {
+ IFunctionNode node = getMethod("public override function foo(bar:String, baz:int = null):int{\treturn -1;}");
+ JSSharedData.OUTPUT_ALTERNATE = true;
+ visitor.visitFunction(node);
+ assertOutDebug("/**\n * @param {string} bar\n * @param {number=} baz\n * @return {number}\n * @override\n */\nA.prototype.foo = function(bar, baz) {\n\tbaz = typeof baz !== 'undefined' ? baz : null;\n\treturn -1;\n};");
+ }
+
+ @Override
+ @Test
+ public void testMethod_withNamespaceModifierOverrideBackwards()
+ {
+ IFunctionNode node = getMethod("override public function foo(bar:String, baz:int = null):int{return -1;}");
+ JSSharedData.OUTPUT_ALTERNATE = true;
+ visitor.visitFunction(node);
+ assertOut("/**\n * @param {string} bar\n * @param {number=} baz\n * @return {number}\n * @override\n */\nA.prototype.foo = function(bar, baz) {\n\tbaz = typeof baz !== 'undefined' ? baz : null;\n\treturn -1;\n};");
+ }
+
+ @Override
+ protected IFunctionNode getMethod(String code)
+ {
+ JSSharedData.OUTPUT_ALTERNATE = false;
+
+ return super.getMethod(code);
+ }
+
+ @Override
+ protected IBackend createBackend()
+ {
+ return new GoogBackend();
+ }
+}
Propchange: incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx.tests/src/org/apache/flex/compiler/internal/js/codegen/goog/TestGoogMethodMembers.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx/src/org/apache/flex/compiler/as/codegen/IASEmitter.java
URL: http://svn.apache.org/viewvc/incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx/src/org/apache/flex/compiler/as/codegen/IASEmitter.java?rev=1426963&r1=1426962&r2=1426963&view=diff
==============================================================================
--- incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx/src/org/apache/flex/compiler/as/codegen/IASEmitter.java (original)
+++ incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx/src/org/apache/flex/compiler/as/codegen/IASEmitter.java Sun Dec 30 16:47:02 2012
@@ -62,6 +62,11 @@ public interface IASEmitter
void indentPush();
/**
+ * Writes the block closing character(s)
+ */
+ void writeBlockClose();
+
+ /**
* Pops an indent from the emitter so after newlines are emitted, the output
* is correctly formatted.
*/
Modified: incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx/src/org/apache/flex/compiler/internal/as/codegen/ASAfterNodeStrategy.java
URL: http://svn.apache.org/viewvc/incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx/src/org/apache/flex/compiler/internal/as/codegen/ASAfterNodeStrategy.java?rev=1426963&r1=1426962&r2=1426963&view=diff
==============================================================================
--- incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx/src/org/apache/flex/compiler/internal/as/codegen/ASAfterNodeStrategy.java (original)
+++ incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx/src/org/apache/flex/compiler/internal/as/codegen/ASAfterNodeStrategy.java Sun Dec 30 16:47:02 2012
@@ -60,7 +60,9 @@ public class ASAfterNodeStrategy impleme
emitter.indentPop();
emitter.write("\n");
}
- emitter.write("}");
+
+ // (erikdebruin) moved this to utility method to allow overriding
+ emitter.writeBlockClose();
}
else if (type == ContainerType.IMPLICIT
|| type == ContainerType.SYNTHESIZED)
Modified: incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx/src/org/apache/flex/compiler/internal/as/codegen/ASEmitter.java
URL: http://svn.apache.org/viewvc/incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx/src/org/apache/flex/compiler/internal/as/codegen/ASEmitter.java?rev=1426963&r1=1426962&r2=1426963&view=diff
==============================================================================
--- incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx/src/org/apache/flex/compiler/internal/as/codegen/ASEmitter.java (original)
+++ incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx/src/org/apache/flex/compiler/internal/as/codegen/ASEmitter.java Sun Dec 30 16:47:02 2012
@@ -147,6 +147,16 @@ public class ASEmitter implements IASEmi
currentIndent--;
}
+ // (erikdebruin) I needed a way to add a semi-colon after the closing curly
+ // bracket of a block in the 'goog'-ified output. Instead of
+ // subclassing 'ASAfterNodeStrategy' and copying
+ // the entire function body, I thought I might use this little
+ // utility method and override that. Am I doing it right?
+ public void writeBlockClose()
+ {
+ write("}");
+ }
+
public void writeIndent()
{
String indent = "";
Modified: incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx/src/org/apache/flex/compiler/internal/js/codegen/JSEmitter.java
URL: http://svn.apache.org/viewvc/incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx/src/org/apache/flex/compiler/internal/js/codegen/JSEmitter.java?rev=1426963&r1=1426962&r2=1426963&view=diff
==============================================================================
--- incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx/src/org/apache/flex/compiler/internal/js/codegen/JSEmitter.java (original)
+++ incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx/src/org/apache/flex/compiler/internal/js/codegen/JSEmitter.java Sun Dec 30 16:47:02 2012
@@ -117,4 +117,11 @@ public class JSEmitter extends ASEmitter
// }
}
+ @Override
+ public void writeBlockClose()
+ {
+ super.writeBlockClose();
+
+ write(";");
+ }
}
Modified: incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx/src/org/apache/flex/compiler/internal/js/codegen/goog/JSGoogDocEmitter.java
URL: http://svn.apache.org/viewvc/incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx/src/org/apache/flex/compiler/internal/js/codegen/goog/JSGoogDocEmitter.java?rev=1426963&r1=1426962&r2=1426963&view=diff
==============================================================================
--- incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx/src/org/apache/flex/compiler/internal/js/codegen/goog/JSGoogDocEmitter.java (original)
+++ incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx/src/org/apache/flex/compiler/internal/js/codegen/goog/JSGoogDocEmitter.java Sun Dec 30 16:47:02 2012
@@ -91,15 +91,21 @@ public class JSGoogDocEmitter extends JS
@Override
public void emitOverride(IFunctionNode node)
{
- // TODO Auto-generated method stub
-
+ write(" * @override\n");
}
@Override
public void emitParam(IParameterNode node)
{
- write(" * @param {" + node.getVariableType() + "} " + node.getName()
- + "\n");
+ String postfix = (node.getDefaultValue() == null) ? "" : "=";
+
+ String paramType = "";
+ if (node.isRest())
+ paramType = "...";
+ else
+ paramType = convertASTypeToJS(node.getVariableType());
+
+ write(" * @param {" + paramType + postfix + "} " + node.getName() + "\n");
}
@Override
@@ -122,7 +128,7 @@ public class JSGoogDocEmitter extends JS
// TODO convert js types
String rtype = node.getReturnType();
if (rtype != null)
- write(" * @return {" + rtype + "}\n");
+ write(" * @return {" + convertASTypeToJS(rtype) + "}\n");
}
@Override
@@ -135,8 +141,9 @@ public class JSGoogDocEmitter extends JS
public void emitType(IASNode node)
{
//String type = SemanticUtils.getTypeOfStem(node, emitter.getProject());
- String type = ((IVariableNode) node).getVariableType(); // XXX need to map to js types
- write(" * @type {" + type + "}\n");
+ String type = ((IVariableNode) node).getVariableType();
+ // XXX need to map to js types
+ write(" * @type {" + convertASTypeToJS(type) + "}\n");
}
@Override
@@ -155,4 +162,22 @@ public class JSGoogDocEmitter extends JS
end();
}
+ //--------------------------------------------------------------------------
+
+ private String convertASTypeToJS(String name)
+ {
+ String result = name;
+
+ if (name.equals(""))
+ result = "*";
+
+ if (name.equals("String"))
+ result = "string";
+
+ if (name.equals("int") || name.equals("uint"))
+ result = "number";
+
+ return result;
+ }
+
}
Modified: incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx/src/org/apache/flex/compiler/internal/js/codegen/goog/JSGoogEmitter.java
URL: http://svn.apache.org/viewvc/incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx/src/org/apache/flex/compiler/internal/js/codegen/goog/JSGoogEmitter.java?rev=1426963&r1=1426962&r2=1426963&view=diff
==============================================================================
--- incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx/src/org/apache/flex/compiler/internal/js/codegen/goog/JSGoogEmitter.java (original)
+++ incubator/flex/whiteboard/mschmalle/falconjx/compiler.jx/src/org/apache/flex/compiler/internal/js/codegen/goog/JSGoogEmitter.java Sun Dec 30 16:47:02 2012
@@ -26,6 +26,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import org.apache.flex.compiler.common.ASModifier;
import org.apache.flex.compiler.definitions.IClassDefinition;
import org.apache.flex.compiler.definitions.IPackageDefinition;
import org.apache.flex.compiler.definitions.ITypeDefinition;
@@ -228,17 +229,64 @@ public class JSGoogEmitter extends JSEmi
}
else
{
- getDoc().begin();
- getDoc().emitThis(type);
+ Boolean hasDoc = false;
+
+ // @this
+ // TODO (erikdebruin) only emit @this when there actually is
+ // a 'this' reference in the method block
+ /*
+ if (false)
+ {
+ getDoc().begin();
+ hasDoc = true;
+
+ getDoc().emitThis(type);
+ }
+ //*/
+
// @param
IParameterNode[] parameters = node.getParameterNodes();
for (IParameterNode pnode : parameters)
{
+ if (!hasDoc)
+ {
+ getDoc().begin();
+ hasDoc = true;
+ }
+
getDoc().emitParam(pnode);
}
+
// @return
- getDoc().emitReturn(node);
- getDoc().end();
+ // TODO (erikdebruin) only emit @return when there actually is
+ // a return value defined
+ String returnType = node.getReturnType();
+ if (returnType != "")
+ {
+ if (!hasDoc)
+ {
+ getDoc().begin();
+ hasDoc = true;
+ }
+
+ getDoc().emitReturn(node);
+ }
+
+ // @override
+ Boolean override = node.hasModifier(ASModifier.OVERRIDE);
+ if (override)
+ {
+ if (!hasDoc)
+ {
+ getDoc().begin();
+ hasDoc = true;
+ }
+
+ getDoc().emitOverride(node);
+ }
+
+ if (hasDoc)
+ getDoc().end();
}
}
}
@@ -260,6 +308,8 @@ public class JSGoogEmitter extends JSEmi
{
write(qname);
write(".");
+ if (!fn.hasModifier(ASModifier.STATIC))
+ write("prototype.");
}
emitMemberName(node);
@@ -274,6 +324,8 @@ public class JSGoogEmitter extends JSEmi
@Override
public void emitFunctionBlockHeader(IFunctionNode node)
{
+ emitRestParameterCodeBlock(node);
+
if (JSSharedData.OUTPUT_ALTERNATE)
{
emitDefaultParameterCodeBlock_Alternate(node);
@@ -391,6 +443,24 @@ public class JSGoogEmitter extends JSEmi
}
}
+ private void emitRestParameterCodeBlock(IFunctionNode node)
+ {
+ IParameterNode[] pnodes = node.getParameterNodes();
+
+ IParameterNode rest = getRest(pnodes);
+ if (rest != null)
+ {
+ final StringBuilder code = new StringBuilder();
+
+ code.append(rest.getName() + " = "
+ + "Array.prototype.slice.call(arguments, "
+ + (pnodes.length - 1)
+ + ");\n");
+
+ write(code.toString());
+ }
+ }
+
@Override
public void emitParameter(IParameterNode node)
{
@@ -428,6 +498,17 @@ public class JSGoogEmitter extends JSEmi
return result;
}
+ private IParameterNode getRest(IParameterNode[] nodes)
+ {
+ for (IParameterNode node : nodes)
+ {
+ if (node.isRest())
+ return node;
+ }
+
+ return null;
+ }
+
private static ITypeDefinition getTypeDefinition(IDefinitionNode node)
{
ITypeNode tnode = (ITypeNode) node.getAncestorOfType(ITypeNode.class);