Skip to content

Commit

Permalink
Rework block handling in C# and VB formatters; fixes #67
Browse files Browse the repository at this point in the history
  • Loading branch information
zspitz committed Jun 18, 2019
1 parent be88bd8 commit e5c4217
Show file tree
Hide file tree
Showing 17 changed files with 428 additions and 195 deletions.
21 changes: 21 additions & 0 deletions Shared/CSharpBlockMetadata.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static ExpressionToString.CSharpMultilineBlockTypes;

namespace ExpressionToString {
//internal class CSharpBlockMetadata {
// internal CSharpMultilineBlockTypes BlockType { get; private set; } = Inline;
// internal string Delimiter { get; private set; } = ",";
// internal static CSharpBlockMetadata CreateMetadata(CSharpMultilineBlockTypes blockType = Inline, string delimiter = ",") => new CSharpBlockMetadata {
// BlockType = blockType,
// Delimiter = delimiter
// };
// internal void Deconstruct(out CSharpMultilineBlockTypes blockType, out string delimiter) {
// blockType = BlockType;
// delimiter = Delimiter;
// }
//}
}
142 changes: 101 additions & 41 deletions Shared/CSharpCodeWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using static System.Linq.Enumerable;
using static System.Linq.Expressions.ExpressionType;
using static System.Linq.Expressions.GotoExpressionKind;
using static ExpressionToString.CSharpMultilineBlockTypes;

