A class filled with methods for checking whether a node has the correct LNode.Name and structure. For example, IsPropertyDefinition(node) checks whether node meets the requirements for being a property definition, such as having a Name equal to #property, and having name and return value that are complex identifiers.
This class also has useful helper functions, such as KeyNameComponentOf(LNode).
Example #1
0
        private bool PrintBracedBlockOrStmt(LNode stmt, Ambiguity flags, NewlineOpt beforeBrace = NewlineOpt.BeforeExecutableBrace)
        {
            var name = stmt.Name;

            if (name == S.Braces && !HasPAttrs(stmt) && HasSimpleHeadWPA(stmt))
            {
                PrintBracedBlock(stmt, beforeBrace);
                return(true);
            }
            // Detect "else if (...)", and suppress newline/indent between "else" and "if".
            if (name == S.If && (flags & Ambiguity.ElseClause) != 0)
            {
                using (With(stmt))
                    if (EcsValidators.OtherBlockStmtType(_n, Pedantics) == S.If)
                    {
                        PrintStmt(flags & (Ambiguity.FinalStmt | Ambiguity.ElseClause));
                        return(false);
                    }
            }
            using (Indented)
            {
                Newline(NewlineOpt.BeforeSingleSubstmt);
                PrintStmt(stmt, flags & (Ambiguity.FinalStmt | Ambiguity.NoIfWithoutElse));
                return(false);
            }
        }
Example #2
0
        public SPResult AutoPrintEvent(Ambiguity flags)
        {
            var eventType = EcsValidators.EventDefinitionType(_n, Pedantics);

            if (eventType == EcsValidators.EventDef.Invalid)
            {
                return(SPResult.Fail);
            }

            var ifClause = PrintTypeAndName(false, false, AttrStyle.IsDefinition, "event ");

            if (eventType == EcsValidators.EventDef.WithBody)
            {
                return(AutoPrintBodyOfMethodOrProperty(_n.Args[2, null], ifClause));
            }
            else               // EcsValidators.EventDef.List
            {
                for (int i = 2, c = _n.ArgCount; i < c; i++)
                {
                    WriteThenSpace(',', SpaceOpt.AfterComma);
                    PrintExpr(_n.Args[i], ContinueExpr);
                }
                return(SPResult.NeedSemicolon);
            }
        }
Example #3
0
        public SPResult AutoPrintTwoArgBlockStmt()
        {
            // S.Do, S.Fixed, S.Lock, S.Switch, S.UsingStmt, S.While
            var type = EcsValidators.TwoArgBlockStmtType(_n, Pedantics);

            if (type == null)
            {
                return(SPResult.Fail);
            }

            var allowAttrs = (_name == S.UsingStmt ? AttrStyle.AllowKeywordAttrs : AttrStyle.AllowWordAttrs);

            G.Verify(0 == PrintAttrs(allowAttrs));

            if (type == S.DoWhile)
            {
                _out.Write("do", true);
                bool braces = PrintBracedBlockOrStmt(_n.Args[0], NewlineOpt.BeforeSimpleStmtBrace);

                // Print newline in front of "while" if appropriate and avoid printing
                // "while (\ncondition)" when condition has an explicit newline; use
                // "\nwhile (condition)" instead.
                LNode cond = _n.Args[1];
                LNode condWithoutNewline = cond.WithoutAttrNamed(S.TriviaNewline);
                if (cond != condWithoutNewline)
                {
                    _out.Newline();
                }
                else if (!Newline(braces ? NewlineOpt.BeforeExecutableBrace : NewlineOpt.Default))
                {
                    Space(SpaceOpt.Default);
                }

                _out.Write("while", true);
                PrintWithinParens(ParenFor.KeywordCall, condWithoutNewline);
                return(SPResult.NeedSemicolon);
            }
            else
            {
                WriteOperatorName(_name);
                Ambiguity argFlags = 0;
                if (_name == S.Fixed)
                {
                    argFlags |= Ambiguity.AllowPointer;
                }
                PrintWithinParens(ParenFor.KeywordCall, _n.Args[0], argFlags);
                PrintBracedBlockOrStmt(_n.Args[1]);
                return(SPResult.NeedSuffixTrivia);
            }
        }
