private void PrintExpressionsInBraces(LNode body, bool isInitializer, Ambiguity flags)
        {
            bool anyNewlines = false;

            using (Indented)
            {
                NewlineOpt nlo      = isInitializer ? NewlineOpt.AfterOpenBraceInNewExpr : NewlineOpt.Minimal | NewlineOpt.BeforeEachEnumItem;
                NewlineOpt next_nlo = isInitializer ? NewlineOpt.AfterEachInitializer : NewlineOpt.BeforeEachEnumItem;

                for (int i = 0, c = body.ArgCount; i < c; i++)
                {
                    var stmt = body.Args[i];
                    if (i != 0)
                    {
                        _out.Write(',');
                        nlo = next_nlo;
                    }
                    if (NewlineOrSpace(nlo, IsDefaultNewlineSuppressed(stmt), SpaceOpt.AfterComma))
                    {
                        anyNewlines = true;
                    }
                    PrintExpr(stmt, StartExpr, flags);
                }
            }
            NewlineOrSpace(isInitializer ? NewlineOpt.BeforeCloseBraceInExpr : NewlineOpt.Default, !anyNewlines);
        }
Exemple #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);
            }
        }
Exemple #3
0
        private void PrintVariableDecl(bool printAttrs, Precedence context, Ambiguity allowPointer)
        {
            if (printAttrs)
            {
                G.Verify(0 == PrintAttrs(StartExpr, AttrStyle.IsDefinition, 0));
            }

            Debug.Assert(_n.Name == S.Var);
            var a = _n.Args;

            if (IsSimpleSymbolWPA(a[0], S.Missing))
            {
                _out.Write("var", true);
            }
            else
            {
                PrintType(a[0], context, allowPointer & Ambiguity.AllowPointer);
            }
            _out.Space();
            for (int i = 1; i < a.Count; i++)
            {
                var @var = a[i];
                if (i > 1)
                {
                    WriteThenSpace(',', SpaceOpt.AfterComma);
                }

                PrintExpr(@var, EP.Assign.RightContext(context), Ambiguity.NoParenthesis);
            }
        }
Exemple #4
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);
            }
        }
Exemple #5
0
        protected internal void PrintExpr(Precedence context, Ambiguity flags = 0)
        {
            if (!EP.Primary.CanAppearIn(context) && !_n.IsParenthesizedExpr())
            {
                Debug.Assert((flags & Ambiguity.AllowUnassignedVarDecl) == 0);
                // Above EP.Primary (inside '$' or unary '.'), we can't use prefix
                // notation or most other operators so we're very limited in what
                // we can print.
                if (!HasPAttrs(_n))
                {
                    if (!_n.IsCall)
                    {
                        PrintSimpleSymbolOrLiteral(flags);
                        return;
                    }
                }
                PrintWithinParens(ParenFor.Grouping, _n);
                return;
            }

            NodeStyle style = _n.BaseStyle;

            if (style == NodeStyle.PrefixNotation && !PreferPlainCSharp)
            {
                PrintPrefixNotation(context, true, flags, false);
            }
            else
            {
                bool isVarDecl = IsVariableDecl(false, (flags & (Ambiguity.AllowUnassignedVarDecl | Ambiguity.ForEachInitializer)) != 0);

                int inParens = 0;
                if (_n.AttrCount != 0)
                {
                    inParens = PrintAttrs(ref context, isVarDecl ? AttrStyle.IsDefinition : AttrStyle.AllowKeywordAttrs, flags);
                }

                bool startStmt = context.RangeEquals(StartStmt);
                bool startExpr = context.RangeEquals(StartExpr);

                if (isVarDecl && (startExpr || startStmt || (flags & Ambiguity.ForEachInitializer) != 0))
                {
                    PrintVariableDecl(false, context, flags);
                }
                else if (startExpr && IsNamedArgument())
                {
                    PrintNamedArg(context);
                }
                else if (!AutoPrintOperator(context, flags))
                {
                    PrintPrefixNotation(context, true, flags, true);
                }

                WriteCloseParens(inParens);
            }
            if (context.Lo != StartStmt.Lo)
            {
                PrintSuffixTrivia(false);
            }
        }
Exemple #6
0
 public bool PrintRawText(Precedence mainPrec, Precedence context, Ambiguity flags)
 {
     if (OmitRawText)
     {
         return(false);
     }
     _out.Write(GetRawText(_n), true);
     return(true);
 }
Exemple #7
0
 public SPResult AutoPrintResult(Ambiguity flags)
 {
     if (!IsResultExpr(_n) || (flags & Ambiguity.FinalStmt) == 0)
     {
         return(SPResult.Fail);
     }
     PrintExpr(_n.Args[0], StartExpr);             // not StartStmt => allows multiplication e.g. a*b by avoiding ptr ambiguity
     return(SPResult.NeedSuffixTrivia);
 }
Exemple #8
0
 public SPResult AutoPrintAssemblyAttribute(Ambiguity flags)
 {
     Debug.Assert(_n.Calls(S.Assembly));
     PrintAttrs(StartStmt, AttrStyle.NoKeywordAttrs, flags);
     _out.Write("[assembly:", true);
     Space(SpaceOpt.Default);
     PrintArgs(_n, flags, false);
     _out.Write(']', true);
     return(SPResult.NeedSuffixTrivia);
 }
Exemple #9
0
 public SPResult AutoPrintMissingStmt(Ambiguity flags)
 {
     Debug.Assert(_n.Name == S.Missing);
     if (!_n.IsId)
     {
         return(SPResult.Fail);
     }
     G.Verify(0 == PrintAttrs(StartStmt, AttrStyle.AllowKeywordAttrs, flags));
     return(SPResult.NeedSemicolon);
 }
Exemple #10
0
 public SPResult AutoPrintRawText(Ambiguity flags)
 {
     if (OmitRawText)
     {
         return(SPResult.Fail);
     }
     G.Verify(0 == PrintAttrs(StartStmt, AttrStyle.NoKeywordAttrs, flags));
     WriteRawText(GetRawText(_n));
     return(SPResult.NeedSuffixTrivia);
 }