namespace ExpressionToString {
public class CSharpCodeWriter : WriterBase {
Expand Down Expand Up @@ -202,7 +203,20 @@ protected override void WriteLambda(LambdaExpression expr) {
Write("(");
WriteNodes("Parameters", expr.Parameters, false, ", ", true);
Write(") => ");
WriteNode("Body", expr.Body);

if (CanInline(expr.Body)) {
WriteNode("Body", expr.Body);
return;
}

Write("{");
Indent();
WriteEOL();
if (expr.Body.Type != typeof(void)) { Write("return "); }
WriteNode("Body", expr.Body, CSharpMultilineBlockTypes.Block);
WriteStatementEnd(expr.Body);
WriteEOL(true);
Write("}");
}

protected override void WriteParameterDeclarationImpl(ParameterExpression prm) {
Expand Down Expand Up @@ -437,24 +451,55 @@ protected override void WriteNewArray(NewArrayExpression expr) {
}
}

private bool CanInline(Expression expr) {
switch (expr) {
case ConditionalExpression cexpr when cexpr.Type == typeof(void):
case BlockExpression bexpr when
bexpr.Expressions.Count > 1 ||
bexpr.Variables.Any() ||
(bexpr.Expressions.Count == 1 && CanInline(bexpr.Expressions.First())):
case SwitchExpression _:
case LambdaExpression _:
case TryExpression _:
return false;
case RuntimeVariablesExpression _:
throw new NotImplementedException();
}
return true;
}

protected override void WriteConditional(ConditionalExpression expr) {
if (expr.Type == typeof(void)) { // if block, or if..else block
Write("if (");
WriteNode("Test", expr.Test, false, true);
Write(") ");
WriteNode("IfTrue", expr.IfTrue, false, true);
WriteSemicolon(expr.IfTrue);
if (!expr.IfFalse.IsEmpty()) {
Write(" else ");
WriteNode("IfFalse", expr.IfFalse, false, true);
WriteSemicolon(expr.IfFalse);
}
} else {
WriteNode("Test", expr.Test, false, true);
if (expr.Type != typeof(void)) {
WriteNode("Test", expr.Test);
Write(" ? ");
WriteNode("IfTrue", expr.IfTrue);
Write(" : ");
WriteNode("IfFalse", expr.IfFalse);
return;
}

Write("if (");
WriteNode("Test", expr.Test, Test);
Write(") {");
Indent();
WriteEOL();
WriteNode("IfTrue", expr.IfTrue, CSharpMultilineBlockTypes.Block);
WriteStatementEnd(expr.IfTrue);
WriteEOL(true);
Write("}");
if (!expr.IfFalse.IsEmpty()) {
Write(" else ");
if (!(expr.IfFalse is ConditionalExpression)) {
Write("{");
Indent();
WriteEOL();
}
WriteNode("IfFalse", expr.IfFalse, false, true);
WriteStatementEnd(expr.IfFalse);
if (!(expr.IfFalse is ConditionalExpression)) {
WriteEOL(true);
Write("}");
}
}
}

Expand Down Expand Up @@ -486,31 +531,46 @@ protected override void WriteInvocation(InvocationExpression expr) {
protected override void WriteIndex(IndexExpression expr) =>
WriteIndexerAccess("Object", expr.Object, "Arguments", expr.Arguments);

protected override void WriteBlock(BlockExpression expr, bool? explicitBlock) {
var useExplicitBlock = explicitBlock ?? expr.Variables.Count > 0;
if (useExplicitBlock) {
Write("{");
Indent();
WriteEOL();
expr.Variables.ForEach((v, index) => {
if (index > 0) { WriteEOL(); }
WriteNode($"Variables[{index}]", v, true);
protected override void WriteBlock(BlockExpression expr, object metadata) {
var blockType = (CSharpMultilineBlockTypes)(metadata ?? Inline);
if (blockType == CSharpMultilineBlockTypes.Block) {
expr.Variables.ForEach((subexpr, index) => {
WriteNode($"Variable[{index}]", subexpr, true);
Write(";");
WriteEOL();
});
expr.Expressions.ForEach((subexpr, index) => {
if (index > 0) { WriteEOL(); }
if (subexpr is LabelExpression) { TrimEnd(); }
WriteNode($"Expressions[{index}]", subexpr, CSharpMultilineBlockTypes.Block);
WriteStatementEnd(subexpr);
});
return;
}

if (expr.HasMultipleLines()) {
if (blockType == Inline) { Write("("); }
Indent();
WriteEOL();
}
WriteNodes("Variables", expr.Variables, true, ",", true);
expr.Expressions.ForEach((subexpr, index) => {
if (index > 0 || expr.Variables.Count > 0) { WriteEOL(); }
if (index > 0 || expr.Variables.Count > 0) {
var previousExpr = index > 0 ? expr.Expressions[index - 1] : null;
if (previousExpr is null || !(previousExpr is LabelExpression || subexpr is RuntimeVariablesExpression)) { Write(","); }
WriteEOL();
}
if (subexpr is LabelExpression) { TrimEnd(); }
WriteNode($"Expressions[{index}]", subexpr);
WriteSemicolon(subexpr);
});
if (useExplicitBlock) {
if (expr.HasMultipleLines()) {
WriteEOL(true);
Write("}");
if (blockType == Inline) { Write(")"); }
}
return;
}

private void WriteSemicolon(Expression expr) {
private void WriteStatementEnd(Expression expr) {
switch (expr) {
case ConditionalExpression cexpr when cexpr.Type == typeof(void):
case BlockExpression _:
Expand All @@ -533,15 +593,15 @@ protected override void WriteSwitchCase(SwitchCase switchCase) {
});
Indent();
WriteEOL();
WriteNode("Body", switchCase.Body, false, false);
WriteSemicolon(switchCase.Body);
WriteNode("Body", switchCase.Body, CSharpMultilineBlockTypes.Block);
WriteStatementEnd(switchCase.Body);
WriteEOL();
Write("break;");
}

protected override void WriteSwitch(SwitchExpression expr) {
Write("switch (");
WriteNode("SwitchValue", expr.SwitchValue, false, true);
WriteNode("SwitchValue", expr.SwitchValue, Test);
Write(") {");
Indent();
WriteEOL();
Expand All @@ -555,8 +615,8 @@ protected override void WriteSwitch(SwitchExpression expr) {
Write("default:");
Indent();
WriteEOL();
WriteNode("DefaultBody", expr.DefaultBody);
WriteSemicolon(expr.DefaultBody);
WriteNode("DefaultBody", expr.DefaultBody, CSharpMultilineBlockTypes.Block);
WriteStatementEnd(expr.DefaultBody);
Dedent();
}
WriteEOL(true);
Expand All @@ -575,15 +635,15 @@ protected override void WriteCatchBlock(CatchBlock catchBlock) {
Write(") ");
if (catchBlock.Filter != null) {
Write("when (");
WriteNode("Filter", catchBlock.Filter, false, true);
WriteNode("Filter", catchBlock.Filter, false, Test);
Write(") ");
}
}
Write("{");
Indent();
WriteEOL();
WriteNode("Body", catchBlock.Body);
WriteSemicolon(catchBlock.Body);
WriteNode("Body", catchBlock.Body, CSharpMultilineBlockTypes.Block);
WriteStatementEnd(catchBlock.Body);
WriteEOL(true);
Write("}");
}
Expand All @@ -593,7 +653,7 @@ protected override void WriteTry(TryExpression expr) {
Indent();
WriteEOL();
WriteNode("Body", expr.Body);
WriteSemicolon(expr.Body);
WriteStatementEnd(expr.Body);
WriteEOL(true);
Write("}");
expr.Handlers.ForEach((catchBlock, index) => {
Expand All @@ -605,7 +665,7 @@ protected override void WriteTry(TryExpression expr) {
Indent();
WriteEOL();
WriteNode("Fault", expr.Fault);
WriteSemicolon(expr.Fault);
WriteStatementEnd(expr.Fault);
WriteEOL(true);
Write("}");
}
Expand All @@ -614,7 +674,7 @@ protected override void WriteTry(TryExpression expr) {
Indent();
WriteEOL();
WriteNode("Finally", expr.Finally);
WriteSemicolon(expr.Finally);
WriteStatementEnd(expr.Finally);
WriteEOL(true);
Write("}");
}
Expand Down Expand Up @@ -660,8 +720,8 @@ protected override void WriteLoop(LoopExpression expr) {
Write("while (true) {");
Indent();
WriteEOL();
WriteNode("Body", expr.Body);
WriteSemicolon(expr.Body);
WriteNode("Body", expr.Body,CSharpMultilineBlockTypes.Block);
WriteStatementEnd(expr.Body);
WriteEOL(true);
Write("}");
}
Expand Down
13 changes: 13 additions & 0 deletions Shared/CSharpMultilineBlockTypes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ExpressionToString {
public enum CSharpMultilineBlockTypes {
Inline,
Test,
Block
}
}
2 changes: 1 addition & 1 deletion Shared/FactoryMethodsFormatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ protected override void WriteIndex(IndexExpression expr) {
WriteMethodCall(() => ArrayAccess(expr.Object, expr.Arguments.ToArray()));
}

protected override void WriteBlock(BlockExpression expr, bool? explicitBlock = null) {
protected override void WriteBlock(BlockExpression expr, object metadata) {
if (expr.Type != expr.Expressions.Last().Type) {
if (expr.Variables.Any()) {
WriteMethodCall(() => Block(expr.Type, expr.Variables, expr.Expressions.ToArray()));
Expand Down
4 changes: 4 additions & 0 deletions Shared/Shared.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@
<Import_RootNamespace>ExpressionToString</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)CSharpBlockMetadata.cs" />
<Compile Include="$(MSBuildThisFileDirectory)CSharpMultilineBlockTypes.cs" />
<Compile Include="$(MSBuildThisFileDirectory)FactoryMethodsFormatter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Util\Extensions\BlockExpression.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Util\Extensions\IListT.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Util\Extensions\MethodInfo.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Util\Extensions\ParameterInfo.cs" />
<Compile Include="$(MSBuildThisFileDirectory)VBBlockMetadata.cs" />
<Compile Include="$(MSBuildThisFileDirectory)WriterBase.cs" />
<Compile Include="$(MSBuildThisFileDirectory)CSharpCodeWriter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ExpressionExtension.cs" />
Expand Down
12 changes: 12 additions & 0 deletions Shared/Util/Extensions/BlockExpression.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace ExpressionToString.Util {
public static class BlockExpressionExtensions {
public static bool HasMultipleLines(this BlockExpression expr) => expr.Variables.Any() || expr.Expressions.Count > 1;
}
}
16 changes: 16 additions & 0 deletions Shared/VBBlockMetadata.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ExpressionToString {
internal class VBBlockMetadata {
internal bool IsInMutiline { get; private set; }
internal bool ParentIsBlock { get; set; }
internal static VBBlockMetadata CreateMetadata(bool isInMultiline, bool parentIsBlock) => new VBBlockMetadata {
IsInMutiline = isInMultiline,
ParentIsBlock = parentIsBlock
};
}
}
Loading

0 comments on commit e5c4217

Please sign in to comment.