Example #4
0
        public SPResult AutoPrintSimpleStmt(Ambiguity flags)
        {
            // S.Break, S.Continue, S.Goto, S.GotoCase, S.Return, S.Throw, S.Import
            if (!EcsValidators.IsSimpleExecutableKeywordStmt(_n, Pedantics))
            {
                return(SPResult.Fail);
            }

            var   name        = _n.Name;
            LNode usingStatic = name == S.Import && _n.AttrCount > 0 && _n.Attrs.Last.IsIdNamed(S.Static) ? _n.Attrs.Last : null;
            var   allowAttrs  = (name == S.Import ? AttrStyle.AllowKeywordAttrs : AttrStyle.AllowWordAttrs);

            G.Verify(0 == PrintAttrs(StartStmt, allowAttrs, flags, usingStatic));

            if (name == S.GotoCase)
            {
                _out.Write("goto case", true);
                if (_n.ArgCount == 1 && _n.Args[0].IsIdNamed(S.Default))
                {
                    _out.Write("default", true);
                    return(SPResult.NeedSemicolon);
                }
            }
            else if (name == S.Import)
            {
                _out.Write(usingStatic != null ? "using static" : "using", true);
            }
            else
            {
                WriteOperatorName(name);
            }

            int i = 0;

            foreach (var arg in _n.Args)
            {
                if (i++ == 0)
                {
                    Space(SpaceOpt.Default);
                }
                else
                {
                    WriteThenSpace(',', SpaceOpt.AfterComma);
                }
                PrintExpr(arg, StartExpr);
            }
            return(SPResult.NeedSemicolon);
        }
Example #5
0
        private bool AutoPrintForwardedProperty()
        {
            if (!EcsValidators.IsForwardedProperty(_n, Pedantics))
            {
                return(false);
            }

            G.Verify(0 == PrintAttrs(StartStmt, AttrStyle.AllowKeywordAttrs, Ambiguity.NoParenthesis));
            PrintSimpleIdent(_n.Name, 0);
            Space(SpaceOpt.BeforeForwardArrow);
            _out.Write("==>", true);
            PrefixSpace(EP.Forward);
            PrintExpr(_n.Args[0].Args[0], EP.Forward.RightContext(StartExpr));
            _out.Write(";", true);
            return(true);
        }
Example #6
0
        public SPResult AutoPrintSimpleStmt()
        {
            // S.Break, S.Continue, S.Goto, S.GotoCase, S.Return, S.Throw, S.Import
            if (!EcsValidators.IsSimpleExecutableKeywordStmt(_n, Pedantics))
            {
                return(SPResult.Fail);
            }

            LNode usingStatic = _name == S.Import && _n.AttrCount > 0 && _n.Attrs.Last.IsIdNamed(S.Static) ? _n.Attrs.Last : null;
            var   allowAttrs  = (_name == S.Import ? AttrStyle.AllowKeywordAttrs : AttrStyle.AllowWordAttrs);

            G.Verify(0 == PrintAttrs(allowAttrs, usingStatic));

            PrintReturnThrowEtc(usingStatic != null ? _using_static : _name, _n.Args[0, null]);

            return(SPResult.NeedSemicolon);
        }
        public SPResult AutoPrintLabelStmt()
        {
            if (!EcsValidators.IsLabelStmt(_n, Pedantics))
            {
                return(SPResult.Fail);
            }

            _out.Indent(PrinterIndentHint.Label);

            G.Verify(0 == PrintAttrs(AttrStyle.AllowWordAttrs));

            if (_name == S.Label)
            {
                if (_n.Args[0].Name == S.Default)
                {
                    _out.Write("default");
                }
                else
                {
                    PrintExpr(_n.Args[0], StartStmt);
                }
            }
            else if (_name == S.Case)
            {
                _out.Write("case");
                _out.Space();
                bool first = true;
                foreach (var arg in _n.Args)
                {
                    if (first)
                    {
                        first = false;
                    }
                    else
                    {
                        WriteThenSpace(',', SpaceOpt.AfterComma);
                    }
                    PrintExpr(arg, StartExpr, Ambiguity.AllowUnassignedVarDecl);
                }
            }
            _out.Write(':');

            _out.Dedent(PrinterIndentHint.Label);
            return(SPResult.NeedSuffixTrivia);
        }
