Great addition! Love it! Suggestion: When you add features, it’s a good idea to add a Github issue to make it easier to track changes for release notes.
Thanks, Harbs > On Jan 24, 2019, at 12:58 AM, [email protected] wrote: > > 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"; > +} >