Exemple #11
0
        public SPResult AutoPrintBlockOfStmts(Ambiguity flags)
        {
            if (!_n.Calls(S.Braces))
            {
                return(SPResult.Fail);
            }

            G.Verify(0 == PrintAttrs(StartStmt, AttrStyle.AllowKeywordAttrs, flags));
            PrintBracedBlock(_n, 0);
            return(SPResult.NeedSuffixTrivia);
        }
Exemple #12
0
 static void Main(string[] args)
 {
     Ambiguity.DateAmbiguity();
     Ambiguity.TimeAmbiguity();
     Ambiguity.DateTimeAmbiguity();
     Ranges.DateRange();
     Ranges.TimeRange();
     Parsing.Examples();
     LanguageGeneration.Examples();
     Resolution.Examples();
     Constraints.Examples();
 }
Exemple #13
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);
            }
        }
Exemple #14
0
        public SPResult AutoPrintVarDecl(Ambiguity flags)
        {
            if (!IsVariableDecl(true, true))
            {
                return(SPResult.Fail);
            }

            var ifClause = GetIfClause();

            G.Verify(0 == PrintAttrs(StartStmt, AttrStyle.IsDefinition, flags, ifClause));
            PrintVariableDecl(false, StartStmt, flags);
            AutoPrintIfClause(ifClause);
            return(SPResult.NeedSemicolon);
        }
        public void PrintStmt(Ambiguity flags = 0)
        {
            if ((flags & Ambiguity.ElseClause) == 0)
            {
                _out.BeginStatement();
            }

            if (AllowChangeParenthesis || !_n.IsParenthesizedExpr())
            {
                var style = _n.BaseStyle;
                StatementPrinter printer;
                var name = _n.Name;
                if (StatementPrinters.TryGetValue(name, out printer) && HasSimpleHeadWPA(_n))
                {
                    if (PreferPlainCSharp || name == S.RawText ||
                        (style != NodeStyle.Expression && style != NodeStyle.PrefixNotation))
                    {
                        var result = printer(this, flags | Ambiguity.NoParenthesis);
                        if (result != SPResult.Fail)
                        {
                            if (result != SPResult.Complete)
                            {
                                PrintSuffixTrivia(result == SPResult.NeedSemicolon);
                            }
                            return;
                        }
                    }
                }

                if (style == NodeStyle.Special && AutoPrintMacroBlockCall(flags | Ambiguity.NoParenthesis))
                {
                    return;
                }

                var attrs = _n.Attrs;
                for (int i = 0, c = attrs.Count; i < c; i++)
                {
                    var a = attrs[i];
                    if ((a.Name == S.TriviaMacroAttribute && AutoPrintMacroAttribute()) ||
                        (a.Name == S.TriviaForwardedProperty && AutoPrintForwardedProperty()))
                    {
                        return;
                    }
                }
            }

            PrintExpr(StartStmt);
            PrintSuffixTrivia(true);
        }
Exemple #16
0
        static void Main(string[] args)
        {
            // Creating TIMEX expressions from natural language using the Recognizer package.
            Ambiguity.DateAmbiguity();
            Ambiguity.TimeAmbiguity();
            Ambiguity.DateTimeAmbiguity();
            Ranges.DateRange();
            Ranges.TimeRange();

            // Manipulating TIMEX expressions in code using the TIMEX Datatype package.
            Parsing.Examples();
            LanguageGeneration.Examples();
            Resolution.Examples();
            Constraints.Examples();
        }
Exemple #17
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);
        }
Exemple #18
0
 private void PrintSimpleSymbolOrLiteral(Ambiguity flags)
 {
     Debug.Assert(_n.HasSimpleHead());
     if (_n.IsLiteral)
     {
         PrintLiteral();
     }
     else if (_n.Name == S.RawText && !OmitRawText)
     {
         _out.Write(GetRawText(_n), true);
     }
     else
     {
         PrintSimpleIdent(_n.Name, flags, false, _n.AttrNamed(S.TriviaUseOperatorKeyword) != null);
     }
 }
Exemple #19
0
 private void PrintArgs(VList <LNode> args, Ambiguity flags, bool omitMissingArguments, char separator = ',')
 {
     for (int i = 0; i < args.Count; i++)
     {
         var  arg     = args[i];
         bool missing = omitMissingArguments && IsSimpleSymbolWPA(arg, S.Missing) && args.Count > 1;
         if (i != 0)
         {
             WriteThenSpace(separator, missing ? SpaceOpt.MissingAfterComma : SpaceOpt.AfterComma);
         }
         if (!missing)
         {
             PrintExpr(arg, StartExpr, flags);
         }
     }
 }
Exemple #20
0
        private void WriteOperatorName(Symbol name, Ambiguity flags = 0)
        {
            string opName = name.Name;

            if ((flags & Ambiguity.UseBacktick) != 0)
            {
                PrintString(opName, '`', null);
            }
            else if (opName.StartsWith("#"))
            {
                _out.Write(opName.Substring(1), true);
            }
            else
            {
                _out.Write(opName, true);
            }
        }
        public SPResult AutoPrintProperty(Ambiguity flags)
        {
            // S.Property:
            // #property(int, Foo, {
            //     get({ return _foo; });
            //     set({ _foo = value; });
            // });
            if (!IsPropertyDefinition())
            {
                return(SPResult.Fail);
            }

            var ifClause = PrintTypeAndName(false);

            PrintWhereClauses(_n.Args[1]);

            return(AutoPrintBodyOfMethodOrProperty(_n.Args[2, null], ifClause));
        }
Exemple #22
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);
        }
Exemple #23
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);
        }