Example #8
0
        public SPResult AutoPrintLabelStmt(Ambiguity flags)
        {
            if (!EcsValidators.IsLabelStmt(_n, Pedantics))
            {
                return(SPResult.Fail);
            }

            _out.BeginLabel();

            G.Verify(0 == PrintAttrs(StartStmt, AttrStyle.AllowWordAttrs, flags));

            if (_n.Name == S.Label)
            {
                if (_n.Args[0].Name == S.Default)
                {
                    _out.Write("default", true);
                }
                else
                {
                    PrintExpr(_n.Args[0], StartStmt);
                }
            }
            else if (_n.Name == S.Case)
            {
                _out.Write("case", true);
                _out.Space();
                bool first = true;
                foreach (var arg in _n.Args)
                {
                    if (first)
                    {
                        first = false;
                    }
                    else
                    {
                        WriteThenSpace(',', SpaceOpt.AfterComma);
                    }
                    PrintExpr(arg, StartStmt);
                }
            }
            _out.Write(':', true);
            return(SPResult.NeedSuffixTrivia);
        }
Example #9
0
 protected override void StartToken(char nextCh)
 {
     if (_newlinePending)
     {
         Newline();
     }
     if ((EcsValidators.IsIdentContChar(_lastCh) || _lastCh == '#') &&
         (EcsValidators.IsIdentContChar(nextCh) || nextCh == '@'))
     {
         _out.Write(' ');
     }
     else if ((_lastCh == '#' && nextCh == '#') || (_lastCh == '+' && nextCh == '+') ||
              (_lastCh == '-' && nextCh == '-') ||
              (_lastCh == '.' && (nextCh == '.' || char.IsDigit(nextCh))) ||
              (_lastCh == '/' && nextCh == '*'))
     {
         _out.Write(' ');
     }
 }
Example #10
0
        public SPResult AutoPrintProperty(Ambiguity flags)
        {
            // For S.Property (#property), _n typically looks like this:
            // #property(int, Foo, @``, {
            //     get({ return _foo; });
            //     set({ _foo = value; });
            // });
            if (!EcsValidators.IsPropertyDefinition(_n, Pedantics))
            {
                return(SPResult.Fail);
            }

            var ifClause = PrintTypeAndName(false);

            PrintWhereClauses(_n.Args[1]);

            // Detect if property has argument list (T this[...] {...})
            if (_n.Args[2].Calls(S.AltList))
            {
                // Do what PrintArgList does, only with [] instead of ()
                Space(SpaceOpt.BeforeMethodDeclArgList);
                _out.Write('[', true);
                WriteInnerSpace(ParenFor.MethodDecl);
                PrintArgs(_n.Args[2].Args, flags | Ambiguity.AllowUnassignedVarDecl, false);
                WriteInnerSpace(ParenFor.MethodDecl);
                _out.Write(']', true);
            }

            var spr = AutoPrintBodyOfMethodOrProperty(_n.Args[3, null], ifClause);

            if (_n.Args.Count >= 5)
            {
                var initializer = _n.Args[4];
                if (!initializer.IsIdNamed(S.Missing))
                {
                    PrintInfixWithSpace(S.Assign, EcsPrecedence.Assign, 0);
                    PrintExpr(initializer, StartExpr, flags);
                    return(SPResult.NeedSemicolon);
                }
            }
            return(spr);
        }
