handle differences in Array, Int, Uint, Date
Project: http://git-wip-us.apache.org/repos/asf/flex-falcon/repo Commit: http://git-wip-us.apache.org/repos/asf/flex-falcon/commit/8e270130 Tree: http://git-wip-us.apache.org/repos/asf/flex-falcon/tree/8e270130 Diff: http://git-wip-us.apache.org/repos/asf/flex-falcon/diff/8e270130 Branch: refs/heads/master Commit: 8e2701303c98d6a1ccde5d85c327ac96330ef014 Parents: 49c3296 Author: Alex Harui <[email protected]> Authored: Wed Mar 9 11:49:41 2016 -0800 Committer: Alex Harui <[email protected]> Committed: Thu Mar 10 19:32:14 2016 -0800 ---------------------------------------------------------------------- .../js/flexjs/TestFlexJSGlobalClasses.java | 104 ++++++++++++++++ .../codegen/js/flexjs/JSFlexJSEmitter.java | 74 +++++++++++ .../codegen/js/jx/BinaryOperatorEmitter.java | 124 +++++++++++++++++++ .../codegen/js/jx/IdentifierEmitter.java | 57 +++++++++ .../codegen/js/jx/MemberAccessEmitter.java | 32 ++++- externs/js/missing.js | 72 +++++++++++ 6 files changed, 462 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/8e270130/compiler.jx.tests/src/org/apache/flex/compiler/internal/codegen/js/flexjs/TestFlexJSGlobalClasses.java ---------------------------------------------------------------------- diff --git a/compiler.jx.tests/src/org/apache/flex/compiler/internal/codegen/js/flexjs/TestFlexJSGlobalClasses.java b/compiler.jx.tests/src/org/apache/flex/compiler/internal/codegen/js/flexjs/TestFlexJSGlobalClasses.java index 1f0360f..a3a50c1 100644 --- a/compiler.jx.tests/src/org/apache/flex/compiler/internal/codegen/js/flexjs/TestFlexJSGlobalClasses.java +++ b/compiler.jx.tests/src/org/apache/flex/compiler/internal/codegen/js/flexjs/TestFlexJSGlobalClasses.java @@ -28,6 +28,7 @@ import org.apache.flex.compiler.internal.tree.as.VariableNode; import org.apache.flex.compiler.tree.as.IASNode; import org.apache.flex.compiler.tree.as.IBinaryOperatorNode; import org.apache.flex.compiler.tree.as.IForLoopNode; +import org.apache.flex.compiler.tree.as.IFunctionCallNode; import org.apache.flex.compiler.tree.as.IFunctionNode; import org.apache.flex.compiler.tree.as.IUnaryOperatorNode; import org.apache.flex.compiler.tree.as.IVariableNode; @@ -103,6 +104,109 @@ public class TestFlexJSGlobalClasses extends TestGoogGlobalClasses assertOut("var /** @type {Array} */ a = new Array(['Hello', 'World'])"); } + @Test + public void testArrayConstCaseInsensitive() + { + IVariableNode node = getVariable("var a:Number = Array.CASEINSENSITIVE"); + asBlockWalker.visitVariable(node); + assertOut("var /** @type {number} */ a = 1"); + } + + @Test + public void testArrayConstNumeric() + { + IVariableNode node = getVariable("var a:Number = Array.NUMERIC"); + asBlockWalker.visitVariable(node); + assertOut("var /** @type {number} */ a = 16"); + } + + @Ignore + public void testArrayRemoveAt() + { + // requires FP19 or newer + IBinaryOperatorNode node = getBinaryNode("var a:Array = new Array(); a.removeAt(2)"); + IFunctionCallNode parentNode = (IFunctionCallNode)(node.getParent()); + asBlockWalker.visitFunctionCall(parentNode); + assertOut("a.splice(2, 1)"); + } + + @Ignore + public void testArrayInsertAt() + { + // requires FP19 or newer + IBinaryOperatorNode node = getBinaryNode("var a:Array = new Array(); a.insertAt(2, 'foo')"); + IFunctionCallNode parentNode = (IFunctionCallNode)(node.getParent()); + asBlockWalker.visitFunctionCall(parentNode); + assertOut("a.splice(2, 0, 'foo')"); + } + + @Test + public void testIntConstMaxValue() + { + IVariableNode node = getVariable("var a:Number = int.MAX_VALUE"); + asBlockWalker.visitVariable(node); + assertOut("var /** @type {number} */ a = 2147483648"); + } + + @Test + public void testIntConstMinValue() + { + IVariableNode node = getVariable("var a:Number = int.MIN_VALUE"); + asBlockWalker.visitVariable(node); + assertOut("var /** @type {number} */ a = -2147483648"); + } + + @Test + public void testUintConstMaxValue() + { + IVariableNode node = getVariable("var a:Number = uint.MAX_VALUE"); + asBlockWalker.visitVariable(node); + assertOut("var /** @type {number} */ a = 4294967295"); + } + + @Test + public void testUintConstMinValue() + { + IVariableNode node = getVariable("var a:Number = uint.MIN_VALUE"); + asBlockWalker.visitVariable(node); + assertOut("var /** @type {number} */ a = 0"); + } + + @Test + public void testDateGetMinutes() + { + IVariableNode node = getVariable("var a:Date = new Date(); var b:Number = a.minutes"); + node = (IVariableNode)(node.getParent().getChild(1)); + asBlockWalker.visitVariable(node); + assertOut("var /** @type {number} */ b = a.getMinutes()"); + } + + @Test + public void testDateSetMinutes() + { + IBinaryOperatorNode node = getBinaryNode("var a:Date = new Date(); a.minutes = 10"); + asBlockWalker.visitBinaryOperator(node); + assertOut("a.setMinutes(10, a.getSeconds(), a.getMilliseconds())"); + } + + @Test + public void testDateGetMinutesMethod() + { + IVariableNode node = getVariable("var a:Date = new Date(); var b:Number = a.getMinutes()"); + node = (IVariableNode)(node.getParent().getChild(1)); + asBlockWalker.visitVariable(node); + assertOut("var /** @type {number} */ b = a.getMinutes()"); + } + + @Test + public void testDateSetMinutesMethod() + { + IBinaryOperatorNode node = getBinaryNode("var a:Date = new Date(); a.setMinutes(10, 0, 0)"); + IFunctionCallNode parentNode = (IFunctionCallNode)(node.getParent()); + asBlockWalker.visitFunctionCall(parentNode); + assertOut("a.setMinutes(10, 0, 0)"); + } + @Override @Test public void testVector() http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/8e270130/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/flexjs/JSFlexJSEmitter.java ---------------------------------------------------------------------- diff --git a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/flexjs/JSFlexJSEmitter.java b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/flexjs/JSFlexJSEmitter.java index 72a59f1..de50ace 100644 --- a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/flexjs/JSFlexJSEmitter.java +++ b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/flexjs/JSFlexJSEmitter.java @@ -53,6 +53,7 @@ import org.apache.flex.compiler.internal.codegen.js.jx.SelfReferenceEmitter; import org.apache.flex.compiler.internal.codegen.js.jx.SuperCallEmitter; import org.apache.flex.compiler.internal.codegen.js.jx.VarDeclarationEmitter; import org.apache.flex.compiler.internal.codegen.mxml.flexjs.MXMLFlexJSEmitter; +import org.apache.flex.compiler.internal.definitions.AccessorDefinition; import org.apache.flex.compiler.internal.projects.FlexJSProject; import org.apache.flex.compiler.internal.projects.FlexProject; import org.apache.flex.compiler.internal.tree.as.BinaryOperatorAsNode; @@ -62,6 +63,7 @@ import org.apache.flex.compiler.internal.tree.as.FunctionCallNode; import org.apache.flex.compiler.internal.tree.as.IdentifierNode; import org.apache.flex.compiler.internal.tree.as.LabeledStatementNode; import org.apache.flex.compiler.internal.tree.as.MemberAccessExpressionNode; +import org.apache.flex.compiler.internal.tree.as.NumericLiteralNode; import org.apache.flex.compiler.projects.ICompilerProject; import org.apache.flex.compiler.tree.ASTNodeID; import org.apache.flex.compiler.tree.as.IASNode; @@ -508,6 +510,52 @@ public class JSFlexJSEmitter extends JSGoogEmitter implements IJSFlexJSEmitter } @Override + public void walkArguments(IExpressionNode[] nodes) + { + if (nodes.length == 2) + { + ICompilerProject project = getWalker().getProject();; + IFunctionCallNode fcNode = (IFunctionCallNode)(nodes[0].getParent().getParent()); + IExpressionNode nameNode = fcNode.getNameNode(); + IDefinition def = nameNode.resolve(project); + if (def != null && def.getBaseName().equals("insertAt")) + { + if (def.getParent() != null && + def.getParent().getQualifiedName().equals("Array")) + { + if (nameNode instanceof MemberAccessExpressionNode) + { + IExpressionNode[] newArgs = new IExpressionNode[3]; + newArgs[0] = nodes[0]; + newArgs[2] = nodes[1]; + newArgs[1] = new NumericLiteralNode("0"); + nodes = newArgs; + } + } + } + } + super.walkArguments(nodes); + if (nodes.length == 1) + { + ICompilerProject project = getWalker().getProject();; + IFunctionCallNode fcNode = (IFunctionCallNode)(nodes[0].getParent().getParent()); + IExpressionNode nameNode = fcNode.getNameNode(); + IDefinition def = nameNode.resolve(project); + if (def != null && def.getBaseName().equals("removeAt")) + { + if (def.getParent() != null && + def.getParent().getQualifiedName().equals("Array")) + { + if (nameNode instanceof MemberAccessExpressionNode) + { + write(", 1"); + } + } + } + } + } + + @Override public void emitE4XFilter(IMemberAccessExpressionNode node) { getWalker().walk(node.getLeftOperandNode()); @@ -813,6 +861,32 @@ public class JSFlexJSEmitter extends JSGoogEmitter implements IJSFlexJSEmitter * @param obj * @return */ + public boolean isDateProperty(IExpressionNode obj) + { + FlexProject project = (FlexProject)getWalker().getProject(); + if (obj.getNodeID() == ASTNodeID.MemberAccessExpressionID) + { + IDefinition leftDef; + IExpressionNode leftNode = ((MemberAccessExpressionNode)obj).getLeftOperandNode(); + IExpressionNode rightNode = ((MemberAccessExpressionNode)obj).getRightOperandNode(); + leftDef = leftNode.resolveType(project); + IDefinition rightDef = rightNode.resolve(project); + if (leftDef != null && leftDef.getQualifiedName().equals("Date") && rightDef instanceof AccessorDefinition) + { + return true; + } + } + return false; + } + + /** + * resolveType on an XML expression returns null + * (see IdentiferNode.resolveType). + * So, we have to walk the tree ourselves and resolve + * individual pieces. + * @param obj + * @return + */ public boolean isXML(IExpressionNode obj) { // See if the left side is XML or XMLList http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/8e270130/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/BinaryOperatorEmitter.java ---------------------------------------------------------------------- diff --git a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/BinaryOperatorEmitter.java b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/BinaryOperatorEmitter.java index 03a0f2c..e37f0e1 100644 --- a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/BinaryOperatorEmitter.java +++ b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/BinaryOperatorEmitter.java @@ -217,6 +217,11 @@ public class BinaryOperatorEmitter extends JSSubEmitter implements return; } } + else if (((JSFlexJSEmitter)getEmitter()).isDateProperty((MemberAccessExpressionNode)leftSide)) + { + specialCaseDate(node, (MemberAccessExpressionNode)leftSide); + return; + } } super_emitBinaryOperator(node); @@ -368,4 +373,123 @@ public class BinaryOperatorEmitter extends JSSubEmitter implements if (ASNodeUtils.hasParenOpen(node)) write(ASEmitterTokens.PAREN_CLOSE); } + + private enum DateProperties + { + FULLYEAR("fullYear", "setFullYear"), + MONTH("month", "setMonth"), + DATE("date", "setDate"), + FULLYEARUTC("fullYearUTC", "setUTCFullYear"), + MONTHUTC("monthUTC", "setUTCMonth"), + DATEUTC("dateUTC", "setUTCDate"), + HOURS("hours", "setHours"), + MINUTES("minutes", "setMinutes"), + SECONDS("seconds", "setSeconds"), + MILLISECONDS("milliseconds", "setMilliseconds"), + HOURSUTC("hoursUTC", "setUTCHours"), + MINUTESUTC("minutesUTC", "setUTCMinutes"), + SECONDSUTC("secondsUTC", "setUTCSeconds"), + MILLISECONDSUTC("millisecondsUTC", "setUTCMilliseconds"); + + DateProperties(String value, String functionName) + { + this.value = value; + this.functionName = functionName; + } + + private String value; + private String functionName; + + public String getFunctionName() + { + return functionName; + } + } + + void specialCaseDate(IBinaryOperatorNode node, MemberAccessExpressionNode leftSide) + { + MemberAccessExpressionNode dateNode = (MemberAccessExpressionNode)leftSide; + IIdentifierNode rightSide = (IIdentifierNode)dateNode.getRightOperandNode(); + getWalker().walk(dateNode.getLeftOperandNode()); + String rightName = rightSide.getName(); + DateProperties prop = DateProperties.valueOf(rightName.toUpperCase()); + write(ASEmitterTokens.MEMBER_ACCESS); + write(prop.getFunctionName()); + write(ASEmitterTokens.PAREN_OPEN); + getWalker().walk(node.getRightOperandNode()); + switch (prop) + { + case FULLYEAR: + write(ASEmitterTokens.COMMA); + write(ASEmitterTokens.SPACE); + getWalker().walk(dateNode.getLeftOperandNode()); + write(ASEmitterTokens.MEMBER_ACCESS); + write("getMonth()"); + // fall through + case MONTH: + write(ASEmitterTokens.COMMA); + write(ASEmitterTokens.SPACE); + getWalker().walk(dateNode.getLeftOperandNode()); + write(ASEmitterTokens.MEMBER_ACCESS); + write("getDate()"); + break; + case FULLYEARUTC: + write(ASEmitterTokens.COMMA); + write(ASEmitterTokens.SPACE); + getWalker().walk(dateNode.getLeftOperandNode()); + write(ASEmitterTokens.MEMBER_ACCESS); + write("getMonthUTC()"); + // fall through + case MONTHUTC: + write(ASEmitterTokens.COMMA); + write(ASEmitterTokens.SPACE); + getWalker().walk(dateNode.getLeftOperandNode()); + write(ASEmitterTokens.MEMBER_ACCESS); + write("getDateUTC()"); + break; + case HOURS: + write(ASEmitterTokens.COMMA); + write(ASEmitterTokens.SPACE); + getWalker().walk(dateNode.getLeftOperandNode()); + write(ASEmitterTokens.MEMBER_ACCESS); + write("getMinutes()"); + // fall through + case MINUTES: + write(ASEmitterTokens.COMMA); + write(ASEmitterTokens.SPACE); + getWalker().walk(dateNode.getLeftOperandNode()); + write(ASEmitterTokens.MEMBER_ACCESS); + write("getSeconds()"); + // fall through + case SECONDS: + write(ASEmitterTokens.COMMA); + write(ASEmitterTokens.SPACE); + getWalker().walk(dateNode.getLeftOperandNode()); + write(ASEmitterTokens.MEMBER_ACCESS); + write("getMilliseconds()"); + break; + case HOURSUTC: + write(ASEmitterTokens.COMMA); + write(ASEmitterTokens.SPACE); + getWalker().walk(dateNode.getLeftOperandNode()); + write(ASEmitterTokens.MEMBER_ACCESS); + write("getUTCMinutes()"); + // fall through + case MINUTESUTC: + write(ASEmitterTokens.COMMA); + write(ASEmitterTokens.SPACE); + getWalker().walk(dateNode.getLeftOperandNode()); + write(ASEmitterTokens.MEMBER_ACCESS); + write("getUTCSeconds()"); + // fall through + case SECONDSUTC: + write(ASEmitterTokens.COMMA); + write(ASEmitterTokens.SPACE); + getWalker().walk(dateNode.getLeftOperandNode()); + write(ASEmitterTokens.MEMBER_ACCESS); + write("getUTCMilliseconds()"); + break; + } + write(ASEmitterTokens.PAREN_CLOSE); + } } http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/8e270130/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/IdentifierEmitter.java ---------------------------------------------------------------------- diff --git a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/IdentifierEmitter.java b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/IdentifierEmitter.java index cf1faa5..7d64896 100644 --- a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/IdentifierEmitter.java +++ b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/IdentifierEmitter.java @@ -65,6 +65,63 @@ public class IdentifierEmitter extends JSSubEmitter implements if (nodeDef != null && nodeDef.isStatic()) { String sname = nodeDef.getParent().getQualifiedName(); + if (sname.equals("Array")) + { + String baseName = nodeDef.getBaseName(); + if (baseName.equals("CASEINSENSITIVE")) + { + write("1"); + return; + } + else if (baseName.equals("DESCENDING")) + { + write("2"); + return; + } + else if (baseName.equals("UNIQUESORT")) + { + write("4"); + return; + } + else if (baseName.equals("RETURNINDEXEDARRAY")) + { + write("8"); + return; + } + else if (baseName.equals("NUMERIC")) + { + write("16"); + return; + } + } + else if (sname.equals("int")) + { + String baseName = nodeDef.getBaseName(); + if (baseName.equals("MAX_VALUE")) + { + write("2147483648"); + return; + } + else if (baseName.equals("MIN_VALUE")) + { + write("-2147483648"); + return; + } + } + else if (sname.equals("uint")) + { + String baseName = nodeDef.getBaseName(); + if (baseName.equals("MAX_VALUE")) + { + write("4294967295"); + return; + } + else if (baseName.equals("MIN_VALUE")) + { + write("0"); + return; + } + } if (sname.length() > 0) { write(getEmitter().formatQualifiedName(sname)); http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/8e270130/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/MemberAccessEmitter.java ---------------------------------------------------------------------- diff --git a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/MemberAccessEmitter.java b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/MemberAccessEmitter.java index df1f00a..2fcc160 100644 --- a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/MemberAccessEmitter.java +++ b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/MemberAccessEmitter.java @@ -61,12 +61,12 @@ public class MemberAccessEmitter extends JSSubEmitter implements IASNode leftNode = node.getLeftOperandNode(); IASNode rightNode = node.getRightOperandNode(); + JSFlexJSEmitter fjs = (JSFlexJSEmitter)getEmitter(); IDefinition def = node.resolve(getProject()); if (def == null) { IASNode parentNode = node.getParent(); // could be XML - JSFlexJSEmitter fjs = (JSFlexJSEmitter)getEmitter(); boolean isXML = false; boolean isProxy = false; if (leftNode instanceof MemberAccessExpressionNode) @@ -137,6 +137,36 @@ public class MemberAccessEmitter extends JSSubEmitter implements } } } + else if (fjs.isDateProperty(node)) + { + writeLeftSide(node, leftNode, rightNode); + write(".get"); + String rightName = ((IIdentifierNode)rightNode).getName(); + String firstChar = rightName.substring(0, 1); + firstChar = firstChar.toUpperCase(); + rightName = rightName.substring(1); + write(firstChar); + write(rightName); + write(ASEmitterTokens.PAREN_OPEN); + write(ASEmitterTokens.PAREN_CLOSE); + return; + } + else if (def.getParent() != null && + def.getParent().getQualifiedName().equals("Array")) + { + if (def.getBaseName().equals("removeAt")) + { + writeLeftSide(node, leftNode, rightNode); + write(".splice"); + return; + } + else if (def.getBaseName().equals("insertAt")) + { + writeLeftSide(node, leftNode, rightNode); + write(".splice"); + return; + } + } boolean isStatic = false; if (def != null && def.isStatic()) isStatic = true; http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/8e270130/externs/js/missing.js ---------------------------------------------------------------------- diff --git a/externs/js/missing.js b/externs/js/missing.js index d53e13b..c0241d4 100644 --- a/externs/js/missing.js +++ b/externs/js/missing.js @@ -173,3 +173,75 @@ function trace(rest) {} * @const */ var console; + + +/** + * @type {number} + * @const + */ +Array.CASEINSENSITIVE = 1; + +/** + * @type {number} + * @const + */ +Array.DESCENDING = 2; + +/** + * @type {number} + * @const + */ +Array.UNIQUESORT = 4; + +/** + * @type {number} + * @const + */ +Array.RETURNINDEXEDARRAY = 8; + +/** + * @type {number} + * @const + */ +Array.NUMERIC = 16; + + +/** + * @param {number} index The index. + * @param {Object} element The Object. + */ +Array.prototype.insertAt = function(index, element) {}; + +/** + * @param {number} index The index. + */ +Array.prototype.removeAt = function(index) {}; + + + +/** + * @type {number} + * @const + */ +int.MAX_VALUE = 2147483648; + + +/** + * @type {number} + * @const + */ +int.MIN_VALUE = -2147483648; + + +/** + * @type {number} + * @const + */ +uint.MAX_VALUE = 4294967295; + + +/** + * @type {number} + * @const + */ +uint.MIN_VALUE = 0;
