You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@royale.apache.org by gr...@apache.org on 2019/05/04 08:50:33 UTC
[royale-compiler] 01/01: Squashed commit of cumulative work on
Language improvements
This is an automated email from the ASF dual-hosted git repository.
gregdove pushed a commit to branch improvements/Language
in repository https://gitbox.apache.org/repos/asf/royale-compiler.git
commit 88b2c1f52e7b15d2573d1d40e6963de4aa15b24f
Author: greg-dove <gr...@gmail.com>
AuthorDate: Sat May 4 18:21:57 2019 +1200
Squashed commit of cumulative work on Language improvements
---
.../royale/compiler/clients/JSConfiguration.java | 119 ++++++++-
.../compiler/internal/codegen/js/JSEmitter.java | 204 ++++++++++++++-
.../internal/codegen/js/jx/AsIsEmitter.java | 31 ++-
.../codegen/js/jx/BinaryOperatorEmitter.java | 42 ++-
.../codegen/js/jx/DynamicAccessEmitter.java | 57 +++++
.../codegen/js/jx/FunctionCallEmitter.java | 282 ++++++++++++++++-----
.../internal/codegen/js/jx/IdentifierEmitter.java | 42 +--
.../codegen/js/jx/MemberAccessEmitter.java | 30 +--
.../internal/codegen/js/jx/MethodEmitter.java | 8 +-
.../codegen/js/jx/UnaryOperatorEmitter.java | 29 +++
.../codegen/js/royale/JSRoyaleDocEmitter.java | 98 ++++++-
.../codegen/js/royale/JSRoyaleEmitter.java | 40 +--
.../codegen/js/royale/JSRoyaleEmitterTokens.java | 9 +-
.../internal/projects/RoyaleJSProject.java | 20 +-
.../compiler/utils/JSClosureCompilerWrapper.java | 2 +
.../apache/royale/compiler/utils/NativeUtils.java | 42 ++-
.../codegen/js/royale/TestRoyaleExpressions.java | 8 +-
.../codegen/js/royale/TestRoyaleGlobalClasses.java | 61 ++++-
.../js/royale/TestRoyaleGlobalFunctions.java | 15 +-
.../internal/tree/as/DynamicAccessNode.java | 7 +-
20 files changed, 972 insertions(+), 174 deletions(-)
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/clients/JSConfiguration.java b/compiler-jx/src/main/java/org/apache/royale/compiler/clients/JSConfiguration.java
index c75b550..ae06bf7 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/clients/JSConfiguration.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/clients/JSConfiguration.java
@@ -461,6 +461,121 @@ public class JSConfiguration extends Configuration
{
jsVectorEmulationClass = b;
}
-
-
+
+
+ //
+ // 'js-no-complex-implicit-coercions'
+ //
+
+ private boolean jsNoComplexImplicitCoercions = false;
+
+ public boolean getJsNoComplexImplicitCoercions()
+ {
+ return jsNoComplexImplicitCoercions;
+ }
+
+ /**
+ * Support for avoiding more complex implicit assignment coercions
+ * example
+ * var array:Array = [new MyClass()];
+ * var myOtherClass:MyOtherClass = array[0];
+ *
+ * In the above example, the compiler will (by default) output an implicit coercion
+ * that is equivalent in actionscript to:
+ * var myOtherClass:MyOtherClass = MyOtherClass(array[0]);
+ *
+ * By setting this configuration option to true, the implicit coercion code in situations similar to the above
+ * is not generated (other primitive implicit coercions, such as int/uint/Number/String and Boolean coercions remain)
+ * This is a global setting, it is possible to leave it on and specifically avoid it via doc
+ * settings. The doc comment compiler directive for that is: @royalesuppresscompleximplicitcoercion
+ * Another option is to add the explicit coercions in code and then avoid their output
+ * via specific @royaleignorecoercion doc comment directives. Doing so however may add extra unwanted output
+ * in other compiler targets (for example, swf bytecode) if the same source code is shared between targets.
+ */
+ @Config(advanced = true)
+ @Mapping("js-no-complex-implicit-coercions")
+ public void setJsNoComplexImplicitCoercions(ConfigurationValue cv, boolean value)
+ throws ConfigurationException
+ {
+ jsNoComplexImplicitCoercions = value;
+ }
+
+ //
+ // 'js-no-resolve-uncertain'
+ //
+
+ private boolean jsNoResolveUncertain = false;
+
+ public boolean getJsNoResolveUncertain()
+ {
+ return jsNoResolveUncertain;
+ }
+
+ /**
+ * Support for avoiding more overhead of resolving instantiations from
+ * unknown constructors
+ * example
+ * var myClass:Class = String;
+ * var myString:* = new myClass("test");
+ *
+ * In the above example, the compiler will (by default) output
+ * a call to a Language.resolveUncertain method which wraps the 'new myClass("test")'
+ *
+ *
+ * This normalizes the return value for some primitive constructors, so that (for example)
+ * strict equality and inequality operators provide the same results between compiler
+ * targets.
+ * In situations where it is certain that the resolveUncertain method is not needed,
+ * this option provides a way to switch it off 'globally'.
+ * It can also be switched off or on locally using the '@royalesuppressresolveuncertain'
+ * doc comment compiler directive.
+ */
+ @Config(advanced = true)
+ @Mapping("js-no-resolve-uncertain")
+ public void setJsNoResolveUncertain(ConfigurationValue cv, boolean value)
+ throws ConfigurationException
+ {
+ jsNoResolveUncertain = value;
+ }
+
+ //
+ // 'js-no-vector-index-checks'
+ //
+
+ private boolean jsNoVectorIndexChecks = false;
+
+ public boolean getJsNoVectorIndexChecks()
+ {
+ return jsNoVectorIndexChecks;
+ }
+
+ /**
+ * Support for avoiding more overhead of adding checks into
+ * assignments via Vector index access
+ * example
+ * var myVector:Vector.<int> = new Vector.<int>();
+ * myVector[0] = 42;
+ *
+ * In the above example, the compiler will (by default) wrap
+ * the '0' inside myVector[0] with a method call on the vector instance
+ * that checks to see if the index is valid for the Vector it is being used against
+ *
+ * This check will throw an error if the index is out of range, and the
+ * range checking differs if the Vector is 'fixed' or non-'fixed'
+ *
+ * In situations where it is certain that the index will always be valid for Vector instance
+ * being targeted, or where all cases in a given codebase are certain to be valid, it is possible
+ * to avoid the overhead of this check. This is especially important in loops.
+ * This config setting affects the global setting for the current compilation.
+ * It can be adjusted locally within code, using the '@royalesuppressvectorindexcheck'
+ * doc comment compiler directive.
+ */
+ @Config(advanced = true)
+ @Mapping("js-no-vector-index-checks")
+ public void setJsNoVectorIndexChecks(ConfigurationValue cv, boolean value)
+ throws ConfigurationException
+ {
+ jsNoVectorIndexChecks = value;
+ }
+
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/JSEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/JSEmitter.java
index b9e80bb..5457ed1 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/JSEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/JSEmitter.java
@@ -23,6 +23,7 @@ import java.io.FilterWriter;
import java.util.ArrayList;
import java.util.List;
+import org.apache.royale.compiler.codegen.IASGlobalFunctionConstants;
import org.apache.royale.compiler.codegen.IDocEmitter;
import org.apache.royale.compiler.codegen.IEmitter;
import org.apache.royale.compiler.codegen.ISubEmitter;
@@ -32,6 +33,8 @@ import org.apache.royale.compiler.common.ISourceLocation;
import org.apache.royale.compiler.constants.IASLanguageConstants;
import org.apache.royale.compiler.constants.IMetaAttributeConstants;
import org.apache.royale.compiler.constants.IASLanguageConstants.BuiltinType;
+import org.apache.royale.compiler.definitions.IAppliedVectorDefinition;
+import org.apache.royale.compiler.definitions.IClassDefinition;
import org.apache.royale.compiler.definitions.IDefinition;
import org.apache.royale.compiler.definitions.metadata.IMetaTag;
import org.apache.royale.compiler.definitions.metadata.IMetaTagAttribute;
@@ -64,8 +67,10 @@ import org.apache.royale.compiler.internal.codegen.js.jx.UnaryOperatorEmitter;
import org.apache.royale.compiler.internal.codegen.js.jx.WhileLoopEmitter;
import org.apache.royale.compiler.internal.codegen.js.jx.WithEmitter;
import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleDocEmitter;
+import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitterTokens;
+import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
import org.apache.royale.compiler.internal.semantics.SemanticUtils;
-import org.apache.royale.compiler.internal.tree.as.FunctionNode;
+import org.apache.royale.compiler.internal.tree.as.*;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.tree.as.IASNode;
import org.apache.royale.compiler.tree.as.ICatchNode;
@@ -97,6 +102,9 @@ import org.apache.royale.compiler.tree.as.IWithNode;
import com.google.debugging.sourcemap.FilePosition;
+import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
+import org.apache.royale.compiler.utils.NativeUtils;
+
/**
* @author Michael Schmalle
*/
@@ -220,12 +228,12 @@ public class JSEmitter extends ASEmitter implements IJSEmitter
public void emitClosureStart()
{
-
+
}
public void emitClosureEnd(IASNode node, IDefinition nodeDef)
{
-
+
}
public void emitSourceMapDirective(ITypeNode node)
@@ -501,7 +509,7 @@ public class JSEmitter extends ASEmitter implements IJSEmitter
/**
* Adjusts the line numbers saved in the source map when a line should be
* removed during post processing.
- *
+ *
* @param lineIndex
*/
protected void removeLineFromMappings(int lineIndex)
@@ -546,6 +554,7 @@ public class JSEmitter extends ASEmitter implements IJSEmitter
}
String coercionStart = null;
String coercionEnd = null;
+ boolean avoidCoercion = false;
if (project.getBuiltinType(BuiltinType.INT).equals(definition))
{
boolean needsCoercion = false;
@@ -566,6 +575,10 @@ public class JSEmitter extends ASEmitter implements IJSEmitter
endMapping(assignedNode);
return;
}
+ else if(assignedNode instanceof BinaryOperatorAsNode)
+ {
+ needsCoercion = true;
+ }
else if(!project.getBuiltinType(BuiltinType.INT).equals(assignedTypeDef))
{
needsCoercion = true;
@@ -596,6 +609,10 @@ public class JSEmitter extends ASEmitter implements IJSEmitter
endMapping(assignedNode);
return;
}
+ else if(assignedNode instanceof BinaryOperatorAsNode)
+ {
+ needsCoercion = true;
+ }
else if(!project.getBuiltinType(BuiltinType.UINT).equals(assignedTypeDef))
{
needsCoercion = true;
@@ -631,6 +648,8 @@ public class JSEmitter extends ASEmitter implements IJSEmitter
if (t.equals(IASLanguageConstants.Number))
{
needsCoercion = false;
+ //explicitly prevent other coercion detection rules from picking this up
+ avoidCoercion = true;
}
}
}
@@ -695,6 +714,183 @@ public class JSEmitter extends ASEmitter implements IJSEmitter
coercionStart = "org.apache.royale.utils.Language.string(";
}
}
+ if ( assignedDef != null
+ && assignedDef instanceof IAppliedVectorDefinition
+ && assignedNode instanceof TypedExpressionNode) {
+ //assign a Vector class as the assigned value, e.g. var c:Class = Vector.<int>
+ startMapping(assignedNode);
+ write(JSRoyaleEmitterTokens.SYNTH_VECTOR);
+ write(ASEmitterTokens.PAREN_OPEN);
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ //the element type of the Vector:
+ write(((TypedExpressionNode)assignedNode).getTypeNode().resolve(project).getQualifiedName());
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write(ASEmitterTokens.PAREN_CLOSE);
+ endMapping(assignedNode);
+ if (project instanceof RoyaleJSProject)
+ ((RoyaleJSProject)project).needLanguage = true;
+ getModel().needLanguage = true;
+
+ return;
+ }
+ if (assignedDef instanceof IClassDefinition
+ && assignedNode instanceof IdentifierNode
+ && ((IdentifierNode)assignedNode).getName().equals(IASGlobalFunctionConstants.Vector)){
+ startMapping(assignedNode);
+ write(JSRoyaleEmitterTokens.SYNTH_VECTOR);
+ write(ASEmitterTokens.PAREN_OPEN);
+ //null to signify not a valid constructor
+ write(ASEmitterTokens.NULL);
+ write(ASEmitterTokens.PAREN_CLOSE);
+ endMapping(assignedNode);
+ if (project instanceof RoyaleJSProject)
+ ((RoyaleJSProject)project).needLanguage = true;
+ getModel().needLanguage = true;
+ return;
+ }
+ if (coercionStart == null
+ && !avoidCoercion
+ && assignedTypeDef !=null
+ && definition !=null
+ && (project.getBuiltinType(BuiltinType.ANY_TYPE).equals(assignedTypeDef)
+ || project.getBuiltinType(BuiltinType.OBJECT).equals(assignedTypeDef))
+ && !(project.getBuiltinType(BuiltinType.ANY_TYPE).equals(definition)
+ || project.getBuiltinType(BuiltinType.OBJECT).equals(definition)
+ || project.getBuiltinType(BuiltinType.CLASS).equals(definition))) {
+ //catch leftovers: remaining implicit coercion of loosely typed assigned values to strongly typed context
+ //assignment to Class definitions is excluded because there is no 'Class' type in JS
+ //Possibility: 'Class' could be implemented as a synthType
+ boolean needsCoercion = true;
+
+ if (((RoyaleJSProject)project).config.getJsNoComplexImplicitCoercions()) {
+ needsCoercion = false;
+ }
+
+ IDocEmitter docEmitter = getDocEmitter();
+ if (docEmitter instanceof JSRoyaleDocEmitter)
+ {
+ JSRoyaleDocEmitter royaleDocEmitter = (JSRoyaleDocEmitter) docEmitter;
+ //check for local toggle
+ needsCoercion = royaleDocEmitter.getLocalSettingAsBoolean(
+ JSRoyaleEmitterTokens.SUPPRESS_COMPLEX_IMPLICIT_COERCION, needsCoercion);
+ if (needsCoercion) {
+ //check for individual specified suppression
+
+ String definitionName = definition.getQualifiedName();
+ //for Vectors, use the unqualified name to match the source code
+ if (NativeUtils.isVector(definitionName)) {
+ definitionName = definition.getBaseName();
+ }
+
+ if (royaleDocEmitter.getLocalSettingIncludesString(
+ JSRoyaleEmitterTokens.SUPPRESS_COMPLEX_IMPLICIT_COERCION,
+ definitionName
+ )){
+ needsCoercion = false;
+ }
+
+ }
+ }
+
+ //Avoid specific compile-time 'fake' class(es)
+ if (needsCoercion && definition.getQualifiedName().equals("org.apache.royale.core.WrappedHTMLElement")) {
+ //*actual* coercion fails here, because this is not actually instantiated, it is
+ //simply a type definition representing the 'wrapped' (or tagged) HTMLElement
+ needsCoercion = false;
+ }
+
+ //Avoid XML/XMLList:
+ if (needsCoercion && project.getBuiltinType(BuiltinType.XML) != null) {
+ if (project.getBuiltinType(BuiltinType.XML).equals(definition)
+ || project.getBuiltinType(BuiltinType.XMLLIST).equals(definition)) {
+ //XML/XMLList has complex output and would need more work
+ needsCoercion = false;
+ }
+ }
+
+ //avoid scenario with ArrayElementType specified as metadata definition type - assume it is 'typed'
+ if (needsCoercion && assignedNode instanceof IDynamicAccessNode)
+ {
+ IDynamicAccessNode dynamicAccess = (IDynamicAccessNode) assignedNode;
+ IDefinition dynamicAccessIndexDef = dynamicAccess.getRightOperandNode().resolveType(project);
+ if (project.getBuiltinType(BuiltinType.NUMBER).equals(dynamicAccessIndexDef))
+ {
+ IDefinition leftDef = dynamicAccess.getLeftOperandNode().resolveType(project);
+ if (leftDef != null) {
+ IMetaTag[] metas = leftDef.getAllMetaTags();
+ for (IMetaTag meta : metas)
+ {
+ if (meta.getTagName().equals(IMetaAttributeConstants.ATTRIBUTE_ARRAYELEMENTTYPE))
+ {
+ IMetaTagAttribute[] attrs = meta.getAllAttributes();
+ for (IMetaTagAttribute attr : attrs)
+ {
+ String t = attr.getValue();
+ if (t.equals(definition.getQualifiedName()))
+ {
+ needsCoercion = false;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (needsCoercion && project.getBuiltinType(BuiltinType.STRING).equals(definition)) {
+ //explicit suppression of String coercion
+ if (docEmitter instanceof JSRoyaleDocEmitter)
+ {
+ JSRoyaleDocEmitter royaleDocEmitter = (JSRoyaleDocEmitter) docEmitter;
+ needsCoercion = royaleDocEmitter.emitStringConversions;
+ }
+ if (needsCoercion
+ && assignedNode instanceof FunctionCallNode
+ && ((FunctionCallNode) assignedNode).getNameNode() instanceof MemberAccessExpressionNode
+ && ((MemberAccessExpressionNode)((FunctionCallNode) assignedNode).getNameNode()).getRightOperandNode() instanceof IdentifierNode
+ && ((IdentifierNode)(((MemberAccessExpressionNode)((FunctionCallNode) assignedNode).getNameNode()).getRightOperandNode())).getName().equals("toString")) {
+ //even if toString() is called in an untyped way, assume a call to a method named 'toString' is actually providing a String
+ needsCoercion = false;
+ }
+ }
+
+ if (needsCoercion) {
+ //add a comment tag leader, so implicit casts are identifiable in the output
+ coercionStart = "/* implicit cast */ "
+ + JSRoyaleEmitterTokens.LANGUAGE_QNAME.getToken()
+ + ASEmitterTokens.MEMBER_ACCESS.getToken()
+ + ASEmitterTokens.AS.getToken()
+ + ASEmitterTokens.PAREN_OPEN.getToken();
+ String coercionTypeString = definition.getQualifiedName();
+ if (NativeUtils.isSyntheticJSType(coercionTypeString)) {
+ String synthCall;
+ String synthethicType;
+ if (NativeUtils.isVector(coercionTypeString)) {
+ synthCall = JSRoyaleEmitterTokens.SYNTH_VECTOR.getToken();
+ synthethicType = coercionTypeString.substring(8, coercionTypeString.length() -1);
+ } else {
+ synthCall = JSRoyaleEmitterTokens.SYNTH_TYPE.getToken();
+ synthethicType = coercionTypeString;
+ }
+ coercionTypeString = synthCall
+ + ASEmitterTokens.PAREN_OPEN.getToken()
+ + ASEmitterTokens.SINGLE_QUOTE.getToken()
+ + synthethicType
+ + ASEmitterTokens.SINGLE_QUOTE.getToken()
+ + ASEmitterTokens.PAREN_CLOSE.getToken();
+ }
+
+ coercionEnd = ASEmitterTokens.COMMA.getToken()
+ + ASEmitterTokens.SPACE.getToken()
+ + coercionTypeString
+ + ASEmitterTokens.COMMA.getToken()
+ + ASEmitterTokens.SPACE.getToken()
+ + ASEmitterTokens.TRUE.getToken()
+ + ASEmitterTokens.PAREN_CLOSE.getToken();
+ if (project instanceof RoyaleJSProject)
+ ((RoyaleJSProject)project).needLanguage = true;
+ getModel().needLanguage = true;
+ }
+ }
if (coercionStart != null)
{
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/AsIsEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/AsIsEmitter.java
index e8ffe98..9ddea56 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/AsIsEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/AsIsEmitter.java
@@ -22,6 +22,7 @@ package org.apache.royale.compiler.internal.codegen.js.jx;
import org.apache.royale.compiler.asdoc.royale.ASDocComment;
import org.apache.royale.compiler.codegen.js.IJSEmitter;
import org.apache.royale.compiler.constants.IASLanguageConstants;
+import org.apache.royale.compiler.definitions.IAppliedVectorDefinition;
import org.apache.royale.compiler.definitions.IClassDefinition;
import org.apache.royale.compiler.definitions.IDefinition;
import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
@@ -29,12 +30,14 @@ import org.apache.royale.compiler.internal.codegen.js.JSSubEmitter;
import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitter;
import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitterTokens;
import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
+import org.apache.royale.compiler.parsing.IASToken;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.tree.ASTNodeID;
import org.apache.royale.compiler.tree.as.IASNode;
import org.apache.royale.compiler.tree.as.IBinaryOperatorNode;
import org.apache.royale.compiler.tree.as.IExpressionNode;
import org.apache.royale.compiler.tree.as.IFunctionNode;
+import org.apache.royale.compiler.utils.NativeUtils;
public class AsIsEmitter extends JSSubEmitter
{
@@ -53,7 +56,7 @@ public class AsIsEmitter extends JSSubEmitter
.resolve(getProject()) : null;
if (id != ASTNodeID.Op_IsID && dnode != null)
{
- boolean emit = coercion ?
+ boolean emit = coercion ?
!((RoyaleJSProject)getProject()).config.getJSOutputOptimizations().contains(JSRoyaleEmitterTokens.SKIP_FUNCTION_COERCIONS.getToken()) :
!((RoyaleJSProject)getProject()).config.getJSOutputOptimizations().contains(JSRoyaleEmitterTokens.SKIP_AS_COERCIONS.getToken());
@@ -147,7 +150,7 @@ public class AsIsEmitter extends JSSubEmitter
getEmitter().getModel().needLanguage = true;
if (node instanceof IBinaryOperatorNode)
{
- IBinaryOperatorNode binaryOperatorNode = (IBinaryOperatorNode) node;
+ IBinaryOperatorNode binaryOperatorNode = (IBinaryOperatorNode) node;
startMapping(node, binaryOperatorNode.getLeftOperandNode());
}
else
@@ -181,7 +184,29 @@ public class AsIsEmitter extends JSSubEmitter
if (dnode instanceof IClassDefinition)
{
startMapping(right);
- write(getEmitter().formatQualifiedName(((JSRoyaleEmitter)getEmitter()).convertASTypeToJS(dnode.getQualifiedName())));
+ if (NativeUtils.isSyntheticJSType(dnode.getQualifiedName())) {
+ JSRoyaleEmitterTokens langMethod;
+ String synthName;
+ if (NativeUtils.isVector(dnode.getQualifiedName()) && dnode instanceof IAppliedVectorDefinition) {
+ langMethod = JSRoyaleEmitterTokens.SYNTH_VECTOR;
+ synthName = getEmitter().formatQualifiedName(((IAppliedVectorDefinition) dnode).resolveElementType(project).getQualifiedName());
+ } else {
+ //non-vector, e.g. int/uint
+ langMethod = JSRoyaleEmitterTokens.SYNTH_TYPE;
+ synthName = getEmitter().formatQualifiedName(dnode.getQualifiedName());
+ }
+ write(langMethod);
+ write(ASEmitterTokens.PAREN_OPEN);
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write(synthName);
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write(ASEmitterTokens.PAREN_CLOSE);
+ if (project instanceof RoyaleJSProject)
+ ((RoyaleJSProject)project).needLanguage = true;
+ getEmitter().getModel().needLanguage = true;
+ } else {
+ write(getEmitter().formatQualifiedName(((JSRoyaleEmitter)getEmitter()).convertASTypeToJS(dnode.getQualifiedName())));
+ }
endMapping(right);
}
else
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/BinaryOperatorEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/BinaryOperatorEmitter.java
index 1533bf4..4d02be3 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/BinaryOperatorEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/BinaryOperatorEmitter.java
@@ -21,6 +21,7 @@ package org.apache.royale.compiler.internal.codegen.js.jx;
import org.apache.royale.compiler.codegen.ISubEmitter;
import org.apache.royale.compiler.codegen.js.IJSEmitter;
+import org.apache.royale.compiler.constants.IASLanguageConstants;
import org.apache.royale.compiler.definitions.IDefinition;
import org.apache.royale.compiler.definitions.ITypeDefinition;
import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
@@ -30,10 +31,9 @@ import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitter;
import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.goog.JSGoogEmitterTokens;
import org.apache.royale.compiler.internal.definitions.AccessorDefinition;
+import org.apache.royale.compiler.internal.definitions.AppliedVectorDefinition;
import org.apache.royale.compiler.internal.semantics.SemanticUtils;
-import org.apache.royale.compiler.internal.tree.as.DynamicAccessNode;
-import org.apache.royale.compiler.internal.tree.as.MemberAccessExpressionNode;
-import org.apache.royale.compiler.internal.tree.as.UnaryOperatorAtNode;
+import org.apache.royale.compiler.internal.tree.as.*;
import org.apache.royale.compiler.tree.ASTNodeID;
import org.apache.royale.compiler.tree.as.IASNode;
import org.apache.royale.compiler.tree.as.IBinaryOperatorNode;
@@ -100,7 +100,7 @@ public class BinaryOperatorEmitter extends JSSubEmitter implements
{
IASNode lnode = leftSide.getChild(0);
IASNode rnode = leftSide.getChild(1);
- IDefinition rnodeDef = (rnode instanceof IIdentifierNode) ?
+ IDefinition rnodeDef = (rnode instanceof IIdentifierNode) ?
((IIdentifierNode) rnode).resolve(getWalker().getProject()) :
null;
boolean isDynamicAccess = rnode instanceof DynamicAccessNode;
@@ -117,7 +117,7 @@ public class BinaryOperatorEmitter extends JSSubEmitter implements
else
write(getEmitter().formatQualifiedName(
getModel().getCurrentClass().getQualifiedName()));
-
+
write(ASEmitterTokens.MEMBER_ACCESS);
write(JSGoogEmitterTokens.SUPERCLASS);
write(ASEmitterTokens.MEMBER_ACCESS);
@@ -391,10 +391,11 @@ public class BinaryOperatorEmitter extends JSSubEmitter implements
}
}
-
- super_emitBinaryOperator(node, isAssignment);
+
+ super_emitBinaryOperator(node, isAssignment);
}
}
+
private void super_emitBinaryOperator(IBinaryOperatorNode node, boolean isAssignment)
{
@@ -431,8 +432,27 @@ public class BinaryOperatorEmitter extends JSSubEmitter implements
}
else
{
- getWalker().walk(node.getLeftOperandNode());
-
+ if (isAssignment
+ && node.getLeftOperandNode() instanceof MemberAccessExpressionNode
+ && ((MemberAccessExpressionNode) node.getLeftOperandNode()).getRightOperandNode() instanceof IdentifierNode
+ && ((IdentifierNode) ((MemberAccessExpressionNode) node.getLeftOperandNode()).getRightOperandNode()).getName().equals("length")
+ && ((MemberAccessExpressionNode) node.getLeftOperandNode()).getLeftOperandNode().resolveType(getProject()) instanceof AppliedVectorDefinition)
+ {
+ //for vectors, when setting length, we need to set it on the associated 'synthType' instance which tags the native
+ //Array representation of the Vector. This allows running 'setter' code because it is not possible to override the native length setter on Array
+ //unless using a different approach, like es6 Proxy.
+ //this code inserts the extra access name for setting length, e.g. myVectInstance['_synthType'].length = assignedValue
+ //the dynamic access field name is a constant on Language, so it can be different/shorter in release build
+ getWalker().walk(((MemberAccessExpressionNode) node.getLeftOperandNode()).getLeftOperandNode());
+ write(ASEmitterTokens.SQUARE_OPEN);
+ write(JSRoyaleEmitterTokens.LANGUAGE_QNAME.getToken());
+ write(ASEmitterTokens.MEMBER_ACCESS);
+ write(JSRoyaleEmitterTokens.ROYALE_SYNTH_TAG_FIELD_NAME);
+ write(ASEmitterTokens.SQUARE_CLOSE);
+ write(ASEmitterTokens.MEMBER_ACCESS);
+ getWalker().walk(((MemberAccessExpressionNode) node.getLeftOperandNode()).getRightOperandNode());
+ }
+ else getWalker().walk(node.getLeftOperandNode());
startMapping(node, node.getLeftOperandNode());
if (id != ASTNodeID.Op_CommaID)
@@ -469,12 +489,14 @@ public class BinaryOperatorEmitter extends JSSubEmitter implements
}
else
{
+
getWalker().walk(node.getRightOperandNode());
+
if (node.getNodeID() == ASTNodeID.Op_InID &&
((JSRoyaleEmitter)getEmitter()).isXML(node.getRightOperandNode()))
{
write(".elementNames()");
- }
+ }
else if (node.getNodeID() == ASTNodeID.Op_InID &&
((JSRoyaleEmitter)getEmitter()).isProxy(node.getRightOperandNode()))
{
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/DynamicAccessEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/DynamicAccessEmitter.java
index 2fd5085..9c65d4f 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/DynamicAccessEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/DynamicAccessEmitter.java
@@ -19,20 +19,30 @@
package org.apache.royale.compiler.internal.codegen.js.jx;
+import org.apache.royale.compiler.codegen.IDocEmitter;
import org.apache.royale.compiler.codegen.ISubEmitter;
import org.apache.royale.compiler.codegen.js.IJSEmitter;
import org.apache.royale.compiler.constants.IASLanguageConstants;
import org.apache.royale.compiler.definitions.ITypeDefinition;
import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
+import org.apache.royale.compiler.internal.codegen.js.JSEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.JSSubEmitter;
+import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleDocEmitter;
import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitter;
+import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitterTokens;
+import org.apache.royale.compiler.internal.definitions.AppliedVectorDefinition;
+import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
+import org.apache.royale.compiler.internal.tree.as.BinaryOperatorAssignmentNode;
import org.apache.royale.compiler.internal.tree.as.FunctionCallNode;
+import org.apache.royale.compiler.internal.tree.as.IdentifierNode;
import org.apache.royale.compiler.internal.tree.as.MemberAccessExpressionNode;
+import org.apache.royale.compiler.parsing.IASToken;
import org.apache.royale.compiler.tree.ASTNodeID;
import org.apache.royale.compiler.tree.as.IDynamicAccessNode;
import org.apache.royale.compiler.tree.as.IExpressionNode;
import org.apache.royale.compiler.tree.as.ILiteralNode;
import org.apache.royale.compiler.tree.as.IOperatorNode.OperatorType;
+import org.apache.royale.compiler.utils.NativeUtils;
public class DynamicAccessEmitter extends JSSubEmitter implements
ISubEmitter<IDynamicAccessNode>
@@ -98,8 +108,55 @@ public class DynamicAccessEmitter extends JSSubEmitter implements
startMapping(node, leftOperandNode);
write(ASEmitterTokens.SQUARE_OPEN);
endMapping(node);
+ boolean wrapVectorIndex = false;
+ if (getProject() instanceof RoyaleJSProject) {
+ if (node.getNodeID().equals(ASTNodeID.ArrayIndexExpressionID)){
+ if (node.getParent() instanceof BinaryOperatorAssignmentNode) {
+ if (node.getLeftOperandNode().resolveType(getProject()) instanceof AppliedVectorDefinition) {
+ boolean suppressVectorIndexCheck = false;
+ if (((RoyaleJSProject)getProject()).config.getJsNoVectorIndexChecks()) {
+ //wrapVectorIndex = false;
+ suppressVectorIndexCheck = true;
+ }
+ IDocEmitter docEmitter = getEmitter().getDocEmitter();
+ if (docEmitter instanceof JSRoyaleDocEmitter)
+ {
+ JSRoyaleDocEmitter royaleDocEmitter = (JSRoyaleDocEmitter) docEmitter;
+ //check for local toggle
+ suppressVectorIndexCheck = royaleDocEmitter.getLocalSettingAsBoolean(
+ JSRoyaleEmitterTokens.SUPPRESS_VECTOR_INDEX_CHECK, suppressVectorIndexCheck);
+
+ if (!suppressVectorIndexCheck) {
+ //check for individual specified suppression, based on variable name
+ if (leftOperandNode instanceof IdentifierNode) {
+ if (royaleDocEmitter.getLocalSettingIncludesString(
+ JSRoyaleEmitterTokens.SUPPRESS_VECTOR_INDEX_CHECK,
+ ((IdentifierNode) leftOperandNode).getName()
+ )){
+ suppressVectorIndexCheck = true;
+ }
+ }
+ }
+ }
+ if (!suppressVectorIndexCheck) {
+ getModel().needLanguage = true;
+ ((RoyaleJSProject) getProject()).needLanguage = true;
+ getWalker().walk(leftOperandNode);
+ write(ASEmitterTokens.SQUARE_OPEN);
+ write(JSRoyaleEmitterTokens.VECTOR_INDEX_CHECK_METHOD_NAME);
+ write(ASEmitterTokens.SQUARE_CLOSE);
+ write(ASEmitterTokens.PAREN_OPEN);
+ wrapVectorIndex = true;
+ }
+ }
+ }
+ }
+ }
getWalker().walk(rightOperandNode);
+ if (wrapVectorIndex) {
+ write(ASEmitterTokens.PAREN_CLOSE);
+ }
if (type != null && type.getQualifiedName().contentEquals(IASLanguageConstants.QName))
write(".objectAccessFormat()");
startMapping(node, rightOperandNode);
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/FunctionCallEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/FunctionCallEmitter.java
index 1e0bae0..84e5f84 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/FunctionCallEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/FunctionCallEmitter.java
@@ -20,8 +20,10 @@
package org.apache.royale.compiler.internal.codegen.js.jx;
import org.apache.royale.compiler.codegen.IASGlobalFunctionConstants;
+import org.apache.royale.compiler.codegen.IDocEmitter;
import org.apache.royale.compiler.codegen.ISubEmitter;
import org.apache.royale.compiler.codegen.js.IJSEmitter;
+import org.apache.royale.compiler.common.SourceLocation;
import org.apache.royale.compiler.constants.IASLanguageConstants;
import org.apache.royale.compiler.constants.IASLanguageConstants.BuiltinType;
import org.apache.royale.compiler.definitions.IDefinition;
@@ -29,28 +31,18 @@ import org.apache.royale.compiler.definitions.ITypeDefinition;
import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.JSSessionModel;
import org.apache.royale.compiler.internal.codegen.js.JSSubEmitter;
+import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleDocEmitter;
import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitter;
import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.utils.EmitterUtils;
-import org.apache.royale.compiler.internal.definitions.AppliedVectorDefinition;
-import org.apache.royale.compiler.internal.definitions.ClassDefinition;
-import org.apache.royale.compiler.internal.definitions.FunctionDefinition;
-import org.apache.royale.compiler.internal.definitions.InterfaceDefinition;
-import org.apache.royale.compiler.internal.definitions.NamespaceDefinition;
+import org.apache.royale.compiler.internal.definitions.*;
import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
-import org.apache.royale.compiler.internal.tree.as.ContainerNode;
-import org.apache.royale.compiler.internal.tree.as.IdentifierNode;
-import org.apache.royale.compiler.internal.tree.as.MemberAccessExpressionNode;
-import org.apache.royale.compiler.internal.tree.as.NamespaceIdentifierNode;
-import org.apache.royale.compiler.internal.tree.as.VectorLiteralNode;
+import org.apache.royale.compiler.internal.tree.as.*;
import org.apache.royale.compiler.problems.TooFewFunctionParametersProblem;
import org.apache.royale.compiler.problems.TooManyFunctionParametersProblem;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.tree.ASTNodeID;
-import org.apache.royale.compiler.tree.as.IASNode;
-import org.apache.royale.compiler.tree.as.IContainerNode;
-import org.apache.royale.compiler.tree.as.IExpressionNode;
-import org.apache.royale.compiler.tree.as.IFunctionCallNode;
+import org.apache.royale.compiler.tree.as.*;
import org.apache.royale.compiler.utils.NativeUtils;
public class FunctionCallEmitter extends JSSubEmitter implements ISubEmitter<IFunctionCallNode>
@@ -66,7 +58,6 @@ public class FunctionCallEmitter extends JSSubEmitter implements ISubEmitter<IFu
{
// TODO (mschmalle) will remove this cast as more things get abstracted
JSRoyaleEmitter fjs = (JSRoyaleEmitter) getEmitter();
-
IASNode cnode = node.getChild(0);
if (cnode.getNodeID() == ASTNodeID.MemberAccessExpressionID)
@@ -80,16 +71,42 @@ public class FunctionCallEmitter extends JSSubEmitter implements ISubEmitter<IFu
def = nameNode.resolve(getProject());
boolean isClassCast = false;
-
+ boolean wrapResolve = false;
if (node.isNewExpression())
{
- if (!(node.getChild(1) instanceof VectorLiteralNode))
+ boolean omitNew = false;
+ if (nameNode instanceof IdentifierNode
+ && (((IdentifierNode) nameNode).getName().equals(IASLanguageConstants.String)
+ || ((IdentifierNode) nameNode).getName().equals(IASLanguageConstants.Boolean)
+ || ((IdentifierNode) nameNode).getName().equals(IASLanguageConstants.Number)))
+ {
+ omitNew = true;
+ }
+
+ if (!((node.getChild(1) instanceof VectorLiteralNode)))
{
- if (def == null || !(def.getBaseName().equals(IASGlobalFunctionConstants._int) ||
- def.getBaseName().equals(IASGlobalFunctionConstants.uint) ||
- def instanceof AppliedVectorDefinition))
+ if (!omitNew
+ && (def == null
+ || !(def.getBaseName().equals(IASGlobalFunctionConstants._int)
+ || def.getBaseName().equals(IASGlobalFunctionConstants.uint)))
+ )
{
- startMapping(node.getNewKeywordNode());
+ if (getProject() instanceof RoyaleJSProject
+ && nameNode.resolveType(getProject()) != null
+ && nameNode.resolveType(getProject()).getQualifiedName().equals("Class")) {
+
+ wrapResolve = shouldResolveUncertain(nameNode, false);
+
+ if (wrapResolve) {
+ ((RoyaleJSProject) getProject()).needLanguage = true;
+ getModel().needLanguage = true;
+ write(JSRoyaleEmitterTokens.LANGUAGE_QNAME);
+ write(ASEmitterTokens.MEMBER_ACCESS);
+ write("resolveUncertain");
+ write(ASEmitterTokens.PAREN_OPEN);
+ }
+ }
+ startMapping(node.getNewKeywordNode());
writeToken(ASEmitterTokens.NEW);
endMapping(node.getNewKeywordNode());
}
@@ -98,13 +115,46 @@ public class FunctionCallEmitter extends JSSubEmitter implements ISubEmitter<IFu
{
VectorLiteralNode vectorLiteralNode = (VectorLiteralNode) node.getChild(1);
String vectorClassName = (((RoyaleJSProject)fjs.getWalker().getProject()).config.getJsVectorEmulationClass());
+ SourceLocation mappingLocation = null;
if (vectorClassName != null)
{
writeToken(ASEmitterTokens.NEW);
write(vectorClassName);
write(ASEmitterTokens.PAREN_OPEN);
+ } else {
+ //no 'new' output in this case, just coercion, so map from the start of 'new'
+ startMapping(node);
+ write(JSRoyaleEmitterTokens.SYNTH_VECTOR);
+ write(ASEmitterTokens.PAREN_OPEN);
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ //the element type of the Vector:
+ write(((AppliedVectorDefinition)def).resolveElementType(getWalker().getProject()).getQualifiedName());
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write(ASEmitterTokens.PAREN_CLOSE);
+ write(ASEmitterTokens.SQUARE_OPEN);
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write("coerce");
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write(ASEmitterTokens.SQUARE_CLOSE);
+ mappingLocation = new SourceLocation(vectorLiteralNode.getCollectionTypeNode());
+ mappingLocation.setEndColumn(mappingLocation.getEndColumn() + 1);
+ endMapping(mappingLocation);
+ write(ASEmitterTokens.PAREN_OPEN);
+ if (getProject() instanceof RoyaleJSProject)
+ ((RoyaleJSProject)getProject()).needLanguage = true;
+ getEmitter().getModel().needLanguage = true;
+
}
+ mappingLocation = new SourceLocation(vectorLiteralNode.getContentsNode());
+ if (mappingLocation.getColumn()>0) mappingLocation.setColumn(mappingLocation.getColumn() -1);
+ mappingLocation.setEndColumn(mappingLocation.getColumn()+1);
+ startMapping(mappingLocation);
write("[");
+
+ /*mappingLocation = new SourceLocation(vectorLiteralNode.getContentsNode());
+ mappingLocation.setLine(vectorLiteralNode.getContentsNode().getLine());
+ mappingLocation.setColumn(vectorLiteralNode.getContentsNode().getColumn() + 1);*/
+ endMapping(mappingLocation);
ContainerNode contentsNode = vectorLiteralNode.getContentsNode();
int len = contentsNode.getChildCount();
for (int i = 0; i < len; i++)
@@ -115,7 +165,13 @@ public class FunctionCallEmitter extends JSSubEmitter implements ISubEmitter<IFu
writeToken(ASEmitterTokens.COMMA);
}
}
+ mappingLocation = new SourceLocation(vectorLiteralNode.getContentsNode());
+ mappingLocation.setLine(vectorLiteralNode.getContentsNode().getEndLine());
+ mappingLocation.setColumn(vectorLiteralNode.getContentsNode().getEndColumn());
+ mappingLocation.setEndColumn(mappingLocation.getColumn() + 1);
+ startMapping(mappingLocation);
write("]");
+ endMapping(mappingLocation);
if (vectorClassName != null)
{
writeToken(ASEmitterTokens.COMMA);
@@ -123,6 +179,8 @@ public class FunctionCallEmitter extends JSSubEmitter implements ISubEmitter<IFu
write(((AppliedVectorDefinition)def).resolveElementType(getWalker().getProject()).getBaseName());
write(ASEmitterTokens.SINGLE_QUOTE);
write(ASEmitterTokens.PAREN_CLOSE);
+ } else {
+ write(ASEmitterTokens.PAREN_CLOSE);
}
return;
}
@@ -131,12 +189,15 @@ public class FunctionCallEmitter extends JSSubEmitter implements ISubEmitter<IFu
{
def = node.getNameNode().resolve(getProject());
- isClassCast = (def instanceof ClassDefinition || def instanceof InterfaceDefinition)
+ isClassCast = def != null && (def instanceof ClassDefinition
+ || def instanceof InterfaceDefinition
+ || ( def instanceof VariableDefinition && ((VariableDefinition) def).resolveType(getProject()).getBaseName().equals("Class")))
&& !(NativeUtils.isJSNative(def.getBaseName()))
&& !def.getBaseName().equals(IASLanguageConstants.XML)
&& !def.getBaseName().equals(IASLanguageConstants.XMLList);
+
}
-
+
if (node.isNewExpression())
{
def = node.resolveCalledExpression(getProject());
@@ -177,30 +238,23 @@ public class FunctionCallEmitter extends JSSubEmitter implements ISubEmitter<IFu
if (nameNode.hasParenthesis())
write(ASEmitterTokens.PAREN_CLOSE);
}
-
- if (def instanceof AppliedVectorDefinition)
+ if ( def instanceof AppliedVectorDefinition
+ && (fjs.getWalker().getProject() instanceof RoyaleJSProject)
+ && (((RoyaleJSProject)fjs.getWalker().getProject()).config.getJsVectorEmulationClass() != null))
{
- ContainerNode args = node.getArgumentsNode();
- if (args.getChildCount() == 0)
- {
- String vectorClassName = (((RoyaleJSProject)fjs.getWalker().getProject()).config.getJsVectorEmulationClass());
- if (vectorClassName != null)
- {
- write(ASEmitterTokens.PAREN_OPEN);
- write(ASEmitterTokens.SQUARE_OPEN);
- write(ASEmitterTokens.SQUARE_CLOSE);
- write(ASEmitterTokens.COMMA);
- write(ASEmitterTokens.SPACE);
- write(ASEmitterTokens.SINGLE_QUOTE);
- write(((AppliedVectorDefinition)def).resolveElementType(getWalker().getProject()).getBaseName());
- write(ASEmitterTokens.SINGLE_QUOTE);
- write(ASEmitterTokens.PAREN_CLOSE);
- }
- else
- getEmitter().emitArguments(node.getArgumentsNode());
- }
- else
- {
+ ContainerNode args = node.getArgumentsNode();
+ if (args.getChildCount() == 0)
+ {
+ write(ASEmitterTokens.PAREN_OPEN);
+ write(ASEmitterTokens.SQUARE_OPEN);
+ write(ASEmitterTokens.SQUARE_CLOSE);
+ write(ASEmitterTokens.COMMA);
+ write(ASEmitterTokens.SPACE);
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write(((AppliedVectorDefinition)def).resolveElementType(getWalker().getProject()).getQualifiedName());
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write(ASEmitterTokens.PAREN_CLOSE);
+ } else {
startMapping(node);
write(ASEmitterTokens.PAREN_OPEN);
endMapping(node);
@@ -208,28 +262,32 @@ public class FunctionCallEmitter extends JSSubEmitter implements ISubEmitter<IFu
write(ASEmitterTokens.COMMA);
write(ASEmitterTokens.SPACE);
write(ASEmitterTokens.SINGLE_QUOTE);
- write(((AppliedVectorDefinition)def).resolveElementType(getWalker().getProject()).getBaseName());
+ write(((AppliedVectorDefinition)def).resolveElementType(getWalker().getProject()).getQualifiedName());
write(ASEmitterTokens.SINGLE_QUOTE);
if (args.getChildCount() == 2)
{
- IASNode second = args.getChild(1);
- if (second instanceof IExpressionNode)
- {
- ITypeDefinition secondType =
- ((IExpressionNode)second).resolveType(fjs.getWalker().getProject());
- if (fjs.getWalker().getProject().getBuiltinType(BuiltinType.BOOLEAN).equals(secondType))
- {
+ IASNode second = args.getChild(1);
+ if (second instanceof IExpressionNode)
+ {
+ ITypeDefinition secondType =
+ ((IExpressionNode)second).resolveType(fjs.getWalker().getProject());
+ if (fjs.getWalker().getProject().getBuiltinType(BuiltinType.BOOLEAN).equals(secondType))
+ {
write(ASEmitterTokens.COMMA);
write(ASEmitterTokens.SPACE);
- getWalker().walk(second);
- }
- }
+ getWalker().walk(second);
+ }
+ }
}
write(ASEmitterTokens.PAREN_CLOSE);
- }
+ }
+ } else {
+ getEmitter().emitArguments(node.getArgumentsNode());
+ }
+ //end wrap resolve
+ if (wrapResolve) {
+ write(ASEmitterTokens.PAREN_CLOSE);
}
- else
- getEmitter().emitArguments(node.getArgumentsNode());
}
else if (!isClassCast)
{
@@ -300,7 +358,35 @@ public class FunctionCallEmitter extends JSSubEmitter implements ISubEmitter<IFu
}
}
}
-
+ else if ((def.getBaseName().equals("insertAt")
+ || def.getBaseName().equals("removeAt"))
+ && def.getParent() instanceof AppliedVectorDefinition) {
+ //unlike Array implementation of these methods, the synthetic Vector implementation supports these methods at runtime,
+ //and they behave differently with fixed length vectors compared to the native 'splice' method output which is used to
+ //support them in Array, however they are not protected from GCL renaming in release builds by any actual class definition,
+ //so we explicitly 'protect' them here
+
+ ExpressionNodeBase leftSide = (ExpressionNodeBase)(((BinaryOperatorNodeBase) (node.getNameNode())).getLeftOperandNode());
+ LiteralNode dynamicName = new LiteralNode(ILiteralNode.LiteralType.STRING, "'" + def.getBaseName() + "'");
+ dynamicName.setSourceLocation(((BinaryOperatorNodeBase) (node.getNameNode())).getRightOperandNode());
+ DynamicAccessNode replacement = new DynamicAccessNode(leftSide);
+ leftSide.setParent(replacement);
+ replacement.setSourceLocation(node.getNameNode());
+ replacement.setRightOperandNode(dynamicName);
+ dynamicName.setParent(replacement);
+
+ FunctionCallNode replacer = new FunctionCallNode(replacement) ;
+ replacement.setParent(replacer);
+ IExpressionNode[] args = node.getArgumentNodes();
+ for (IExpressionNode arg : args) {
+ replacer.getArgumentsNode().addItem((NodeBase) arg);
+ }
+ replacer.getArgumentsNode().setParent(replacer);
+ replacer.getArgumentsNode().setSourceLocation(node.getArgumentsNode());
+ replacer.setParent((NodeBase) node.getParent());
+ //swap it out
+ node = replacer;
+ }
else if (def instanceof AppliedVectorDefinition)
{
IExpressionNode[] argumentNodes = node.getArgumentNodes();
@@ -315,9 +401,25 @@ public class FunctionCallEmitter extends JSSubEmitter implements ISubEmitter<IFu
}
else
{
- IExpressionNode argumentNode = argumentNodes[0];
- getWalker().walk(argumentNode);
- write(".slice()");
+ startMapping(node.getNameNode());
+ write(JSRoyaleEmitterTokens.SYNTH_VECTOR);
+ write(ASEmitterTokens.PAREN_OPEN);
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ //the element type of the Vector:
+ write(((TypedExpressionNode)nameNode).getTypeNode().resolve(getProject()).getQualifiedName());
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write(ASEmitterTokens.PAREN_CLOSE);
+ write(ASEmitterTokens.SQUARE_OPEN);
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write("coerce");
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write(ASEmitterTokens.SQUARE_CLOSE);
+ endMapping(node.getNameNode());
+
+ getEmitter().emitArguments(node.getArgumentsNode());
+ if (getProject() instanceof RoyaleJSProject)
+ ((RoyaleJSProject)getProject()).needLanguage = true;
+ getEmitter().getModel().needLanguage = true;
}
return;
}
@@ -327,6 +429,22 @@ public class FunctionCallEmitter extends JSSubEmitter implements ISubEmitter<IFu
getEmitter().emitArguments(node.getArgumentsNode());
return;
}
+ else if (def.getQualifiedName().equals(IASLanguageConstants.Object)) {
+ //'resolveUncertain' always output here
+ //unless a) there are no arguments
+ //or b) it is *explicitly* suppressed for 'Object'
+ if (node.getArgumentNodes().length > 0) {
+ if (shouldResolveUncertain(nameNode, true)) {
+ wrapResolve = true;
+ ((RoyaleJSProject) getProject()).needLanguage = true;
+ getModel().needLanguage = true;
+ write(JSRoyaleEmitterTokens.LANGUAGE_QNAME);
+ write(ASEmitterTokens.MEMBER_ACCESS);
+ write("resolveUncertain");
+ write(ASEmitterTokens.PAREN_OPEN);
+ }
+ }
+ }
else if (nameNode.getNodeID() == ASTNodeID.NamespaceAccessExpressionID && def instanceof FunctionDefinition)
{
if (fjs.isCustomNamespace((FunctionDefinition)def))
@@ -336,7 +454,7 @@ public class FunctionCallEmitter extends JSSubEmitter implements ISubEmitter<IFu
NamespaceDefinition nsDef = (NamespaceDefinition)nin.resolve(getProject());
IdentifierNode idNode = (IdentifierNode)nameNode.getChild(1);
String propName = idNode.getName();
- fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names
+ fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names
String s = nsDef.getURI();
write(JSRoyaleEmitter.formatNamespacedProperty(s, propName, true));
getEmitter().emitArguments(node.getArgumentsNode());
@@ -367,6 +485,11 @@ public class FunctionCallEmitter extends JSSubEmitter implements ISubEmitter<IFu
getWalker().walk(node.getNameNode());
getEmitter().emitArguments(node.getArgumentsNode());
+
+ //end wrap resolve
+ if (wrapResolve) {
+ write(ASEmitterTokens.PAREN_CLOSE);
+ }
}
else //function-style cast
{
@@ -378,5 +501,34 @@ public class FunctionCallEmitter extends JSSubEmitter implements ISubEmitter<IFu
fjs.emitSuperCall(node, JSSessionModel.SUPER_FUNCTION_CALL);
}
}
+
+
+ private boolean shouldResolveUncertain(IExpressionNode nameNode, boolean forceExplicit) {
+ //default if not avoided globally
+ boolean should = true;
+ //just in case:
+ if (!(getProject() instanceof RoyaleJSProject)) return false;
+ if (((RoyaleJSProject)getProject()).config.getJsNoResolveUncertain()) {
+ //start with global toggle
+ should = false;
+ }
+ IDocEmitter docEmitter = getEmitter().getDocEmitter();
+ if (docEmitter instanceof JSRoyaleDocEmitter)
+ {
+ JSRoyaleDocEmitter royaleDocEmitter = (JSRoyaleDocEmitter) docEmitter;
+ //look for local boolean toggle, unless forceExplicit is set
+ boolean suppress = !forceExplicit && royaleDocEmitter.getLocalSettingAsBoolean(
+ JSRoyaleEmitterTokens.SUPPRESS_RESOLVE_UNCERTAIN, !should);
+ //if it is still on, look for sepcific/named 'off' setting based on name node
+ if (!suppress && nameNode !=null) {
+ //check to suppress for indvidual named node
+ if (nameNode instanceof IdentifierNode) {
+ suppress = royaleDocEmitter.getLocalSettingIncludesString(JSRoyaleEmitterTokens.SUPPRESS_RESOLVE_UNCERTAIN, ((IdentifierNode) nameNode).getName());
+ }
+ }
+ should = !suppress;
+ }
+ return should;
+ }
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/IdentifierEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/IdentifierEmitter.java
index 26d8649..4d42069 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/IdentifierEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/IdentifierEmitter.java
@@ -34,18 +34,15 @@ import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.JSSubEmitter;
import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitter;
import org.apache.royale.compiler.internal.codegen.js.goog.JSGoogEmitterTokens;
+import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.utils.EmitterUtils;
-import org.apache.royale.compiler.internal.definitions.AccessorDefinition;
-import org.apache.royale.compiler.internal.definitions.ClassDefinition;
-import org.apache.royale.compiler.internal.definitions.FunctionDefinition;
-import org.apache.royale.compiler.internal.definitions.TypeDefinitionBase;
+import org.apache.royale.compiler.internal.definitions.*;
+import org.apache.royale.compiler.internal.tree.as.BinaryOperatorAssignmentNode;
+import org.apache.royale.compiler.internal.tree.as.BinaryOperatorDivisionAssignmentNode;
+import org.apache.royale.compiler.internal.tree.as.MemberAccessExpressionNode;
import org.apache.royale.compiler.internal.tree.as.NonResolvingIdentifierNode;
import org.apache.royale.compiler.tree.ASTNodeID;
-import org.apache.royale.compiler.tree.as.IASNode;
-import org.apache.royale.compiler.tree.as.IFunctionNode;
-import org.apache.royale.compiler.tree.as.IFunctionObjectNode;
-import org.apache.royale.compiler.tree.as.IIdentifierNode;
-import org.apache.royale.compiler.tree.as.IMemberAccessExpressionNode;
+import org.apache.royale.compiler.tree.as.*;
import org.apache.royale.compiler.utils.NativeUtils;
public class IdentifierEmitter extends JSSubEmitter implements
@@ -239,7 +236,7 @@ public class IdentifierEmitter extends JSSubEmitter implements
{
Namespace ns = (Namespace)((INamespaceResolvedReference)((FunctionDefinition)nodeDef).getNamespaceReference()).resolveAETNamespace(getProject());
INamespaceDefinition nsDef = ((FunctionDefinition)nodeDef).getNamespaceReference().resolveNamespaceReference(getProject());
- fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names
+ fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names
String nsName = ns.getName();
write(JSRoyaleEmitter.formatNamespacedProperty(nsName, node.getName(), true));
}
@@ -315,20 +312,31 @@ public class IdentifierEmitter extends JSSubEmitter implements
}
else if (identifierIsAccessorFunction && isStatic)
{
- write("[\"" +node.getName() + "\"]");
+ write("[\"" +node.getName() + "\"]");
}
else
{
qname = node.getName();
if (nodeDef != null && !isStatic && (nodeDef.getParent() instanceof ClassDefinition) && (!(nodeDef instanceof IParameterDefinition)) && nodeDef.isPrivate() && getProject().getAllowPrivateNameConflicts())
qname = getEmitter().formatPrivateName(nodeDef.getParent().getQualifiedName(), qname);
- write(qname);
+ write(qname);
}
}
else if (isPackageOrFileMember)
write(getEmitter().formatQualifiedName(qname));
else if (nodeDef instanceof TypeDefinitionBase)
- write(getEmitter().formatQualifiedName(qname));
+ {
+ if (NativeUtils.isSyntheticJSType(qname) && !(parentNode instanceof IFunctionCallNode)) {
+ getEmitter().getModel().needLanguage = true;
+ write(JSRoyaleEmitterTokens.SYNTH_TYPE);
+ write(ASEmitterTokens.PAREN_OPEN);
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write(getEmitter().formatQualifiedName(qname));
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write(ASEmitterTokens.PAREN_CLOSE);
+ }
+ else write(getEmitter().formatQualifiedName(qname));
+ }
else if (isCustomNamespace)
{
String ns = ((INamespaceResolvedReference)((FunctionDefinition)nodeDef).getNamespaceReference()).resolveAETNamespace(getProject()).getName();
@@ -336,9 +344,9 @@ public class IdentifierEmitter extends JSSubEmitter implements
}
else if (identifierIsAccessorFunction && isStatic)
{
- write("[\"" + qname + "\"]");
+ write("[\"" + qname + "\"]");
}
- else
+ else
{
if (nodeDef != null && !isStatic && (nodeDef.getParent() instanceof ClassDefinition) && (!(nodeDef instanceof IParameterDefinition)) && nodeDef.isPrivate() && getProject().getAllowPrivateNameConflicts())
qname = getEmitter().formatPrivateName(nodeDef.getParent().getQualifiedName(), qname);
@@ -353,7 +361,7 @@ public class IdentifierEmitter extends JSSubEmitter implements
write("child('");
write(node.getName());
write("')");
- endMapping(node);
+ endMapping(node);
}
else
{
@@ -363,5 +371,7 @@ public class IdentifierEmitter extends JSSubEmitter implements
}
}
}
+
+
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/MemberAccessEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/MemberAccessEmitter.java
index 23e5ec0..968b78b 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/MemberAccessEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/MemberAccessEmitter.java
@@ -34,22 +34,15 @@ import org.apache.royale.compiler.internal.definitions.AccessorDefinition;
import org.apache.royale.compiler.internal.definitions.AppliedVectorDefinition;
import org.apache.royale.compiler.internal.definitions.FunctionDefinition;
import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
-import org.apache.royale.compiler.internal.tree.as.DynamicAccessNode;
-import org.apache.royale.compiler.internal.tree.as.FunctionCallNode;
-import org.apache.royale.compiler.internal.tree.as.GetterNode;
-import org.apache.royale.compiler.internal.tree.as.IdentifierNode;
-import org.apache.royale.compiler.internal.tree.as.MemberAccessExpressionNode;
-import org.apache.royale.compiler.internal.tree.as.NamespaceAccessExpressionNode;
+import org.apache.royale.compiler.internal.tree.as.*;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.tree.ASTNodeID;
-import org.apache.royale.compiler.tree.as.IASNode;
-import org.apache.royale.compiler.tree.as.IExpressionNode;
-import org.apache.royale.compiler.tree.as.IIdentifierNode;
-import org.apache.royale.compiler.tree.as.ILanguageIdentifierNode;
-import org.apache.royale.compiler.tree.as.IMemberAccessExpressionNode;
+import org.apache.royale.compiler.tree.as.*;
import org.apache.royale.compiler.tree.as.IOperatorNode.OperatorType;
import org.apache.royale.compiler.utils.ASNodeUtils;
+import javax.sound.midi.SysexMessage;
+
public class MemberAccessEmitter extends JSSubEmitter implements
ISubEmitter<IMemberAccessExpressionNode>
{
@@ -199,21 +192,6 @@ public class MemberAccessEmitter extends JSSubEmitter implements
return;
}
}
- else if (def.getParent() instanceof AppliedVectorDefinition)
- {
- 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;
- }
- }
else if (rightNode instanceof NamespaceAccessExpressionNode)
{
boolean isStatic = false;
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/MethodEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/MethodEmitter.java
index aad1184..0fc7b0b 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/MethodEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/MethodEmitter.java
@@ -108,8 +108,12 @@ public class MethodEmitter extends JSSubEmitter implements
}
endMapping(node.getNameExpressionNode());
}
-
- startMapping(node);
+ if (node.getMetaTags() != null) {
+ //offset mapping by any metadata tags that will be in the first child node
+ startMapping(node.getChild(1));
+ } else {
+ startMapping(node);
+ }
write(ASEmitterTokens.SPACE);
writeToken(ASEmitterTokens.EQUAL);
write(ASEmitterTokens.FUNCTION);
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/UnaryOperatorEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/UnaryOperatorEmitter.java
index b575d55..bc040e7 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/UnaryOperatorEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/UnaryOperatorEmitter.java
@@ -23,8 +23,12 @@ import org.apache.royale.compiler.codegen.ISubEmitter;
import org.apache.royale.compiler.codegen.js.IJSEmitter;
import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.JSSubEmitter;
+import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitterTokens;
+import org.apache.royale.compiler.internal.definitions.AppliedVectorDefinition;
+import org.apache.royale.compiler.internal.tree.as.*;
import org.apache.royale.compiler.tree.ASTNodeID;
import org.apache.royale.compiler.tree.as.IExpressionNode;
+import org.apache.royale.compiler.tree.as.ILiteralNode;
import org.apache.royale.compiler.tree.as.IUnaryOperatorNode;
import org.apache.royale.compiler.utils.ASNodeUtils;
@@ -41,6 +45,31 @@ public class UnaryOperatorEmitter extends JSSubEmitter implements
{
if (ASNodeUtils.hasParenOpen(node))
write(ASEmitterTokens.PAREN_OPEN);
+
+ Boolean isAssignment = (node.getNodeID() == ASTNodeID.Op_PreIncrID
+ || node.getNodeID() == ASTNodeID.Op_PreDecrID
+ || node.getNodeID() == ASTNodeID.Op_PostIncrID
+ || node.getNodeID() == ASTNodeID.Op_PostDecrID);
+
+ if (isAssignment && (node.getOperandNode() instanceof MemberAccessExpressionNode)
+ && (((MemberAccessExpressionNode)(node.getOperandNode())).getRightOperandNode() instanceof IdentifierNode)
+ && ((IdentifierNode)(((MemberAccessExpressionNode)(node.getOperandNode())).getRightOperandNode())).getName().equals("length")
+ && ((MemberAccessExpressionNode)(node.getOperandNode())).getLeftOperandNode().resolveType(getProject()) instanceof AppliedVectorDefinition
+ ) {
+ //support for output of alternate length setter, example: vectorInst.length++ as vectorInst['_synthType'].length++
+ //likewise for pre/post increment/decrement
+
+ String synthTagName = JSRoyaleEmitterTokens.LANGUAGE_QNAME.getToken() + ASEmitterTokens.MEMBER_ACCESS.getToken() + JSRoyaleEmitterTokens.ROYALE_SYNTH_TAG_FIELD_NAME.getToken();
+ LiteralNode synthType = new LiteralNode(ILiteralNode.LiteralType.STRING, synthTagName);
+ synthType.setSynthetic(true);
+ DynamicAccessNode patchedVectorReference = new DynamicAccessNode(((ExpressionNodeBase)((MemberAccessExpressionNode) node.getOperandNode()).getLeftOperandNode()));
+ ((ExpressionNodeBase)((MemberAccessExpressionNode) node.getOperandNode()).getLeftOperandNode()).setParent(patchedVectorReference);
+ patchedVectorReference.setRightOperandNode(synthType);
+ synthType.setParent(patchedVectorReference);
+ patchedVectorReference.setParent((NodeBase) node.getOperandNode());
+ patchedVectorReference.setSourceLocation(((MemberAccessExpressionNode) node.getOperandNode()).getLeftOperandNode());
+ ((MemberAccessExpressionNode) node.getOperandNode()).setLeftOperandNode(patchedVectorReference);
+ }
if (node.getNodeID() == ASTNodeID.Op_PreIncrID
|| node.getNodeID() == ASTNodeID.Op_PreDecrID
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleDocEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleDocEmitter.java
index 8cfd1c9..1ab5268 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleDocEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleDocEmitter.java
@@ -19,8 +19,7 @@
package org.apache.royale.compiler.internal.codegen.js.royale;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.*;
import org.apache.royale.compiler.asdoc.royale.ASDocComment;
import org.apache.royale.compiler.codegen.as.IASEmitter;
@@ -41,6 +40,7 @@ import org.apache.royale.compiler.internal.codegen.js.goog.JSGoogDocEmitter;
import org.apache.royale.compiler.internal.codegen.js.jx.BindableEmitter;
import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
import org.apache.royale.compiler.internal.scopes.ASScope;
+import org.apache.royale.compiler.parsing.IASToken;
import org.apache.royale.compiler.problems.PublicVarWarningProblem;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.tree.ASTNodeID;
@@ -53,6 +53,7 @@ public class JSRoyaleDocEmitter extends JSGoogDocEmitter
private List<String> classIgnoreList;
private List<String> ignoreList;
private List<String> coercionList;
+ private Map<String,List<String>> localSettings;
public boolean emitStringConversions = true;
private boolean emitExports = true;
private boolean exportProtected = false;
@@ -128,6 +129,7 @@ public class JSRoyaleDocEmitter extends JSGoogDocEmitter
coercionList = null;
ignoreList = null;
+ localSettings = null;
emitStringConversions = true;
IClassDefinition classDefinition = resolveClassDefinition(node);
@@ -228,6 +230,22 @@ public class JSRoyaleDocEmitter extends JSGoogDocEmitter
.getToken();
if (docText.contains(noStringToken))
emitStringConversions = false;
+
+ String noImplicitComplexCoercion = JSRoyaleEmitterTokens.SUPPRESS_COMPLEX_IMPLICIT_COERCION
+ .getToken();
+ if (docText.contains(noImplicitComplexCoercion))
+ loadLocalSettings(docText, noImplicitComplexCoercion, "true");
+
+ String noResolveUncertain = JSRoyaleEmitterTokens.SUPPRESS_RESOLVE_UNCERTAIN
+ .getToken();
+ if (docText.contains(noResolveUncertain))
+ loadLocalSettings(docText,noResolveUncertain, "true");
+
+ String suppressVectorIndexCheck = JSRoyaleEmitterTokens.SUPPRESS_VECTOR_INDEX_CHECK
+ .getToken();
+ if (docText.contains(suppressVectorIndexCheck))
+ loadLocalSettings(docText,suppressVectorIndexCheck, "true");
+
write(changeAnnotations(asDoc.commentNoEnd()));
}
else
@@ -312,6 +330,82 @@ public class JSRoyaleDocEmitter extends JSGoogDocEmitter
end();
}
}
+
+ /**
+ *
+ */
+ private void loadLocalSettings(String doc, String settingToken, String defaultSetting)
+ {
+ if (localSettings == null) localSettings = new HashMap<String, List<String>>();
+ int index = doc.indexOf(settingToken);
+ List<String> settings = localSettings.containsKey(settingToken) ? localSettings.get(settingToken) : null;
+ while (index != -1)
+ {
+ String setting = doc.substring(index + settingToken.length());
+ int endIndex = setting.indexOf("\n");
+ setting = setting.substring(0, endIndex);
+ setting = setting.trim();
+ if (settings == null) {
+ settings = new ArrayList<String>();
+ localSettings.put(settingToken, settings);
+ }
+ List<String> settingItems = null;
+ if (setting.length() >0) {
+ settingItems = Arrays.asList(setting.split("\\s*(,\\s*)+"));
+ } else {
+ settingItems = Arrays.asList(defaultSetting);
+ }
+ for (String settingItem: settingItems) {
+ if (settings.contains(settingItem)) {
+ //change the order to reflect the latest addition
+ settings.remove(settingItem);
+ }
+ settings.add(settingItem);
+ System.out.println("---Adding setting "+settingToken+":"+settingItem);
+ }
+
+ index = doc.indexOf(settingToken, index + endIndex);
+ }
+ }
+
+ public boolean hasLocalSetting(String settingToken) {
+ if (localSettings == null) return false;
+ return (localSettings.keySet().contains(settingToken));
+ }
+
+ public boolean getLocalSettingAsBoolean(JSRoyaleEmitterTokens token, Boolean defaultValue) {
+ return getLocalSettingAsBoolean(token.getToken(), defaultValue);
+ }
+
+ public boolean getLocalSettingAsBoolean(String settingToken, Boolean defaultValue) {
+ boolean setting = defaultValue;
+ if (hasLocalSetting(settingToken)) {
+ for (String stringVal: localSettings.get(settingToken)) {
+ //don't bail out after finding a boolean-ish string val
+ //'last one wins'
+ if (stringVal.equals("false")) setting = false;
+ else if (stringVal.equals("true")) setting = true;
+ }
+ }
+ return setting;
+ }
+
+ public boolean getLocalSettingIncludesString(JSRoyaleEmitterTokens token, String searchValue) {
+ return getLocalSettingIncludesString(token.getToken(), searchValue);
+ }
+
+ public boolean getLocalSettingIncludesString(String settingToken, String searchValue) {
+ boolean hasValue = false;
+ if (hasLocalSetting(settingToken)) {
+ for (String stringVal: localSettings.get(settingToken)) {
+ if (stringVal.equals(searchValue)) {
+ hasValue = true;
+ break;
+ }
+ }
+ }
+ return hasValue;
+ }
private void loadIgnores(String doc)
{
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleEmitter.java
index 834ce4d..2335b31 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleEmitter.java
@@ -718,12 +718,10 @@ public class JSRoyaleEmitter extends JSGoogEmitter implements IJSRoyaleEmitter
else if (name.equals(IASLanguageConstants._int)
|| name.equals(IASLanguageConstants.uint))
result = IASLanguageConstants.Number;
-
- boolean isBuiltinFunction = name.matches("Vector\\.<.*>");
- if (isBuiltinFunction)
- {
- result = IASLanguageConstants.Array;
+ else if (name.equals(IASLanguageConstants.Vector) || name.equals("__AS3__.vec.Vector")) {
+ result = JSRoyaleEmitterTokens.VECTOR.getToken();
}
+
return result;
}
@@ -925,10 +923,6 @@ public class JSRoyaleEmitter extends JSGoogEmitter implements IJSRoyaleEmitter
newNode = EmitterUtils.insertArgumentsAt(node, 1, new NumericLiteralNode("0"));
}
}
- else if (def.getParent() != null && def.getParent() instanceof AppliedVectorDefinition)
- {
- newNode = EmitterUtils.insertArgumentsAt(node, 1, new NumericLiteralNode("0"));
- }
}
}
if (len == 1)
@@ -947,10 +941,6 @@ public class JSRoyaleEmitter extends JSGoogEmitter implements IJSRoyaleEmitter
newNode = EmitterUtils.insertArgumentsAfter(node, new NumericLiteralNode("1"));
}
}
- else if (def.getParent() != null && def.getParent() instanceof AppliedVectorDefinition)
- {
- newNode = EmitterUtils.insertArgumentsAfter(node, new NumericLiteralNode("1"));
- }
}
else if (def != null && def.getBaseName().equals("parseInt"))
{
@@ -1479,12 +1469,32 @@ public class JSRoyaleEmitter extends JSGoogEmitter implements IJSRoyaleEmitter
String vectorClassName = ((RoyaleJSProject)project).config == null ? null : ((RoyaleJSProject)project).config.getJsVectorEmulationClass();
if (vectorClassName != null)
{
- writeToken(ASEmitterTokens.NEW);
write(vectorClassName);
return;
}
}
- write(JSRoyaleEmitterTokens.VECTOR);
+ Boolean written = false;
+ if (node instanceof TypedExpressionNode) {
+ startMapping(node);
+ write(ASEmitterTokens.PAREN_OPEN);
+ /*write(JSRoyaleEmitterTokens.LANGUAGE_QNAME);
+ write(ASEmitterTokens.MEMBER_ACCESS);
+ write("synthVector");*/
+ write(JSRoyaleEmitterTokens.SYNTH_VECTOR);
+ write(ASEmitterTokens.PAREN_OPEN);
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ //the element type of the Vector:
+ write(node.getTypeNode().resolve(project).getQualifiedName());
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write(ASEmitterTokens.PAREN_CLOSE);
+ write(ASEmitterTokens.PAREN_CLOSE);
+ endMapping(node);
+ written = true;
+ }
+
+ if (!written) {
+ write(JSRoyaleEmitterTokens.VECTOR);
+ }
if (getModel().inStaticInitializer)
{
if (!staticUsedNames.contains(JSRoyaleEmitterTokens.LANGUAGE_QNAME.getToken()))
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleEmitterTokens.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleEmitterTokens.java
index 20bc298..1c61fb3 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleEmitterTokens.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleEmitterTokens.java
@@ -35,6 +35,7 @@ public enum JSRoyaleEmitterTokens implements IEmitterTokens
ROYALE_CLASS_INFO_CLASS_KIND("class"),
ROYALE_CLASS_INFO_INTERFACE_KIND("interface"),
ROYALE_CLASS_INFO_IS_DYNAMIC("isDynamic"),
+ ROYALE_SYNTH_TAG_FIELD_NAME("SYNTH_TAG_FIELD"),
GOOG_EXPORT_PROPERTY("goog.exportProperty"),
GOOG_EXPORT_SYMBOL("goog.exportSymbol"),
INDENT(" "),
@@ -50,6 +51,9 @@ public enum JSRoyaleEmitterTokens implements IEmitterTokens
IGNORE_IMPORT("@royaleignoreimport"),
IGNORE_STRING_COERCION("@royalenoimplicitstringconversion"),
SUPPRESS_PUBLIC_VAR_WARNING("@royalesuppresspublicvarwarning"),
+ SUPPRESS_COMPLEX_IMPLICIT_COERCION("@royalesuppresscompleximplicitcoercion"),
+ SUPPRESS_RESOLVE_UNCERTAIN("@royalesuppressresolveuncertain"),
+ SUPPRESS_VECTOR_INDEX_CHECK("@royalesuppressvectorindexcheck"),
DEBUG_COMMENT("@royaledebug"),
DEBUG_RETURN("if(!goog.DEBUG)return;"),
PREINCREMENT("preincrement"),
@@ -65,7 +69,10 @@ public enum JSRoyaleEmitterTokens implements IEmitterTokens
SKIP_AS_COERCIONS("skipAsCoercions"),
SKIP_FUNCTION_COERCIONS("skipFunctionCoercions"),
JSX("JSX"),
- VECTOR("org.apache.royale.utils.Language.Vector"),
+ VECTOR(LANGUAGE_QNAME.getToken() + ".Vector"),
+ SYNTH_TYPE(LANGUAGE_QNAME.getToken() + ".synthType"),
+ SYNTH_VECTOR(LANGUAGE_QNAME.getToken() + ".synthVector"),
+ VECTOR_INDEX_CHECK_METHOD_NAME(LANGUAGE_QNAME.getToken() + ".CHECK_INDEX"),
;
private String token;
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleJSProject.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleJSProject.java
index 06348a5..42e647c 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleJSProject.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleJSProject.java
@@ -39,6 +39,7 @@ import org.apache.royale.compiler.config.Configurator;
import org.apache.royale.compiler.css.ICSSMediaQueryCondition;
import org.apache.royale.compiler.css.ICSSRule;
import org.apache.royale.compiler.definitions.IDefinition;
+import org.apache.royale.compiler.definitions.IFunctionDefinition;
import org.apache.royale.compiler.definitions.ITypeDefinition;
import org.apache.royale.compiler.definitions.metadata.IMetaTag;
import org.apache.royale.compiler.definitions.metadata.IMetaTagAttribute;
@@ -116,7 +117,7 @@ public class RoyaleJSProject extends RoyaleProject
if (defNode instanceof IClassNode || defNode instanceof IInterfaceNode)
{
String defname = def.getQualifiedName();
- IASDocComment asDoc = (defNode instanceof IClassNode) ?
+ IASDocComment asDoc = (defNode instanceof IClassNode) ?
(IASDocComment) ((IClassNode)defNode).getASDocComment() :
(IASDocComment) ((IInterfaceNode)defNode).getASDocComment();
if (asDoc != null && (asDoc instanceof ASDocComment))
@@ -163,7 +164,7 @@ public class RoyaleJSProject extends RoyaleProject
super.addDependency(from, to, dt, qname);
}
- private synchronized void updateRequiresMap(ICompilationUnit from, ICompilationUnit to,
+ private synchronized void updateRequiresMap(ICompilationUnit from, ICompilationUnit to,
DependencyType dt, String qname)
{
HashMap<String, DependencyType> reqs;
@@ -188,10 +189,10 @@ public class RoyaleJSProject extends RoyaleProject
if (qname.equals("XML"))
needXML = true;
reqs.put(qname, dt);
- }
+ }
}
- private synchronized void updateJSModulesMap(ICompilationUnit from, ICompilationUnit to,
+ private synchronized void updateJSModulesMap(ICompilationUnit from, ICompilationUnit to,
DependencyType dt, String qname)
{
HashMap<String, DependencyType> reqs;
@@ -219,7 +220,7 @@ public class RoyaleJSProject extends RoyaleProject
}
}
- private synchronized void updateInterfacesMap(ICompilationUnit from, ICompilationUnit to,
+ private synchronized void updateInterfacesMap(ICompilationUnit from, ICompilationUnit to,
DependencyType dt, String qname)
{
HashMap<String, String> interfacesArr;
@@ -530,6 +531,15 @@ public class RoyaleJSProject extends RoyaleProject
}
return false;
}
+
+ @Override
+ public boolean isParameterCountMismatchAllowed(IFunctionDefinition func,
+ int formalCount, int actualCount) {
+ if ((func.getBaseName().equals("int") || func.getBaseName().equals("uint")) && func.isConstructor()) {
+ if (actualCount == 1) return true;
+ }
+ return super.isParameterCountMismatchAllowed(func, formalCount, actualCount);
+ }
/**
* List of compiler defines so it can be overridden
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/utils/JSClosureCompilerWrapper.java b/compiler-jx/src/main/java/org/apache/royale/compiler/utils/JSClosureCompilerWrapper.java
index 74e1bb6..a305b4f 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/utils/JSClosureCompilerWrapper.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/utils/JSClosureCompilerWrapper.java
@@ -356,6 +356,8 @@ public class JSClosureCompilerWrapper
"playerversion", "langversion", "copy", "span", "para", "throw", "tiptext",
"asparam", "asreturn", "asreturns", "asprivate",
"royaleignoreimport", "royaleignorecoercion", "royaleemitcoercion",
+ "royalesuppresscompleximplicitcoercion","royalesuppressresolveuncertain",
+ "royalesuppressvectorindexcheck",
"royalenoimplicitstringconversion","royaledebug"};
options_.setExtraAnnotationNames(Arrays.asList(asdocTags));
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/utils/NativeUtils.java b/compiler-jx/src/main/java/org/apache/royale/compiler/utils/NativeUtils.java
index 0653542..51ea799 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/utils/NativeUtils.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/utils/NativeUtils.java
@@ -122,8 +122,8 @@ public class NativeUtils
unescape("unescape"),
window("window"),
- // (erikdebruin) These aren't strictly 'native' to JS, but the
- // Publisher provides global functions, so, for all
+ // (erikdebruin) These aren't strictly 'native' to JS, but the
+ // Publisher provides global functions, so, for all
// intends and purposes they behave like they are.
_int("int"),
trace("trace"),
@@ -154,6 +154,25 @@ public class NativeUtils
}
}
+ public enum SyntheticJSType
+ {
+ _int("int"),
+ uint("uint"),
+ Vector("Vector");
+
+ private final String value;
+
+ SyntheticJSType(String value)
+ {
+ this.value = value;
+ }
+
+ public String getValue()
+ {
+ return value;
+ }
+ }
+
public static boolean isNative(String type)
{
for (NativeASType test : NativeASType.values())
@@ -175,5 +194,24 @@ public class NativeUtils
}
return false;
}
+
+ public static boolean isSyntheticJSType(String type)
+ {
+ for (SyntheticJSType test : SyntheticJSType.values())
+ {
+ if (test.getValue().equals(type)) {
+ return true;
+ }
+ }
+ if (type.startsWith("Vector.<")) {
+ return true;
+ }
+ return false;
+ }
+
+ public static boolean isVector(String type)
+ {
+ return type != null && type.startsWith("Vector.<");
+ }
}
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleExpressions.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleExpressions.java
index 0b32b4a..0179d35 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleExpressions.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleExpressions.java
@@ -1220,7 +1220,7 @@ public class TestRoyaleExpressions extends TestGoogExpressions
"public class B {public function b() { function c(f:Function):void {}; var f:Array = [b]; c(f[0]); }}",
IFunctionNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitFunction(node);
- assertOut("/**\n * @export\n */\nB.prototype.b = function() {\n var self = this;\n function c(f) {\n };\n var /** @type {Array} */ f = [org.apache.royale.utils.Language.closure(this.b, this, 'b')];\n c(f[0]);\n}");
+ assertOut("/**\n * @export\n */\nB.prototype.b = function() {\n var self = this;\n function c(f) {\n };\n var /** @type {Array} */ f = [org.apache.royale.utils.Language.closure(this.b, this, 'b')];\n c(/* implicit cast */ org.apache.royale.utils.Language.as(f[0], Function, true));\n}");
}
@Test
@@ -1512,7 +1512,7 @@ public class TestRoyaleExpressions extends TestGoogExpressions
{
IBinaryOperatorNode node = getBinaryNode("a as int");
asBlockWalker.visitBinaryOperator(node);
- assertOut("org.apache.royale.utils.Language.as(a, Number)");
+ assertOut("org.apache.royale.utils.Language.as(a, org.apache.royale.utils.Language.synthType('int'))");
}
@Test
@@ -1520,7 +1520,7 @@ public class TestRoyaleExpressions extends TestGoogExpressions
{
IBinaryOperatorNode node = getBinaryNode("a as uint");
asBlockWalker.visitBinaryOperator(node);
- assertOut("org.apache.royale.utils.Language.as(a, Number)");
+ assertOut("org.apache.royale.utils.Language.as(a, org.apache.royale.utils.Language.synthType('uint'))");
}
@Test
@@ -1530,7 +1530,7 @@ public class TestRoyaleExpressions extends TestGoogExpressions
"public class B {private var memberVar:Class; public function b(o:Object):int { var a:B = null; a = o as memberVar; }}",
IFunctionNode.class, WRAP_LEVEL_PACKAGE, true);
asBlockWalker.visitFunction(node);
- assertOut("/**\n * @export\n * @param {Object} o\n * @return {number}\n */\nfoo.bar.B.prototype.b = function(o) {\n var /** @type {foo.bar.B} */ a = null;\n a = org.apache.royale.utils.Language.as(o, this.memberVar);\n}");
+ assertOut("/**\n * @export\n * @param {Object} o\n * @return {number}\n */\nfoo.bar.B.prototype.b = function(o) {\n var /** @type {foo.bar.B} */ a = null;\n a = /* implicit cast */ org.apache.royale.utils.Language.as(org.apache.royale.utils.Language.as(o, this.memberVar), foo.bar.B, true);\n}");
}
@Test
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleGlobalClasses.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleGlobalClasses.java
index 4f590d3..6957c18 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleGlobalClasses.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleGlobalClasses.java
@@ -287,6 +287,16 @@ public class TestRoyaleGlobalClasses extends TestGoogGlobalClasses
asBlockWalker.visitVariable(node);
assertOut("var /** @type {number} */ a = Math[\"PI\"]");
}
+
+ @Override
+ @Test
+ public void testClass()
+ {
+ IVariableNode node = getVariable("var a:Class = String; var b:* = new a('test')");
+ node = (IVariableNode)(node.getParent().getChild(1));
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {*} */ b = org.apache.royale.utils.Language.resolveUncertain(new a('test'))");
+ }
@Test
public void testDateSetSeconds()
@@ -379,7 +389,7 @@ public class TestRoyaleGlobalClasses extends TestGoogGlobalClasses
IVariableNode node = getVariable("var a:Vector.<String> = new Vector.<String>(['Hello', 'World']);");
asBlockWalker.visitVariable(node);
//MXMLC does not report an error. Should we?
- assertOut("var /** @type {Array} */ a = org.apache.royale.utils.Language.Vector(['Hello', 'World'], 'String')");
+ assertOut("var /** @type {Array} */ a = new (org.apache.royale.utils.Language.synthVector('String'))(['Hello', 'World'])");
}
@Test
@@ -387,7 +397,7 @@ public class TestRoyaleGlobalClasses extends TestGoogGlobalClasses
{
IVariableNode node = getVariable("var a:Vector.<String> = new <String>[];");
asBlockWalker.visitVariable(node);
- assertOut("var /** @type {Array} */ a = []");
+ assertOut("var /** @type {Array} */ a = org.apache.royale.utils.Language.synthVector('String')['coerce']([])");
}
@Test
@@ -395,7 +405,7 @@ public class TestRoyaleGlobalClasses extends TestGoogGlobalClasses
{
IVariableNode node = getVariable("var a:Vector.<int> = new <int>[0, 1, 2, 3];");
asBlockWalker.visitVariable(node);
- assertOut("var /** @type {Array} */ a = [0, 1, 2, 3]");
+ assertOut("var /** @type {Array} */ a = org.apache.royale.utils.Language.synthVector('int')['coerce']([0, 1, 2, 3])");
}
@Test
@@ -403,7 +413,7 @@ public class TestRoyaleGlobalClasses extends TestGoogGlobalClasses
{
IVariableNode node = getVariable("var a:Vector.<String> = new <String>[\"one\", \"two\", \"three\";");
asBlockWalker.visitVariable(node);
- assertOut("var /** @type {Array} */ a = [\"one\", \"two\", \"three\"]");
+ assertOut("var /** @type {Array} */ a = org.apache.royale.utils.Language.synthVector('String')['coerce']([\"one\", \"two\", \"three\"])");
}
@Test
@@ -411,7 +421,7 @@ public class TestRoyaleGlobalClasses extends TestGoogGlobalClasses
{
IVariableNode node = getVariable("var a:Vector.<String> = new Vector.<String>();");
asBlockWalker.visitVariable(node);
- assertOut("var /** @type {Array} */ a = org.apache.royale.utils.Language.Vector()");
+ assertOut("var /** @type {Array} */ a = new (org.apache.royale.utils.Language.synthVector('String'))()");
}
@Test
@@ -420,7 +430,7 @@ public class TestRoyaleGlobalClasses extends TestGoogGlobalClasses
IVariableNode node = getVariable("var a:Vector.<String> = new Vector.<String>('Hello', 'World');");
asBlockWalker.visitVariable(node);
//MXMLC does not report an error. Should we?
- assertOut("var /** @type {Array} */ a = org.apache.royale.utils.Language.Vector('Hello', 'String')");
+ assertOut("var /** @type {Array} */ a = new (org.apache.royale.utils.Language.synthVector('String'))('Hello', 'World')");
}
@Test
@@ -429,7 +439,7 @@ public class TestRoyaleGlobalClasses extends TestGoogGlobalClasses
IVariableNode node = getVariable("var a:Vector.<String> = new Vector.<String>('Hello', 'World', 'Three');");
asBlockWalker.visitVariable(node);
//MXMLC does not report an error. Should we?
- assertOut("var /** @type {Array} */ a = org.apache.royale.utils.Language.Vector('Hello', 'String')");
+ assertOut("var /** @type {Array} */ a = new (org.apache.royale.utils.Language.synthVector('String'))('Hello', 'World', 'Three')");
}
@Test
@@ -437,7 +447,7 @@ public class TestRoyaleGlobalClasses extends TestGoogGlobalClasses
{
IVariableNode node = getVariable("var a:Vector.<String> = new Vector.<String>(30);");
asBlockWalker.visitVariable(node);
- assertOut("var /** @type {Array} */ a = org.apache.royale.utils.Language.Vector(30, 'String')");
+ assertOut("var /** @type {Array} */ a = new (org.apache.royale.utils.Language.synthVector('String'))(30)");
}
@Test
@@ -446,7 +456,7 @@ public class TestRoyaleGlobalClasses extends TestGoogGlobalClasses
IVariableNode node = getVariable("var a:Vector.<String> = new Vector.<String>(30, 40);");
asBlockWalker.visitVariable(node);
//MXMLC does not report an error. Should we?
- assertOut("var /** @type {Array} */ a = org.apache.royale.utils.Language.Vector(30, 'String')");
+ assertOut("var /** @type {Array} */ a = new (org.apache.royale.utils.Language.synthVector('String'))(30, 40)");
}
@Test
@@ -455,7 +465,7 @@ public class TestRoyaleGlobalClasses extends TestGoogGlobalClasses
IVariableNode node = getVariable("var a:Vector.<String> = new Vector.<String>(['Hello', 'World']);");
asBlockWalker.visitVariable(node);
//MXMLC does not report an error. Should we?
- assertOut("var /** @type {Array} */ a = org.apache.royale.utils.Language.Vector(['Hello', 'World'], 'String')");
+ assertOut("var /** @type {Array} */ a = new (org.apache.royale.utils.Language.synthVector('String'))(['Hello', 'World'])");
}
@Test
@@ -468,7 +478,7 @@ public class TestRoyaleGlobalClasses extends TestGoogGlobalClasses
IBinaryOperatorNode node = getBinaryNode("var a:Vector.<String> = new Vector.<String>(); a.removeAt(2)");
IFunctionCallNode parentNode = (IFunctionCallNode)(node.getParent());
asBlockWalker.visitFunctionCall(parentNode);
- assertOut("a.splice(2, 1)");
+ assertOut("a['removeAt'](2)");
}
}
@@ -482,7 +492,7 @@ public class TestRoyaleGlobalClasses extends TestGoogGlobalClasses
IBinaryOperatorNode node = getBinaryNode("var a:Vector.<String> = new Vector.<String>(); a.insertAt(2, 'foo')");
IFunctionCallNode parentNode = (IFunctionCallNode)(node.getParent());
asBlockWalker.visitFunctionCall(parentNode);
- assertOut("a.splice(2, 0, 'foo')");
+ assertOut("a['insertAt'](2, 'foo')");
}
}
@@ -590,6 +600,33 @@ public class TestRoyaleGlobalClasses extends TestGoogGlobalClasses
assertOut("var /** @type {CustomVector} */ a = new CustomVector(['Hello', 'World'], 'String')");
}
+ @Override
+ @Test
+ public void testBoolean()
+ {
+ IVariableNode node = getVariable("var a:Boolean = new Boolean(1);");
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {boolean} */ a = Boolean(1)");
+ }
+
+ @Override
+ @Test
+ public void testNumber()
+ {
+ IVariableNode node = getVariable("var a:Number = new Number(\"1\");");
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {number} */ a = Number(\"1\")");
+ }
+
+ @Override
+ @Test
+ public void testString()
+ {
+ IVariableNode node = getVariable("var a:String = new String(\"100\");");
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {string} */ a = String(\"100\")");
+ }
+
@Test
public void testXML()
{
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleGlobalFunctions.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleGlobalFunctions.java
index 8f2f9d1..baef176 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleGlobalFunctions.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleGlobalFunctions.java
@@ -100,6 +100,15 @@ public class TestRoyaleGlobalFunctions extends TestGoogGlobalFunctions
asBlockWalker.visitVariable(node);
assertOut("var /** @type {Array} */ a = Array(['Hello', 'World'])");
}
+
+ @Override
+ @Test
+ public void testObject()
+ {
+ IVariableNode node = getVariable("var a:Object = Object(\"1\");");
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {Object} */ a = org.apache.royale.utils.Language.resolveUncertain(Object(\"1\"))");
+ }
@Test
public void testParseInt()
@@ -159,7 +168,7 @@ public class TestRoyaleGlobalFunctions extends TestGoogGlobalFunctions
{
IVariableNode node = getVariable("var a:Vector.<String> = Vector.<String>(['Hello', 'World']);");
asBlockWalker.visitVariable(node);
- assertOut("var /** @type {Array} */ a = ['Hello', 'World'].slice()");
+ assertOut("var /** @type {Array} */ a = org.apache.royale.utils.Language.synthVector('String')['coerce'](['Hello', 'World'])");
}
@Test
@@ -184,7 +193,7 @@ public class TestRoyaleGlobalFunctions extends TestGoogGlobalFunctions
IVariableNode node = getVariable("var a:Vector.<String> = Vector.<String>(30);");
asBlockWalker.visitVariable(node);
// MXMLC doesn't report an error either. Maybe we should.
- assertOut("var /** @type {Array} */ a = 30.slice()");
+ assertOut("var /** @type {Array} */ a = org.apache.royale.utils.Language.synthVector('String')['coerce'](30)");
}
@Test
@@ -200,7 +209,7 @@ public class TestRoyaleGlobalFunctions extends TestGoogGlobalFunctions
{
IVariableNode node = getVariable("var a:Vector.<String> = Vector.<String>(['Hello', 'World']);");
asBlockWalker.visitVariable(node);
- assertOut("var /** @type {Array} */ a = ['Hello', 'World'].slice()");
+ assertOut("var /** @type {Array} */ a = org.apache.royale.utils.Language.synthVector('String')['coerce'](['Hello', 'World'])");
}
@Override
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/DynamicAccessNode.java b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/DynamicAccessNode.java
index dd974a7..7b9f34e 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/DynamicAccessNode.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/DynamicAccessNode.java
@@ -21,6 +21,7 @@ package org.apache.royale.compiler.internal.tree.as;
import org.apache.royale.compiler.definitions.IAppliedVectorDefinition;
import org.apache.royale.compiler.definitions.ITypeDefinition;
+import org.apache.royale.compiler.internal.semantics.SemanticUtils;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.tree.ASTNodeID;
import org.apache.royale.compiler.tree.as.IDynamicAccessNode;
@@ -81,8 +82,10 @@ public class DynamicAccessNode extends BinaryOperatorNodeBase implements IDynami
ITypeDefinition leftType = getLeftOperandNode().resolveType(project);
if (leftType instanceof IAppliedVectorDefinition)
{
- IAppliedVectorDefinition vectorDef = (IAppliedVectorDefinition) leftType;
- return vectorDef.resolveElementType(project);
+ if (SemanticUtils.isNumericType(getRightOperandNode().resolveType(project), project)) {
+ IAppliedVectorDefinition vectorDef = (IAppliedVectorDefinition) leftType;
+ return vectorDef.resolveElementType(project);
+ }
}
return super.resolveType(project);
}