Example #11
0
        public SPResult AutoPrintTwoArgBlockStmt(Ambiguity flags)
        {
            // S.Do, S.Fixed, S.Lock, S.Switch, S.UsingStmt, S.While
            var type = EcsValidators.TwoArgBlockStmtType(_n, Pedantics);

            if (type == null)
            {
                return(SPResult.Fail);
            }

            var allowAttrs = (_n.Name == S.UsingStmt ? AttrStyle.AllowKeywordAttrs : AttrStyle.AllowWordAttrs);

            G.Verify(0 == PrintAttrs(StartStmt, allowAttrs, flags));

            if (type == S.DoWhile)
            {
                _out.Write("do", true);
                bool braces = PrintBracedBlockOrStmt(_n.Args[0], flags, NewlineOpt.BeforeSimpleStmtBrace);
                if (!Newline(braces ? NewlineOpt.BeforeExecutableBrace : NewlineOpt.Default))
                {
                    Space(SpaceOpt.Default);
                }
                _out.Write("while", true);
                PrintWithinParens(ParenFor.KeywordCall, _n.Args[1]);
                return(SPResult.NeedSemicolon);
            }
            else
            {
                WriteOperatorName(_n.Name);
                Ambiguity argFlags = 0;
                if (_n.Name == S.Fixed)
                {
                    argFlags |= Ambiguity.AllowPointer;
                }
                PrintWithinParens(ParenFor.KeywordCall, _n.Args[0], argFlags);
                PrintBracedBlockOrStmt(_n.Args[1], flags);
                return(SPResult.NeedSuffixTrivia);
            }
        }
Example #12
0
        public SPResult AutoPrintEvent()
        {
            LNode type, name, body;

            if (!EcsValidators.IsEventDefinition(_n, out type, out name, out body, Pedantics))
            {
                return(SPResult.Fail);
            }

            G.Verify(0 == PrintAttrs(AttrStyle.IsDefinition));
            _out.Write("event ", true);
            PrintType(type, ContinueExpr, Ambiguity.AllowPointer);
            _out.Space();

            if (name.Calls(S.AltList))
            {
                bool first = true;
                foreach (var name2 in name.Args)
                {
                    if (first)
                    {
                        first = false;
                    }
                    else
                    {
                        WriteThenSpace(',', SpaceOpt.AfterComma);
                    }
                    PrintExpr(name2, ContinueExpr);
                }
            }
            else
            {
                PrintExpr(name, ContinueExpr);
            }

            return(AutoPrintBodyOfMethodOrProperty(body));
        }
Example #13
0
        protected override void OnNodeChanged(char nextCh)
        {
            var _lastCh = IsAtStartOfLine ? '\n' : LastCharWritten;

            if ((EcsValidators.IsIdentContChar(_lastCh) || _lastCh == '#') &&
                (EcsValidators.IsIdentContChar(nextCh) || nextCh == '@'))
            {
                Write(' ');
            }
            else if ((_lastCh == '#' && nextCh == '#') || (_lastCh == '+' && nextCh == '+') ||
                     (_lastCh == '-' && nextCh == '-') ||
                     (_lastCh == '.' && (nextCh == '.' || char.IsDigit(nextCh))) ||
                     (_lastCh == '/' && nextCh == '*'))
            {
                Write(' ');
            }
            // EC# allows operator punctuation in identifiers after @' (or @0 to @9),
            // e.g. @'Foo= is an identifier. So we must not print an expression like
            // @'Foo . Bar as @'Foo.Bar which would be a single identifier.
            else if (_punctuationIdentifierEndIndex == StringBuilder.Length && _lastCh != '`' && nextCh > ' ' && nextCh != '(' && nextCh != '[' && nextCh != ')' && nextCh != ']' && nextCh != ';' && nextCh != ',')
            {
                Write(' ');
            }
        }
