This is an automated email from the ASF dual-hosted git repository.
joshtynjala pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/royale-compiler.git
The following commit(s) were added to refs/heads/develop by this push:
new 9094bbfe1 New [RoyaleCallableInstances] meta may be added to a typedef
class to allow instances of the class to be called like a function, to support
the jQuery $ symbol both being callable and having members
9094bbfe1 is described below
commit 9094bbfe179ffd0f21f5f5eff5abed346717f5a6
Author: Josh Tynjala <[email protected]>
AuthorDate: Wed Sep 18 13:48:06 2024 -0700
New [RoyaleCallableInstances] meta may be added to a typedef class to allow
instances of the class to be called like a function, to support the jQuery $
symbol both being callable and having members
This basically reverts commit 1152253d28ce140f5e1339e525645ec9e64424fe,
which made the compiler more lenient when calling a variable or accessor to
support jQuery. That change unfortunately moved errors on most objects that are
not callable from compile-time to run-time, which is not ideal. This new
metadata allows us to go back to the same strictness as the Flex SDK compiler
for most code, with the option to opt into the extra lenience on specific
classes.
This metadata does not currently allow defining a function signature,
including checking parameter and return types, but that wasn't possible before
either. It could potentially be added through parameters on the metadata in the
future, though.
(closes #112)
---
.../compiler/clients/ExternCConfiguration.java | 15 ++++++++++
.../codegen/typedefs/reference/ClassReference.java | 17 +++++++++++
.../codegen/typedefs/reference/ReferenceModel.java | 1 +
.../constants/IMetaAttributeConstants.java | 4 +++
.../semantics/MethodBodySemanticChecker.java | 33 ++++++++++++++--------
compiler/src/test/java/as/ASVariableTests.java | 31 +++++++++++++++++++-
6 files changed, 88 insertions(+), 13 deletions(-)
diff --git
a/compiler-externc/src/main/java/org/apache/royale/compiler/clients/ExternCConfiguration.java
b/compiler-externc/src/main/java/org/apache/royale/compiler/clients/ExternCConfiguration.java
index ca77287fe..a331448b4 100644
---
a/compiler-externc/src/main/java/org/apache/royale/compiler/clients/ExternCConfiguration.java
+++
b/compiler-externc/src/main/java/org/apache/royale/compiler/clients/ExternCConfiguration.java
@@ -58,6 +58,7 @@ public class ExternCConfiguration extends Configuration
private List<String> namedModules = new ArrayList<String>();
+ private List<String> callableInstances = new ArrayList<String>();
private List<String> classToFunctions = new ArrayList<String>();
private List<ExcludedMember> excludesClass = new
ArrayList<ExcludedMember>();
private List<ExcludedMember> excludesField = new
ArrayList<ExcludedMember>();
@@ -437,6 +438,20 @@ public class ExternCConfiguration extends Configuration
return null;
}
+ @Config(allowMultiple = true)
+ @Mapping("class-callable-instances")
+ @Arguments("class")
+ @InfiniteArguments
+ public void setClassCallableInstances(ConfigurationValue cfgval,
List<String> values) throws IOException, CannotOpen
+ {
+ callableInstances.addAll(values);
+ }
+
+ public boolean classHasCallableInstances(BaseReference reference)
+ {
+ return callableInstances.contains(reference.getQualifiedName());
+ }
+
diff --git
a/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/ClassReference.java
b/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/ClassReference.java
index f22aa832b..1bf634034 100644
---
a/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/ClassReference.java
+++
b/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/ClassReference.java
@@ -46,6 +46,7 @@ public class ClassReference extends BaseReference
{
private boolean isFinal;
private boolean isDynamic;
+ private boolean callableInstances;
private String moduleName;
private int enumConstantCounter = 0;
@@ -140,6 +141,16 @@ public class ClassReference extends BaseReference
this.isDynamic = isDynamic;
}
+ public boolean hasCallableInstances()
+ {
+ return callableInstances;
+ }
+
+ public void setCallableInstances(boolean callableInstances)
+ {
+ this.callableInstances = callableInstances;
+ }
+
public boolean isFinal()
{
return isFinal;
@@ -393,6 +404,12 @@ public class ClassReference extends BaseReference
sb.append("]");
sb.append("\n");
}
+ if (callableInstances)
+ {
+ sb.append(indent);
+ sb.append("[RoyaleCallableInstances]\n");
+ }
+
emitComment(sb);
diff --git
a/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/ReferenceModel.java
b/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/ReferenceModel.java
index 1fe4d5cc1..f6be49200 100644
---
a/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/ReferenceModel.java
+++
b/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/ReferenceModel.java
@@ -149,6 +149,7 @@ public class ReferenceModel
log("Model.addClass(" + qualifiedName + ")");
ClassReference reference = new ClassReference(this, node,
qualifiedName);
+
reference.setCallableInstances(configuration.classHasCallableInstances(reference));
// TODO (mschmalle) Figure out if gcc makes any decisions about what
is final or dynamic
if (reference.getQualifiedName().equals("Object")
diff --git
a/compiler/src/main/java/org/apache/royale/compiler/constants/IMetaAttributeConstants.java
b/compiler/src/main/java/org/apache/royale/compiler/constants/IMetaAttributeConstants.java
index 2d195f20d..855d0a24e 100644
---
a/compiler/src/main/java/org/apache/royale/compiler/constants/IMetaAttributeConstants.java
+++
b/compiler/src/main/java/org/apache/royale/compiler/constants/IMetaAttributeConstants.java
@@ -214,6 +214,9 @@ public interface IMetaAttributeConstants
// [RoyaleAbstract]
static final String ATTRIBUTE_ABSTRACT = "RoyaleAbstract";
+ // [RoyaleCallable]
+ static final String ATTRIBUTE_CALLABLE_INSTANCES =
"RoyaleCallableInstances";
+
// [RoyaleFunctionType]
static final String ATTRIBUTE_FUNCTION_TYPE = "RoyaleFunctionType";
static final String NAME_FUNCTION_TYPE_RETURNS = "returns";
@@ -242,6 +245,7 @@ public interface IMetaAttributeConstants
ATTRIBUTE_EXCLUDECLASS,
ATTRIBUTE_ABSTRACT,
ATTRIBUTE_PRIVATE_CONSTRUCTOR,
+ ATTRIBUTE_CALLABLE_INSTANCES,
})));
}
diff --git
a/compiler/src/main/java/org/apache/royale/compiler/internal/semantics/MethodBodySemanticChecker.java
b/compiler/src/main/java/org/apache/royale/compiler/internal/semantics/MethodBodySemanticChecker.java
index 1f1372a32..629791cda 100644
---
a/compiler/src/main/java/org/apache/royale/compiler/internal/semantics/MethodBodySemanticChecker.java
+++
b/compiler/src/main/java/org/apache/royale/compiler/internal/semantics/MethodBodySemanticChecker.java
@@ -1252,12 +1252,17 @@ public class MethodBodySemanticChecker
{
AccessorDefinition accessorDef = (AccessorDefinition)def;
IDefinition accessorType = accessorDef.resolveType(project);
- if (accessorType != null && // Null here means the ANY_TYPE
-
(accessorType.equals(project.getBuiltinType(BuiltinType.NUMBER)) ||
-
accessorType.equals(project.getBuiltinType(BuiltinType.BOOLEAN)) ||
-
accessorType.equals(project.getBuiltinType(BuiltinType.INT)) ||
-
accessorType.equals(project.getBuiltinType(BuiltinType.UINT)) ||
-
accessorType.equals(project.getBuiltinType(BuiltinType.STRING))))
+
+ if (accessorType == null || // Null here means the ANY_TYPE
+ accessorType.equals(project.getBuiltinType(BuiltinType.CLASS))
||
+
accessorType.equals(project.getBuiltinType(BuiltinType.FUNCTION)) ||
+
accessorType.equals(project.getBuiltinType(BuiltinType.OBJECT)) ||
+
accessorType.equals(project.getBuiltinType(BuiltinType.ANY_TYPE)) ||
+
accessorType.getMetaTagByName(IMetaAttributeConstants.ATTRIBUTE_CALLABLE_INSTANCES)
!= null)
+ {
+ // assume it can be called
+ }
+ else
{
addProblem(new CallNonFunctionProblem(iNode,
method_binding.getName().getBaseName()));
}
@@ -1271,12 +1276,16 @@ public class MethodBodySemanticChecker
{
VariableDefinition varDef = (VariableDefinition)def;
IDefinition varType = varDef.resolveType(project);
- if (varType != null && // Null here means the ANY_TYPE
-
(varType.equals(project.getBuiltinType(BuiltinType.NUMBER)) ||
-
varType.equals(project.getBuiltinType(BuiltinType.BOOLEAN)) ||
- varType.equals(project.getBuiltinType(BuiltinType.INT)) ||
- varType.equals(project.getBuiltinType(BuiltinType.UINT)) ||
-
varType.equals(project.getBuiltinType(BuiltinType.STRING))))
+ if (varType == null || // Null here means the ANY_TYPE
+ varType.equals(project.getBuiltinType(BuiltinType.CLASS)) ||
+ varType.equals(project.getBuiltinType(BuiltinType.FUNCTION)) ||
+ varType.equals(project.getBuiltinType(BuiltinType.OBJECT)) ||
+ varType.equals(project.getBuiltinType(BuiltinType.ANY_TYPE)) ||
+
varType.getMetaTagByName(IMetaAttributeConstants.ATTRIBUTE_CALLABLE_INSTANCES)
!= null)
+ {
+ // assume it can be called
+ }
+ else
{
addProblem(new CallNonFunctionProblem(iNode,
method_binding.getName().getBaseName()));
}
diff --git a/compiler/src/test/java/as/ASVariableTests.java
b/compiler/src/test/java/as/ASVariableTests.java
index 3b042a8b9..c3e851859 100644
--- a/compiler/src/test/java/as/ASVariableTests.java
+++ b/compiler/src/test/java/as/ASVariableTests.java
@@ -124,7 +124,7 @@ public class ASVariableTests extends ASFeatureTestsBase
}
@Test
- public void ASVariableTests_constIsClassCastFunction()
+ public void
ASVariableTests_constIsClassCastFunction_noCallableInstancesMeta()
{
String[] imports = new String[]
{
@@ -147,6 +147,35 @@ public class ASVariableTests extends ASFeatureTestsBase
"}"
};
String source = getAS(imports, declarations, testCode, extraCode);
+ compileAndExpectErrors(source, false, false, false, new String[0],
+ "Call to innerClass is not a function.\n");
+ }
+
+ @Test
+ public void
ASVariableTests_constIsClassCastFunction_withCallableInstancesMeta()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ "private const innerClass:InnerClass = null;",
+ };
+ String[] testCode = new String[]
+ {
+ "if (false) { var test:Object = innerClass('foo')};",
+ };
+ String[] extraCode = new String[]
+ {
+ "[RoyaleCallableInstances]",
+ "class InnerClass",
+ "{",
+ " public function InnerClass(obj:Object)",
+ " {",
+ " }",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extraCode);
compileAndRun(source);
}