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); } }
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); } }
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); } }
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); }
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); }
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); }
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); }
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(' '); } }
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); }
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); } }
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)); }
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(' '); } }
// 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); } }
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 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)); }
/// <summary>Given a complex name such as <c>global::Foo<int>.Bar<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<T></c> => Foo.</summary> /// <remarks>This was moved to EcsValidators.</remarks> public static Symbol KeyNameComponentOf(LNode name) { return(EcsValidators.KeyNameComponentOf(name)); }
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); }