Example #14
0
        // Prints a child statement that could be a braced block, or not
        private bool PrintBracedBlockOrStmt(LNode child, NewlineOpt beforeBrace = NewlineOpt.BeforeExecutableBrace)
        {
            var name = child.Name;

            if (name == S.Braces && !HasPAttrs(child) && HasSimpleHeadWPA(child))
            {
                PrintBracedBlock(child, beforeBrace);
                return(true);
            }
            // Detect "else if (...)", and suppress newline/indent between "else" and "if".
            if (name == S.If && Flagged(Ambiguity.ElseClause))
            {
                if (EcsValidators.OtherBlockStmtType(_n, Pedantics) == S.If)
                {
                    PrintStmt(child, _flags & (Ambiguity.FinalStmt | Ambiguity.ElseClause | Ambiguity.OneLiner));
                    return(false);
                }
            }
            using (Indented)
            {
                PrintStmt(child, _flags & (Ambiguity.FinalStmt | Ambiguity.NoIfWithoutElse | Ambiguity.OneLiner) | Ambiguity.NewlineBeforeChildStmt);
                return(false);
            }
        }
Example #15
0
        public SPResult AutoPrintOtherBlockStmt(Ambiguity flags)
        {
            // S.If, S.For, S.ForEach, S.Checked, S.Unchecked, S.Try
            var type = EcsValidators.OtherBlockStmtType(_n, Pedantics);

            if (type == null)
            {
                return(SPResult.Fail);
            }

            if (type == S.If)
            {
                var  @else          = _n.Args[2, null];
                bool needCloseBrace = false;
                if (@else == null && (flags & Ambiguity.NoIfWithoutElse) != 0)
                {
                    if (AllowExtraBraceForIfElseAmbig)
                    {
                        _out.Write('{', true);
                        needCloseBrace = true;
                    }
                    else
                    {
                        return(SPResult.Fail);
                    }
                }

                // Note: the "if" statement in particular cannot have "word" attributes
                //       because they would create ambiguity with property declarations
                G.Verify(0 == PrintAttrs(StartStmt, AttrStyle.AllowKeywordAttrs, flags));

                _out.Write("if", true);
                PrintWithinParens(ParenFor.KeywordCall, _n.Args[0]);

                var thenFlags = flags & ~(Ambiguity.ElseClause);
                if (@else != null)
                {
                    thenFlags |= Ambiguity.NoIfWithoutElse;
                }
                bool braces = PrintBracedBlockOrStmt(_n.Args[1], thenFlags);

                if (@else != null)
                {
                    if (!Newline(braces ? NewlineOpt.BeforeExecutableBrace : NewlineOpt.Default))
                    {
                        Space(SpaceOpt.Default);
                    }
                    _out.Write("else", true);
                    PrintBracedBlockOrStmt(@else, flags | Ambiguity.ElseClause);
                }

                if (needCloseBrace)
                {
                    _out.Write('}', true);
                }
                return(SPResult.NeedSuffixTrivia);
            }

            G.Verify(0 == PrintAttrs(StartStmt, AttrStyle.AllowWordAttrs, flags));

            if (type == S.For)
            {
                _out.Write("for", true);
                PrintArgList(_n.Args.First(3), ParenFor.KeywordCall, flags, true, ';');
                PrintBracedBlockOrStmt(_n.Args[3], flags);
            }
            else if (type == S.ForEach)
            {
                _out.Write("foreach", true);
                WriteOpenParen(ParenFor.KeywordCall);
                PrintExpr(_n.Args[0], EP.Equals.LeftContext(StartStmt), Ambiguity.AllowUnassignedVarDecl | Ambiguity.ForEachInitializer);
                _out.Space();
                _out.Write("in", true);
                _out.Space();
                PrintExpr(_n.Args[1], ContinueExpr, flags);
                WriteCloseParen(ParenFor.KeywordCall);

                PrintBracedBlockOrStmt(_n.Args[2], flags);
            }
            else if (type == S.Try)
            {
                _out.Write("try", true);
                bool braces = PrintBracedBlockOrStmt(_n.Args[0], flags, NewlineOpt.BeforeSimpleStmtBrace);
                for (int i = 1, c = _n.ArgCount; i < c; i++)
                {
                    if (!Newline(braces ? NewlineOpt.BeforeExecutableBrace : NewlineOpt.Default))
                    {
                        Space(SpaceOpt.Default);
                    }
                    var   clause = _n.Args[i];
                    LNode first = clause.Args[0], second = clause.Args[1, null];

                    WriteOperatorName(clause.Name);
                    if (clause.Name == S.Finally)
                    {
                        braces = PrintBracedBlockOrStmt(clause.Args[0], flags);
                    }
                    else                       // catch
                    {
                        var eVar = clause.Args[0];
                        if (!eVar.IsIdNamed(S.Missing))
                        {
                            PrintWithinParens(ParenFor.KeywordCall, eVar, Ambiguity.AllowUnassignedVarDecl);
                        }
                        var when = clause.Args[1];
                        if (!when.IsIdNamed(S.Missing))
                        {
                            Space(SpaceOpt.Default);
                            _out.Write("when", true);
                            PrintWithinParens(ParenFor.KeywordCall, when);
                        }
                        braces = PrintBracedBlockOrStmt(clause.Args[2], flags);
                    }
                }
            }
            else if (type == S.Checked)             // includes S.Unchecked
            {
                WriteOperatorName(_n.Name);
                PrintBracedBlockOrStmt(_n.Args[0], flags, NewlineOpt.BeforeSimpleStmtBrace);
            }

            return(SPResult.NeedSuffixTrivia);
        }
