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";
+}

Reply via email to