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 6a85bc1 compiler: added support for abstract classes in ActionScript
6a85bc1 is described below
commit 6a85bc1cd0c09e4ca07cf221a55ec9dd13e5d63c
Author: Josh Tynjala <[email protected]>
AuthorDate: Wed Jan 23 14:51:00 2019 -0800
compiler: added support for abstract classes in ActionScript
When a developer attempts to instantiate an abstract class with the "new"
keyword, the compiler will report an error. This is a compile time check for
now, but emitters could hypothetically add runtime checks too.
The abstract modifier is allowed on classes only at this time, and trying
to use it on other definitions, like interfaces, methods, and variables results
in a syntax problem.
To enable abstract classes, use the new allow-abstract-classes compiler
option. Support for abstract classes is disabled by default, meaning using this
experimental new syntax is completely opt-in. Even if the syntax widely
adopted, we should keep it disabled by default in the compiler to avoid syntax
conflicts when using the compiler for code intelligence with other SDKs. To
enable it by default for a particular SDK, modify the appropriate
frameworks/*-config.xml file.
Behind the scenes, When the "abstract" keyword is encountered as a modifier
on a class, [RoyaleAbstract] metadata is created. This allows bytecode to store
whether a class is abstract, without actually having to update the bytecode
format and runtimes that support it. The metadata also allows classes in
libraries to remain abstract when compiled to SWC.
---
.../apache/royale/compiler/common/ASModifier.java | 8 +++-
.../royale/compiler/config/Configuration.java | 22 +++++++++++
.../compiler/constants/IASKeywordConstants.java | 1 +
.../royale/compiler/definitions/IDefinition.java | 7 ++++
.../royale/compiler/projects/ICompilerProject.java | 5 +++
.../royale/compiler/internal/parsing/as/ASParser.g | 3 +-
.../constants/IMetaAttributeConstants.java | 4 ++
.../as/codegen/ClassDirectiveProcessor.java | 9 +++++
.../as/codegen/GlobalDirectiveProcessor.java | 19 +++++++++-
.../as/codegen/InterfaceDirectiveProcessor.java | 5 +++
.../internal/definitions/ClassDefinitionBase.java | 26 +++++++++++++
.../internal/definitions/DefinitionBase.java | 24 ++++++++++++
.../compiler/internal/parsing/as/ASToken.java | 4 ++
.../compiler/internal/parsing/as/BaseASParser.java | 3 +-
.../internal/parsing/as/ConfigProcessor.java | 6 +++
.../internal/parsing/as/StreamingASTokenizer.java | 4 ++
.../compiler/internal/projects/ASCProject.java | 6 +++
.../compiler/internal/projects/RoyaleProject.java | 15 ++++++++
.../projects/RoyaleProjectConfigurator.java | 1 +
.../semantics/MethodBodySemanticChecker.java | 11 ++++++
.../internal/tree/as/BaseDefinitionNode.java | 2 +
.../AbstractClassCannotBeInstantiatedProblem.java | 42 +++++++++++++++++++++
.../problems/AbstractOutsideClassProblem.java | 43 ++++++++++++++++++++++
23 files changed, 265 insertions(+), 5 deletions(-)
diff --git
a/compiler-common/src/main/java/org/apache/royale/compiler/common/ASModifier.java
b/compiler-common/src/main/java/org/apache/royale/compiler/common/ASModifier.java
index bb686ea..a601f80 100644
---
a/compiler-common/src/main/java/org/apache/royale/compiler/common/ASModifier.java
+++
b/compiler-common/src/main/java/org/apache/royale/compiler/common/ASModifier.java
@@ -60,6 +60,11 @@ public class ASModifier
* Represents the <code>virtual</code> modifier.
*/
public static final ASModifier VIRTUAL = new
ASModifier(IASKeywordConstants.VIRTUAL, 1 << 6);
+
+ /**
+ * Represents the <code>abstract</code> modifier.
+ */
+ public static final ASModifier ABSTRACT = new
ASModifier(IASKeywordConstants.ABSTRACT, 1 << 7);
/**
* A list of all the modifiers that exist within AS3
@@ -71,7 +76,8 @@ public class ASModifier
NATIVE,
OVERRIDE,
STATIC,
- VIRTUAL
+ VIRTUAL,
+ ABSTRACT
};
/**
diff --git
a/compiler-common/src/main/java/org/apache/royale/compiler/config/Configuration.java
b/compiler-common/src/main/java/org/apache/royale/compiler/config/Configuration.java
index 5f8a3e0..478d346 100644
---
a/compiler-common/src/main/java/org/apache/royale/compiler/config/Configuration.java
+++
b/compiler-common/src/main/java/org/apache/royale/compiler/config/Configuration.java
@@ -1508,6 +1508,28 @@ public class Configuration
}
//
+ // 'compiler.allow-abstract-classes' option
+ //
+
+ private boolean allowAbstractClasses = false;
+
+ public boolean getCompilerAllowAbstractClasses()
+ {
+ return allowAbstractClasses;
+ }
+
+ /**
+ * Whether the compiler will allow classes to be abstract.
+ */
+ @Config
+ @Mapping({ "compiler", "allow-abstract-classes" })
+ @RoyaleOnly
+ public void setCompilerAllowAbstractClasses(ConfigurationValue cv, boolean
allow)
+ {
+ this.allowAbstractClasses = allow;
+ }
+
+ //
// 'compiler.actionscript-file-encoding' option
//
diff --git
a/compiler-common/src/main/java/org/apache/royale/compiler/constants/IASKeywordConstants.java
b/compiler-common/src/main/java/org/apache/royale/compiler/constants/IASKeywordConstants.java
index b45cea2..54e17ac 100644
---
a/compiler-common/src/main/java/org/apache/royale/compiler/constants/IASKeywordConstants.java
+++
b/compiler-common/src/main/java/org/apache/royale/compiler/constants/IASKeywordConstants.java
@@ -26,6 +26,7 @@ import com.google.common.collect.ImmutableSet;
*/
public interface IASKeywordConstants
{
+ static final String ABSTRACT = "abstract";
static final String AS = "as";
static final String BREAK = "break";
static final String CASE = "case";
diff --git
a/compiler-common/src/main/java/org/apache/royale/compiler/definitions/IDefinition.java
b/compiler-common/src/main/java/org/apache/royale/compiler/definitions/IDefinition.java
index 21f225b..89bfd78 100644
---
a/compiler-common/src/main/java/org/apache/royale/compiler/definitions/IDefinition.java
+++
b/compiler-common/src/main/java/org/apache/royale/compiler/definitions/IDefinition.java
@@ -268,6 +268,13 @@ public interface IDefinition
boolean isStatic();
/**
+ * Is this definition marked as <code>abstract</code>?
+ *
+ * @return <code>true</code> if the definition is <code>abstract</code>.
+ */
+ boolean isAbstract();
+
+ /**
* Determines whether the specified modifier is present on this definition.
* See {@link ASModifier} for the list of modifiers.
*
diff --git
a/compiler-common/src/main/java/org/apache/royale/compiler/projects/ICompilerProject.java
b/compiler-common/src/main/java/org/apache/royale/compiler/projects/ICompilerProject.java
index b3eea14..61d7489 100644
---
a/compiler-common/src/main/java/org/apache/royale/compiler/projects/ICompilerProject.java
+++
b/compiler-common/src/main/java/org/apache/royale/compiler/projects/ICompilerProject.java
@@ -271,5 +271,10 @@ public interface ICompilerProject
* @return True if import aliases are allowed.
*/
boolean getAllowImportAliases();
+
+ /**
+ * @return True if abstract classes are allowed.
+ */
+ boolean getAllowAbstractClasses();
}
diff --git
a/compiler/src/main/antlr/org/apache/royale/compiler/internal/parsing/as/ASParser.g
b/compiler/src/main/antlr/org/apache/royale/compiler/internal/parsing/as/ASParser.g
index b4839ce..8a6a299 100644
---
a/compiler/src/main/antlr/org/apache/royale/compiler/internal/parsing/as/ASParser.g
+++
b/compiler/src/main/antlr/org/apache/royale/compiler/internal/parsing/as/ASParser.g
@@ -212,7 +212,7 @@ attributedDefinition[ContainerNode c]
/**
* Matches an attribute such as:
- * - Modifiers: dynamic, final, native, override, static, virtual.
+ * - Modifiers: dynamic, final, native, override, static, virtual, abstract.
* - Namespace names.
* - Reserved namespace names: internal, private, public, protected.
*
@@ -580,6 +580,7 @@ modifierAttribute returns [ModifierNode modifierNode]
| TOKEN_MODIFIER_STATIC
| TOKEN_MODIFIER_NATIVE
| TOKEN_MODIFIER_VIRTUAL
+ | TOKEN_MODIFIER_ABSTRACT
)
{ modifierNode = new ModifierNode((ASToken) modifierT); }
;
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 dee1690..189f8ea 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
@@ -210,6 +210,9 @@ public interface IMetaAttributeConstants
static final String NAME_MIN_VALUE_EXCLUSIVE = "minValueExclusive";
static final String NAME_MAX_VALUE = "maxValue";
static final String NAME_MAX_VALUE_EXCLUSIVE = "maxValueExclusive";
+
+ // [RoyaleAbstract]
+ static final String ATTRIBUTE_ABSTRACT = "RoyaleAbstract";
/**
* List of metadata tags that do not inherit
@@ -222,6 +225,7 @@ public interface IMetaAttributeConstants
ATTRIBUTE_DEPRECATED,
ATTRIBUTE_DISCOURAGED_FOR_PROFILE,
ATTRIBUTE_EXCLUDECLASS,
+ ATTRIBUTE_ABSTRACT,
})));
}
diff --git
a/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/ClassDirectiveProcessor.java
b/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/ClassDirectiveProcessor.java
index cc1fef1..ff3a627 100644
---
a/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/ClassDirectiveProcessor.java
+++
b/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/ClassDirectiveProcessor.java
@@ -58,6 +58,7 @@ import
org.apache.royale.compiler.definitions.IInterfaceDefinition;
import org.apache.royale.compiler.definitions.metadata.IMetaTag;
import org.apache.royale.compiler.definitions.metadata.IMetaTagAttribute;
import org.apache.royale.compiler.exceptions.CodegenInterruptedException;
+import org.apache.royale.compiler.problems.AbstractOutsideClassProblem;
import org.apache.royale.compiler.problems.CircularTypeReferenceProblem;
import
org.apache.royale.compiler.problems.ConstructorCannotHaveReturnTypeProblem;
import org.apache.royale.compiler.problems.ConstructorIsGetterSetterProblem;
@@ -1091,6 +1092,10 @@ class ClassDirectiveProcessor extends DirectiveProcessor
{
classScope.addProblem(new VirtualOutsideClassProblem(site) );
}
+ if( modifiersSet.hasModifier(ASModifier.ABSTRACT) )
+ {
+ classScope.addProblem(new AbstractOutsideClassProblem(site) );
+ }
}
classScope.getMethodBodySemanticChecker().checkForDuplicateModifiers(f);
// Functions in a class allow all modifiers
@@ -1127,6 +1132,10 @@ class ClassDirectiveProcessor extends DirectiveProcessor
{
classScope.addProblem(new VirtualOutsideClassProblem(site));
}
+ else if( modifier == ASModifier.ABSTRACT )
+ {
+ classScope.addProblem(new AbstractOutsideClassProblem(site));
+ }
}
classScope.getMethodBodySemanticChecker().checkForDuplicateModifiers(v);
}
diff --git
a/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/GlobalDirectiveProcessor.java
b/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/GlobalDirectiveProcessor.java
index 0f4f3c8..ca63800 100644
---
a/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/GlobalDirectiveProcessor.java
+++
b/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/GlobalDirectiveProcessor.java
@@ -30,6 +30,7 @@ import org.apache.royale.compiler.tree.as.IASNode;
import org.apache.royale.compiler.tree.as.IExpressionNode;
import org.apache.royale.compiler.common.ASModifier;
import org.apache.royale.compiler.common.ModifiersSet;
+import org.apache.royale.compiler.constants.IASKeywordConstants;
import org.apache.royale.compiler.constants.IMetaAttributeConstants;
import org.apache.royale.compiler.definitions.IDefinition;
import org.apache.royale.compiler.internal.definitions.ClassDefinition;
@@ -45,6 +46,7 @@ import
org.apache.royale.compiler.internal.tree.as.NamespaceIdentifierNode;
import org.apache.royale.compiler.internal.tree.as.PackageNode;
import org.apache.royale.compiler.internal.tree.as.VariableNode;
import org.apache.royale.compiler.internal.tree.mxml.MXMLDocumentNode;
+import org.apache.royale.compiler.problems.AbstractOutsideClassProblem;
import org.apache.royale.compiler.problems.DynamicNotOnClassProblem;
import org.apache.royale.compiler.problems.EmbedOnlyOnClassesAndVarsProblem;
import org.apache.royale.compiler.problems.FinalOutsideClassProblem;
@@ -54,6 +56,7 @@ import
org.apache.royale.compiler.problems.NativeNotOnFunctionProblem;
import org.apache.royale.compiler.problems.NativeVariableProblem;
import org.apache.royale.compiler.problems.OverrideOutsideClassProblem;
import org.apache.royale.compiler.problems.StaticOutsideClassProblem;
+import org.apache.royale.compiler.problems.SyntaxProblem;
import org.apache.royale.compiler.problems.VirtualOutsideClassProblem;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.tree.mxml.IMXMLDocumentNode;
@@ -320,6 +323,16 @@ class GlobalDirectiveProcessor extends DirectiveProcessor
*/
protected void verifyClassModifiers(ClassNode c)
{
+ if(!currentScope.getProject().getAllowAbstractClasses() &&
c.getDefinition().isAbstract())
+ {
+ IASNode problemNode = c.getNameExpressionNode();
+ if (problemNode == null)
+ {
+ problemNode = c;
+ }
+ currentScope.addProblem(new SyntaxProblem(problemNode,
IASKeywordConstants.ABSTRACT));
+ }
+
ModifiersSet modifiersSet = c.getModifiers();
if (modifiersSet == null)
return;
@@ -328,8 +341,8 @@ class GlobalDirectiveProcessor extends DirectiveProcessor
IExpressionNode site = c.getNameExpressionNode();
for (ASModifier modifier : modifiers)
{
- // final allowed on a class
- if( modifier == ASModifier.FINAL || modifier == ASModifier.DYNAMIC)
+ // final, dynamic, and abstract allowed on a class
+ if( modifier == ASModifier.FINAL || modifier == ASModifier.DYNAMIC
|| modifier == ASModifier.ABSTRACT)
{
continue;
}
@@ -408,6 +421,8 @@ class GlobalDirectiveProcessor extends DirectiveProcessor
currentScope.addProblem(new OverrideOutsideClassProblem(site));
else if( modifier == ASModifier.VIRTUAL )
currentScope.addProblem(new VirtualOutsideClassProblem(site));
+ else if( modifier == ASModifier.ABSTRACT )
+ currentScope.addProblem(new AbstractOutsideClassProblem(site));
}
/**
diff --git
a/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/InterfaceDirectiveProcessor.java
b/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/InterfaceDirectiveProcessor.java
index f564c1b..46cfd3d 100644
---
a/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/InterfaceDirectiveProcessor.java
+++
b/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/InterfaceDirectiveProcessor.java
@@ -55,6 +55,7 @@ import org.apache.royale.compiler.internal.tree.as.ImportNode;
import org.apache.royale.compiler.internal.tree.as.InterfaceNode;
import org.apache.royale.compiler.internal.tree.as.NamespaceIdentifierNode;
import org.apache.royale.compiler.internal.tree.as.VariableNode;
+import org.apache.royale.compiler.problems.AbstractOutsideClassProblem;
import org.apache.royale.compiler.problems.AmbiguousReferenceProblem;
import org.apache.royale.compiler.problems.CannotExtendClassProblem;
import org.apache.royale.compiler.problems.ConstructorInInterfaceProblem;
@@ -456,6 +457,10 @@ public class InterfaceDirectiveProcessor extends
DirectiveProcessor
{
interfaceScope.addProblem(new
VirtualOutsideClassProblem(site));
}
+ else if( modifier == ASModifier.ABSTRACT )
+ {
+ interfaceScope.addProblem(new
AbstractOutsideClassProblem(site));
+ }
else if ( modifier == ASModifier.DYNAMIC )
{
// Allow this and continue.
diff --git
a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/ClassDefinitionBase.java
b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/ClassDefinitionBase.java
index e00eda3..2dcf3ed 100644
---
a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/ClassDefinitionBase.java
+++
b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/ClassDefinitionBase.java
@@ -32,8 +32,10 @@ import org.apache.royale.compiler.definitions.IDefinition;
import org.apache.royale.compiler.definitions.IInterfaceDefinition;
import org.apache.royale.compiler.definitions.ITypeDefinition;
import org.apache.royale.compiler.definitions.metadata.IMetaTag;
+import org.apache.royale.compiler.definitions.metadata.IMetaTagAttribute;
import org.apache.royale.compiler.definitions.references.IReference;
import org.apache.royale.compiler.internal.as.codegen.BindableHelper;
+import org.apache.royale.compiler.internal.definitions.metadata.MetaTag;
import org.apache.royale.compiler.internal.projects.CompilerProject;
import org.apache.royale.compiler.internal.scopes.ASProjectScope;
import org.apache.royale.compiler.internal.scopes.ASScope;
@@ -536,6 +538,30 @@ public abstract class ClassDefinitionBase extends
TypeDefinitionBase implements
return interfaces;
}
+ @Override
+ public boolean isAbstract()
+ {
+ if(super.isAbstract())
+ {
+ return true;
+ }
+ IMetaTag[] metaTags =
getMetaTagsByName(IMetaAttributeConstants.ATTRIBUTE_ABSTRACT);
+ return metaTags != null && metaTags.length > 0;
+ }
+
+ /**
+ * Utility to mark a definition as abstract. This method should only ever
be
+ * called during construction or initialization of a definition.
+ */
+ @Override
+ public void setAbstract()
+ {
+ super.setAbstract();
+
+ MetaTag abstractMetaTag = new MetaTag(this,
IMetaAttributeConstants.ATTRIBUTE_ABSTRACT, new IMetaTagAttribute[0]);
+ addMetaTag(abstractMetaTag);
+ }
+
/*
* This inner class implements an iterator that enumerates all of this
* ClassDefinition's superclasses. <p> It will stop iterating when it
diff --git
a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/DefinitionBase.java
b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/DefinitionBase.java
index 2e4c859..a219328 100644
---
a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/DefinitionBase.java
+++
b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/DefinitionBase.java
@@ -701,6 +701,21 @@ public abstract class DefinitionBase implements
IDocumentableDefinition, IDefini
flags |= FLAG_STATIC;
}
+ // instead of increasing the size of "flags" from a short to int, I added
+ // a boolean variable instead. feel free to change this, if desired. -JT
+ private boolean abstractFlag = false;
+
+ @Override
+ public boolean isAbstract()
+ {
+ return abstractFlag;
+ }
+
+ public void setAbstract()
+ {
+ abstractFlag = true;
+ }
+
@Override
public boolean hasModifier(ASModifier modifier)
{
@@ -731,6 +746,10 @@ public abstract class DefinitionBase implements
IDocumentableDefinition, IDefini
// Ignore "virtual" modifier.
return false;
}
+ else if (modifier == ASModifier.ABSTRACT)
+ {
+ return abstractFlag;
+ }
else
{
assert false : "Unknown modifier: " + modifier;
@@ -752,6 +771,8 @@ public abstract class DefinitionBase implements
IDocumentableDefinition, IDefini
result.addModifier(ASModifier.DYNAMIC);
if ((flags & FLAG_NATIVE) != 0)
result.addModifier(ASModifier.NATIVE);
+ if (abstractFlag)
+ result.addModifier(ASModifier.ABSTRACT);
return result;
}
@@ -774,6 +795,9 @@ public abstract class DefinitionBase implements
IDocumentableDefinition, IDefini
else if (modifier == ASModifier.NATIVE)
flags |= FLAG_NATIVE;
+ else if (modifier == ASModifier.ABSTRACT)
+ setAbstract();
+
else
assert false;
}
diff --git
a/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/ASToken.java
b/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/ASToken.java
index 52f2040..fa8b149 100644
---
a/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/ASToken.java
+++
b/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/ASToken.java
@@ -463,6 +463,7 @@ public class ASToken extends TokenBase implements IASToken,
ASTokenTypes
case TOKEN_MODIFIER_NATIVE:
case TOKEN_MODIFIER_OVERRIDE:
case TOKEN_MODIFIER_STATIC:
+ case TOKEN_MODIFIER_ABSTRACT:
return true;
}
return false;
@@ -514,6 +515,7 @@ public class ASToken extends TokenBase implements IASToken,
ASTokenTypes
case TOKEN_MODIFIER_OVERRIDE:
case TOKEN_MODIFIER_STATIC:
case TOKEN_MODIFIER_VIRTUAL:
+ case TOKEN_MODIFIER_ABSTRACT:
case TOKEN_RESERVED_WORD_GET:
case TOKEN_RESERVED_WORD_SET:
case TOKEN_RESERVED_WORD_NAMESPACE:
@@ -655,6 +657,7 @@ public class ASToken extends TokenBase implements IASToken,
ASTokenTypes
case TOKEN_MODIFIER_NATIVE:
case TOKEN_MODIFIER_OVERRIDE:
case TOKEN_MODIFIER_STATIC:
+ case TOKEN_MODIFIER_ABSTRACT:
return true;
}
return false;
@@ -918,6 +921,7 @@ public class ASToken extends TokenBase implements IASToken,
ASTokenTypes
case TOKEN_MODIFIER_NATIVE:
case TOKEN_MODIFIER_OVERRIDE:
case TOKEN_MODIFIER_STATIC:
+ case TOKEN_MODIFIER_ABSTRACT:
return ASTokenKind.MODIFIER;
case HIDDEN_TOKEN_BUILTIN_NS:
case TOKEN_NAMESPACE_ANNOTATION:
diff --git
a/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/BaseASParser.java
b/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/BaseASParser.java
index a8c3d7f..c247c89 100644
---
a/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/BaseASParser.java
+++
b/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/BaseASParser.java
@@ -2329,7 +2329,7 @@ abstract class BaseASParser extends LLkParser implements
IProblemReporter
}
private static final ImmutableSet<String>
CONTEXTUAL_RESERVED_KEYWORD_MODIFIERS =
- ImmutableSet.of("dynamic", "final", "native", "static",
"override");
+ ImmutableSet.of("dynamic", "final", "native", "static",
"override", "abstract");
/**
* Recover from {@link CanNotInsertSemicolonProblem} after an expression
@@ -2854,6 +2854,7 @@ abstract class BaseASParser extends LLkParser implements
IProblemReporter
case TOKEN_MODIFIER_OVERRIDE:
case TOKEN_MODIFIER_STATIC:
case TOKEN_MODIFIER_VIRTUAL:
+ case TOKEN_MODIFIER_ABSTRACT:
return true;
}
}
diff --git
a/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/ConfigProcessor.java
b/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/ConfigProcessor.java
index 1cf7922..af2dd3b 100644
---
a/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/ConfigProcessor.java
+++
b/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/ConfigProcessor.java
@@ -164,6 +164,12 @@ public class ConfigProcessor
// TODO Auto-generated method stub
return false;
}
+
+ @Override
+ public boolean getAllowAbstractClasses() {
+ // TODO Auto-generated method stub
+ return false;
+ }
}
/**
diff --git
a/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/StreamingASTokenizer.java
b/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/StreamingASTokenizer.java
index 2cb8e99..32017a4 100644
---
a/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/StreamingASTokenizer.java
+++
b/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/StreamingASTokenizer.java
@@ -101,6 +101,7 @@ public class StreamingASTokenizer implements ASTokenTypes,
IASTokenizer, Closeab
.put(IASKeywordConstants.OVERRIDE, TOKEN_MODIFIER_OVERRIDE)
.put(IASKeywordConstants.STATIC, TOKEN_MODIFIER_STATIC)
.put(IASKeywordConstants.VIRTUAL, TOKEN_MODIFIER_VIRTUAL)
+ .put(IASKeywordConstants.ABSTRACT, TOKEN_MODIFIER_ABSTRACT)
.put(IASKeywordConstants.SET, TOKEN_RESERVED_WORD_SET)
// Keywords with special token types that affect subsequent blocks
.put(IASKeywordConstants.CATCH, TOKEN_KEYWORD_CATCH)
@@ -917,6 +918,7 @@ public class StreamingASTokenizer implements ASTokenTypes,
IASTokenizer, Closeab
case TOKEN_MODIFIER_OVERRIDE:
case TOKEN_MODIFIER_STATIC:
case TOKEN_MODIFIER_VIRTUAL:
+ case TOKEN_MODIFIER_ABSTRACT:
{
// previous token is either a modifier or a namespace, or
if
// null, assume keyword
@@ -938,6 +940,7 @@ public class StreamingASTokenizer implements ASTokenTypes,
IASTokenizer, Closeab
case TOKEN_MODIFIER_OVERRIDE:
case TOKEN_MODIFIER_STATIC:
case TOKEN_MODIFIER_VIRTUAL:
+ case TOKEN_MODIFIER_ABSTRACT:
case TOKEN_NAMESPACE_ANNOTATION:
case TOKEN_NAMESPACE_NAME:
case HIDDEN_TOKEN_BUILTIN_NS:
@@ -1773,6 +1776,7 @@ public class StreamingASTokenizer implements
ASTokenTypes, IASTokenizer, Closeab
case TOKEN_MODIFIER_OVERRIDE:
case TOKEN_MODIFIER_STATIC:
case TOKEN_MODIFIER_VIRTUAL:
+ case TOKEN_MODIFIER_ABSTRACT:
case TOKEN_KEYWORD_CLASS:
case TOKEN_KEYWORD_INTERFACE:
case TOKEN_NAMESPACE_ANNOTATION:
diff --git
a/compiler/src/main/java/org/apache/royale/compiler/internal/projects/ASCProject.java
b/compiler/src/main/java/org/apache/royale/compiler/internal/projects/ASCProject.java
index d229ca3..de04bb2 100644
---
a/compiler/src/main/java/org/apache/royale/compiler/internal/projects/ASCProject.java
+++
b/compiler/src/main/java/org/apache/royale/compiler/internal/projects/ASCProject.java
@@ -86,4 +86,10 @@ public class ASCProject extends CompilerProject implements
IASCProject
// TODO Auto-generated method stub
return false;
}
+
+ @Override
+ public boolean getAllowAbstractClasses() {
+ // TODO Auto-generated method stub
+ return false;
+ }
}
diff --git
a/compiler/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleProject.java
b/compiler/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleProject.java
index 6a03191..c99f5bb 100644
---
a/compiler/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleProject.java
+++
b/compiler/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleProject.java
@@ -2445,6 +2445,21 @@ public class RoyaleProject extends ASProject implements
IRoyaleProject, ICompile
allowImportAliases = allow;
}
+ private boolean allowAbstractClasses = false;
+
+ /**
+ * Indicates if abstract classes are allowed.
+ */
+ @Override
+ public boolean getAllowAbstractClasses()
+ {
+ return allowAbstractClasses;
+ }
+ public void setAllowAbstractClasses(boolean allow)
+ {
+ allowAbstractClasses = allow;
+ }
+
@Override
public boolean isPlatformRule(ICSSRule rule) {
return true;
diff --git
a/compiler/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleProjectConfigurator.java
b/compiler/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleProjectConfigurator.java
index 409dfd9..cb3a35b 100644
---
a/compiler/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleProjectConfigurator.java
+++
b/compiler/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleProjectConfigurator.java
@@ -264,6 +264,7 @@ public class RoyaleProjectConfigurator extends Configurator
project.setAllowPrivateNameConflicts(configuration.getCompilerAllowPrivateNameConflicts());
project.setAllowImportAliases(configuration.getCompilerAllowImportAliases());
+
project.setAllowAbstractClasses(configuration.getCompilerAllowAbstractClasses());
DataTranscoder.embedClassName =
configuration.getByteArrayEmbedClass();
}
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 0e009fe..c142116 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
@@ -2089,6 +2089,13 @@ public class MethodBodySemanticChecker
{
ClassDefinition class_def = (ClassDefinition)def;
+ if ( project.getAllowAbstractClasses() && class_def.isAbstract() )
+ {
+ addProblem(new AbstractClassCannotBeInstantiatedProblem(
+ roundUpUsualSuspects(class_binding, iNode)
+ ));
+ }
+
IFunctionDefinition ctor = class_def.getConstructor();
if ( ctor instanceof FunctionDefinition )
@@ -2456,6 +2463,10 @@ public class MethodBodySemanticChecker
{
currentScope.addProblem(new
StaticOutsideClassProblem(site));
}
+ else if( modifier == ASModifier.ABSTRACT )
+ {
+ currentScope.addProblem(new
AbstractOutsideClassProblem(site));
+ }
}
}
diff --git
a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/BaseDefinitionNode.java
b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/BaseDefinitionNode.java
index a1d9609..c45def6 100644
---
a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/BaseDefinitionNode.java
+++
b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/BaseDefinitionNode.java
@@ -401,6 +401,8 @@ public abstract class BaseDefinitionNode extends TreeNode
implements IDocumentab
db.setOverride();
if (hasModifier(ASModifier.STATIC))
db.setStatic();
+ if (hasModifier(ASModifier.ABSTRACT))
+ db.setAbstract();
}
protected void fillInMetadata(DefinitionBase definition)
diff --git
a/compiler/src/main/java/org/apache/royale/compiler/problems/AbstractClassCannotBeInstantiatedProblem.java
b/compiler/src/main/java/org/apache/royale/compiler/problems/AbstractClassCannotBeInstantiatedProblem.java
new file mode 100644
index 0000000..e9d34d1
--- /dev/null
+++
b/compiler/src/main/java/org/apache/royale/compiler/problems/AbstractClassCannotBeInstantiatedProblem.java
@@ -0,0 +1,42 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.royale.compiler.problems;
+
+import org.apache.royale.compiler.tree.as.IASNode;
+
+/**
+ * Semantics diagnostic emitted when the method body
+ * semantic checker detects an attempt to instantiate an abstract class.
+ */
+public final class AbstractClassCannotBeInstantiatedProblem extends
SemanticProblem
+{
+ public static final String DESCRIPTION =
+ "Abstract classes cannot be instantiated with the ${NEW} operator.";
+
+ public static final int errorCode = 1156;
+
+ public AbstractClassCannotBeInstantiatedProblem(IASNode site)
+ {
+ super(site);
+ }
+
+ // Prevent these from being localized.
+ public final String NEW = "new";
+}
diff --git
a/compiler/src/main/java/org/apache/royale/compiler/problems/AbstractOutsideClassProblem.java
b/compiler/src/main/java/org/apache/royale/compiler/problems/AbstractOutsideClassProblem.java
new file mode 100644
index 0000000..4fea9f1
--- /dev/null
+++
b/compiler/src/main/java/org/apache/royale/compiler/problems/AbstractOutsideClassProblem.java
@@ -0,0 +1,43 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.royale.compiler.problems;
+
+import org.apache.royale.compiler.tree.as.IASNode;
+
+/**
+ * Problem generated when 'abstract' is used outside of a class
+ */
+public final class AbstractOutsideClassProblem extends CodegenProblem
+{
+ // TODO ErrorMSG: not specific to methods
+ public static final String DESCRIPTION =
+ "The ${ABSTRACT} attribute may be used only ${CLASS} property
definitions.";
+
+ public static final int errorCode = 1011;
+
+ public AbstractOutsideClassProblem(IASNode site)
+ {
+ super(site);
+ }
+
+ // Prevent these from being localized.
+ public final String ABSTRACT = "abstract";
+ public final String CLASS = "class";
+}