Example #16
0
        public SPResult AutoPrintMethodDefinition(Ambiguity flags)
        {
            // S.Fn, S.Delegate: #fn(#int32, Square, #(int x), { return x * x; });
            if (EcsValidators.MethodDefinitionKind(_n, true, Pedantics) == null)
            {
                return(SPResult.Fail);
            }

            LNode retType = _n.Args[0], name = _n.Args[1];
            LNode args          = _n.Args[2];
            LNode body          = _n.Args[3, null];
            bool  isConstructor = _n.Name == S.Constructor;
            bool  isDestructor  = !isConstructor && name.Calls(S._Destruct, 1);

            LNode firstStmt = null;

            if (isConstructor && body != null && body.CallsMin(S.Braces, 1))
            {
                // Detect ": this(...)" or ": base(...)"
                firstStmt = body.Args[0];
                if (!CallsWPAIH(firstStmt, S.This) &&
                    !CallsWPAIH(firstStmt, S.Base))
                {
                    firstStmt = null;
                }
            }

            if (!AllowConstructorAmbiguity)
            {
                if (isDestructor && _spaceName == S.Fn)
                {
                    // When destructor syntax is ambiguous, use prefix notation.
                    return(SPResult.Fail);
                }
                else if (isConstructor && firstStmt == null)
                {
                    // When constructor syntax is ambiguous, use prefix notation.
                    if (name.IsIdNamed(S.This))
                    {
                        if (_spaceName == S.Fn)
                        {
                            return(SPResult.Fail);
                        }
                    }
                    else if (!name.IsIdNamed(_spaceName))
                    {
                        return(SPResult.Fail);
                    }
                }
            }

            // A cast operator with the structure: #fn(Foo, operator`#cast`, #(...))
            // can be printed in a special format: operator Foo(...);
            bool isCastOperator = (name.Name == S.Cast && name.AttrNamed(S.TriviaUseOperatorKeyword) != null);

            var ifClause = PrintTypeAndName(isConstructor || isDestructor, isCastOperator,
                                            isConstructor && !name.IsIdNamed(S.This) ? AttrStyle.IsConstructor : AttrStyle.IsDefinition);

            PrintArgList(args.Args, ParenFor.MethodDecl, Ambiguity.AllowUnassignedVarDecl, OmitMissingArguments);

            PrintWhereClauses(name);

            // If this is a constructor where the first statement is this(...) or
            // base(...), we must change the notation to ": this(...) {...}" as
            // required in plain C#
            if (firstStmt != null)
            {
                using (Indented) {
                    if (!Newline(NewlineOpt.BeforeConstructorColon))
                    {
                        Space(SpaceOpt.BeforeConstructorColon);
                    }
                    WriteThenSpace(':', SpaceOpt.AfterColon);
                    PrintExpr(firstStmt, StartExpr, Ambiguity.NoBracedBlock);
                }
            }

            return(AutoPrintBodyOfMethodOrProperty(body, ifClause, firstStmt != null));
        }