Exemple #24
0
        static Symbol SpecialTypeKind(LNode n, Ambiguity flags, Precedence context)
        {
            // detects when notation for special types applies: Foo[], Foo*, Foo?
            // assumes IsComplexIdentifier() is already known to be true
            LNode first;

            if (n.Calls(S.Of, 2) && (first = n.Args[0]).IsId && (flags & Ambiguity.TypeContext) != 0)
            {
                var kind = first.Name;
                if (S.IsArrayKeyword(kind) || kind == S.QuestionMark)
                {
                    return(kind);
                }
                if (kind == S._Pointer && ((flags & Ambiguity.AllowPointer) != 0 || context.Left == StartStmt.Left))
                {
                    return(kind);
                }
            }
            return(null);
        }
        public SPResult AutoPrintSimpleStmt(Ambiguity flags)
        {
            // S.Break, S.Continue, S.Goto, S.GotoCase, S.Return, S.Throw
            if (!IsSimpleKeywordStmt())
            {
                return(SPResult.Fail);
            }

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

            var name = _n.Name;

            if (name == S.GotoCase)
            {
                _out.Write("goto case", true);
            }
            else if (name == S.Import)
            {
                _out.Write("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);
        }
Exemple #26
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);
            }
        }
Exemple #27
0
        private bool AutoPrintOperator(Precedence context, Ambiguity flags)
        {
            if (!_n.IsCall || !_n.HasSimpleHead())
            {
                return(false);
            }
            Pair <Precedence, OperatorPrinter> info;

            if (OperatorPrinters.TryGetValue(_n.Name, out info))
            {
                return(info.Item2(this, info.Item1, context, flags));
            }
            else if (_n.BaseStyle == NodeStyle.Operator)
            {
                if (_n.ArgCount == 2)
                {
                    return(AutoPrintInfixBinaryOperator(EP.Backtick, context, flags | Ambiguity.UseBacktick));
                }
                //if (_n.ArgCount == 1)
                //	return AutoPrintPrefixUnaryOperator(EP.Backtick, context, flags | Ambiguity.UseBacktick);
            }
            return(false);
        }
Exemple #28
0
        public SPResult AutoPrintEvent(Ambiguity flags)
        {
            LNode type, name, body;

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

            G.Verify(0 == PrintAttrs(StartStmt, AttrStyle.IsDefinition, 0));
            _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, null));
        }
