private bool CheckGrammarModifiers()

in Public/Src/FrontEnd/TypeScript.Net/TypeScript.Net/TypeChecking/Checker.cs [22612:22912]


        private bool CheckGrammarModifiers(INode node)
        {
            switch (node.Kind)
            {
                case SyntaxKind.GetAccessor:
                case SyntaxKind.SetAccessor:
                case SyntaxKind.Constructor:
                case SyntaxKind.PropertyDeclaration:
                case SyntaxKind.PropertySignature:
                case SyntaxKind.MethodDeclaration:
                case SyntaxKind.MethodSignature:
                case SyntaxKind.IndexSignature:
                case SyntaxKind.ModuleDeclaration:
                case SyntaxKind.ImportDeclaration:
                case SyntaxKind.ImportEqualsDeclaration:
                case SyntaxKind.ExportDeclaration:
                case SyntaxKind.ExportAssignment:
                case SyntaxKind.Parameter:
                    break;

                case SyntaxKind.FunctionDeclaration:
                    if (node.Modifiers != null && (node.Modifiers.Count > 1 || (node.Modifiers.Count > 0 && node.Modifiers[0].Kind != SyntaxKind.AsyncKeyword)) &&
                        node.Parent.Kind != SyntaxKind.ModuleBlock && node.Parent.Kind != SyntaxKind.SourceFile)
                    {
                        return GrammarErrorOnFirstToken(node, Errors.Modifiers_cannot_appear_here);
                    }

                    break;

                case SyntaxKind.ClassDeclaration:
                case SyntaxKind.InterfaceDeclaration:
                case SyntaxKind.VariableStatement:
                case SyntaxKind.TypeAliasDeclaration:
                    if (node.Modifiers != null && node.Parent.Kind != SyntaxKind.ModuleBlock && node.Parent.Kind != SyntaxKind.SourceFile)
                    {
                        return GrammarErrorOnFirstToken(node, Errors.Modifiers_cannot_appear_here);
                    }

                    break;

                case SyntaxKind.EnumDeclaration:
                    if (node.Modifiers != null && (node.Modifiers.Count > 1 || (node.Modifiers.Count > 0 && node.Modifiers[0].Kind != SyntaxKind.ConstKeyword)) &&
                        node.Parent.Kind != SyntaxKind.ModuleBlock && node.Parent.Kind != SyntaxKind.SourceFile)
                    {
                        return GrammarErrorOnFirstToken(node, Errors.Modifiers_cannot_appear_here);
                    }

                    break;

                default:
                    return false;
            }

            if (node.Modifiers == null)
            {
                // TODO: original implementation returns nothing.
                // Potentially, it means that this function returns 3 different states: true, false, undefined
                return false;
            }

            INode lastStatic = null, lastPrivate = null, lastProtected = null, lastDeclare = null, lastAsync = null;
            NodeFlags flags = NodeFlags.None;

            foreach (var modifier in node.Modifiers)
            {
                switch (modifier.Kind)
                {
                    case SyntaxKind.ConstKeyword:
                        if (node.Kind != SyntaxKind.EnumDeclaration && node.Parent.Kind == SyntaxKind.ClassDeclaration)
                        {
                            return GrammarErrorOnNode(node, Errors.A_class_member_cannot_have_the_0_keyword, TokenToString(SyntaxKind.ConstKeyword));
                        }

                        break;

                    case SyntaxKind.PublicKeyword:
                    case SyntaxKind.ProtectedKeyword:
                    case SyntaxKind.PrivateKeyword:
                        string text = null;
                        if (modifier.Kind == SyntaxKind.PublicKeyword)
                        {
                            text = "public";
                        }
                        else if (modifier.Kind == SyntaxKind.ProtectedKeyword)
                        {
                            text = "protected";
                            lastProtected = modifier;
                        }
                        else
                        {
                            text = "private";
                            lastPrivate = modifier;
                        }

                        if ((flags & NodeFlags.AccessibilityModifier) != NodeFlags.None)
                        {
                            return GrammarErrorOnNode(modifier, Errors.Accessibility_modifier_already_seen);
                        }
                        else if ((flags & NodeFlags.Static) != NodeFlags.None)
                        {
                            return GrammarErrorOnNode(modifier, Errors.Modifier0_must_precede_modifier1, text, "static");
                        }
                        else if ((flags & NodeFlags.Async) != NodeFlags.None)
                        {
                            return GrammarErrorOnNode(modifier, Errors.Modifier0_must_precede_modifier1, text, "async");
                        }
                        else if (node.Parent.Kind == SyntaxKind.ModuleBlock || node.Parent.Kind == SyntaxKind.SourceFile)
                        {
                            return GrammarErrorOnNode(modifier, Errors.Modifier0_cannot_appear_on_a_module_element, text);
                        }
                        else if ((flags & NodeFlags.Abstract) != NodeFlags.None)
                        {
                            if (modifier.Kind == SyntaxKind.PrivateKeyword)
                            {
                                return GrammarErrorOnNode(modifier, Errors.Zero_modifier_cannot_be_used_with_1_modifier, text, "abstract");
                            }
                            else
                            {
                                return GrammarErrorOnNode(modifier, Errors.Modifier0_must_precede_modifier1, text, "abstract");
                            }
                        }

                        flags |= modifier.Kind.ModifierToFlag();
                        break;

                    case SyntaxKind.StaticKeyword:
                        if ((flags & NodeFlags.Static) != NodeFlags.None)
                        {
                            return GrammarErrorOnNode(modifier, Errors.Modifier0_already_seen, "static");
                        }
                        else if ((flags & NodeFlags.Async) != NodeFlags.None)
                        {
                            return GrammarErrorOnNode(modifier, Errors.Modifier0_must_precede_modifier1, "static", "async");
                        }
                        else if (node.Parent.Kind == SyntaxKind.ModuleBlock || node.Parent.Kind == SyntaxKind.SourceFile)
                        {
                            return GrammarErrorOnNode(modifier, Errors.Modifier0_cannot_appear_on_a_module_element, "static");
                        }
                        else if (node.Kind == SyntaxKind.Parameter)
                        {
                            return GrammarErrorOnNode(modifier, Errors.Zero_modifier_cannot_appear_on_a_parameter, "static");
                        }
                        else if ((flags & NodeFlags.Abstract) != NodeFlags.None)
                        {
                            return GrammarErrorOnNode(modifier, Errors.Zero_modifier_cannot_be_used_with_1_modifier, "static", "abstract");
                        }

                        flags |= NodeFlags.Static;
                        lastStatic = modifier;
                        break;

                    case SyntaxKind.ExportKeyword:
                        if ((flags & NodeFlags.Export) != NodeFlags.None)
                        {
                            return GrammarErrorOnNode(modifier, Errors.Modifier0_already_seen, "export");
                        }
                        else if ((flags & NodeFlags.Ambient) != NodeFlags.None)
                        {
                            return GrammarErrorOnNode(modifier, Errors.Modifier0_must_precede_modifier1, "export", "declare");
                        }
                        else if ((flags & NodeFlags.Abstract) != NodeFlags.None)
                        {
                            return GrammarErrorOnNode(modifier, Errors.Modifier0_must_precede_modifier1, "export", "abstract");
                        }
                        else if ((flags & NodeFlags.Async) != NodeFlags.None)
                        {
                            return GrammarErrorOnNode(modifier, Errors.Modifier0_must_precede_modifier1, "export", "async");
                        }
                        else if (node.Parent.Kind == SyntaxKind.ClassDeclaration)
                        {
                            return GrammarErrorOnNode(modifier, Errors.Modifier0_cannot_appear_on_a_class_element, "export");
                        }
                        else if (node.Kind == SyntaxKind.Parameter)
                        {
                            return GrammarErrorOnNode(modifier, Errors.Zero_modifier_cannot_appear_on_a_parameter, "export");
                        }

                        flags |= NodeFlags.Export;
                        break;

                    case SyntaxKind.DeclareKeyword:
                        if ((flags & NodeFlags.Ambient) != NodeFlags.None)
                        {
                            return GrammarErrorOnNode(modifier, Errors.Modifier0_already_seen, "declare");
                        }
                        else if ((flags & NodeFlags.Async) != NodeFlags.None)
                        {
                            return GrammarErrorOnNode(modifier, Errors.Modifier0_cannot_be_used_in_an_ambient_context, "async");
                        }
                        else if (node.Parent.Kind == SyntaxKind.ClassDeclaration)
                        {
                            return GrammarErrorOnNode(modifier, Errors.Modifier0_cannot_appear_on_a_class_element, "declare");
                        }
                        else if (node.Kind == SyntaxKind.Parameter)
                        {
                            return GrammarErrorOnNode(modifier, Errors.Zero_modifier_cannot_appear_on_a_parameter, "declare");
                        }
                        else if (IsInAmbientContext(node.Parent) && node.Parent.Kind == SyntaxKind.ModuleBlock)
                        {
                            return GrammarErrorOnNode(modifier, Errors.A_declare_modifier_cannot_be_used_in_an_already_ambient_context);
                        }

                        flags |= NodeFlags.Ambient;
                        lastDeclare = modifier;
                        break;

                    case SyntaxKind.AbstractKeyword:
                        if ((flags & NodeFlags.Abstract) != NodeFlags.None)
                        {
                            return GrammarErrorOnNode(modifier, Errors.Modifier0_already_seen, "abstract");
                        }

                        if (node.Kind != SyntaxKind.ClassDeclaration)
                        {
                            if (node.Kind != SyntaxKind.MethodDeclaration)
                            {
                                return GrammarErrorOnNode(modifier, Errors.Abstract_modifier_can_only_appear_on_a_class_or_method_declaration);
                            }

                            if (!(node.Parent.Kind == SyntaxKind.ClassDeclaration && (node.Parent.Flags & NodeFlags.Abstract) != NodeFlags.None))
                            {
                                return GrammarErrorOnNode(modifier, Errors.Abstract_methods_can_only_appear_within_an_abstract_class);
                            }

                            if ((flags & NodeFlags.Static) != NodeFlags.None)
                            {
                                return GrammarErrorOnNode(modifier, Errors.Zero_modifier_cannot_be_used_with_1_modifier, "static", "abstract");
                            }

                            if ((flags & NodeFlags.Private) != NodeFlags.None)
                            {
                                return GrammarErrorOnNode(modifier, Errors.Zero_modifier_cannot_be_used_with_1_modifier, "private", "abstract");
                            }
                        }

                        flags |= NodeFlags.Abstract;
                        break;

                    case SyntaxKind.AsyncKeyword:
                        if ((flags & NodeFlags.Async) != NodeFlags.None)
                        {
                            return GrammarErrorOnNode(modifier, Errors.Modifier0_already_seen, "async");
                        }
                        else if ((flags & NodeFlags.Ambient) != NodeFlags.None || IsInAmbientContext(node.Parent))
                        {
                            return GrammarErrorOnNode(modifier, Errors.Modifier0_cannot_be_used_in_an_ambient_context, "async");
                        }
                        else if (node.Kind == SyntaxKind.Parameter)
                        {
                            return GrammarErrorOnNode(modifier, Errors.Zero_modifier_cannot_appear_on_a_parameter, "async");
                        }

                        flags |= NodeFlags.Async;
                        lastAsync = modifier;
                        break;
                }
            }

            if (node.Kind == SyntaxKind.Constructor)
            {
                if ((flags & NodeFlags.Static) != NodeFlags.None)
                {
                    return GrammarErrorOnNode(lastStatic, Errors.Zero_modifier_cannot_appear_on_a_constructor_declaration, "static");
                }

                if ((flags & NodeFlags.Abstract) != NodeFlags.None)
                {
                    return GrammarErrorOnNode(lastStatic, Errors.Zero_modifier_cannot_appear_on_a_constructor_declaration, "abstract");
                }
                else if ((flags & NodeFlags.Protected) != NodeFlags.None)
                {
                    return GrammarErrorOnNode(lastProtected, Errors.Zero_modifier_cannot_appear_on_a_constructor_declaration, "protected");
                }
                else if ((flags & NodeFlags.Private) != NodeFlags.None)
                {
                    return GrammarErrorOnNode(lastPrivate, Errors.Zero_modifier_cannot_appear_on_a_constructor_declaration, "private");
                }
                else if ((flags & NodeFlags.Async) != NodeFlags.None)
                {
                    return GrammarErrorOnNode(lastAsync, Errors.Zero_modifier_cannot_appear_on_a_constructor_declaration, "async");
                }

                // TODO: this was just 'return'. It means that this function potentially could have 3 different return values!
                return false;
            }
            else if ((node.Kind == SyntaxKind.ImportDeclaration || node.Kind == SyntaxKind.ImportEqualsDeclaration) && (flags & NodeFlags.Ambient) != NodeFlags.None)
            {
                return GrammarErrorOnNode(lastDeclare, Errors.A_0_modifier_cannot_be_used_with_an_import_declaration, "declare");
            }
            else if (node.Kind == SyntaxKind.Parameter && (flags & NodeFlags.AccessibilityModifier) != NodeFlags.None && IsBindingPattern(node.Cast<IParameterDeclaration>().Name) != null)
            {
                return GrammarErrorOnNode(node, Errors.A_parameter_property_may_not_be_a_binding_pattern);
            }

            if ((flags & NodeFlags.Async) != NodeFlags.None)
            {
                return CheckGrammarAsyncModifier(node, lastAsync);
            }

            return false;
        }