Example #17
0
 /// <summary>Given a complex name such as <c>global::Foo&lt;int>.Bar&lt;T></c>,
 /// this method identifies the base name component, which in this example
 /// is Bar. This is used, for example, to identify the expected name for
 /// a constructor based on the class name, e.g. <c>Foo&lt;T></c> => Foo.</summary>
 /// <remarks>This was moved to EcsValidators.</remarks>
 public static Symbol KeyNameComponentOf(LNode name)
 {
     return(EcsValidators.KeyNameComponentOf(name));
 }
Example #18
0
        public SPResult AutoPrintSpaceDefinition(Ambiguity flags)
        {
            // Spaces: S.Struct, S.Class, S.Trait, S.Enum, S.Alias, S.Interface, S.Namespace
            var kind = EcsValidators.SpaceDefinitionKind(_n, Pedantics);

            if (kind == null)
            {
                return(SPResult.Fail);
            }

            var ifClause = GetIfClause();

            int ai;
            var old_n = _n;

            if (kind == S.Alias && (ai = _n.Attrs.IndexWhere(a => a.IsIdNamed(S.FilePrivate))) > -1)
            {
                // Cause "[#filePrivate] #alias x = y;" to print as "using x = y;"
                _n   = _n.WithAttrs(_n.Attrs.RemoveAt(ai)).WithTarget(S.UsingStmt);
                kind = S.UsingStmt;
            }

            G.Verify(0 == PrintAttrs(StartStmt, AttrStyle.IsDefinition, flags, ifClause));

            LNode name = _n.Args[0], bases = _n.Args[1], body = _n.Args[2, null];

            WriteOperatorName(kind);

            _n = old_n;

            _out.Space();
            PrintExpr(name, ContinueExpr, Ambiguity.InDefinitionName);

            if (bases.CallsMin(S.AltList, 1))
            {
                Space(SpaceOpt.BeforeBaseListColon);
                WriteThenSpace(':', SpaceOpt.AfterColon);
                for (int i = 0, c = bases.ArgCount; i < c; i++)
                {
                    if (i != 0)
                    {
                        WriteThenSpace(',', SpaceOpt.AfterComma);
                    }
                    PrintType(bases.Args[i], ContinueExpr);
                }
            }
            bool alias = name.Calls(S.Assign, 2);
            var  name2 = name;

            if (name2.Calls(S.Of) || (alias && (name2 = name.Args[0]).Calls(S.Of)))
            {
                PrintWhereClauses(name2);
            }

            AutoPrintIfClause(ifClause);

            if (body == null)
            {
                return(SPResult.NeedSemicolon);
            }

            if (kind == S.Enum)
            {
                PrintEnumBody(body);
            }
            else
            {
                PrintBracedBlock(body, NewlineOpt.BeforeSpaceDefBrace, false, KeyNameComponentOf(name));
            }
            return(SPResult.NeedSuffixTrivia);
        }