Exemple #29
0
        public bool AutoPrintCallOperator(Precedence precedence, Precedence context, Ambiguity flags)
        {
            // Handles "call operators" such as default(...) and checked(...)
            bool needParens;

            Debug.Assert(CanAppearIn(precedence, context, out needParens));
            Debug.Assert(_n.HasSpecialName);
            if (_n.ArgCount != 1)
            {
                return(false);
            }
            var  name = _n.Name;
            var  arg  = _n.Args[0];
            bool type = (name == S.Default || name == S.Typeof || name == S.Sizeof);

            if (type && !IsComplexIdentifier(arg, ICI.Default | ICI.AllowAttrs))
            {
                return(false);
            }

            WriteOperatorName(name);
            PrintWithinParens(ParenFor.MethodCall, arg, type ? Ambiguity.TypeContext | Ambiguity.AllowPointer : 0);
            return(true);
        }
		private void PrintVariableDecl(bool printAttrs, Precedence context, Ambiguity allowPointer)
		{
			if (printAttrs)
				G.Verify(0 == PrintAttrs(StartExpr, AttrStyle.IsDefinition, 0));

			Debug.Assert(_n.Name == S.Var);
			var a = _n.Args;
			if (IsSimpleSymbolWPA(a[0], S.Missing))
				_out.Write("var", true);
			else
				PrintType(a[0], context, allowPointer & Ambiguity.AllowPointer);
			_out.Space();
			for (int i = 1; i < a.Count; i++) {
				var @var = a[i];
				if (i > 1)
					WriteThenSpace(',', SpaceOpt.AfterComma);

				PrintExpr(@var, EP.Assign.RightContext(context), Ambiguity.NoParenthesis);
			}
		}
		private void PrintSimpleSymbolOrLiteral(Ambiguity flags)
		{
			Debug.Assert(_n.HasSimpleHead());
			if (_n.IsLiteral)
				PrintLiteral();
			else if (_n.Name == S.RawText && !OmitRawText)
				_out.Write(GetRawText(_n), true);
			else
				PrintSimpleIdent(_n.Name, flags, false, _n.AttrNamed(S.TriviaUseOperatorKeyword) != null);
		}
		internal void PrintPrefixNotation(Precedence context, bool purePrefixNotation, Ambiguity flags = 0, bool skipAttrs = false)
		{
			Debug.Assert(EP.Primary.CanAppearIn(context) || _n.IsParenthesizedExpr());
			int inParens = 0;
			if (!skipAttrs)
				inParens = PrintAttrs(ref context, purePrefixNotation ? AttrStyle.NoKeywordAttrs : AttrStyle.AllowKeywordAttrs, flags);

			if (!_n.IsCall)
				PrintSimpleSymbolOrLiteral(flags);
			else if (!purePrefixNotation && IsComplexIdentifier(_n, ICI.Default | ICI.AllowAttrs | ICI.AllowParensAround))
				PrintExpr(context);
			else {
				if (!AllowConstructorAmbiguity && _n.Calls(_spaceName) && context == StartStmt && inParens == 0)
				{
					inParens++;
					WriteOpenParen(ParenFor.Grouping);
				}

				// Print Target
				var target = _n.Target;
				var f = Ambiguity.IsCallTarget;
				if (_spaceName == S.Fn || context != StartStmt)
					f |= Ambiguity.AllowThisAsCallTarget;
				PrintExpr(target, EP.Primary.LeftContext(context), f);

				// Print argument list
				WriteOpenParen(ParenFor.MethodCall);

				bool first = true;
				foreach (var arg in _n.Args) {
					if (OmitMissingArguments && IsSimpleSymbolWPA(arg, S.Missing) && _n.ArgCount > 1) {
						if (!first) WriteThenSpace(',', SpaceOpt.MissingAfterComma);
					} else {
						if (!first) WriteThenSpace(',', SpaceOpt.AfterComma);
						PrintExpr(arg, StartExpr);
					}
					first = false;
				}
				WriteCloseParen(ParenFor.MethodCall);
			}
			WriteCloseParens(inParens);
		}
		void PrintType(LNode n, Precedence context, Ambiguity flags = 0)
		{
			using (With(n))
				PrintExpr(context, flags | Ambiguity.TypeContext);
		}
		protected internal void PrintExpr(Precedence context, Ambiguity flags = 0)
		{
			if (!EP.Primary.CanAppearIn(context) && !_n.IsParenthesizedExpr())
			{
				Debug.Assert((flags & Ambiguity.AllowUnassignedVarDecl) == 0);
				// Above EP.Primary (inside '$' or unary '.'), we can't use prefix 
				// notation or most other operators so we're very limited in what
				// we can print.
				if (!HasPAttrs(_n))
				{
					if (!_n.IsCall) {
						PrintSimpleSymbolOrLiteral(flags);
						return;
					}
				}
				PrintWithinParens(ParenFor.Grouping, _n);
				return;
			}

			NodeStyle style = _n.BaseStyle;
			if (style == NodeStyle.PrefixNotation && !PreferPlainCSharp)
				PrintPrefixNotation(context, true, flags, false);
			else {
				bool isVarDecl = IsVariableDecl(false, (flags & (Ambiguity.AllowUnassignedVarDecl|Ambiguity.ForEachInitializer)) != 0);
				
				int inParens = 0;
				if (_n.AttrCount != 0)
					inParens = PrintAttrs(ref context, isVarDecl ? AttrStyle.IsDefinition : AttrStyle.AllowKeywordAttrs, flags);
				
				bool startStmt = context.RangeEquals(StartStmt);
				bool startExpr = context.RangeEquals(StartExpr);
				
				if (isVarDecl && (startExpr || startStmt || (flags & Ambiguity.ForEachInitializer) != 0))
					PrintVariableDecl(false, context, flags);
				else if (startExpr && IsNamedArgument())
					PrintNamedArg(context);
				else if (!AutoPrintOperator(context, flags))
					PrintPrefixNotation(context, true, flags, true);

				WriteCloseParens(inParens);
			}
			if (context.Lo != StartStmt.Lo)
				PrintSuffixTrivia(false);
		}
		void PrintExpr(LNode n, Precedence context, Ambiguity flags)
		{
			using (With(n, context, CheckOneLiner(flags, n)))
				PrintCurrentExpr();
		}
		private bool AutoPrintOperator(Precedence context, Ambiguity flags)
		{
			if (!_n.IsCall || !_n.HasSimpleHead())
				return false;
			Pair<Precedence, OperatorPrinter> info;
			if (OperatorPrinters.TryGetValue(_n.Name, out info))
				return info.Item2(this, info.Item1, context, flags);
			else if (_n.BaseStyle == NodeStyle.Operator)
			{
				if (_n.ArgCount == 2)
					return AutoPrintInfixBinaryOperator(EP.Backtick, context, flags | Ambiguity.UseBacktick);
				//if (_n.ArgCount == 1)
				//	return AutoPrintPrefixUnaryOperator(EP.Backtick, context, flags | Ambiguity.UseBacktick);
			}
			return false;
		}
		public SPResult AutoPrintBlockOfStmts(Ambiguity flags)
		{
			if (!IsBlockOfStmts(_n))
				return SPResult.Fail;

			G.Verify(0 == PrintAttrs(StartStmt, AttrStyle.AllowKeywordAttrs, flags));
			PrintBracedBlock(_n, 0);
			return SPResult.NeedSuffixTrivia;
		}
		void PrintStmt(LNode n, Ambiguity flags)
		{
			using (With(n, StartStmt, CheckOneLiner(flags, n)))
				PrintCurrentStmt();
		}
		public bool AutoPrintComplexIdentOperator(Precedence precedence, Precedence context, Ambiguity flags)
		{
			// Handles #of and #., including array types
			int argCount = _n.ArgCount;
			Symbol name = _n.Name;
			Debug.Assert((name == S.Of || name == S.Dot) && _n.IsCall);
			
			var first = _n.Args[0, null];
			if (first == null)
				return false; // no args

			bool needParens, needSpecialOfNotation = false;
			if (!CanAppearIn(precedence, context, out needParens) || needParens)
				return false; // this only happens inside $ operator, e.g. $(a.b)

			if (name == S.Dot) {
				// The trouble with the dot is its high precedence; because of 
				// this, arguments after a dot cannot use prefix notation as a 
				// fallback. For example "@.(a, b(c))" cannot be printed "a.b(c)"
				// since that means @.(a, b)(c)". The first argument to non-
				// unary "." can use prefix notation safely though, e.g. 
				// "@.(b(c), a)" can (and must) be printed "b(c).a".
				if (argCount > 2)
					return false;
				if (HasPAttrs(first))
					return false;
				LNode afterDot = _n.Args.Last;
				// Unary dot is no problem: .(a) is parsed the same as .a, i.e. 
				// the parenthesis are ignored, so we can print an expr like 
				// @`.`(a+b) as .(a+b), but the parser counts parens on binary 
				// dot, so in that case the argument after the dot must not be any 
				// kind of call (except substitution) and must not have attributes,
				// unless it is in parens.
				if (argCount == 2 && !afterDot.IsParenthesizedExpr()) {
					if (HasPAttrs(afterDot))
						return false;
					if (afterDot.IsCall && afterDot.Name != S.Substitute)
						return false;
				}
			} else if (name == S.Of) {
				var ici = ICI.Default | ICI.AllowAttrs;
				if ((flags & Ambiguity.InDefinitionName) != 0)
					ici |= ICI.NameDefinition;
				if (!IsComplexIdentifier(_n, ici)) {
					if (IsComplexIdentifier(_n, ici | ICI.AllowAnyExprInOf))
						needSpecialOfNotation = true;
					else
						return false;
				}
			}

			if (name == S.Dot)
			{
				if (argCount == 1) {
					_out.Write('.', true);
					PrintExpr(first, EP.Substitute);
				} else {
					PrintExpr(first, precedence.LeftContext(context), flags & Ambiguity.TypeContext);
					_out.Write('.', true);
					PrintExpr(_n.Args[1], precedence.RightContext(context));
				}
			}
			else if (_n.Name == S.Of)
			{
				// Check for special type names such as Foo? or Foo[]
				Symbol stk = SpecialTypeKind(_n, flags, context);
				if (stk != null)
				{
					if (S.IsArrayKeyword(stk)) {
						// We do something very strange in case of arrays of arrays:
						// the order of the square brackets must be reversed when 
						// arrays are nested. For example, an array of two-dimensional 
						// arrays of int is written int[][,], rather than int[,][] 
						// which would be much easier to handle.
						var stack = InternalList<Symbol>.Empty;
						var innerType = _n;
						do {
							stack.Add(stk);
							innerType = innerType.Args[1];
						} while (S.IsArrayKeyword(stk = SpecialTypeKind(innerType, flags, context) ?? GSymbol.Empty));

						PrintType(innerType, EP.Primary.LeftContext(context), (flags & Ambiguity.AllowPointer));

						for (int i = 0; i < stack.Count; i++)
							_out.Write(stack[i].Name, true); // e.g. [] or [,]
					} else {
						PrintType(_n.Args[1], EP.Primary.LeftContext(context), (flags & Ambiguity.AllowPointer));
						_out.Write(stk == S._Pointer ? '*' : '?', true);
					}
					return true;
				}

				PrintExpr(first, precedence.LeftContext(context));

				_out.Write(needSpecialOfNotation ? "!(" : "<", true);
				for (int i = 1; i < argCount; i++) {
					if (i > 1)
						WriteThenSpace(',', SpaceOpt.AfterCommaInOf);
					PrintType(_n.Args[i], StartExpr, Ambiguity.InOf | Ambiguity.AllowPointer | (flags & Ambiguity.InDefinitionName));
				}
				_out.Write(needSpecialOfNotation ? ')' : '>', true);
			}
			else 
			{
				Debug.Assert(_n.Name == S.Substitute);
				G.Verify(AutoPrintOperator(ContinueExpr, 0));
			}
			return true;
		}
		static Symbol SpecialTypeKind(LNode n, Ambiguity flags, Precedence context)
		{
			// detects when notation for special types applies: Foo[], Foo*, Foo?
			// assumes IsComplexIdentifier() is already known to be true
			LNode first;
			if (n.Calls(S.Of, 2) && (first = n.Args[0]).IsId && (flags & Ambiguity.TypeContext)!=0) {
				var kind = first.Name;
				if (S.IsArrayKeyword(kind) || kind == S.QuestionMark)
					return kind;
				if (kind == S._Pointer && ((flags & Ambiguity.AllowPointer) != 0 || context.Left == StartStmt.Left))
					return kind;
			}
			return null;
		}
		public bool AutoPrintListOperator(Precedence precedence, Precedence context, Ambiguity flags)
		{
			// Handles #tuple and {} braces.
			int argCount = _n.ArgCount;
			Symbol name = _n.Name;
			Debug.Assert(_n.IsCall);
			
			bool? braceMode;
			if (name == S.Tuple) {
				braceMode = false;
				flags &= Ambiguity.AllowUnassignedVarDecl;
			} else if (name == S.Braces) {
				// A braced block is not allowed at start of an expression 
				// statement; the parser would mistake it for a standalone 
				// braced block (the difference is that a standalone braced 
				// block ends automatically after '}', with no semicolon.)
				if (context.Left == StartStmt.Left || (flags & Ambiguity.NoBracedBlock) != 0)
					return false;
				braceMode = true;
				if (context.Left <= ContinueExpr.Left && _n.BaseStyle == NodeStyle.OldStyle)
					braceMode = null; // initializer mode
			} else if (name == S.ArrayInit) {
				braceMode = null; // initializer mode
			} else {
				Debug.Assert(false);
				// Code quote operator has been REMOVED from EC#, in favor of #quote(...), at least for now.
				//Debug.Assert(name == S.CodeQuote || name == S.CodeQuoteSubstituting || name == S.List);
				//_out.Write(name == S.CodeQuote ? "@" : "@@", false);
				braceMode = _n.BaseStyle == NodeStyle.Statement && (flags & Ambiguity.NoBracedBlock) == 0;
				flags = 0;
			}

			int c = _n.ArgCount;
			if (braceMode ?? true)
			{
				if (!Newline(NewlineOpt.BeforeOpenBraceInExpr))
					Space(SpaceOpt.OutsideParens);
				_out.Write('{', true);
				if (braceMode == true) {
					using (Indented) {
						for (int i = 0; i < c; i++)
							PrintStmt(_n.Args[i], i + 1 == c ? Ambiguity.FinalStmt : 0);
					}
				} else {
					_out.Space();
					for (int i = 0; i < c; i++) {
						if (i != 0) WriteThenSpace(',', SpaceOpt.AfterComma);
						PrintExpr(_n.Args[i], StartExpr, flags);
					}
				}
				if (!Newline(NewlineOpt.BeforeCloseBraceInExpr))
					_out.Space();
				_out.Write('}', true);
				if (!Newline(NewlineOpt.AfterCloseBraceInExpr))
					Space(SpaceOpt.OutsideParens);
			}
			else
			{
				WriteOpenParen(ParenFor.Grouping);
				for (int i = 0; i < c; i++)
				{
					if (i != 0) WriteThenSpace(',', SpaceOpt.AfterComma);
					PrintExpr(_n.Args[i], StartExpr, flags);
				}
				if (name == S.Tuple && c == 1)
					_out.Write(',', true);
				WriteCloseParen(ParenFor.Grouping);
			}
			return true;
		}
		public bool AutoPrintCastOperator(Precedence precedence, Precedence context, Ambiguity flags)
		{
			if (_n.ArgCount != 2)
				return false;

			// Cast operators can have attributes on the second argument using 
			// alternate notation, e.g. x(as [A] Foo) is legal but "x as [A] Foo"
			// is not, because attributes must only appear at the beginning of an 
			// expression and only the second case treats the text after 'as' as 
			// the beginning of a new expression. Also, because a standard cast 
			// like (Foo)(x) is ambiguous (is x being cast to type Foo, or is a
			// delegate named Foo being called with x as an argument?), an 
			// attribute list can be used to resolve the ambiguity. So (Foo)(x) 
			// is considered a cast, while ([ ] Foo)(x) is a call to Foo in which 
			// Foo happens to be placed in parenthesis. Thus, if target type of a 
			// cast has attributes, it must be expressed in alternate form, e.g.
			// (x)(->[A] Foo), or in prefix form.
			//
			// There is an extra rule for (X)Y casts: X must be a complex (or 
			// simple) identifier, since anything else won't be parsed as a cast.
			Symbol name = _n.Name;
			bool alternate = (_n.Style & NodeStyle.Alternate) != 0 && !PreferPlainCSharp;
			LNode subject = _n.Args[0], target = _n.Args[1];
			if (HasPAttrs(subject))
				return false;
			if (HasPAttrs(target) || (name == S.Cast && !IsComplexIdentifier(target, ICI.Default | ICI.AllowAnyExprInOf)))
				alternate = true;
			
			bool needParens;
			if (alternate)
				precedence = EP.Primary;
			if (!CanAppearIn(precedence, context, out needParens)) {
				// There are two different precedences for cast operators; we prefer 
				// the traditional forms (T)x, x as T, x using T which have lower 
				// precedence, but they don't work in this context so consider using 
				// x(->T), x(as T) or x(using T) instead.
				alternate = true;
				precedence = EP.Primary;
				if (!CanAppearIn(precedence, context, out needParens))
					return false;
			}

			if (alternate && PreferPlainCSharp)
				return false; // old-style cast is impossible here

			if (WriteOpenParen(ParenFor.Grouping, needParens))
				context = StartExpr;

			if (alternate) {
				PrintExpr(subject, precedence.LeftContext(context));
				WriteOpenParen(ParenFor.NewCast);
				_out.Write(GetCastText(_n.Name), true);
				Space(SpaceOpt.AfterCastArrow);
				PrintType(target, StartExpr, Ambiguity.AllowPointer);
				WriteCloseParen(ParenFor.NewCast);
			} else {
				if (_n.Name == S.Cast) {
					WriteOpenParen(ParenFor.Grouping);
					PrintType(target, ContinueExpr, Ambiguity.AllowPointer);
					WriteCloseParen(ParenFor.Grouping);
					Space(SpaceOpt.AfterCast);
					PrintExpr(subject, precedence.RightContext(context), Ambiguity.CastRhs);
				} else {
					// "x as y" or "x using y"
					PrintExpr(subject, precedence.LeftContext(context));
					_out.Write(GetCastText(_n.Name), true);
					PrintType(target, precedence.RightContext(context));
				}
			}

			WriteCloseParen(ParenFor.Grouping, needParens);
			return true;
		}
		private void PrintArgs(VList<LNode> args, Ambiguity flags, bool omitMissingArguments, char separator = ',')
		{
			for (int i = 0; i < args.Count; i++)
			{
				var arg = args[i];
				bool missing = omitMissingArguments && IsSimpleSymbolWPA(arg, S.Missing) && args.Count > 1;
				if (i != 0)
					WriteThenSpace(separator, missing ? SpaceOpt.MissingAfterComma : SpaceOpt.AfterComma);
				if (!missing)
					PrintExpr(arg, StartExpr, flags);
			}
		}
		public SPResult AutoPrintOtherBlockStmt(Ambiguity flags)
		{
			// S.If, S.For, S.ForEach, S.Checked, S.Unchecked, S.Try
			var type = OtherBlockStmtType();
			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, ParenFor.KeywordCall, 3, 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 (second != null && !IsSimpleSymbolWPA(first, S.Missing))
						PrintWithinParens(ParenFor.KeywordCall, first, Ambiguity.AllowUnassignedVarDecl);
					braces = PrintBracedBlockOrStmt(second ?? first, flags);
				}
			}
			else if (type == S.Checked) // includes S.Unchecked
			{
				WriteOperatorName(_n.Name);
				PrintBracedBlockOrStmt(_n.Args[0], flags, NewlineOpt.BeforeSimpleStmtBrace);
			}

			return SPResult.NeedSuffixTrivia;
		}
		public void PrintStmt(Ambiguity flags = 0)
		{
			if ((flags & Ambiguity.ElseClause) == 0)
				_out.BeginStatement();

			if (AllowChangeParenthesis || !_n.IsParenthesizedExpr())
			{
				var style = _n.BaseStyle;
				StatementPrinter printer;
				var name = _n.Name;
				if (StatementPrinters.TryGetValue(name, out printer) && HasSimpleHeadWPA(_n))
				{
					if (PreferPlainCSharp || name == S.RawText ||
						(style != NodeStyle.Expression && style != NodeStyle.PrefixNotation))
					{
						var result = printer(this, flags | Ambiguity.NoParenthesis);
						if (result != SPResult.Fail) {
							if (result != SPResult.Complete)
								PrintSuffixTrivia(result == SPResult.NeedSemicolon);
							return;
						}
					}
				}

				if (style == NodeStyle.Special && AutoPrintMacroBlockCall(flags | Ambiguity.NoParenthesis))
					return;

				var attrs = _n.Attrs;
				for (int i = 0, c = attrs.Count; i < c; i++)
				{
					var a = attrs[i];
					if ((a.Name == S.TriviaMacroAttribute && AutoPrintMacroAttribute()) ||
						(a.Name == S.TriviaForwardedProperty && AutoPrintForwardedProperty()))
						return;
				}
			}

			PrintExpr(StartStmt);
			PrintSuffixTrivia(true);
		}
		public SPResult AutoPrintSimpleStmt(Ambiguity flags)
		{
			// S.Break, S.Continue, S.Goto, S.GotoCase, S.Return, S.Throw
			if (!IsSimpleKeywordStmt())
				return SPResult.Fail;

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

			var name = _n.Name;
			if (name == S.GotoCase)
				_out.Write("goto case", true);
			else if (name == S.Import)
				_out.Write("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;
		}
		void PrintStmt(LNode n, Ambiguity flags = 0)
		{
			using (With(n))
				PrintStmt(flags);
		}
		public bool AutoPrintPrefixUnaryOperator(Precedence precedence, Precedence context, Ambiguity flags)
		{
			if (!IsPrefixOperator(_n, false))
				return false;
			var name = _n.Name;
			var arg = _n.Args[0];

			bool needParens;
			if (CanAppearIn(precedence, context, out needParens, true))
			{
				// Check for the ambiguous case of (Foo)-x, (Foo)*x, etc.
				if ((flags & Ambiguity.CastRhs) != 0 && !needParens && (
					name == S._Dereference || name == S.PreInc || name == S.PreDec || 
					name == S._UnaryPlus || name == S._Negate || name == S.NotBits ||
					name == S._AddressOf) && !_n.IsParenthesizedExpr())
				{
					if (AllowChangeParenthesis)
						needParens = true; // Resolve ambiguity with extra parens
					else
						return false; // Fallback to prefix notation
				}
				// Check for the ambiguous case of "~Foo(...);"
				if (name == S.NotBits && context.Lo == StartStmt.Lo && arg.IsCall)
					return false;

				if (WriteOpenParen(ParenFor.Grouping, needParens))
					context = StartExpr;
				_out.Write(_n.Name.Name, true);
				PrefixSpace(precedence);
				PrintExpr(arg, precedence.RightContext(context), name == S.Forward ? Ambiguity.TypeContext : 0);
				//if (backtick) {
				//    Debug.Assert(precedence == EP.Backtick);
				//    if ((SpacingOptions & SpaceOpt.AroundInfix) != 0 && precedence.Lo < SpaceAroundInfixStopPrecedence)
				//        _out.Space();
				//    PrintOperatorName(_n.Name, Ambiguity.UseBacktick);
				//}
				WriteCloseParen(ParenFor.Grouping, needParens);
				return true;
			}
			return false;
		}
		public SPResult AutoPrintLabelStmt(Ambiguity flags)
		{
			if (!IsLabelStmt())
				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;
		}
		public bool AutoPrintCallOperator(Precedence precedence, Precedence context, Ambiguity flags)
		{
			// Handles "call operators" such as default(...) and checked(...)
			bool needParens;
			Debug.Assert(CanAppearIn(precedence, context, out needParens));
			Debug.Assert(_n.HasSpecialName);
			if (_n.ArgCount != 1)
				return false;
			var name = _n.Name;
			var arg = _n.Args[0];
			bool type = (name == S.Default || name == S.Typeof || name == S.Sizeof);
			if (type && !IsComplexIdentifier(arg, ICI.Default | ICI.AllowAttrs))
				return false;

			WriteOperatorName(name);
			PrintWithinParens(ParenFor.MethodCall, arg, type ? Ambiguity.TypeContext | Ambiguity.AllowPointer : 0);
			return true;
		}
		public SPResult AutoPrintTwoArgBlockStmt(Ambiguity flags)
		{
			// S.Do, S.Fixed, S.Lock, S.Switch, S.UsingStmt, S.While
			var type = TwoArgBlockStmtType();
			if (type == null)
				return SPResult.Fail;

			G.Verify(0 == PrintAttrs(StartStmt, AttrStyle.AllowWordAttrs, 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;
			}
		}
		public bool PrintRawText(Precedence mainPrec, Precedence context, Ambiguity flags)
		{
			if (OmitRawText)
				return false;
			_out.Write(GetRawText(_n), true);
			return true;
		}
		public bool AutoPrintNewOperator(Precedence precedence, Precedence context, Ambiguity flags)
		{
			// Prints the new Xyz(...) {...} operator
			Debug.Assert (_n.Name == S.New);
			int argCount = _n.ArgCount;
			if (argCount == 0)
				return false;
			bool needParens;
			Debug.Assert(CanAppearIn(precedence, context, out needParens) && !needParens);

			LNode cons = _n.Args[0];
			LNode type = cons.Target;
			var consArgs = cons.Args;

			// There are two basic uses of new: for objects, and for arrays.
			// In all cases, #new has 1 arg plus optional initializer arguments,
			// and there's always a list of "constructor args" even if it is empty 
			// (exception: new {...}).
			// 1. Init an object: 1a. new Foo<Bar>() { ... }  <=> #new(Foo<bar>(...), ...)
			//                    1b. new { ... }             <=> #new(@``, ...)
			// 2. Init an array:  2a. new int[] { ... },      <=> #new(int[](), ...) <=> #new(#of(@`[]`, int)(), ...)
			//                    2b. new[,] { ... }.         <=> #new(@`[,]`(), ...)
			//                    2c. new int[10,10] { ... }, <=> #new(#of(@`[,]`, int)(10,10), ...)
			//                    2d. new int[10][] { ... },  <=> #new(#of(@`[]`, #of(@`[]`, int))(10), ...)
			if (HasPAttrs(cons))
				return false;
			if (type == null ? !cons.IsIdNamed(S.Missing) : HasPAttrs(type) || !IsComplexIdentifier(type))
				return false;

			// Okay, we can now be sure that it's printable, but is it an array decl?
			if (type == null) {
				// 1b, new {...}
				_out.Write("new ", true);
				PrintBracedBlockInNewExpr();
			} else if (type != null && type.IsId && S.CountArrayDimensions(type.Name) > 0) { // 2b
				_out.Write("new", true);
				_out.Write(type.Name.Name, true);
				Space(SpaceOpt.Default);
				PrintBracedBlockInNewExpr();
			} else {
				_out.Write("new ", true);
				int dims = CountDimensionsIfArrayType(type);
				if (dims > 0 && cons.Args.Count == dims) {
					PrintTypeWithArraySizes(cons);
				} else {
					// Otherwise we can print the type name without caring if it's an array or not.
					PrintType(type, EP.Primary.LeftContext(context));
					if (cons.ArgCount != 0 || (argCount == 1 && dims == 0))
						PrintArgList(cons, ParenFor.MethodCall, cons.ArgCount, 0, OmitMissingArguments);
				}
				if (_n.Args.Count > 1)
					PrintBracedBlockInNewExpr();
			}
			return true;
		}
		void PrintExpr(LNode n, Precedence context, Ambiguity flags = 0)
		{
			using (With(n))
				PrintExpr(context, flags);
		}
		public bool AutoPrintInfixBinaryOperator(Precedence prec, Precedence context, Ambiguity flags)
		{
			var name = _n.Name;
			Debug.Assert(!CastOperators.ContainsKey(name)); // not called for cast operators
			if (_n.ArgCount != 2)
				return false;
			// Attributes on the children disqualify operator notation
			LNode left = _n.Args[0], right = _n.Args[1];
			if (HasPAttrs(left) || HasPAttrs(right))
				return false;

			bool needParens, backtick = (_n.Style & NodeStyle.Alternate) != 0;
			if (CanAppearIn(ref prec, context, out needParens, ref backtick))
			{
				// Check for the ambiguous case of "A * b;" and consider using `*` instead
				if (name == S.Mul && context.Left == StartStmt.Left && IsComplexIdentifier(left)) {
					backtick = true;
					prec = EP.Backtick;
					if (!CanAppearIn(prec, context, out needParens, false))
						return false;
				}

				if (WriteOpenParen(ParenFor.Grouping, needParens))
					context = StartExpr;
				PrintExpr(left, prec.LeftContext(context), (name == S.Assign || name == S.Lambda ? Ambiguity.AllowUnassignedVarDecl : 0));
				if (backtick)
					flags |= Ambiguity.UseBacktick;
				PrintInfixWithSpace(_n.Name, prec, flags);
				PrintExpr(right, prec.RightContext(context));
				WriteCloseParen(ParenFor.Grouping, needParens);
				return true;
			}
			return false;
		}
		public bool AutoPrintOtherSpecialOperator(Precedence precedence, Precedence context, Ambiguity flags)
		{
			// Handles one of:  ?  []  suf++  suf--
			int argCount = _n.ArgCount;
			Symbol name = _n.Name;
			if (argCount < 1)
				return false; // no args
			bool needParens;
			if (!CanAppearIn(precedence, context, out needParens))
				return false; // precedence fail

			// Verify that the special operator can appear at this precedence 
			// level and that its arguments fit the operator's constraints.
			var first = _n.Args[0];
			if (name == S.Bracks) {
				// Careful: a[] means #of(@`[]`, a) in a type context, @`[]`(a) otherwise
				int minArgs = (flags&Ambiguity.TypeContext)!=0 ? 2 : 1;
				if (argCount < minArgs || HasPAttrs(first))
					return false;
			} else if (name == S.QuestionMark) {
				if (argCount != 3 || HasPAttrs(first) || HasPAttrs(_n.Args[1]) || HasPAttrs(_n.Args[2]))
					return false;
			} else {
				Debug.Assert(name == S.PostInc || name == S.PostDec || name == S.IsLegal);
				if (argCount != 1 || HasPAttrs(first))
					return false;
			}

			// Print the thing!
			WriteOpenParen(ParenFor.Grouping, needParens);

			if (name == S.Bracks)
			{
				PrintExpr(first, precedence.LeftContext(context));
				Space(SpaceOpt.BeforeMethodCall);
				_out.Write('[', true);
				Space(SpaceOpt.InsideCallParens);
				for (int i = 1, c = _n.ArgCount; i < c; i++)
				{
					if (i != 1) WriteThenSpace(',', SpaceOpt.AfterComma);
					PrintExpr(_n.Args[i], StartExpr);
				}
				Space(SpaceOpt.InsideCallParens);
				_out.Write(']', true);
			}
			else if (name == S.QuestionMark)
			{
				PrintExpr(_n.Args[0], precedence.LeftContext(context));
				PrintInfixWithSpace(S.QuestionMark, EP.IfElse, 0);
				PrintExpr(_n.Args[1], ContinueExpr);
				PrintInfixWithSpace(S.Colon, EP.IfElse, 0);
				PrintExpr(_n.Args[2], precedence.RightContext(context));
			}
			else
			{
				Debug.Assert(name == S.PostInc || name == S.PostDec || name == S.IsLegal);
				PrintExpr(first, precedence.LeftContext(context));
				_out.Write(name == S.PostInc ? "++" : name == S.PostDec ? "--" : "is legal", true);
			}

			WriteCloseParen(ParenFor.Grouping, needParens);
			return true;
		}
Exemple #57
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);
        }
		public bool AutoPrintPrefixOrInfixOperator(Precedence infixPrec, Precedence context, Ambiguity flags)
		{
			if (_n.ArgCount == 2)
				return AutoPrintInfixBinaryOperator(infixPrec, context, flags);
			else
				return AutoPrintPrefixUnaryOperator(PrefixOperators[_n.Name], context, flags);
		}
		protected void PrintType(LNode n, Precedence context, Ambiguity flags = 0)
		{
			using (With(n, context, CheckOneLiner(flags | Ambiguity.TypeContext, n)))
				PrintCurrentType();
		}
		private void WriteOperatorName(Symbol name, Ambiguity flags = 0)
		{
			string opName = name.Name;
			if ((flags & Ambiguity.UseBacktick) != 0)
				PrintString(opName, '`', null);
			else if (opName.StartsWith("#"))
				_out.Write(opName.Substring(1), true);
			else
				_out.Write(opName, true);
		}